major change in algortihm

This commit is contained in:
Marty Kraimer
2001-03-30 20:20:55 +00:00
parent 5645505564
commit 1e33387764

View File

@@ -19,17 +19,6 @@ of this distribution.
/************** DISCUSSION OF DYNAMIC LINK MODIFICATION **********************
Since the purpose of lock sets is to prevent multiple thread from simultaneously
accessing records in set, dynamically changing lock sets presents a problem.
Four problems arise:
1) Two threads simultaneoulsy trying to change lock sets
2) Another thread has successfully issued a dbScanLock and currently owns it.
3) While lock set is being changed, a thread issues a dbScanLock.
Solution:
A routine attempting to modify a link must do the following:
Call dbLockSetGblLock before modifying any link and dbLockSetGblUnlock after.
@@ -37,14 +26,23 @@ Call dbLockSetRecordLock for any record referenced during change. It MUST NOT U
Call dbLockSetSplit before changing any link that is originally a DB_LINK
Call dbLockSetMerge if changed link becomes a DB_LINK.
Discussion:
Since the purpose of lock sets is to prevent multiple thread from simultaneously
accessing records in set, dynamically changing lock sets presents a problem.
Three problems arise:
Each problem above is solved as follows:
1) dbLockGlobal solves this problem.
2) dbLockSetRecordLock solves this problem. It takes the lock and then immediately unlocks.
3) dbScanLock first takes the global lock.
1) Two threads simultaneoulsy trying to change lock sets
2) Another thread has successfully issued a dbScanLock and currently owns it.
3) While lock set is being changed, a thread issues a dbScanLock.
solution:
1) globalLock is locked during the entire time a thread is modifying lock sets
2) lockSetModifyLock is locked whenever any fields in lockSet are being accessed
or lockRecord.plockSet is being accessed.
NOTE:
dblsr may crash if executed while lock sets are being modified.
It is NOT a good idea to make it more robust by issuing dbLockSetGblLock
@@ -60,6 +58,7 @@ since this will delay all other threads.
#include "dbBase.h"
#include "epicsMutex.h"
#include "epicsThread.h"
#include "epicsAssert.h"
#include "cantProceed.h"
#include "ellLib.h"
#include "dbBase.h"
@@ -76,49 +75,103 @@ since this will delay all other threads.
#define STATIC static
STATIC int lockListInitialized = FALSE;
STATIC int dbLockIsInitialized = FALSE;
STATIC ELLLIST lockList;
typedef enum {
listTypeScanLock = 0,
listTypeRecordLock = 1,
listTypeFree = 2
} listType;
#define nlistType listTypeFree + 1
STATIC ELLLIST lockSetList[nlistType];
STATIC epicsMutexId globalLock;
STATIC epicsMutexId lockSetModifyLock;
STATIC unsigned long id = 0;
typedef enum {
lockSetStateFree=0, lockSetStateScanLock, lockSetStateRecordLock
} lockSetState;
typedef struct lockSet {
ELLNODE node;
ELLLIST recordList;
epicsMutexId lock;
epicsThreadId thread_id;
dbCommon *precord;
unsigned long id;
ELLNODE node;
ELLLIST recordList;
epicsMutexId lock;
unsigned long id;
listType type;
lockSetState state;
epicsThreadId thread_id;
dbCommon *precord;
int nRecursion;
int nWaiting;
} lockSet;
typedef struct splitNode {
ELLNODE node;
struct lockRecord *plockRecord;
}splitNode;
/* dbCommon.LSET is a plockRecord */
typedef struct lockRecord {
ELLNODE node;
lockSet *plockSet;
dbCommon *precord;
ELLNODE node;
splitNode node2;
lockSet *plockSet;
dbCommon *precord;
} lockRecord;
/*private routines */
STATIC void initLockList(void)
STATIC void dbLockInitialize(void)
{
if(lockListInitialized) return;
ellInit(&lockList);
int i;
if(dbLockIsInitialized) return;
for(i=0; i< nlistType; i++) ellInit(&lockSetList[i]);
globalLock = epicsMutexMustCreate();
lockListInitialized = TRUE;
lockSetModifyLock = epicsMutexMustCreate();
dbLockIsInitialized = TRUE;
}
STATIC lockSet * allocLock(lockRecord *plockRecord)
unsigned long epicsShareAPI dbLockGetLockId(dbCommon *precord)
{
lockRecord *plockRecord = precord->lset;
lockSet *plockSet;
long id = 0;
assert(plockRecord);
epicsMutexMustLock(lockSetModifyLock);
plockSet = plockRecord->plockSet;
if(!plockSet) id = plockSet->id;
epicsMutexUnlock(lockSetModifyLock);
return(id);
}
STATIC lockSet * allocLock(
lockRecord *plockRecord, listType type,
lockSetState state, epicsThreadId thread_id, dbCommon *precord)
{
lockSet *plockSet;
if(!lockListInitialized) initLockList();
plockSet = dbCalloc(1,sizeof(lockSet));
assert(dbLockIsInitialized);
plockSet = (lockSet *)ellFirst(&lockSetList[listTypeFree]);
if(plockSet) {
ellDelete(&lockSetList[listTypeFree],&plockSet->node);
} else {
plockSet = dbCalloc(1,sizeof(lockSet));
plockSet->lock = epicsMutexMustCreate();
}
ellInit(&plockSet->recordList);
plockRecord->plockSet = plockSet;
id++;
plockSet->id = id;
plockSet->type = type;
plockSet->state = state;
plockSet->thread_id = thread_id;
plockSet->precord = precord;
plockSet->nRecursion = 0;
plockSet->nWaiting = 0;
ellAdd(&plockSet->recordList,&plockRecord->node);
ellAdd(&lockList,&plockSet->node);
plockSet->lock = epicsMutexMustCreate();
ellAdd(&lockSetList[type],&plockSet->node);
return(plockSet);
}
@@ -131,12 +184,29 @@ STATIC void lockAddRecord(lockSet *plockSet,lockRecord *pnew)
void epicsShareAPI dbLockSetGblLock(void)
{
if(!lockListInitialized) initLockList();
assert(dbLockIsInitialized);
epicsMutexMustLock(globalLock);
}
void epicsShareAPI dbLockSetGblUnlock(void)
{
lockSet *plockSet;
lockSet *pnext;
epicsMutexMustLock(lockSetModifyLock);
plockSet = (lockSet *)ellFirst(&lockSetList[listTypeRecordLock]);
while(plockSet) {
pnext = (lockSet *)ellNext(&plockSet->node);
ellDelete(&lockSetList[listTypeRecordLock],&plockSet->node);
plockSet->type = listTypeScanLock;
plockSet->state = lockSetStateFree;
plockSet->thread_id = 0;
plockSet->precord = 0;
plockSet->nRecursion = 0;
plockSet->nWaiting = 0;
ellAdd(&lockSetList[listTypeScanLock],&plockSet->node);
plockSet = pnext;
}
epicsMutexUnlock(lockSetModifyLock);
epicsMutexUnlock(globalLock);
return;
}
@@ -149,65 +219,103 @@ void epicsShareAPI dbLockSetRecordLock(dbCommon *precord)
/*Must make sure that no other thread has lock*/
assert(plockRecord);
epicsMutexMustLock(lockSetModifyLock);
plockSet = plockRecord->plockSet;
if(!plockSet) return;
if(plockSet->thread_id==epicsThreadGetIdSelf()) return;
/*Wait for up to 1 minute*/
status = epicsMutexLockWithTimeout(plockRecord->plockSet->lock,60.0);
if(status==epicsMutexLockOK) {
plockSet->thread_id = epicsThreadGetIdSelf();
plockSet->precord = (void *)precord;
/*give it back in case it will not be changed*/
epicsMutexUnlock(plockRecord->plockSet->lock);
return;
if(!plockSet || (plockSet->type==listTypeRecordLock)) {
epicsMutexUnlock(lockSetModifyLock);
return;
}
/*Should never reach this point*/
errlogPrintf("dbLockSetRecordLock timeout caller 0x%x owner 0x%x",
epicsThreadGetIdSelf(),plockSet->thread_id);
errlogPrintf(" record %s\n",precord->name);
cantProceed("dbLockSetRecordLock");
plockSet->state = lockSetStateRecordLock;
while(plockSet->nWaiting) {
epicsMutexUnlock(lockSetModifyLock);
epicsThreadSleep(.1);
}
/*
status = epicsMutexTryLock(plockRecord->plockSet->lock);
assert(status==epicsMutexLockOK);
epicsMutexUnlock(plockRecord->plockSet->lock);
*/
ellDelete(&lockSetList[plockSet->type],&plockSet->node);
ellAdd(&lockSetList[listTypeRecordLock],&plockSet->node);
plockSet->type = listTypeRecordLock;
plockSet->thread_id = epicsThreadGetIdSelf();
plockSet->precord = 0;
epicsMutexUnlock(lockSetModifyLock);
}
void epicsShareAPI dbScanLock(dbCommon *precord)
{
lockRecord *plockRecord;
lockRecord *plockRecord = precord->lset;
lockSet *plockSet;
epicsMutexLockStatus status;
epicsThreadId idSelf = epicsThreadGetIdSelf();
if(!(plockRecord= precord->lset)) {
epicsPrintf("dbScanLock lset is NULL for record %s\n",
precord->name);
epicsThreadSuspendSelf();
assert(dbLockIsInitialized);
while(1) {
epicsMutexMustLock(lockSetModifyLock);
plockSet = plockRecord->plockSet;
if(!plockSet) goto getGlobalLock;
switch(plockSet->state) {
case lockSetStateFree:
status = epicsMutexTryLock(plockSet->lock);
assert(status==epicsMutexLockOK);
plockSet->nRecursion = 1;
plockSet->thread_id = idSelf;
plockSet->precord = precord;
plockSet->state = lockSetStateScanLock;
epicsMutexUnlock(lockSetModifyLock);
return;
case lockSetStateScanLock:
if(plockSet->thread_id!=idSelf) {
plockSet->nWaiting +=1;
epicsMutexUnlock(lockSetModifyLock);
epicsMutexMustLock(plockSet->lock);
epicsMutexMustLock(lockSetModifyLock);
plockSet->nWaiting -=1;
plockSet->nRecursion = 1;
plockSet->thread_id = idSelf;
plockSet->precord = precord;
} else {
plockSet->nRecursion += 1;
}
epicsMutexUnlock(lockSetModifyLock);
return;
case lockSetStateRecordLock:
/*Only recursive locking is permitted*/
if((plockSet->nRecursion==0) || (plockSet->thread_id!=idSelf))
goto getGlobalLock;
plockSet->nRecursion += 1;
epicsMutexUnlock(lockSetModifyLock);
return;
default:
cantProceed("dbScanLock. Bad case choice");
}
getGlobalLock:
epicsMutexUnlock(lockSetModifyLock);
epicsMutexMustLock(globalLock);
epicsMutexUnlock(globalLock);
}
epicsMutexMustLock(globalLock);
plockSet = plockRecord->plockSet;
epicsMutexMustLock(plockSet->lock);
plockSet->thread_id = epicsThreadGetIdSelf();
plockSet->precord = (void *)precord;
epicsMutexUnlock(globalLock);
return;
}
void epicsShareAPI dbScanUnlock(dbCommon *precord)
{
lockRecord *plockRecord = precord->lset;
if(!plockRecord || !plockRecord->plockSet) {
epicsPrintf("dbScanUnlock plockRecord or plockRecord->plockSet NULL\n");
return;
}
epicsMutexUnlock(plockRecord->plockSet->lock);
return;
}
unsigned long epicsShareAPI dbLockGetLockId(dbCommon *precord)
{
lockRecord *plockRecord = precord->lset;
lockSet *plockSet;
if(!plockRecord) return(0);
assert(plockRecord);
epicsMutexMustLock(lockSetModifyLock);
plockSet = plockRecord->plockSet;
if(!plockSet) return(0);
return(plockSet->id);
assert(plockSet);
plockSet->nRecursion -= 1;
if(plockSet->nRecursion==0) {
plockSet->thread_id = 0;
plockSet->precord = 0;
if((plockSet->state == lockSetStateScanLock)
&& (plockSet->nWaiting==0)) plockSet->state = lockSetStateFree;
epicsMutexUnlock(plockRecord->plockSet->lock);
}
epicsMutexUnlock(lockSetModifyLock);
return;
}
void epicsShareAPI dbLockInitRecords(dbBase *pdbbase)
@@ -221,55 +329,59 @@ void epicsShareAPI dbLockInitRecords(dbBase *pdbbase)
int nrecords=0;
lockRecord *plockRecord;
if(!lockListInitialized) initLockList();
if(!dbLockIsInitialized) dbLockInitialize();
/*Allocate and initialize a lockRecord for each record instance*/
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); pdbRecordType;
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
nrecords += ellCount(&pdbRecordType->recList);
nrecords += ellCount(&pdbRecordType->recList);
}
/*Allocate all of them at once */
plockRecord = dbCalloc(nrecords,sizeof(lockRecord));
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); pdbRecordType;
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
precord = pdbRecordNode->precord;
plockRecord->precord = precord;
precord->lset = plockRecord;
plockRecord++;
}
for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
precord = pdbRecordNode->precord;
plockRecord->precord = precord;
plockRecord->node2.plockRecord = plockRecord;
precord->lset = plockRecord;
plockRecord++;
}
}
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
precord = pdbRecordNode->precord;
if(!(precord->name[0])) continue;
for(link=0; link<pdbRecordType->no_links; link++) {
DBADDR *pdbAddr;
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[link]];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if(plink->type != DB_LINK) continue;
pdbAddr = (DBADDR *)(plink->value.pv_link.pvt);
for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
precord = pdbRecordNode->precord;
if(!(precord->name[0])) continue;
plockRecord = precord->lset;
if(!plockRecord->plockSet)
allocLock(plockRecord,listTypeScanLock,lockSetStateFree,0,0);
for(link=0; link<pdbRecordType->no_links; link++) {
DBADDR *pdbAddr;
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[link]];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if(plink->type != DB_LINK) continue;
pdbAddr = (DBADDR *)(plink->value.pv_link.pvt);
/* 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 (pdbFldDes->field_type==DBF_INLINK
&& !(plink->value.pv_link.pvlMask&pvlOptPP)
&& !(plink->value.pv_link.pvlMask&pvlOptMS)
&& pdbAddr->no_elements<=1) continue;
dbLockSetMerge(precord,pdbAddr->precord);
}
plockRecord = precord->lset;
if(!plockRecord->plockSet) allocLock(plockRecord);
}
if (pdbFldDes->field_type==DBF_INLINK
&& !(plink->value.pv_link.pvlMask&pvlOptPP)
&& !(plink->value.pv_link.pvlMask&pvlOptMS)
&& pdbAddr->no_elements<=1) continue;
dbLockSetMerge(precord,pdbAddr->precord);
}
}
}
}
@@ -279,32 +391,38 @@ void epicsShareAPI dbLockSetMerge(dbCommon *pfirst,dbCommon *psecond)
lockRecord *p2lockRecord = psecond->lset;
lockSet *p1lockSet;
lockSet *p2lockSet;
lockRecord *plockRecord;
lockRecord *pnext;
if(pfirst==psecond) return;
epicsMutexMustLock(lockSetModifyLock);
if(pfirst==psecond) goto all_done;
p1lockSet = p1lockRecord->plockSet;
p2lockSet = p2lockRecord->plockSet;
assert(!(!p1lockSet && !p2lockSet));
if(p1lockSet == p2lockSet) goto all_done;
if(!p1lockSet) {
if(p2lockSet) {
lockAddRecord(p2lockSet,p1lockRecord);
return;
}
p1lockSet = allocLock(p1lockRecord);
lockAddRecord(p2lockSet,p1lockRecord);
goto all_done;
}
if(p1lockSet == p2lockSet) return;
if(!p2lockSet) {
lockAddRecord(p1lockSet,p2lockRecord);
return;
lockAddRecord(p1lockSet,p2lockRecord);
goto all_done;
}
/*Move entire second list to first*/
p2lockRecord = (lockRecord *)ellFirst(&p2lockSet->recordList);
while(p2lockRecord) {
p2lockRecord->plockSet = p1lockSet;
p2lockRecord = (lockRecord *)ellNext(&p2lockRecord->node);
assert(p1lockSet->type == p2lockSet->type);
plockRecord = (lockRecord *)ellFirst(&p2lockSet->recordList);
while(plockRecord) {
pnext = (lockRecord *)ellNext(&plockRecord->node);
ellDelete(&p2lockSet->recordList,&plockRecord->node);
plockRecord->plockSet = p1lockSet;
ellAdd(&p1lockSet->recordList,&plockRecord->node);
plockRecord = pnext;
}
ellConcat(&p1lockSet->recordList,&p2lockSet->recordList);
epicsMutexDestroy(p2lockSet->lock);
ellDelete(&lockList,&p2lockSet->node);
free((void *)p2lockSet);
ellDelete(&lockSetList[p2lockSet->type],&p2lockSet->node);
p2lockSet->type = listTypeFree;
ellAdd(&lockSetList[listTypeFree],&p2lockSet->node);
all_done:
epicsMutexUnlock(lockSetModifyLock);
return;
}
@@ -312,59 +430,71 @@ void epicsShareAPI dbLockSetSplit(dbCommon *psource)
{
lockSet *plockSet;
lockRecord *plockRecord;
lockRecord *pnext;
splitNode *psplitNode;
splitNode *pnextSplit;
dbCommon *precord;
int link;
dbRecordType *pdbRecordType;
dbFldDes *pdbFldDes;
DBLINK *plink;
int nrecordsInSet,i;
dbCommon **paprecord;
ELLLIST recordList;
plockRecord = psource->lset;
if(!plockRecord) {
errMessage(-1,"dbLockSetSplit called before lockRecord allocated");
return;
}
if(!plockRecord)
cantProceed("dbLockSetSplit called before lockRecord allocated");
plockSet = plockRecord->plockSet;
if(!plockSet) {
errMessage(-1,"dbLockSetSplit called without lockSet allocated");
return;
}
if(!plockSet)
cantProceed("dbLockSetSplit called without lockSet allocated");
/*First remove all records from lock set*/
nrecordsInSet = ellCount(&plockSet->recordList);
paprecord = dbCalloc(nrecordsInSet,sizeof(dbCommon *));
for(plockRecord = (lockRecord *)ellFirst(&plockSet->recordList), i=0;
plockRecord;
plockRecord = (lockRecord *)ellNext(&plockRecord->node), i++) {
paprecord[i] = plockRecord->precord;
plockRecord->plockSet = 0;
ellInit(&recordList);
epicsMutexMustLock(lockSetModifyLock);
plockRecord = (lockRecord *)ellFirst(&plockSet->recordList);
while(plockRecord) {
pnext = (lockRecord *)ellNext(&plockRecord->node);
ellDelete(&plockSet->recordList,&plockRecord->node);
plockRecord->plockSet = 0;
ellAdd(&recordList,&plockRecord->node2.node);
plockRecord = pnext;
}
ellDelete(&lockSetList[plockSet->type],&plockSet->node);
ellAdd(&lockSetList[listTypeFree],&plockSet->node);
epicsMutexUnlock(lockSetModifyLock);
/*Now recompute lock sets */
for(i=0; i<nrecordsInSet; i++) {
precord = paprecord[i];
plockRecord = precord->lset;
if(!(precord->name[0])) continue;
pdbRecordType = precord->rdes;
psplitNode = (splitNode *)ellFirst(&recordList);
while(psplitNode) {
pnextSplit = (splitNode *)ellNext(&psplitNode->node);
ellDelete(&recordList,&psplitNode->node);
epicsMutexMustLock(lockSetModifyLock);
plockRecord = psplitNode->plockRecord;
if(!plockRecord->plockSet) {
allocLock(plockRecord,listTypeRecordLock,lockSetStateRecordLock,
epicsThreadGetIdSelf(),0);
}
precord = plockRecord->precord;
epicsMutexUnlock(lockSetModifyLock);
if(!(precord->name[0])) {
psplitNode = pnextSplit;
continue;
}
pdbRecordType = precord->rdes;
for(link=0; link<pdbRecordType->no_links; link++) {
DBADDR *pdbAddr;
DBADDR *pdbAddr;
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[link]];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if(plink->type != DB_LINK) continue;
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[link]];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if(plink->type != DB_LINK) continue;
pdbAddr = (DBADDR *)(plink->value.pv_link.pvt);
if (pdbFldDes->field_type==DBF_INLINK
&& !(plink->value.pv_link.pvlMask&pvlOptPP)
&& !(plink->value.pv_link.pvlMask&pvlOptMS)
&& pdbAddr->no_elements<=1) continue;
dbLockSetMerge(precord,pdbAddr->precord);
}
if(!plockRecord->plockSet) allocLock(plockRecord);
pdbAddr = (DBADDR *)(plink->value.pv_link.pvt);
if (pdbFldDes->field_type==DBF_INLINK
&& !(plink->value.pv_link.pvlMask&pvlOptPP)
&& !(plink->value.pv_link.pvlMask&pvlOptMS)
&& pdbAddr->no_elements<=1) continue;
dbLockSetMerge(precord,pdbAddr->precord);
}
psplitNode = pnextSplit;
}
epicsMutexDestroy(plockSet->lock);
ellDelete(&lockList,&plockSet->node);
free((void *)plockSet);
free((void *)paprecord);
}
long epicsShareAPI dblsr(char *recordname,int level)
@@ -380,68 +510,66 @@ long epicsShareAPI dblsr(char *recordname,int level)
dbFldDes *pdbFldDes;
DBLINK *plink;
printf("globalLock %p\n",globalLock);
printf("lockSetModifyLock %p\n",lockSetModifyLock);
if(recordname) {
dbInitEntry(pdbbase,pdbentry);
status = dbFindRecord(pdbentry,recordname);
if(status) {
printf("Record not found\n");
dbFinishEntry(pdbentry);
return(0);
}
precord = pdbentry->precnode->precord;
dbFinishEntry(pdbentry);
plockRecord = precord->lset;
if(!plockRecord) return(0);
plockSet = plockRecord->plockSet;
dbInitEntry(pdbbase,pdbentry);
status = dbFindRecord(pdbentry,recordname);
if(status) {
printf("Record not found\n");
dbFinishEntry(pdbentry);
return(0);
}
precord = pdbentry->precnode->precord;
dbFinishEntry(pdbentry);
plockRecord = precord->lset;
if(!plockRecord) return(0);
plockSet = plockRecord->plockSet;
} else {
plockSet = (lockSet *)ellFirst(&lockList);
plockSet = (lockSet *)ellFirst(&lockSetList[listTypeScanLock]);
}
for( ; plockSet; plockSet = (lockSet *)ellNext(&plockSet->node)) {
printf("Lock Set %lu %d members",
plockSet->id,ellCount(&plockSet->recordList));
if(epicsMutexTryLock(plockSet->lock)==epicsMutexLockOK) {
epicsMutexUnlock(plockSet->lock);
printf(" Not Locked\n");
} else {
printf(" Locked by thread %p",plockSet->thread_id);
if(! plockSet->precord || !plockSet->precord->name)
printf(" NULL record or record name\n");
else
printf(" record %s\n",plockSet->precord->name);
}
if(level==0) {
if(recordname) break;
continue;
}
for(plockRecord = (lockRecord *)ellFirst(&plockSet->recordList);
plockRecord; plockRecord = (lockRecord *)ellNext(&plockRecord->node)) {
precord = plockRecord->precord;
pdbRecordType = precord->rdes;
printf("%s\n",precord->name);
if(level<=1) continue;
for(link=0; (link<pdbRecordType->no_links) ; link++) {
DBADDR *pdbAddr;
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[link]];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if(plink->type != DB_LINK) continue;
pdbAddr = (DBADDR *)(plink->value.pv_link.pvt);
printf("\t%s",pdbFldDes->name);
if(pdbFldDes->field_type==DBF_INLINK) {
printf("\t INLINK");
} else if(pdbFldDes->field_type==DBF_OUTLINK) {
printf("\tOUTLINK");
} else if(pdbFldDes->field_type==DBF_FWDLINK) {
printf("\tFWDLINK");
}
printf(" %s %s",
((plink->value.pv_link.pvlMask&pvlOptPP)?" PP":"NPP"),
((plink->value.pv_link.pvlMask&pvlOptMS)?" MS":"NMS"));
printf(" %s\n",pdbAddr->precord->name);
}
}
if(recordname) break;
printf("Lock Set %lu %d members epicsMutexId %p",
plockSet->id,ellCount(&plockSet->recordList),plockSet->lock);
if(epicsMutexTryLock(plockSet->lock)==epicsMutexLockOK) {
epicsMutexUnlock(plockSet->lock);
printf(" Not Locked\n");
} else {
printf(" thread %p",plockSet->thread_id);
if(! plockSet->precord || !plockSet->precord->name)
printf(" NULL record or record name\n");
else
printf(" record %s\n",plockSet->precord->name);
}
if(level==0) { if(recordname) break; continue; }
for(plockRecord = (lockRecord *)ellFirst(&plockSet->recordList);
plockRecord; plockRecord = (lockRecord *)ellNext(&plockRecord->node)) {
precord = plockRecord->precord;
pdbRecordType = precord->rdes;
printf("%s\n",precord->name);
if(level<=1) continue;
for(link=0; (link<pdbRecordType->no_links) ; link++) {
DBADDR *pdbAddr;
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[link]];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if(plink->type != DB_LINK) continue;
pdbAddr = (DBADDR *)(plink->value.pv_link.pvt);
printf("\t%s",pdbFldDes->name);
if(pdbFldDes->field_type==DBF_INLINK) {
printf("\t INLINK");
} else if(pdbFldDes->field_type==DBF_OUTLINK) {
printf("\tOUTLINK");
} else if(pdbFldDes->field_type==DBF_FWDLINK) {
printf("\tFWDLINK");
}
printf(" %s %s",
((plink->value.pv_link.pvlMask&pvlOptPP)?" PP":"NPP"),
((plink->value.pv_link.pvlMask&pvlOptMS)?" MS":"NMS"));
printf(" %s\n",pdbAddr->precord->name);
}
}
if(recordname) break;
}
return(0);
}