/*************************************************************************\ * Copyright (c) 2014 Brookhaven Science Assoc., as Operator of Brookhaven * National Laboratory. * SPDX-License-Identifier: EPICS * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ #ifndef DBLOCKPVT_H #define DBLOCKPVT_H #include "dbLock.h" #include "epicsSpin.h" /* Define to enable additional error checking */ #undef LOCKSET_DEBUG /* Define to disable the free list for lockSets */ #undef LOCKSET_NOFREE /* Define to disable use of recomputeCnt optimization */ #undef LOCKSET_NOCNT /* except for refcount (and lock), all members of dbLockSet * are guarded by its lock. */ typedef struct dbLockSet { ELLNODE node; ELLLIST lockRecordList; /* holds lockRecord::node */ epicsMutexId lock; unsigned long id; int refcount; #ifdef LOCKSET_DEBUG int ownercount; epicsThreadId owner; #endif dbLocker *ownerlocker; ELLNODE lockernode; int trace; /*For field TPRO*/ } lockSet; struct lockRecord; /* dbCommon.LSET is a plockRecord. * Except for spin and plockSet, all members of lockRecord are guarded * by the present lockset lock. * plockSet is guarded by spin. */ typedef struct lockRecord { ELLNODE node; /* in lockSet::lockRecordList */ /* The association between lockRecord and lockSet * can only be changed while the lockSet is held, * and the lockRecord's spinlock is held. * It may be read which either lock is held. */ lockSet *plockSet; /* the association between lockRecord and dbCommon never changes */ dbCommon *precord; epicsSpinId spin; /* temp used during lockset split. * lockSet must be locked for access */ ELLNODE compnode; unsigned int compflag; } lockRecord; typedef struct { lockRecord *plr; /* the last lock found associated with the ref. * not stable unless lock is locked, or ref spin * is locked. */ lockSet *plockSet; } lockRecordRef; #define DBLOCKER_NALLOC 2 /* a dbLocker can only be used by a single thread. */ struct dbLocker { ELLLIST locked; #ifndef LOCKSET_NOCNT size_t recomp; /* snapshot of recomputeCnt when refs[] cache updated */ #endif size_t maxrefs; lockRecordRef refs[DBLOCKER_NALLOC]; /* actual length is maxrefs */ }; #ifdef __cplusplus extern "C" { #endif /* These are exported for testing only */ DBCORE_API lockSet* dbLockGetRef(lockRecord *lr); /* lookup lockset and increment ref count */ DBCORE_API void dbLockIncRef(lockSet* ls); DBCORE_API void dbLockDecRef(lockSet *ls); /* Calling dbLockerPrepare directly is an internal * optimization used when dbLocker on the stack. * nrecs must be <=DBLOCKER_NALLOC. */ void dbLockerPrepare(struct dbLocker *locker, struct dbCommon * const *precs, size_t nrecs); void dbLockerFinalize(dbLocker *); void dbLockSetMerge(struct dbLocker *locker, struct dbCommon *pfirst, struct dbCommon *psecond); void dbLockSetSplit(struct dbLocker *locker, struct dbCommon *psource, struct dbCommon *psecond); #ifdef __cplusplus } #endif #endif /* DBLOCKPVT_H */