From a8f39800979314983f0a73cf3fa375f512a77a3c Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Mon, 26 Mar 2001 21:40:07 +0000 Subject: [PATCH] Fix dbScanLock so it takes global lock --- src/db/dbAccess.c | 7 ++++++- src/db/dbLock.c | 39 +++++++++++---------------------------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/db/dbAccess.c b/src/db/dbAccess.c index 25b1bf46b..c39b841a9 100644 --- a/src/db/dbAccess.c +++ b/src/db/dbAccess.c @@ -1021,7 +1021,12 @@ long epicsShareAPI dbPutField( if(dbrType!=DBR_STRING) return(S_db_badDbrtype); /*begin kludge for old db_access MAX_STRING_SIZE*/ /*Allow M for MS and (N or NM) for NMS */ - strcpy(buffer,(char *)pbuffer); + if(strlen((char *)pbuffer)>=MAX_STRING_SIZE) { + errlogPrintf("dbPutField input string length >= MAX_STRING_SIZE"); + return(S_db_badField); + } + strncpy(buffer,(char *)pbuffer,MAX_STRING_SIZE); + buffer[MAX_STRING_SIZE] = 0; /*Strip trailing blanks*/ len = strlen(buffer); for(j=len-1; j>0; j--) { diff --git a/src/db/dbLock.c b/src/db/dbLock.c index 7c319dcb6..bcdc40cbd 100644 --- a/src/db/dbLock.c +++ b/src/db/dbLock.c @@ -26,15 +26,14 @@ 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) A thread is waiting for dbScanLock. -4) While lock set is being changed, a thread issues a dbScanLock. +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. -Call dbLockSetRecordLock for any record referenced during change. +Call dbLockSetRecordLock for any record referenced during change. It MUST NOT UNLOCK Call dbLockSetSplit before changing any link that is originally a DB_LINK Call dbLockSetMerge if changed link becomes a DB_LINK. @@ -43,16 +42,9 @@ Discussion: Each problem above is solved as follows: 1) dbLockGlobal solves this problem. -2) dbLockSetRecordLock solves this problem. -3) After changing lock sets original semId id deleted. - This makes all threads in semTake for that semaphore fail. - The code in dbScanLock makes thread recover. -4) The global variable changingLockSets and code in - dbScanLock and semFlush in dbLockSetGblUnlock solves - this problem. +2) dbLockSetRecordLock solves this problem. It takes the lock and then immediately unlocks. +3) dbScanLock first takes the global lock. -Note that all other threads are prevented from processing records between -dbLockSetGblLock and dbLockSetGblUnlock. 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 @@ -89,7 +81,6 @@ STATIC int lockListInitialized = FALSE; STATIC ELLLIST lockList; STATIC epicsMutexId globalLock; STATIC unsigned long id = 0; -STATIC volatile int changingLockSets = FALSE; typedef struct lockSet { ELLNODE node; @@ -109,6 +100,7 @@ typedef struct lockRecord { /*private routines */ STATIC void initLockList(void) { + if(lockListInitialized) return; ellInit(&lockList); globalLock = epicsMutexMustCreate(); lockListInitialized = TRUE; @@ -141,12 +133,10 @@ void epicsShareAPI dbLockSetGblLock(void) { if(!lockListInitialized) initLockList(); epicsMutexMustLock(globalLock); - changingLockSets = TRUE; } void epicsShareAPI dbLockSetGblUnlock(void) { - changingLockSets = FALSE; epicsMutexUnlock(globalLock); return; } @@ -157,12 +147,8 @@ void epicsShareAPI dbLockSetRecordLock(dbCommon *precord) lockSet *plockSet; epicsMutexLockStatus status; - /*Make sure that dbLockSetGblLock was called*/ - if(!changingLockSets) { - cantProceed("dbLockSetRecordLock called before dbLockSetGblLock\n"); - } /*Must make sure that no other thread has lock*/ - if(!plockRecord) return; + assert(plockRecord); plockSet = plockRecord->plockSet; if(!plockSet) return; if(plockSet->thread_id==epicsThreadGetIdSelf()) return; @@ -186,22 +172,18 @@ void epicsShareAPI dbScanLock(dbCommon *precord) { lockRecord *plockRecord; lockSet *plockSet; - epicsMutexLockStatus status; if(!(plockRecord= precord->lset)) { - epicsPrintf("dbScanLock plockRecord is NULL record %s\n", + epicsPrintf("dbScanLock lset is NULL for record %s\n", precord->name); epicsThreadSuspendSelf(); } - while(TRUE) { - while(changingLockSets) epicsThreadSleep(.05); - status = epicsMutexLock(plockRecord->plockSet->lock); - /*epicsMutexLock fails if epicsMutexDestroy was called while active*/ - if(status==epicsMutexLockOK) break; - } + epicsMutexMustLock(globalLock); plockSet = plockRecord->plockSet; + epicsMutexMustLock(plockSet->lock); plockSet->thread_id = epicsThreadGetIdSelf(); plockSet->precord = (void *)precord; + epicsMutexUnlock(globalLock); return; } @@ -239,6 +221,7 @@ void epicsShareAPI dbLockInitRecords(dbBase *pdbbase) int nrecords=0; lockRecord *plockRecord; + if(!lockListInitialized) initLockList(); /*Allocate and initialize a lockRecord for each record instance*/ for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); pdbRecordType; pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {