Changes in db for R3.12 LANL / ANL merge (except dbAccess.c)
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*atodb.c*/
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
/*
|
||||
*
|
||||
* Author: Marty Kraimer
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/* callback.c */
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
|
||||
/* general purpose callback tasks */
|
||||
/*
|
||||
|
||||
+997
@@ -0,0 +1,997 @@
|
||||
/* dbBkpt.c */
|
||||
/* base/src/db $Id$ */
|
||||
/*
|
||||
* Author: Matthew Needes
|
||||
* Date: 8-30-93
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Database Breakpoint Manipulation and User Interface
|
||||
*
|
||||
* USER COMMANDS
|
||||
* dbb(record_name) Set a breakpoint in a record
|
||||
* dbd(record_name) Delete a record's breakpoint
|
||||
* dbc(record_name) Resume record processing
|
||||
* dbs(record_name) Step through record processing through
|
||||
* IO links, forward process links, etc.
|
||||
* dbstat() Display status of stopped records in lock sets.
|
||||
* dbap(record_name) Toggle automatic print after processing.
|
||||
* dbp(record_name) Print out fields from record currently stopped.
|
||||
* dbprc(record_name) Processes a record once without printing it.
|
||||
* (Unless autoprint is on)
|
||||
*
|
||||
* INTERNAL FUNCTIONS
|
||||
* dbBkpt() Process breakpoints, called by dbProcess().
|
||||
* dbPrint() Prints record if autoprint enabled.
|
||||
* dbBkptCont() The task that continues and steps through
|
||||
* records that are stopped at a breakpoint.
|
||||
*/
|
||||
|
||||
/* #define BKPT_DIAG */
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <lstLib.h>
|
||||
#include <types.h>
|
||||
#include <memLib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdioLib.h>
|
||||
#include <string.h>
|
||||
#include <taskLib.h>
|
||||
#include <vxLib.h>
|
||||
#include <tickLib.h>
|
||||
|
||||
#include <fast_lock.h>
|
||||
#include <alarm.h>
|
||||
#include <choice.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbBase.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbManipulate.h>
|
||||
#include <dbScan.h>
|
||||
#include <rec/dbCommon.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <dbRecDes.h>
|
||||
#include <dbRecType.h>
|
||||
#include <dbRecords.h>
|
||||
#include <dbBkpt.h>
|
||||
#include <db_field_log.h>
|
||||
#include <errMdef.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <task_params.h>
|
||||
|
||||
/* private routines */
|
||||
static void remove_lset_from_stack();
|
||||
static void dbBkptCont();
|
||||
static long FIND_CONT_NODE();
|
||||
|
||||
/*
|
||||
* Breakpoints are used as a debugging instrument to suspend the
|
||||
* processing of database records. Once suspended, record
|
||||
* processing may continue if either a continue (dbc()) or a
|
||||
* step (dbs()) command is then issued. The current record's
|
||||
* contents may be printed either with dbp(), or immediately
|
||||
* after processing (use dbap() to toggle the BKPT_PRINT bit).
|
||||
*
|
||||
* dbb() and dbd() add a breakpoint to a record or delete one
|
||||
* from a record. dbstat() prints out comprehensive breakpoint
|
||||
* status information.
|
||||
*
|
||||
* Breakpoints may be set on a per lockset basis. When a
|
||||
* breakpoint is set in a lockset, a new task is created. A
|
||||
* separate task gets created for _every_ lockset containing
|
||||
* a breakpoint. Thus multiple locksets may be debugged
|
||||
* simultaneously. The breakpoint handler then schedules future
|
||||
* processing in that lockset to this task. The separate task is
|
||||
* used so that locksets that do not have breakpoints are isolated
|
||||
* from locksets that do. This allows the processing of other
|
||||
* locksets to continue uninterupted, even if they exist on the same
|
||||
* scan list as a lockset containing a breakpoint.
|
||||
*
|
||||
* An entrypoint is the first record that gets processed in a lockset.
|
||||
* This type of record is the basis for subsequent recursive executions
|
||||
* of dbProcess(). The breakpoint handler monitors and schedules
|
||||
* these entrypoints to the breakpoint tasks.
|
||||
*
|
||||
* Two hooks have been inserted in dbProcess() to manage breakpoints,
|
||||
* dbBkpt() and dbPrint(). The former does two things:
|
||||
*
|
||||
* 1. Schedule entrypoints with the breakpoint task.
|
||||
* 2. Suspend record processing when a breakpoint is detected.
|
||||
*
|
||||
* 1 occurs only if dbProcess() is called outside of the breakpoint
|
||||
* task. Number 2 only occurs when dbProcess() is called from
|
||||
* _within_ the breakpoint task's context. Number 1 is used for
|
||||
* detection and scheduling, while 2 is used for suspending the task.
|
||||
*
|
||||
* The dbPrint() hook is used to print out a record's contents immediately
|
||||
* _after_ a record has been processed.
|
||||
*
|
||||
* The dbBkptCont, or breakpoint task, pends on a semaphore that gets
|
||||
* released whenever new entrypoints are scheduled for it. When
|
||||
* released, this task then runs down its entrypoint queue and
|
||||
* processes each entrypoint in turn. In this context, dbProcess
|
||||
* will execute the dbBkpt() hook in mode 2, allowing this task to
|
||||
* be suspended whenever a breakpoint is detected.
|
||||
*
|
||||
* NOTE: This is not a very "real-time" implementation (even for those
|
||||
* locksets not containing a breakpoint). I may fix this later.
|
||||
*
|
||||
* Final comment: The scary thing is, I don't think this can be done
|
||||
* more simply...
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Flag used by dbProcess() to determine if there are
|
||||
* any breakpoints. This is so that there is only
|
||||
* a single comparison in the critical path during
|
||||
* normal record execution, i.e. when there aren't
|
||||
* any breakpoints set.
|
||||
*/
|
||||
long lset_stack_not_empty = 0;
|
||||
|
||||
/*
|
||||
* Stack--in which each entry represents a different
|
||||
* lock set with either breakpoints and/or stopped
|
||||
* execution. (Breakpoints may be disabled even
|
||||
* though execution is stopped). The order of the
|
||||
* list is maintained so that the entry on the top
|
||||
* of stack is used as a default for dbc() and dbs().
|
||||
* The semaphore is used to prevent conflicts while
|
||||
* operating with this stack.
|
||||
*/
|
||||
static LIST lset_stack;
|
||||
static SEM_ID bkpt_stack_sem;
|
||||
|
||||
/*
|
||||
* Stores the last lockset continued or stepped from.
|
||||
* dbs() and dbc() will print a message if the current
|
||||
* lockset to be continued from differs from this
|
||||
* variable.
|
||||
*/
|
||||
static short last_lset = 0;
|
||||
|
||||
/*
|
||||
* FIND_LOCKSET() finds the stack entry
|
||||
* whose l_num field matches precord's
|
||||
* lset field. The node that is found
|
||||
* is returned in "pnode."
|
||||
*/
|
||||
#define FIND_LOCKSET(precord, pnode) \
|
||||
pnode = (struct LS_LIST *) lstFirst(&lset_stack); \
|
||||
while ((pnode) != NULL) { \
|
||||
if ((pnode)->l_num == (precord)->lset) break; \
|
||||
pnode = (struct LS_LIST *) lstNext((NODE *)pnode); \
|
||||
} \
|
||||
|
||||
/*
|
||||
* FIND_QUEUE_ENTRY() matches entries in an
|
||||
* entry point queue. pep_queue is the queue
|
||||
* being searched, pqe is the pointer to the
|
||||
* queue entry found, and precord is the record
|
||||
* being searched for in *pep_queue.
|
||||
*/
|
||||
#define FIND_QUEUE_ENTRY(pep_queue, pqe, precord) \
|
||||
pqe = (struct EP_LIST *) lstFirst(pep_queue); \
|
||||
while ((pqe) != NULL) { \
|
||||
if ((pqe)->entrypoint == (precord)) break; \
|
||||
pqe = (struct EP_LIST *) lstNext((NODE *)pqe); \
|
||||
} \
|
||||
|
||||
/*
|
||||
* Fills out pnode and precord structures for dbc() and dbs()
|
||||
* MUST LOCK OUT STACK BEFORE ENTRY
|
||||
*/
|
||||
static long FIND_CONT_NODE(
|
||||
char *record_name,
|
||||
struct LS_LIST **ppnode,
|
||||
struct dbCommon **pprecord)
|
||||
{
|
||||
struct dbAddr addr;
|
||||
struct LS_LIST *pnode;
|
||||
struct dbCommon *precord = NULL;
|
||||
long status = 0;
|
||||
|
||||
if (record_name == NULL) {
|
||||
/*
|
||||
* Search through stack, taking the first entry that
|
||||
* is currently stopped at a breakpoint.
|
||||
*/
|
||||
pnode = (struct LS_LIST *) lstFirst(&lset_stack);
|
||||
while (pnode != NULL) {
|
||||
if (pnode->precord != NULL) {
|
||||
precord = pnode->precord;
|
||||
break;
|
||||
}
|
||||
pnode = (struct LS_LIST *) lstNext((NODE *)pnode);
|
||||
}
|
||||
|
||||
if (pnode == NULL) {
|
||||
printf(" BKPT> No records are currently stopped\n");
|
||||
return(S_db_notStopped);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Convert name to address
|
||||
*/
|
||||
status = dbNameToAddr(record_name, &addr);
|
||||
if (status == S_db_notFound)
|
||||
printf(" BKPT> Record %s not found\n", record_name);
|
||||
if (status != 0)
|
||||
return(status);
|
||||
|
||||
precord = addr.precord;
|
||||
|
||||
FIND_LOCKSET(precord, pnode);
|
||||
|
||||
if (pnode == NULL || pnode->precord == NULL) {
|
||||
printf(" BKPT> Currently not stopped in this lockset\n");
|
||||
return(S_db_notStopped);
|
||||
}
|
||||
}
|
||||
|
||||
*pprecord = precord;
|
||||
*ppnode = pnode;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add breakpoint to a lock set
|
||||
* 1. Convert name to address and check breakpoint mask.
|
||||
* 2. Lock database.
|
||||
* 3. If empty, initialize lock set stack and its semaphore.
|
||||
* 4. Take that semaphore.
|
||||
* 5. Find lockset in the list. If it doesn't exist, create it.
|
||||
* 6. Turn on breakpoint field in record.
|
||||
* 7. Add breakpoint to list of breakpoints in structure.
|
||||
* 8. Spawn continuation task if it isn't already running.
|
||||
*/
|
||||
long dbb(char *record_name)
|
||||
{
|
||||
struct dbAddr addr;
|
||||
struct LS_LIST *pnode;
|
||||
struct BP_LIST *pbl;
|
||||
struct dbCommon *precord;
|
||||
long status;
|
||||
|
||||
/*
|
||||
* Convert name to address
|
||||
*/
|
||||
status = dbNameToAddr(record_name, &addr);
|
||||
if (status == S_db_notFound)
|
||||
printf(" BKPT> Record %s not found\n", record_name);
|
||||
if (status != 0) return(status);
|
||||
|
||||
precord = addr.precord;
|
||||
|
||||
if (precord->bkpt & BKPT_ON_MASK) {
|
||||
printf(" BKPT> Breakpoint already set in this record\n");
|
||||
return(S_db_bkptSet);
|
||||
}
|
||||
|
||||
dbScanLock(precord);
|
||||
|
||||
/*
|
||||
* Add lock set to the stack of lock sets that
|
||||
* contain breakpoints and/or stopped records.
|
||||
*/
|
||||
if (! lset_stack_not_empty) {
|
||||
/* initialize list and semaphore */
|
||||
bkpt_stack_sem = semBCreate(SEM_Q_FIFO, SEM_FULL);
|
||||
if (bkpt_stack_sem == NULL) {
|
||||
printf(" BKPT> Out of memory\n");
|
||||
dbScanUnlock(precord);
|
||||
return(1);
|
||||
}
|
||||
lstInit(&lset_stack);
|
||||
lset_stack_not_empty = 1;
|
||||
}
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
|
||||
FIND_LOCKSET(precord, pnode);
|
||||
|
||||
if (pnode == NULL) {
|
||||
/* lockset not found, create node, add to end of list */
|
||||
pnode = (struct LS_LIST *) malloc(sizeof(struct LS_LIST));
|
||||
if (pnode == NULL) {
|
||||
printf(" BKPT> Out of memory\n");
|
||||
dbScanUnlock(precord);
|
||||
semGive(bkpt_stack_sem);
|
||||
return(1);
|
||||
}
|
||||
pnode->precord = NULL;
|
||||
|
||||
/* initialize breakpoint list */
|
||||
lstInit(&pnode->bp_list);
|
||||
|
||||
/* initialize entry point queue */
|
||||
lstInit(&pnode->ep_queue);
|
||||
|
||||
/* create execution semaphore */
|
||||
pnode->ex_sem = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
|
||||
if (pnode->ex_sem == NULL) {
|
||||
printf(" BKPT> Out of memory\n");
|
||||
dbScanUnlock(precord);
|
||||
semGive(bkpt_stack_sem);
|
||||
return(1);
|
||||
}
|
||||
|
||||
pnode->taskid = 0;
|
||||
pnode->step = 0;
|
||||
pnode->l_num = precord->lset;
|
||||
lstAdd(&lset_stack, (NODE *)pnode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add record to breakpoint list
|
||||
*/
|
||||
pbl = (struct BP_LIST *) malloc(sizeof(struct BP_LIST));
|
||||
if (pbl == NULL) {
|
||||
printf(" BKPT> Out of memory\n");
|
||||
dbScanUnlock(precord);
|
||||
semGive(bkpt_stack_sem);
|
||||
return(1);
|
||||
}
|
||||
pbl->precord = precord;
|
||||
lstAdd(&pnode->bp_list, (NODE *)pbl);
|
||||
|
||||
/*
|
||||
* Turn on breakpoint field in record
|
||||
*/
|
||||
precord->bkpt |= BKPT_ON_MASK;
|
||||
|
||||
if (! pnode->taskid) {
|
||||
|
||||
#ifdef BKPT_DIAG
|
||||
printf(" BKPT> Spawning task: %s\n", precord->name);
|
||||
#endif BKPT_DIAG
|
||||
/*
|
||||
* Spawn continuation task
|
||||
*/
|
||||
pnode->taskid = taskSpawn(BKPT_CONT_NAME, PERIODSCAN_PRI, BKPT_CONT_OPT,
|
||||
BKPT_CONT_STACK, (FUNCPTR) dbBkptCont,(int) precord,
|
||||
0,0,0,0,0,0,0,0,0);
|
||||
|
||||
if (pnode->taskid == ERROR) {
|
||||
printf(" BKPT> Cannot spawn task to process record\n");
|
||||
pnode->taskid = 0;
|
||||
dbScanUnlock(precord);
|
||||
semGive(bkpt_stack_sem);
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
dbScanUnlock(precord);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove breakpoint from a record
|
||||
* 1. Convert name to address and check breakpoint mask.
|
||||
* 2. Lock database and take stack semaphore.
|
||||
* 3. Find structure for record's lockset (in stack).
|
||||
* 4. Find and delete record from breakpoint list.
|
||||
* 5. Turn off break point field.
|
||||
* 6. Give up semaphore to "signal" bkptCont task to quit.
|
||||
*/
|
||||
long dbd(char *record_name)
|
||||
{
|
||||
struct dbAddr addr;
|
||||
struct LS_LIST *pnode;
|
||||
struct BP_LIST *pbl;
|
||||
struct dbCommon *precord;
|
||||
long status;
|
||||
|
||||
/*
|
||||
* Convert name to address
|
||||
*/
|
||||
status = dbNameToAddr(record_name, &addr);
|
||||
if (status == S_db_notFound)
|
||||
printf(" BKPT> Record %s not found\n", record_name);
|
||||
if (status != 0) return(status);
|
||||
|
||||
precord = addr.precord;
|
||||
|
||||
if (! precord->bkpt & BKPT_ON_MASK) {
|
||||
printf(" BKPT> No breakpoint set in this record\n");
|
||||
return(S_db_bkptNotSet);
|
||||
}
|
||||
|
||||
dbScanLock(precord);
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
|
||||
FIND_LOCKSET(precord, pnode);
|
||||
|
||||
if (pnode == NULL) {
|
||||
/* not found, error ! */
|
||||
printf(" BKPT> Logic Error in dbd()\n");
|
||||
precord->bkpt &= BKPT_OFF_MASK;
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
dbScanUnlock(precord);
|
||||
return(S_db_bkptLogic);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove record from breakpoint list
|
||||
*/
|
||||
|
||||
/* find record in list */
|
||||
pbl = (struct BP_LIST *) lstFirst(&pnode->bp_list);
|
||||
while (pbl != NULL) {
|
||||
if (pbl->precord == precord) {
|
||||
lstDelete(&pnode->bp_list, (NODE *)pbl);
|
||||
free(pbl);
|
||||
break;
|
||||
}
|
||||
pbl = (struct BP_LIST *) lstNext((NODE *)pbl);
|
||||
}
|
||||
|
||||
if (pbl == NULL) {
|
||||
printf(" BKPT> Logic Error in dbd()\n");
|
||||
precord->bkpt &= BKPT_OFF_MASK;
|
||||
semGive(bkpt_stack_sem);
|
||||
dbScanUnlock(precord);
|
||||
return(S_db_bkptLogic);
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn off breakpoint field in record
|
||||
*/
|
||||
precord->bkpt &= BKPT_OFF_MASK;
|
||||
|
||||
/*
|
||||
* If there are no more breakpoints, give up semaphore
|
||||
* to cause the bkptCont task to quit.
|
||||
*/
|
||||
if (lstCount(&pnode->bp_list) == 0)
|
||||
semGive(pnode->ex_sem);
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
|
||||
dbScanUnlock(precord);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Continue processing in a lock set
|
||||
* 1. Find top node in the lockset stack.
|
||||
* 2. Turn off stepping mode.
|
||||
* 2. Resume dbBkptCont.
|
||||
*/
|
||||
long dbc(char *record_name)
|
||||
{
|
||||
struct LS_LIST *pnode;
|
||||
struct dbCommon *precord = NULL;
|
||||
long status = 0;
|
||||
int taskid;
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
|
||||
status = FIND_CONT_NODE(record_name, &pnode, &precord);
|
||||
if (status) {
|
||||
semGive(bkpt_stack_sem);
|
||||
return(status);
|
||||
}
|
||||
|
||||
if (record_name == NULL && last_lset != pnode->l_num);
|
||||
printf(" BKPT> Continuing: %s\n", pnode->precord->name);
|
||||
|
||||
last_lset = pnode->l_num;
|
||||
|
||||
/*
|
||||
* Turn off stepping mode
|
||||
*/
|
||||
pnode->step = 0;
|
||||
|
||||
/*
|
||||
* Resume dbBkptCont() until dbProcess() is executed
|
||||
* for a record with a breakpoint. This occurs
|
||||
* because stepping mode has been switched off.
|
||||
*/
|
||||
if (taskResume(pnode->taskid) == ERROR) {
|
||||
printf(" BKPT> Cannot continue\n");
|
||||
semGive(bkpt_stack_sem);
|
||||
return(S_db_cntCont);
|
||||
}
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Step through record processing
|
||||
* 1. Find top node in lockset stack.
|
||||
* 2. Resume dbBkptCont.
|
||||
*/
|
||||
long dbs(char *record_name)
|
||||
{
|
||||
struct LS_LIST *pnode;
|
||||
static struct dbAddr addr;
|
||||
struct dbCommon *precord = NULL;
|
||||
long status = 0;
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
|
||||
status = FIND_CONT_NODE(record_name, &pnode, &precord);
|
||||
if (status) {
|
||||
semGive(bkpt_stack_sem);
|
||||
return(status);
|
||||
}
|
||||
|
||||
if (last_lset != pnode->l_num && record_name == NULL)
|
||||
printf(" BKPT> Stepping: %s\n", pnode->precord->name);
|
||||
|
||||
last_lset = pnode->l_num;
|
||||
|
||||
if (taskResume(pnode->taskid) == ERROR) {
|
||||
printf(" BKPT> Cannot step\n");
|
||||
semGive(bkpt_stack_sem);
|
||||
return(S_db_cntCont);
|
||||
}
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Task for continuing record processing
|
||||
* 1. Find lockset in stack for precord.
|
||||
* DO 2-3 while breakpoints exist in the lockset.
|
||||
* 2. Wait on execution semaphore ...
|
||||
* 3. Run through every entrypoint in queue, processing
|
||||
* those that are scheduled.
|
||||
* 4. Free resources for lockset, and exit task.
|
||||
*/
|
||||
static void dbBkptCont(struct dbCommon *precord)
|
||||
{
|
||||
struct LS_LIST *pnode;
|
||||
struct EP_LIST *pqe = NULL;
|
||||
|
||||
/*
|
||||
* Reset breakpoint, process record, and
|
||||
* reset bkpt field in record
|
||||
*/
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
|
||||
FIND_LOCKSET(precord, pnode);
|
||||
|
||||
if (pnode == NULL) {
|
||||
printf(" BKPT> Logic error in dbBkptCont()\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* For every entrypoint scheduled, process. Run process
|
||||
* until there are no more breakpoints remaining in a
|
||||
* lock set.
|
||||
*/
|
||||
do {
|
||||
/* Give up semaphore before waiting to run ... */
|
||||
semGive(bkpt_stack_sem);
|
||||
|
||||
/* Wait to run */
|
||||
semTake(pnode->ex_sem, WAIT_FOREVER);
|
||||
|
||||
/* Bkpt stack must still be stable ! */
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
|
||||
pqe = (struct EP_LIST *) lstFirst(&pnode->ep_queue);
|
||||
|
||||
/* Run through entrypoint queue */
|
||||
while (pqe != NULL) {
|
||||
/* check if entrypoint is currently scheduled */
|
||||
if (pqe->sched) {
|
||||
/* save current entrypoint */
|
||||
pnode->current_ep = pqe->entrypoint;
|
||||
|
||||
/* lock the lockset, process record, unlock */
|
||||
dbScanLock(precord);
|
||||
dbProcess(pqe->entrypoint);
|
||||
dbScanUnlock(precord);
|
||||
|
||||
/* reset schedule and stepping flag - Do this AFTER processing */
|
||||
pqe->sched = 0;
|
||||
pnode->step = 0;
|
||||
}
|
||||
pqe = (struct EP_LIST *) lstNext((NODE *)pqe);
|
||||
}
|
||||
|
||||
/* Reset precord. (Since no records are at a breakpoint) */
|
||||
pnode->precord = NULL;
|
||||
}
|
||||
while (lstCount(&pnode->bp_list) != 0);
|
||||
|
||||
/* remove node from lockset stack */
|
||||
lstDelete(&lset_stack, (NODE *)pnode);
|
||||
|
||||
/* free entrypoint queue */
|
||||
lstFree(&pnode->ep_queue);
|
||||
|
||||
/* remove execution semaphore */
|
||||
semDelete(pnode->ex_sem);
|
||||
|
||||
printf("\n BKPT> End debug of lockset %d\n-> ", pnode->l_num);
|
||||
|
||||
/* free list node */
|
||||
free(pnode);
|
||||
|
||||
/* if last node on stack ... */
|
||||
if (lstCount(&lset_stack) == 0) {
|
||||
/* Unset flag, delete stack semaphore */
|
||||
lset_stack_not_empty = 0;
|
||||
semDelete(bkpt_stack_sem);
|
||||
}
|
||||
|
||||
if (lset_stack_not_empty)
|
||||
semGive(bkpt_stack_sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process breakpoint
|
||||
* Returns a zero if dbProcess() is to execute
|
||||
* record support, a one if dbProcess() is to
|
||||
* skip over record support. See dbProcess().
|
||||
*
|
||||
* 1. See if there is at least a breakpoint set somewhere
|
||||
* in precord's lockset. If not, return immediately.
|
||||
* 2. Check the disable flag.
|
||||
* 3. Add entry points to the queue for future stepping and
|
||||
* schedule new entrypoints for the continuation task.
|
||||
* 4. Check the pact flag.
|
||||
* 5. Check to see if there is a breakpoint set in a record, and
|
||||
* if so, turn on stepping mode.
|
||||
* 6. If stepping mode is set, stop and report the breakpoint.
|
||||
*/
|
||||
int dbBkpt(struct dbCommon *precord)
|
||||
{
|
||||
struct LS_LIST *pnode;
|
||||
struct EP_LIST *pqe;
|
||||
long nRequest = 1, options = 0;
|
||||
|
||||
/*
|
||||
* It is crucial that operations in dbBkpt() execute
|
||||
* in the correct order or certain features in the
|
||||
* breakpoint handler will not work as expected.
|
||||
*/
|
||||
|
||||
FIND_LOCKSET(precord, pnode);
|
||||
|
||||
if (pnode == NULL) {
|
||||
/* no breakpoints in precord's lockset */
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Check disable flag */
|
||||
recGblGetFastLink(&precord->sdis, (void *) precord, &precord->disa);
|
||||
|
||||
if (precord->disa == precord->disv) {
|
||||
/*
|
||||
* Do not process breakpoints if the record is disabled,
|
||||
* but allow disable alarms. Alarms will be raised
|
||||
* in dbProcess() because returning 0 allows dbProcess()
|
||||
* to continue. However processing will be prevented
|
||||
* because disa and disv will be examined again in
|
||||
* dbProcess(). Note that checking for pact will occur
|
||||
* before checking for disa and disv in dbProcess().
|
||||
*/
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Queue entry points for future stepping. The taskid comparison
|
||||
* is used to determine if the source of processing is the
|
||||
* continuation task or an external source. If it is an external
|
||||
* source, queue its execution, but dump out of dbProcess without
|
||||
* calling record support.
|
||||
*/
|
||||
if (pnode->taskid && (taskIdSelf() != pnode->taskid)) {
|
||||
/* CONTINUE TASK CANNOT ENTER HERE */
|
||||
|
||||
/*
|
||||
* Add an entry point to queue, if it does
|
||||
* not already exist.
|
||||
*/
|
||||
FIND_QUEUE_ENTRY(&pnode->ep_queue, pqe, precord);
|
||||
|
||||
if (pqe == NULL) {
|
||||
|
||||
pqe = (struct EP_LIST *) malloc(sizeof(struct EP_LIST));
|
||||
if (pqe == NULL)
|
||||
return(1);
|
||||
|
||||
|
||||
pqe->entrypoint = precord;
|
||||
pqe->count = 1;
|
||||
pqe->time = tickGet();
|
||||
pqe->sched = 0;
|
||||
|
||||
#ifdef BKPT_DIAG
|
||||
printf(" BKPT> Adding entrypoint %s to queue\n", precord->name);
|
||||
#endif BKPT_DIAG
|
||||
|
||||
/*
|
||||
* Take semaphore, wait on continuation task
|
||||
*/
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
|
||||
/* Add entry to queue */
|
||||
lstAdd(&pnode->ep_queue, (NODE *)pqe);
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
}
|
||||
else {
|
||||
if (pqe->count < MAX_EP_COUNT)
|
||||
pqe->count++;
|
||||
}
|
||||
|
||||
/* check pact */
|
||||
if (! precord->pact) {
|
||||
/* schedule if pact not set */
|
||||
pqe->sched = 1;
|
||||
|
||||
/*
|
||||
* Release the semaphore, letting the continuation
|
||||
* task begin execution of the new entrypoint.
|
||||
*/
|
||||
semGive(pnode->ex_sem);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't mess with breakpoints if pact set! Skip
|
||||
* over rest of dbProcess() since we don't want
|
||||
* alarms going off. The pact flag is checked
|
||||
* AFTER entry point queuing so that the record
|
||||
* timing feature will work properly.
|
||||
*/
|
||||
if (precord->pact)
|
||||
return(1);
|
||||
|
||||
/* Turn on stepping mode if a breakpoint is found */
|
||||
if (precord->bkpt & BKPT_ON_MASK) {
|
||||
pnode->step = 1;
|
||||
|
||||
#ifdef BKPT_DIAG
|
||||
printf(" BKPT> Bkpt detected: %s\n", precord->name);
|
||||
#endif BKPT_DIAG
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are currently stepping through the lockset,
|
||||
* suspend task.
|
||||
*/
|
||||
if (pnode->step) {
|
||||
printf("\n BKPT> Stopped at: %s within Entrypoint: %s\n-> ",
|
||||
precord->name, pnode->current_ep->name);
|
||||
|
||||
pnode->precord = precord;
|
||||
|
||||
/* Move current lockset to top of stack */
|
||||
lstDelete(&lset_stack, (NODE *)pnode);
|
||||
lstInsert(&lset_stack, NULL, (NODE *)pnode);
|
||||
/*
|
||||
* Unlock database while the task suspends itself. This
|
||||
* is done so that dbb() dbd() dbc() dbs() may be used
|
||||
* when the task is suspended. Scan tasks that also
|
||||
* use the scan lock feature will not be hung during
|
||||
* a breakpoint, so that records in other locksets will
|
||||
* continue to be processed. Cross your fingers, this
|
||||
* might actually work !
|
||||
*/
|
||||
semGive(bkpt_stack_sem);
|
||||
dbScanUnlock(precord);
|
||||
taskSuspend(pnode->taskid);
|
||||
dbScanLock(precord);
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* print record after processing */
|
||||
void dbPrint(struct dbCommon *precord)
|
||||
{
|
||||
struct LS_LIST *pnode;
|
||||
|
||||
if (! (precord->bkpt & BKPT_PRINT_MASK))
|
||||
return;
|
||||
|
||||
FIND_LOCKSET(precord, pnode);
|
||||
|
||||
/* do not print if lockset does not currently contain breakpoints */
|
||||
if (pnode == NULL)
|
||||
return;
|
||||
|
||||
printf("\n");
|
||||
dbpr(precord->name, 2);
|
||||
printf("-> ");
|
||||
}
|
||||
|
||||
/* print stopped record */
|
||||
long dbp(char *record_name, int interest_level)
|
||||
{
|
||||
struct LS_LIST *pnode;
|
||||
struct dbCommon *precord;
|
||||
int status;
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
|
||||
/* find pnode and precord pointers */
|
||||
status = FIND_CONT_NODE(record_name, &pnode, &precord);
|
||||
if (status) {
|
||||
semGive(bkpt_stack_sem);
|
||||
return(status);
|
||||
}
|
||||
|
||||
/* print out record's fields */
|
||||
dbpr(precord->name, (interest_level == 0) ? 2 : interest_level);
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* toggle printing after processing a certain record */
|
||||
long dbap(char *record_name)
|
||||
{
|
||||
struct dbAddr addr;
|
||||
struct LS_LIST *pnode;
|
||||
struct dbCommon *precord;
|
||||
long status;
|
||||
|
||||
/*
|
||||
* Convert name to address
|
||||
*/
|
||||
status = dbNameToAddr(record_name, &addr);
|
||||
if (status == S_db_notFound)
|
||||
printf(" BKPT> Record %s not found\n", record_name);
|
||||
if (status != 0) return(status);
|
||||
|
||||
precord = addr.precord;
|
||||
|
||||
/*
|
||||
* Toggle print after process field in record
|
||||
*/
|
||||
if (precord->bkpt & BKPT_PRINT_MASK) {
|
||||
printf(" BKPT> Auto print off for record %s\n", precord->name);
|
||||
precord->bkpt &= BKPT_PRINT_OFF_MASK;
|
||||
}
|
||||
else {
|
||||
printf(" BKPT> Auto print on for record %s\n", precord->name);
|
||||
precord->bkpt |= BKPT_PRINT_MASK;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* print list of stopped records, and breakpoints set in locksets */
|
||||
long dbstat()
|
||||
{
|
||||
struct LS_LIST *pnode;
|
||||
struct BP_LIST *pbl;
|
||||
struct EP_LIST *pqe;
|
||||
unsigned long time;
|
||||
int i, j;
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
|
||||
time = tickGet();
|
||||
|
||||
/*
|
||||
* Traverse list, reporting stopped records
|
||||
*/
|
||||
pnode = (struct LS_LIST *) lstFirst(&lset_stack);
|
||||
while (pnode != NULL) {
|
||||
if (pnode->precord != NULL) {
|
||||
|
||||
printf("LSet: %5.5d Stopped at: %-28.28s #B: %5.5d T: 0x%7.7x\n",
|
||||
pnode->l_num, pnode->precord->name, lstCount(&pnode->bp_list), pnode->taskid);
|
||||
|
||||
/* for each entrypoint detected, print out entrypoint statistics */
|
||||
pqe = (struct EP_LIST *) lstFirst(&pnode->ep_queue);
|
||||
while (pqe != NULL) {
|
||||
if (time - pqe->time) {
|
||||
printf(" Entrypoint: %-28.28s #C: %5.5lu C/S: %7.1lf\n",
|
||||
pqe->entrypoint->name, pqe->count,
|
||||
vxTicksPerSecond*pqe->count/((double)(time-pqe->time)));
|
||||
}
|
||||
pqe = (struct EP_LIST *) lstNext((NODE *)pqe);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("LSet: %5.5d #B: %5.5d T: 0x%7.7x\n",
|
||||
pnode->l_num, lstCount(&pnode->bp_list), pnode->taskid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out breakpoints set in the lock set
|
||||
*/
|
||||
pbl = (struct BP_LIST *) lstFirst(&pnode->bp_list);
|
||||
while (pbl != NULL) {
|
||||
printf(" Breakpoint: %-28.28s", pbl->precord->name);
|
||||
|
||||
/* display auto print flag */
|
||||
if (pbl->precord->bkpt & BKPT_PRINT_MASK)
|
||||
printf(" (ap)\n");
|
||||
else
|
||||
printf("\n");
|
||||
|
||||
pbl = (struct BP_LIST *) lstNext((NODE *)pbl);
|
||||
}
|
||||
|
||||
pnode = (struct LS_LIST *) lstNext((NODE *)pnode);
|
||||
}
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a record without printing it.
|
||||
*/
|
||||
long dbprc(char *record_name)
|
||||
{
|
||||
struct dbAddr addr;
|
||||
struct dbCommon *precord;
|
||||
long status;
|
||||
|
||||
/*
|
||||
* Convert name to address
|
||||
*/
|
||||
status = dbNameToAddr(record_name, &addr);
|
||||
if (status == S_db_notFound)
|
||||
printf(" BKPT> Record %s not found\n", record_name);
|
||||
if (status != 0) return(status);
|
||||
|
||||
precord = addr.precord;
|
||||
|
||||
/* lock lockset, process record, unlock lockset */
|
||||
dbScanLock(precord);
|
||||
status = dbProcess(precord);
|
||||
dbScanUnlock(precord);
|
||||
|
||||
return(status);
|
||||
}
|
||||
|
||||
#ifdef BKPT_DIAG
|
||||
|
||||
/* Reset breakpoints */
|
||||
int dbreset()
|
||||
{
|
||||
semGive(bkpt_stack_sem);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif BKPT_DIAG
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/* dbCaDblink.c */
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
|
||||
/****************************************************************
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/* dbCaLink.c */
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
|
||||
/****************************************************************
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+5503
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,5 +1,5 @@
|
||||
/* dbScan.c */
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
|
||||
/* tasks and subroutines to scan the database */
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*dbStaticLib.c*/
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
/*
|
||||
*
|
||||
* Authors: Marty Kraimer
|
||||
|
||||
+158
-1
@@ -1,5 +1,5 @@
|
||||
/* dbTest.c */
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
/* database access test subroutines */
|
||||
/*
|
||||
* Original Author: Bob Dalesio
|
||||
@@ -39,6 +39,7 @@
|
||||
* .08 07-21-92 jba ansi c changes
|
||||
* .09 09-24-93 jbk adjusted dbpr to print vxi links correctly
|
||||
* .10 02-02-94 mrk added dbtpn (test dbPutNotify)
|
||||
* .11 03-18-94 mcn added dbgrep and timing routines.
|
||||
*/
|
||||
|
||||
/* Global Database Test Routines - All can be invoked via vxWorks shell
|
||||
@@ -52,6 +53,9 @@
|
||||
* dbl(ptypeName) list record names.
|
||||
* char *ptypeName; Record type. If null all record types
|
||||
*
|
||||
* dbgrep(pmask) list record names that match the mask
|
||||
* char *pmask;
|
||||
*
|
||||
* dbgf(pname) get field
|
||||
* char *pname;
|
||||
*
|
||||
@@ -85,6 +89,10 @@
|
||||
* dblls(ptypeName) list lock sets
|
||||
* char *ptypeName; Record type. If null all record types
|
||||
*
|
||||
* dbt(record_name) time 100 executions of "record_name"
|
||||
* (includes what records are processed
|
||||
* as a result of that record)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
@@ -232,6 +240,105 @@ long dbl(char *precdesname)
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int specified_by(char *ptest, char *pspec)
|
||||
{
|
||||
short inx;
|
||||
short wild_card_start;
|
||||
|
||||
/* check if the specification begins with a wild card */
|
||||
if (*pspec == '*') wild_card_start = TRUE;
|
||||
else wild_card_start = FALSE;
|
||||
|
||||
/* check for specification */
|
||||
while (TRUE) {
|
||||
/* skip any wild cards */
|
||||
while (*pspec == '*') pspec++;
|
||||
|
||||
/* find the specification chars to compare */
|
||||
inx = 0;
|
||||
while ( (*(pspec+inx) != '*') && (*(pspec+inx)) )
|
||||
inx++;
|
||||
|
||||
/* check for specification ending with wildcard */
|
||||
if (inx == 0) return(TRUE);
|
||||
|
||||
/* find the spec chars in the test string */
|
||||
while ((strlen(ptest) >= inx)
|
||||
&& (strncmp(ptest,pspec,inx) != 0) ) {
|
||||
|
||||
/* check variable beginning */
|
||||
if (!wild_card_start) return(FALSE);
|
||||
else ptest++;
|
||||
}
|
||||
|
||||
/* check segment found */
|
||||
if (strlen(ptest) < inx) return(FALSE);
|
||||
|
||||
/* adjust pointers and wild card indication */
|
||||
wild_card_start = TRUE;
|
||||
ptest += inx;
|
||||
pspec += inx;
|
||||
|
||||
/* check for end of specification */
|
||||
if (*pspec == NULL) {
|
||||
if (*ptest == NULL) return(TRUE);
|
||||
else return(FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long dbgrep(char *pmask)
|
||||
{
|
||||
int rectype, beg, end;
|
||||
struct recLoc *precLoc;
|
||||
struct dbCommon *precord;
|
||||
char *pstr;
|
||||
char name[PVNAME_SZ+1];
|
||||
struct recType *precType;
|
||||
struct recHeader *precHeader;
|
||||
RECNODE *precNode;
|
||||
|
||||
if (!pdbBase) {
|
||||
printf("No database\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!(precType = pdbBase->precType))
|
||||
return(0);
|
||||
|
||||
if (!(precHeader = pdbBase->precHeader))
|
||||
return(0);
|
||||
|
||||
beg = 0;
|
||||
end = precHeader->number - 1;
|
||||
|
||||
for (rectype = beg; rectype <= end; rectype++) {
|
||||
|
||||
if (!(precLoc = GET_PRECLOC(precHeader, rectype)))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Check if there are any record instances defined.
|
||||
*/
|
||||
if (precLoc->preclist == NULL)
|
||||
continue;
|
||||
|
||||
precNode = (RECNODE *) ellFirst(precLoc->preclist);
|
||||
|
||||
for (; precNode != NULL; precNode = (RECNODE *) ellNext(&precNode->node)) {
|
||||
precord = precNode->precord;
|
||||
if (precord == NULL) continue;
|
||||
if (precord->name == NULL) continue;
|
||||
if (precord->name[0] == 0) continue; /* deleted record */
|
||||
|
||||
if (specified_by(precord->name, pmask)) {
|
||||
printf("%s\n", precord->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
long dbgf(char *pname)
|
||||
{
|
||||
/* declare buffer long just to ensure correct alignment */
|
||||
@@ -1660,3 +1767,53 @@ static struct recTypDes *dbprGetRecTypDes(short type)
|
||||
return (NULL);
|
||||
return (precTypDes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call dbProcess() 100 times to make
|
||||
* sure Measurement is accurate, since
|
||||
* timexN() makes use of the 60Hz clock
|
||||
*/
|
||||
static void timing_routine(precord)
|
||||
struct dbCommon *precord;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <100; i++) {
|
||||
dbProcess(precord);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Time execution of record "record_name"
|
||||
*/
|
||||
long dbt(record_name)
|
||||
char *record_name;
|
||||
{
|
||||
struct dbAddr address;
|
||||
struct dbCommon *precord;
|
||||
long status = 0;
|
||||
|
||||
/*
|
||||
* Convert Name To Address
|
||||
*/
|
||||
status = dbNameToAddr(record_name, &address);
|
||||
|
||||
if (status != 0) {
|
||||
printf("Cannot locate %s.\n", record_name);
|
||||
return(status);
|
||||
}
|
||||
|
||||
precord = address.precord;
|
||||
|
||||
printf("!! Time for 100 executions of %s: !!\n", record_name);
|
||||
|
||||
/*
|
||||
* Time the record
|
||||
*/
|
||||
dbScanLock(precord);
|
||||
timexN(timing_routine, precord);
|
||||
dbScanUnlock(precord);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/* db_access.c */
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
/* db_access.c - Interface between old database access and new */
|
||||
/*
|
||||
* Author: Bob Dalesio
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
/* database access subroutines */
|
||||
/*
|
||||
* Author: Bob Dalesio
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*dbta.c*/
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
/*
|
||||
*
|
||||
* Author: Marty Kraimer
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/* devLib.c - support for allocation of common device resources */
|
||||
/* $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
|
||||
/*
|
||||
* Original Author: Marty Kraimer
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/* initHooks.c ioc initialization hooks */
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
/*
|
||||
* Author: Marty Kraimer
|
||||
* Date: 06-01-91
|
||||
|
||||
+530
-104
@@ -1,5 +1,5 @@
|
||||
/* iocInit.c ioc initialization */
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
/*
|
||||
* Author: Marty Kraimer
|
||||
* Date: 06-01-91
|
||||
@@ -53,9 +53,11 @@
|
||||
* .23 09-10-92 rcz changed funcptr pinitHooks from ret long to void
|
||||
* .24 09-11-92 rcz moved setMasterTimeToSelf to a seperate C file
|
||||
* .25 07-15-93 mrk Changed dbLoad for new dbStaticLib support
|
||||
* .26 02-09-94 jbk changed to new time stamp support software ts_init()
|
||||
* .27 03-23-94 mrk Added asInit
|
||||
*
|
||||
<<<<<<< iocInit.c
|
||||
* .26 02-09-94 jbk changed to new time stamp support software ts_init()
|
||||
* .27 03-18-94 mcn added comments
|
||||
* .28 03-23-94 mrk Added asInit
|
||||
* .29 04-04-94 mcn added code for uninitialized conversions (link conversion field)
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
@@ -92,6 +94,7 @@
|
||||
#include <envDefs.h>
|
||||
#include <dbStaticLib.h>
|
||||
#include <initHooks.h>
|
||||
|
||||
/*This module will declare and initilize module_type variables*/
|
||||
#define MODULE_TYPES_INIT 1
|
||||
#include <module_types.h>
|
||||
@@ -118,6 +121,9 @@ static long initialProcess(void);
|
||||
static long getResources(char *fname);
|
||||
void setMasterTimeToSelf(void);
|
||||
|
||||
/*
|
||||
* Initialize EPICS on the IOC.
|
||||
*/
|
||||
int iocInit(char * pResourceFilename)
|
||||
{
|
||||
long status;
|
||||
@@ -126,85 +132,206 @@ int iocInit(char * pResourceFilename)
|
||||
void (*pinitHooks)() = NULL;
|
||||
SYM_TYPE type;
|
||||
|
||||
if(initialized) {
|
||||
if (initialized) {
|
||||
logMsg("iocInit can only be called once\n",0,0,0,0,0,0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (!pdbBase) {
|
||||
logMsg("iocInit aborting because No database loaded by dbLoad\n",0,0,0,0,0,0);
|
||||
return(-1);
|
||||
}
|
||||
if((errSymBld())!=0) {
|
||||
|
||||
/*
|
||||
* Build the data structure for error reporting
|
||||
*/
|
||||
if ((errSymBld()) != 0) {
|
||||
logMsg("iocInit aborting because errSymBld failed to initialize \n",0,0,0,0,0,0);
|
||||
return(-1);
|
||||
}
|
||||
/* if function initHooks exists setup ptr pinitHooks */
|
||||
strcpy(name,"_");
|
||||
strcat(name,"initHooks");
|
||||
rtnval = symFindByName(sysSymTbl,name,(void *)&pinitHooks,&type);
|
||||
if( rtnval==OK && !(type&N_TEXT!=0)) {
|
||||
|
||||
/*
|
||||
* Setup initialization hooks, but only if an initHooks routine has been defined.
|
||||
*/
|
||||
strcpy(name, "_");
|
||||
strcat(name, "initHooks");
|
||||
rtnval = symFindByName(sysSymTbl, name, (void *) &pinitHooks, &type);
|
||||
|
||||
/*
|
||||
* Check to see if initHooks defined, and make sure it is a TEXT symbol (code)
|
||||
* rather than any other kind of vxWorks symbol type.
|
||||
*/
|
||||
if (rtnval == OK && !((type & N_TEXT) != 0)) {
|
||||
logMsg("iocInit - WARNING symbol initHooks has wrong type - skipping all init hooks\n",0,0,0,0,0,0);
|
||||
pinitHooks=NULL;
|
||||
}
|
||||
|
||||
/* Call the user-defined initialization hook before anything else is done */
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKatBeginning);
|
||||
|
||||
/*
|
||||
* Print out version of iocCore
|
||||
*/
|
||||
coreRelease();
|
||||
|
||||
/*
|
||||
* Read EPICS environment
|
||||
*/
|
||||
epicsSetEnvParams();
|
||||
|
||||
/* Hook after environment has been set */
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterSetEnvParams);
|
||||
status=getResources(pResourceFilename);
|
||||
if(status!=0) {
|
||||
|
||||
/*
|
||||
* Read EPICS resources.
|
||||
*/
|
||||
status = getResources(pResourceFilename);
|
||||
if (status != 0) {
|
||||
logMsg("iocInit aborting because getResources failed\n",0,0,0,0,0,0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Call hook for after resources are read. */
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterGetResources);
|
||||
|
||||
/* Initialize log client, and call hook */
|
||||
status = iocLogInit();
|
||||
if(status!=0){
|
||||
if (status!=0) {
|
||||
logMsg("iocInit Failed to Initialize Ioc Log Client \n",0,0,0,0,0,0);
|
||||
}
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterLogInit);
|
||||
|
||||
|
||||
/*
|
||||
* After this point, further calls to iocInit() are disallowed.
|
||||
*/
|
||||
initialized = TRUE;
|
||||
|
||||
/*
|
||||
* Initialize the watchdog task. These is different from vxWorks watchdogs,
|
||||
* this task is assigned to watching and reporting if the vxWorks tasks
|
||||
* (that it has been told to watch) are suspended.
|
||||
*/
|
||||
taskwdInit();
|
||||
|
||||
/*
|
||||
* Initialize EPICS callback tasks
|
||||
*/
|
||||
callbackInit();
|
||||
/* wait 1/10 second */
|
||||
|
||||
/*
|
||||
* Wait 1/10 second to make sure that the above initializations
|
||||
* are complete.
|
||||
*/
|
||||
(void)taskDelay(sysClkRateGet()/10);
|
||||
|
||||
/* Hook after callbacks are initialized */
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterCallbackInit);
|
||||
|
||||
/* added for Channel Access Links */
|
||||
/*
|
||||
* Initialize Channel Access Link mechanism. Pass #1
|
||||
* Call hook after CA links are initialized
|
||||
*/
|
||||
dbCaLinkInit((int) 1);
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterCaLinkInit1);
|
||||
|
||||
if(initDrvSup()!=0) logMsg("iocInit: Drivers Failed during Initialization\n",0,0,0,0,0,0);
|
||||
/*
|
||||
* Initialize Driver Support, Record Support, and finally Device Support.
|
||||
*/
|
||||
if (initDrvSup() != 0)
|
||||
logMsg("iocInit: Drivers Failed during Initialization\n",0,0,0,0,0,0);
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterInitDrvSup);
|
||||
if(initRecSup()!=0) logMsg("iocInit: Record Support Failed during Initialization\n",0,0,0,0,0,0);
|
||||
|
||||
if (initRecSup() != 0)
|
||||
logMsg("iocInit: Record Support Failed during Initialization\n",0,0,0,0,0,0);
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterInitRecSup);
|
||||
if(initDevSup()!=0) logMsg("iocInit: Device Support Failed during Initialization\n",0,0,0,0,0,0);
|
||||
|
||||
if (initDevSup() != 0)
|
||||
logMsg("iocInit: Device Support Failed during Initialization\n",0,0,0,0,0,0);
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterInitDevSup);
|
||||
|
||||
/*
|
||||
* Initialize the time stamp code. This starts up the time-stamp task.
|
||||
*/
|
||||
/* ts_init(); */ /* old time stamp driver (jbk) */
|
||||
TSinit(); /* new time stamp driver (jbk) */
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterTS_init);
|
||||
if(initDatabase()!=0) logMsg("iocInit: Database Failed during Initialization\n",0,0,0,0,0,0);
|
||||
|
||||
/*
|
||||
* First pass at initializing the database structure
|
||||
*/
|
||||
if (initDatabase() != 0)
|
||||
logMsg("iocInit: Database Failed during Initialization\n",0,0,0,0,0,0);
|
||||
|
||||
createLockSets();
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterInitDatabase);
|
||||
/* added for Channel Access Links */
|
||||
|
||||
/* added for Channel Access Links */
|
||||
dbCaLinkInit((int) 2);
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterCaLinkInit2);
|
||||
if(finishDevSup()!=0) logMsg("iocInit: Device Support Failed during Finalization\n",0,0,0,0,0,0);
|
||||
|
||||
/*
|
||||
* Finish initializing device support
|
||||
*/
|
||||
if (finishDevSup() != 0)
|
||||
logMsg("iocInit: Device Support Failed during Finalization\n",0,0,0,0,0,0);
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterFinishDevSup);
|
||||
|
||||
/*
|
||||
* Initialize Scan tasks
|
||||
*/
|
||||
scanInit();
|
||||
|
||||
/* wait 1/2 second to make sure all tasks are started*/
|
||||
|
||||
/* initialize access security */
|
||||
asInit();
|
||||
/* wait 1/2 second to make sure all tasks are started*/
|
||||
|
||||
(void)taskDelay(sysClkRateGet()/2);
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterScanInit);
|
||||
|
||||
/*
|
||||
* Enable scan tasks and some driver support functions.
|
||||
*/
|
||||
interruptAccept=TRUE;
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterInterruptAccept);
|
||||
if(initialProcess()!=0) logMsg("iocInit: initialProcess Failed\n",0,0,0,0,0,0);
|
||||
|
||||
/*
|
||||
* Process all records that have their "process at initialization"
|
||||
* field set (pini).
|
||||
*/
|
||||
if (initialProcess() != 0)
|
||||
logMsg("iocInit: initialProcess Failed\n",0,0,0,0,0,0);
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKafterInitialProcess);
|
||||
|
||||
/*
|
||||
* Start up CA server
|
||||
*/
|
||||
rsrv_init();
|
||||
|
||||
logMsg("iocInit: All initialization complete\n",0,0,0,0,0,0);
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(INITHOOKatEnd);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize Driver Support
|
||||
* Locate all driver support entry tables.
|
||||
* Call the initialization routine (init) for each
|
||||
* driver type.
|
||||
*/
|
||||
static long initDrvSup(void) /* Locate all driver support entry tables */
|
||||
{
|
||||
char *pname;
|
||||
@@ -216,31 +343,63 @@ static long initDrvSup(void) /* Locate all driver support entry tables */
|
||||
long rtnval;
|
||||
STATUS vxstatus;
|
||||
struct drvSup *pdrvSup;
|
||||
|
||||
/*
|
||||
* Make sure at least one device driver is defined in
|
||||
* the ASCII file.
|
||||
*/
|
||||
|
||||
if(!(pdrvSup=pdbBase->pdrvSup)) {
|
||||
if (!(pdrvSup=pdbBase->pdrvSup)) {
|
||||
status = S_drv_noDrvSup;
|
||||
errMessage(status,"No device drivers are defined");
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* For every driver support module, look up the name
|
||||
* for that function in the vxWorks symbol table. If
|
||||
* a driver entry table doesn't exist, report that
|
||||
* fact.
|
||||
*/
|
||||
for(i=0; i< (pdrvSup->number); i++) {
|
||||
if(!(pname = pdrvSup->papDrvName[i])) continue;
|
||||
if (!(pname = pdrvSup->papDrvName[i])) continue;
|
||||
|
||||
strcpy(name,"_");
|
||||
strcat(name,pname);
|
||||
vxstatus = symFindByName(sysSymTbl,name,(void *)&(pdrvSup->papDrvet[i]),&type);
|
||||
if( vxstatus!=OK || ( type&N_TEXT == 0) ) {
|
||||
|
||||
vxstatus = symFindByName(sysSymTbl, name, (void *) &(pdrvSup->papDrvet[i]), &type);
|
||||
|
||||
/* Make sure it is program text */
|
||||
if (vxstatus != OK || (type & N_TEXT == 0)) {
|
||||
strcpy(message,"driver entry table not found for ");
|
||||
strcat(message,pname);
|
||||
status = S_drv_noDrvet;
|
||||
errMessage(status,message);
|
||||
continue;
|
||||
}
|
||||
if(!(pdrvSup->papDrvet[i]->init)) continue;
|
||||
|
||||
/*
|
||||
* If an initialization routine is defined (not NULL),
|
||||
* for the driver support call it.
|
||||
*/
|
||||
if (!(pdrvSup->papDrvet[i]->init))
|
||||
continue;
|
||||
rtnval = (*(pdrvSup->papDrvet[i]->init))();
|
||||
if(status==0) status = rtnval;
|
||||
|
||||
if (status == 0)
|
||||
status = rtnval;
|
||||
}
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize Record Support
|
||||
* Allocate a record support structure for every record type
|
||||
* plus space for an array of pointers to RSETs.
|
||||
* Locate all record support entry tables.
|
||||
* Call the initialization routine (init) for each
|
||||
* record type.
|
||||
*/
|
||||
static long initRecSup(void)
|
||||
{
|
||||
char name[40];
|
||||
@@ -259,36 +418,76 @@ static long initRecSup(void)
|
||||
errMessage(status,"No record types defined");
|
||||
return(status);
|
||||
}
|
||||
nbytes = sizeof(struct recSup) + precType->number*sizeof(void *);
|
||||
|
||||
/*
|
||||
* Allocate record support structure, and a list of pointers
|
||||
* after it to point to the Record Support Entry Tables (RSETs)
|
||||
* of individual record types.
|
||||
*/
|
||||
nbytes = sizeof(struct recSup) + precType->number * sizeof(void *);
|
||||
precSup = dbCalloc(1,nbytes);
|
||||
pdbBase->precSup = precSup;
|
||||
|
||||
/* The number of record support entry tables equals the number of record types */
|
||||
precSup->number = precType->number;
|
||||
|
||||
/*
|
||||
* The pointer to the array of pointers of Record Support Entry Tables
|
||||
* exists at the end of the record support structure.
|
||||
*/
|
||||
precSup->papRset = (void *)((long)precSup + (long)sizeof(struct recSup));
|
||||
|
||||
/*
|
||||
* For every record support module, look up the name
|
||||
* for that function in the vxWorks symbol table. If
|
||||
* a record support entry table doesn't exist, report
|
||||
* that fact.
|
||||
*/
|
||||
for(i=0; i< (precSup->number); i++) {
|
||||
if(precType->papName[i] == NULL)continue;
|
||||
if (precType->papName[i] == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Create string that is the name of the RSET
|
||||
* (record support entry table) structure for
|
||||
* each record type.
|
||||
*/
|
||||
strcpy(name,"_");
|
||||
strcat(name,precType->papName[i]);
|
||||
strcat(name,"RSET");
|
||||
vxstatus = symFindByName(sysSymTbl,name,
|
||||
(void *)(&precSup->papRset[i]),&type);
|
||||
if( vxstatus!=OK || ( type&N_TEXT == 0) ) {
|
||||
|
||||
/* Lookup name in vxWorks symbol table - and make sure it is program text */
|
||||
vxstatus = symFindByName(sysSymTbl, name,
|
||||
(void *) (&precSup->papRset[i]), &type);
|
||||
|
||||
if (vxstatus != OK || ((type & N_TEXT) == 0)) {
|
||||
strcpy(message,"record support entry table not found for ");
|
||||
strcat(message,name);
|
||||
status = S_rec_noRSET;
|
||||
errMessage(status,message);
|
||||
continue;
|
||||
}
|
||||
if(!(precSup->papRset[i]->init)) continue;
|
||||
|
||||
/* If an initialization routine exists for a record type, execute it */
|
||||
if (!(precSup->papRset[i]->init))
|
||||
continue;
|
||||
else {
|
||||
rtnval = (*(precSup->papRset[i]->init))();
|
||||
if(status==0) status = rtnval;
|
||||
if (status==0)
|
||||
status = rtnval;
|
||||
}
|
||||
}
|
||||
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long initDevSup(void) /* Locate all device support entry tables */
|
||||
/*
|
||||
* Initialize Device Support
|
||||
* Locate all device support entry tables.
|
||||
* Call the initialization routine (init) for each
|
||||
* device type (First Pass).
|
||||
*/
|
||||
static long initDevSup(void)
|
||||
{
|
||||
char *pname;
|
||||
char name[40];
|
||||
@@ -301,47 +500,91 @@ static long initDevSup(void) /* Locate all device support entry tables */
|
||||
struct recDevSup *precDevSup;
|
||||
struct devSup *pdevSup;
|
||||
|
||||
if(!(precDevSup=pdbBase->precDevSup)) {
|
||||
if (!(precDevSup = pdbBase->precDevSup)) {
|
||||
status = S_dev_noDevSup;
|
||||
errMessage(status,"No device support is defined");
|
||||
return(status);
|
||||
}
|
||||
for(i=0; i< (precDevSup->number); i++) {
|
||||
if((pdevSup = precDevSup->papDevSup[i]) == NULL) continue;
|
||||
|
||||
/*
|
||||
* For all possible records, initialize their device support
|
||||
* routines. There is usually more than one device support
|
||||
* routine defined for every record type, this accounts for
|
||||
* the doubly nested for() loops. precDevSup->number = number
|
||||
* of record types.
|
||||
*/
|
||||
for (i=0; i< (precDevSup->number); i++) {
|
||||
/*
|
||||
* Find the device support routine in the array of pointers
|
||||
*/
|
||||
if ((pdevSup = precDevSup->papDevSup[i]) == NULL)
|
||||
continue;
|
||||
|
||||
/* For every device support module defined for a record type... */
|
||||
for(j=0; j < (pdevSup->number); j++) {
|
||||
if(!(pname = pdevSup->papDsetName[j])) continue;
|
||||
strcpy(name,"_");
|
||||
strcat(name,pname);
|
||||
vxstatus = (long)symFindByName(sysSymTbl,name,
|
||||
(void *)&(pdevSup->papDset[j]),&type);
|
||||
if( vxstatus!=OK || ( type&N_TEXT == 0) ) {
|
||||
/* Create the name */
|
||||
if (!(pname = pdevSup->papDsetName[j]))
|
||||
continue;
|
||||
strcpy(name, "_");
|
||||
strcat(name, pname);
|
||||
|
||||
/* Lookup name in vxWorks symbol table - make sure it is program text */
|
||||
vxstatus = (long) symFindByName(sysSymTbl, name,
|
||||
(void *) &(pdevSup->papDset[j]), &type);
|
||||
|
||||
if (vxstatus != OK || ((type & N_TEXT) == 0)) {
|
||||
pdevSup->papDset[j]=NULL;
|
||||
strcpy(message,"device support entry table not found for ");
|
||||
strcat(message,pname);
|
||||
strcpy(message, "device support entry table not found for ");
|
||||
strcat(message, pname);
|
||||
status = S_dev_noDSET;
|
||||
errMessage(status,message);
|
||||
errMessage(status, message);
|
||||
continue;
|
||||
}
|
||||
if(!(pdevSup->papDset[j]->init)) continue;
|
||||
|
||||
/* If an init routine exists for the device support module, execute it */
|
||||
if (!(pdevSup->papDset[j]->init))
|
||||
continue;
|
||||
|
||||
rtnval = (*(pdevSup->papDset[j]->init))(0);
|
||||
if(status==0) status = rtnval;
|
||||
|
||||
if (status == 0)
|
||||
status = rtnval;
|
||||
}
|
||||
}
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls the second pass for each device support
|
||||
* initialization routine. The second pass is made
|
||||
* after the database records have been initialized and
|
||||
* placed into lock sets.
|
||||
*/
|
||||
static long finishDevSup(void)
|
||||
{
|
||||
int i,j;
|
||||
struct recDevSup *precDevSup;
|
||||
struct devSup *pdevSup;
|
||||
|
||||
if(!(precDevSup=pdbBase->precDevSup)) return(0);
|
||||
|
||||
/* Find pointer to device support for all record types */
|
||||
if (!(precDevSup=pdbBase->precDevSup))
|
||||
return(0);
|
||||
|
||||
/* For every record type... */
|
||||
for(i=0; i< (precDevSup->number); i++) {
|
||||
if((pdevSup = precDevSup->papDevSup[i]) == NULL) continue;
|
||||
/* Find pointer to device support for an individual record type */
|
||||
if ((pdevSup = precDevSup->papDevSup[i]) == NULL)
|
||||
continue;
|
||||
|
||||
/* For every device support module defined for a record type */
|
||||
for(j=0; j < (pdevSup->number); j++) {
|
||||
if(!(pdevSup->papDset[j])) continue;
|
||||
if(!(pdevSup->papDset[j]->init)) continue;
|
||||
if (!(pdevSup->papDset[j]))
|
||||
continue;
|
||||
|
||||
/* Call the second pass of the initialization, if the routine exists */
|
||||
if (!(pdevSup->papDset[j]->init))
|
||||
continue;
|
||||
|
||||
(*(pdevSup->papDset[j]->init))(1);
|
||||
}
|
||||
|
||||
@@ -369,28 +612,63 @@ static long initDatabase(void)
|
||||
struct devSup *pdevSup;
|
||||
struct recSup *precSup;
|
||||
struct recType *precType;
|
||||
|
||||
|
||||
/* Find the record type and record support structures */
|
||||
if(!(precType=pdbBase->precType)) return(0);
|
||||
if(!(precSup=pdbBase->precSup)) return(0);
|
||||
if(!(precHeader = pdbBase->precHeader)) {
|
||||
|
||||
/*
|
||||
* Locate database record header
|
||||
* This structure contains a pointer to an array of pointers to
|
||||
* record location structures. A record location structure
|
||||
* exists for every record type. It contains a pointer to a
|
||||
* linked list of all instances of records with that type.
|
||||
*/
|
||||
if (!(precHeader = pdbBase->precHeader)) {
|
||||
status = S_record_noRecords;
|
||||
errMessage(status,"No database records are defined");
|
||||
return(status);
|
||||
}
|
||||
if(!(precDes = pdbBase->precDes)) {
|
||||
|
||||
/*
|
||||
* Find record descriptions
|
||||
* The record descriptions contain every piece of information
|
||||
* you ever wanted to know about the individual fields in a
|
||||
* particular record type. See header file for more information.
|
||||
*/
|
||||
if (!(precDes = pdbBase->precDes)) {
|
||||
status = S_record_noRecords;
|
||||
errMessage(status,"Database record descriptions were not defined");
|
||||
return(status);
|
||||
}
|
||||
|
||||
/* For every record type ... */
|
||||
for(i=0; i< (precHeader->number); i++) {
|
||||
if(!(precLoc = precHeader->papRecLoc[i]))continue;
|
||||
if(!precLoc->preclist) continue;
|
||||
/* Get pointer to location structure for instances of record type 'i' */
|
||||
if (!(precLoc = precHeader->papRecLoc[i]))continue;
|
||||
|
||||
if (!precLoc->preclist) continue;
|
||||
|
||||
/*
|
||||
* Find record support entry table, record description, and device
|
||||
* support associated with record type 'i'
|
||||
*/
|
||||
prset = GET_PRSET(precSup,i);
|
||||
precTypDes = precDes->papRecTypDes[i];
|
||||
pdevSup = GET_PDEVSUP(pdbBase->precDevSup,i);
|
||||
for(precNode=(RECNODE *)ellFirst(precLoc->preclist);
|
||||
precNode; precNode = (RECNODE *)ellNext(&precNode->node)) {
|
||||
if(!prset) {
|
||||
|
||||
/*
|
||||
* For all instances of record type 'i '...
|
||||
* These records are contained in the linked list
|
||||
*/
|
||||
for (precNode=(RECNODE *)ellFirst(precLoc->preclist);
|
||||
precNode; precNode = (RECNODE *)ellNext(&precNode->node)) {
|
||||
|
||||
/*
|
||||
* If there is not record support entry table for record
|
||||
* type 'i', report message, and break from for loop.
|
||||
*/
|
||||
if (!prset) {
|
||||
strcpy(name,precType->papName[i]);
|
||||
strcat(name,"RSET");
|
||||
strcpy(message,"record support entry table not found for ");
|
||||
@@ -399,60 +677,126 @@ static long initDatabase(void)
|
||||
errMessage(status,message);
|
||||
break;
|
||||
}
|
||||
/* Find pointer to record instance */
|
||||
precord = precNode->precord;
|
||||
|
||||
/* If NAME is null then skip this record*/
|
||||
if(!(precord->name[0])) continue;
|
||||
/*initialize fields rset*/
|
||||
|
||||
/* Initialize record's record support entry table field */
|
||||
precord->rset = prset;
|
||||
/* initialize mlok and mlis*/
|
||||
|
||||
/*
|
||||
* Initialize mlok and mlis.
|
||||
* (The monitor lock - basically a semaphore) and the
|
||||
* monitor list field. The list of "applications"
|
||||
* observing changes in a database field.
|
||||
*/
|
||||
FASTLOCKINIT(&precord->mlok);
|
||||
ellInit(&(precord->mlis));
|
||||
|
||||
/* Reset the process active field */
|
||||
precord->pact=FALSE;
|
||||
/* Init DSET NOTE that result may be NULL*/
|
||||
|
||||
/* Init DSET NOTE that result may be NULL */
|
||||
precord->dset=(struct dset *)GET_PDSET(pdevSup,precord->dtyp);
|
||||
/* call record support init_record routine - First pass */
|
||||
|
||||
/* Initialize dbCommon structure of the record - First pass (pass=0) */
|
||||
rtnval = dbCommonInit(precord,0);
|
||||
if(!(precSup->papRset[i]->init_record)) continue;
|
||||
|
||||
/*
|
||||
* Call record support init_record routine - First pass
|
||||
* (pass=0). (only if init_record is defined...)
|
||||
*/
|
||||
if (!(precSup->papRset[i]->init_record)) continue;
|
||||
|
||||
rtnval = (*(precSup->papRset[i]->init_record))(precord,0);
|
||||
if(status==0) status = rtnval;
|
||||
|
||||
if (status==0)
|
||||
status = rtnval;
|
||||
}
|
||||
}
|
||||
/* Second pass to resolve links*/
|
||||
|
||||
/*
|
||||
* Second pass to resolve links
|
||||
*/
|
||||
/* For all record types */
|
||||
for(i=0; i< (precHeader->number); i++) {
|
||||
if(!(precLoc = precHeader->papRecLoc[i]))continue;
|
||||
if(!precLoc->preclist) continue;
|
||||
/* Find record instances */
|
||||
if (!(precLoc = precHeader->papRecLoc[i]))continue;
|
||||
|
||||
if (!precLoc->preclist) continue;
|
||||
|
||||
/* Find record field descriptions */
|
||||
precTypDes = precDes->papRecTypDes[i];
|
||||
for(precNode=(RECNODE *)ellFirst(precLoc->preclist);
|
||||
precNode; precNode = (RECNODE *)ellNext(&precNode->node)) {
|
||||
|
||||
/* For all record instances of type 'i' in the linked list... */
|
||||
for (precNode=(RECNODE *)ellFirst(precLoc->preclist);
|
||||
precNode; precNode = (RECNODE *)ellNext(&precNode->node)) {
|
||||
precord = precNode->precord;
|
||||
|
||||
/* If NAME is null then skip this record*/
|
||||
if(!(precord->name[0])) continue;
|
||||
/* Convert all PV_LINKs to DB_LINKs or CA_LINKs*/
|
||||
if (!(precord->name[0])) continue;
|
||||
|
||||
/*
|
||||
* Convert all PV_LINKs to DB_LINKs or CA_LINKs
|
||||
* Figures out what type of link to use. A
|
||||
* database link local to the IOC, or a channel
|
||||
* access link across the network.
|
||||
*/
|
||||
/* For all the links in the record type... */
|
||||
for(j=0; j<precTypDes->no_links; j++) {
|
||||
pfldDes = precTypDes->papFldDes[precTypDes->link_ind[j]];
|
||||
|
||||
/*
|
||||
* The actual link structure is located at this offset
|
||||
* within the link structure.
|
||||
*/
|
||||
plink = (struct link *)((char *)precord + pfldDes->offset);
|
||||
if(plink->type == PV_LINK) {
|
||||
|
||||
/*
|
||||
* Link type should be PV_LINK, unless it is
|
||||
* constant or hardware-specific
|
||||
*/
|
||||
if (plink->type == PV_LINK) {
|
||||
strncpy(name,plink->value.pv_link.pvname,PVNAME_SZ);
|
||||
|
||||
/* create record name */
|
||||
name[PVNAME_SZ]=0;
|
||||
strcat(name,".");
|
||||
strncat(name,plink->value.pv_link.fldname,FLDNAME_SZ);
|
||||
if(dbNameToAddr(name,&dbAddr) == 0) {
|
||||
|
||||
/*
|
||||
* Lookup record name in database
|
||||
* If a record is _not_ local to the IOC, it is a
|
||||
* channel access link, otherwise it is a
|
||||
* database link.
|
||||
*/
|
||||
if (dbNameToAddr(name,&dbAddr) == 0) {
|
||||
plink->type = DB_LINK;
|
||||
plink->value.db_link.pdbAddr =
|
||||
dbCalloc(1,sizeof(struct dbAddr));
|
||||
*((struct dbAddr *)(plink->value.db_link.pdbAddr))=dbAddr;
|
||||
/*
|
||||
* Initialize conversion to "uninitialized" conversion
|
||||
*/
|
||||
plink->value.db_link.conversion = cvt_uninit;
|
||||
}
|
||||
else {
|
||||
/* not a local pvar ... assuming a CA_LINK */
|
||||
/* only supporting NPP, Input MS/NMS, and */
|
||||
/* Output NMS links ... checking here. */
|
||||
|
||||
/*
|
||||
* Not a local process variable ... assuming a CA_LINK
|
||||
* Only supporting Non Process Passive links, Input Maximize
|
||||
* Severity/No Maximize Severity(MS/NMS), and output NMS
|
||||
* links ... The following code checks for this.
|
||||
*/
|
||||
if (plink->value.db_link.process_passive
|
||||
|| (pfldDes->field_type == DBF_OUTLINK
|
||||
&& plink->value.db_link.maximize_sevr))
|
||||
{
|
||||
/* link PP and/or Outlink MS ... */
|
||||
/* neither supported under CA_LINKs */
|
||||
/*
|
||||
* Link PP and/or Outlink MS ...
|
||||
* neither supported under CA_LINKs
|
||||
*/
|
||||
strncpy(message,precord->name,PVNAME_SZ);
|
||||
message[PVNAME_SZ]=0;
|
||||
strcat(message,".");
|
||||
@@ -469,28 +813,46 @@ static long initDatabase(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Call init_record for second time */
|
||||
|
||||
/*
|
||||
* Call record support init_record routine - Second pass
|
||||
*/
|
||||
/* For all record types... */
|
||||
for(i=0; i< (precHeader->number); i++) {
|
||||
if(!(precLoc = precHeader->papRecLoc[i]))continue;
|
||||
if(!precLoc->preclist) continue;
|
||||
if(!(prset=GET_PRSET(precSup,i))) continue;
|
||||
if (!(precLoc = precHeader->papRecLoc[i])) continue;
|
||||
if (!precLoc->preclist) continue;
|
||||
if (!(prset=GET_PRSET(precSup,i))) continue;
|
||||
precTypDes = precDes->papRecTypDes[i];
|
||||
for(precNode=(RECNODE *)ellFirst(precLoc->preclist);
|
||||
|
||||
/* For all record instances of type 'i' */
|
||||
for (precNode=(RECNODE *)ellFirst(precLoc->preclist);
|
||||
precNode; precNode = (RECNODE *)ellNext(&precNode->node)) {
|
||||
/* Locate name of record */
|
||||
precord = precNode->precord;
|
||||
/* If NAME is null then skip this record*/
|
||||
if(!(precord->name[0])) continue;
|
||||
/* If NAME is null then skip this record*/
|
||||
if (!(precord->name[0])) continue;
|
||||
rtnval = dbCommonInit(precord,1);
|
||||
if(status==0) status = rtnval;
|
||||
/* call record support init_record routine - Second pass */
|
||||
if(!(precSup->papRset[i]->init_record)) continue;
|
||||
rtnval = (*(precSup->papRset[i]->init_record))(precord,1);
|
||||
if(status==0) status = rtnval;
|
||||
if (status==0) status = rtnval;
|
||||
/* call record support init_record routine - Second pass (pass = 1) */
|
||||
if (!(precSup->papRset[i]->init_record)) continue;
|
||||
rtnval = (*(precSup->papRset[i]->init_record))(precord, 1);
|
||||
if (status == 0) status = rtnval;
|
||||
}
|
||||
}
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create lock sets for records
|
||||
* A lock set is a set of records that must be locked
|
||||
* with a semaphore so as to prevent mutual exclusion
|
||||
* hazards. Lock sets are determined by examining the
|
||||
* links interconnecting the records. If a link connecting
|
||||
* two records is not an NPP/NMS single-valued input link,
|
||||
* then the two records are considered part of the same
|
||||
* lock set. Records connected by forward links are
|
||||
* definately considered part of the same lockset.
|
||||
*/
|
||||
static void createLockSets(void)
|
||||
{
|
||||
int i,link;
|
||||
@@ -518,7 +880,17 @@ static void createLockSets(void)
|
||||
/* If NAME is null then skip this record*/
|
||||
if(!(precord->name[0])) continue;
|
||||
if(precord->lset) continue; /*already in a lock set*/
|
||||
|
||||
/*
|
||||
* At First, assume record is in a different lockset
|
||||
* We shall see later if this assumption is incorrect.
|
||||
*/
|
||||
precord->lset = maxnset = ++nset;
|
||||
|
||||
/*
|
||||
* Use the process active flag to eliminate traversing
|
||||
* cycles in the database "graph"
|
||||
*/
|
||||
precord->pact = TRUE; again = TRUE;
|
||||
while(again) {
|
||||
again = FALSE;
|
||||
@@ -526,15 +898,41 @@ static void createLockSets(void)
|
||||
struct dbAddr *pdbAddr;
|
||||
|
||||
pfldDes = precTypDes->papFldDes[precTypDes->link_ind[link]];
|
||||
|
||||
/*
|
||||
* Find link structure, which is at an offset in the record
|
||||
*/
|
||||
plink = (struct link *)((char *)precord + pfldDes->offset);
|
||||
/* Ignore link if type is constant, channel access, or hardware specific */
|
||||
if(plink->type != DB_LINK) continue;
|
||||
|
||||
pdbAddr = (struct dbAddr *)(plink->value.db_link.pdbAddr);
|
||||
if( pfldDes->field_type==DBF_INLINK
|
||||
&& ( !(plink->value.db_link.process_passive)
|
||||
&& !(plink->value.db_link.maximize_sevr) )
|
||||
&& pdbAddr->no_elements<=1) continue;
|
||||
|
||||
/* The current record is in a different lockset -IF-
|
||||
* 1. Input link
|
||||
* 2. Not Process Passive
|
||||
* 3. Not Maximize Severity
|
||||
* 4. Not An Array Operation - single element only
|
||||
*/
|
||||
if (pfldDes->field_type==DBF_INLINK
|
||||
&& ( !(plink->value.db_link.process_passive)
|
||||
&& !(plink->value.db_link.maximize_sevr))
|
||||
&& pdbAddr->no_elements<=1) continue;
|
||||
|
||||
/*
|
||||
* Combine the lock sets of the current record with the
|
||||
* remote record pointed to by the link. (recursively)
|
||||
*/
|
||||
newset = makeSameSet(pdbAddr,precord->lset);
|
||||
if(newset!=precord->lset) {
|
||||
|
||||
/*
|
||||
* Perform an iteration of the while-loop again
|
||||
* if we find that the record pointed to by
|
||||
* the link has its lockset set earlier. If
|
||||
* it has, set the current record's lockset to
|
||||
* that of the link's endpoint.
|
||||
*/
|
||||
if (newset!=precord->lset) {
|
||||
if(precord->lset==maxnset && maxnset==nset) nset--;
|
||||
precord->lset = newset;
|
||||
again = TRUE;
|
||||
@@ -548,7 +946,7 @@ static void createLockSets(void)
|
||||
dbScanLockInit(nset);
|
||||
}
|
||||
|
||||
static short makeSameSet( struct dbAddr *paddr, short lset)
|
||||
static short makeSameSet(struct dbAddr *paddr, short lset)
|
||||
{
|
||||
struct dbCommon *precord = paddr->precord;
|
||||
short link;
|
||||
@@ -558,11 +956,35 @@ static short makeSameSet( struct dbAddr *paddr, short lset)
|
||||
struct recDes *precDes;
|
||||
int again;
|
||||
|
||||
/*
|
||||
* Use the process active flag to eliminate traversing
|
||||
* cycles in the database "graph." Effectively converts
|
||||
* the arbitrary database "graph" (where edges are
|
||||
* defined as links) into a tree structure.
|
||||
*/
|
||||
if(precord->pact) return(((precord->lset<lset) ? precord->lset : lset));
|
||||
|
||||
/*
|
||||
* If the lock set of the link's endpoint is already set
|
||||
* to the lockset we are setting it to, return...
|
||||
*/
|
||||
if(lset == precord->lset) return(lset);
|
||||
|
||||
/*
|
||||
* If the record has an uninitialized lock set field,
|
||||
* we set it here.
|
||||
*/
|
||||
if(precord->lset == 0) precord->lset = lset;
|
||||
|
||||
/*
|
||||
* If the record is already in a lockset determined earlier,
|
||||
* return that lock set.
|
||||
*/
|
||||
if(precord->lset < lset) return(precord->lset);
|
||||
|
||||
if(!(precDes = pdbBase->precDes)) return(0);
|
||||
|
||||
/* set pact to prevent cycles */
|
||||
precord->lset = lset; precord->pact = TRUE; again = TRUE;
|
||||
while(again) {
|
||||
again = FALSE;
|
||||
@@ -591,6 +1013,10 @@ static short makeSameSet( struct dbAddr *paddr, short lset)
|
||||
return(precord->lset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process database records at initialization if
|
||||
* their pini (process at init) field is set.
|
||||
*/
|
||||
static long initialProcess(void)
|
||||
{
|
||||
short i;
|
||||
|
||||
+135
-1
@@ -1,5 +1,5 @@
|
||||
/* recGbl.c - Global record processing routines */
|
||||
/* share/src/db/recGbl.c $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
|
||||
/*
|
||||
* Author: Marty Kraimer
|
||||
@@ -38,6 +38,7 @@
|
||||
* .08 09-15-92 jba changed error parm in recGblRecordError calls
|
||||
* .09 09-17-92 jba ANSI C changes
|
||||
* .10 01-27-93 jba set pact to true during calls to dbPutLink
|
||||
* .11 03-21-94 mcn Added fast link routines
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
@@ -475,3 +476,136 @@ double *prangeValue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fast link initialization routines */
|
||||
/*
|
||||
* Get and Put conversion routine lookup tables
|
||||
*/
|
||||
extern long (*get_cvt_table[DBF_DEVCHOICE+1][DBR_ENUM+1])();
|
||||
extern long (*put_cvt_table[DBR_ENUM+1][DBF_DEVCHOICE+1])();
|
||||
|
||||
/*
|
||||
* String if bad database request type chosen
|
||||
*/
|
||||
static char *bad_in_req_type = "recGblInitFastInLink: Bad database request type";
|
||||
static char *bad_out_req_type = "recGblInitFastInLink: Bad database request type";
|
||||
|
||||
/*
|
||||
* Initialize fast input links.
|
||||
*/
|
||||
long recGblInitFastInLink(
|
||||
struct link *plink,
|
||||
void *precord,
|
||||
short dbrType,
|
||||
char *fld_name)
|
||||
{
|
||||
long status = 0;
|
||||
struct db_link *pdb_link = &(plink->value.db_link);
|
||||
struct dbAddr *pdb_addr = (struct dbAddr *) (pdb_link->pdbAddr);
|
||||
long (*cvt_func)();
|
||||
|
||||
/*
|
||||
* Check for CA_LINK
|
||||
*/
|
||||
if (plink->type == PV_LINK) {
|
||||
status = dbCaAddInlink(plink, (struct dbCommon *) precord, fld_name);
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return if not database link (A constant link, for example)
|
||||
*/
|
||||
if (plink->type != DB_LINK)
|
||||
return(0);
|
||||
|
||||
/*
|
||||
* Check for legal conversion range...
|
||||
*/
|
||||
if ((pdb_addr->field_type < DBF_STRING) ||
|
||||
(pdb_addr->field_type > DBF_DEVCHOICE) ||
|
||||
( dbrType < DBR_STRING) ||
|
||||
( dbrType > DBR_ENUM)) {
|
||||
|
||||
pdb_link->conversion = cvt_dummy;
|
||||
recGblDbaddrError(S_db_badDbrtype, pdb_addr, bad_in_req_type);
|
||||
return(S_db_badDbrtype);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup conversion function
|
||||
*/
|
||||
cvt_func = get_cvt_table[pdb_addr->field_type][dbrType];
|
||||
|
||||
if (cvt_func == NULL) {
|
||||
pdb_link->conversion = cvt_dummy;
|
||||
recGblDbaddrError(S_db_badDbrtype, pdb_addr, bad_in_req_type);
|
||||
return(S_db_badDbrtype);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put function it into conversion field (Run Time Link)
|
||||
*/
|
||||
pdb_link->conversion = cvt_func;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize fast output links.
|
||||
*/
|
||||
long recGblInitFastOutLink(
|
||||
struct link *plink,
|
||||
void *precord,
|
||||
short dbrType,
|
||||
char *fld_name)
|
||||
{
|
||||
long status = 0;
|
||||
struct db_link *pdb_link = &(plink->value.db_link);
|
||||
struct dbAddr *pdb_addr = (struct dbAddr *) (pdb_link->pdbAddr);
|
||||
long (*cvt_func)();
|
||||
|
||||
/*
|
||||
* Check for CA_LINK
|
||||
*/
|
||||
if (plink->type == PV_LINK) {
|
||||
status = dbCaAddOutlink(plink, (struct dbCommon *) precord, fld_name);
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return if not database link (A constant link, for example)
|
||||
*/
|
||||
if (plink->type != DB_LINK)
|
||||
return(0);
|
||||
|
||||
/*
|
||||
* Check for legal conversion range...
|
||||
*/
|
||||
if ((pdb_addr->field_type < DBF_STRING) ||
|
||||
(pdb_addr->field_type > DBF_DEVCHOICE) ||
|
||||
( dbrType < DBR_STRING) ||
|
||||
( dbrType > DBR_ENUM)) {
|
||||
|
||||
pdb_link->conversion = cvt_dummy;
|
||||
recGblDbaddrError(S_db_badDbrtype, pdb_addr, bad_out_req_type);
|
||||
return(S_db_badDbrtype);
|
||||
}
|
||||
/*
|
||||
* Lookup conversion function
|
||||
*/
|
||||
cvt_func = put_cvt_table[dbrType][pdb_addr->field_type];
|
||||
|
||||
if (cvt_func == NULL) {
|
||||
pdb_link->conversion = cvt_dummy;
|
||||
recGblDbaddrError(S_db_badDbrtype, pdb_addr, bad_out_req_type);
|
||||
return(S_db_badDbrtype);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put function it into conversion field (Run Time Link)
|
||||
*/
|
||||
pdb_link->conversion = cvt_func;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* setMasterTimeToSelf.c ioc initialization */
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
/*
|
||||
* Author: Bob Zieman
|
||||
* Date: 09-11-92
|
||||
|
||||
+17
-12
@@ -1,5 +1,5 @@
|
||||
/* taskwd.c */
|
||||
/* share/src/db $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
|
||||
/* tasks and subroutines for a general purpose task watchdog */
|
||||
/*
|
||||
@@ -50,7 +50,10 @@ struct task_list {
|
||||
ELLNODE node;
|
||||
VOIDFUNCPTR callback;
|
||||
void *arg;
|
||||
int tid;
|
||||
union {
|
||||
int tid;
|
||||
void *userpvt;
|
||||
} id;
|
||||
int suspended;
|
||||
};
|
||||
|
||||
@@ -91,20 +94,20 @@ void taskwdInsert(int tid,VOIDFUNCPTR callback,void *arg)
|
||||
pt = allocList();
|
||||
ellAdd(&list,(void *)pt);
|
||||
pt->suspended = FALSE;
|
||||
pt->tid = tid;
|
||||
pt->id.tid = tid;
|
||||
pt->callback = callback;
|
||||
pt->arg = arg;
|
||||
FASTUNLOCK(&lock);
|
||||
}
|
||||
|
||||
void taskwdAnyInsert(int tid,VOIDFUNCPTR callback,void *arg)
|
||||
void taskwdAnyInsert(void *userpvt,VOIDFUNCPTR callback,void *arg)
|
||||
{
|
||||
struct task_list *pt;
|
||||
|
||||
FASTLOCK(&anylock);
|
||||
pt = allocList();
|
||||
ellAdd(&anylist,(void *)pt);
|
||||
pt->tid = tid;
|
||||
pt->id.userpvt = userpvt;
|
||||
pt->callback = callback;
|
||||
pt->arg = arg;
|
||||
FASTUNLOCK(&anylock);
|
||||
@@ -117,7 +120,7 @@ void taskwdRemove(int tid)
|
||||
FASTLOCK(&lock);
|
||||
pt = (struct task_list *)ellFirst(&list);
|
||||
while(pt!=NULL) {
|
||||
if (tid == pt->tid) {
|
||||
if (tid == pt->id.tid) {
|
||||
ellDelete(&list,(void *)pt);
|
||||
freeList(pt);
|
||||
FASTUNLOCK(&lock);
|
||||
@@ -129,14 +132,14 @@ void taskwdRemove(int tid)
|
||||
errMessage(-1,"taskwdRemove failed");
|
||||
}
|
||||
|
||||
void taskwdAnyRemove(int tid)
|
||||
void taskwdAnyRemove(void *userpvt)
|
||||
{
|
||||
struct task_list *pt;
|
||||
|
||||
FASTLOCK(&anylock);
|
||||
pt = (struct task_list *)ellFirst(&anylist);
|
||||
while(pt!=NULL) {
|
||||
if (tid == pt->tid) {
|
||||
if (userpvt == pt->id.userpvt) {
|
||||
ellDelete(&anylist,(void *)pt);
|
||||
freeList(pt);
|
||||
FASTUNLOCK(&anylock);
|
||||
@@ -158,20 +161,20 @@ static void taskwdTask(void)
|
||||
pt = (struct task_list *)ellFirst(&list);
|
||||
while(pt) {
|
||||
next = (struct task_list *)ellNext((void *)pt);
|
||||
if(taskIsSuspended(pt->tid)) {
|
||||
if(taskIsSuspended(pt->id.tid)) {
|
||||
char *pname;
|
||||
char message[100];
|
||||
|
||||
pname = taskName(pt->tid);
|
||||
pname = taskName(pt->id.tid);
|
||||
if(!pt->suspended) {
|
||||
struct task_list *ptany,*anynext;
|
||||
|
||||
pt->suspended = TRUE;
|
||||
sprintf(message,"task %x %s suspended",pt->tid,pname);
|
||||
sprintf(message,"task %x %s suspended",pt->id.tid,pname);
|
||||
errMessage(-1,message);
|
||||
ptany = (struct task_list *)ellFirst(&anylist);
|
||||
while(ptany) {
|
||||
if(ptany->callback) (ptany->callback)(ptany->arg,pt->tid);
|
||||
if(ptany->callback) (ptany->callback)(ptany->arg,pt->id.tid);
|
||||
ptany = (struct task_list *)ellNext((ELLNODE *)ptany);
|
||||
}
|
||||
if(pt->callback) {
|
||||
@@ -185,6 +188,8 @@ static void taskwdTask(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pt->suspended = FALSE;
|
||||
}
|
||||
pt = next;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* devLib.c - support for allocation of common device resources */
|
||||
/* $Id$ */
|
||||
/* base/src/db $Id$ */
|
||||
|
||||
/*
|
||||
* Original Author: Marty Kraimer
|
||||
|
||||
Reference in New Issue
Block a user