From: VMware, Inc <> Date: Thu, 27 Oct 2011 18:31:53 +0000 (-0700) Subject: lib/lock: Recursive lock destroy reference counting X-Git-Tag: 2011.10.26-514583~34 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=81afc8b7475769cbe603e2da1a982114ad33f0e4;p=thirdparty%2Fopen-vm-tools.git lib/lock: Recursive lock destroy reference counting Signed-off-by: Marcelo Vanzin --- diff --git a/open-vm-tools/lib/include/userlock.h b/open-vm-tools/lib/include/userlock.h index dff4220fa..8e798db9b 100644 --- a/open-vm-tools/lib/include/userlock.h +++ b/open-vm-tools/lib/include/userlock.h @@ -106,6 +106,13 @@ void MXUser_TimedWaitCondVarRecLock(MXUserRecLock *lock, MXUserCondVar *condVar, uint32 msecWait); +void MXUser_IncRefRecLock(MXUserRecLock *lock); + +void MXUser_DecRefRecLock(MXUserRecLock *lock); + +Bool MXUser_AcquireWeakRefRecLock(MXUserRecLock *lock); + + /* * Read-write lock */ @@ -211,7 +218,6 @@ MXUserRecLock *MXUser_InitFromMXRec(const char *name, struct MX_MutexRec *mutex, MX_Rank rank, Bool isBelowBull); - #endif #if defined(VMX86_DEBUG) && !defined(DISABLE_MXUSER_DEBUG) diff --git a/open-vm-tools/lib/lock/ulRec.c b/open-vm-tools/lib/lock/ulRec.c index 7bea01b49..94e3941a7 100644 --- a/open-vm-tools/lib/lock/ulRec.c +++ b/open-vm-tools/lib/lock/ulRec.c @@ -42,6 +42,8 @@ struct MXUserRecLock MXUserHeader header; MXRecLock recursiveLock; Atomic_Ptr statsMem; + Atomic_uint32 destroyRefCount; + Atomic_uint32 destroyWasCalled; /* * This is the MX recursive lock override pointer. It is used within the @@ -326,6 +328,8 @@ MXUserCreateRecLock(const char *userName, // IN: } lock->vmmLock = NULL; + Atomic_Write(&lock->destroyRefCount, 1); + Atomic_Write(&lock->destroyWasCalled, 0); lock->header.signature = MXUSER_REC_SIGNATURE; lock->header.name = properName; @@ -404,16 +408,17 @@ MXUser_CreateRecLock(const char *userName, // IN: /* *----------------------------------------------------------------------------- * - * MXUser_DestroyRecLock -- + * MXUserCondDestroyRecLock -- * - * Destroy a recursive lock. + * Destroy a recursive lock -- but only if its reference count is zero. * * When the lock is bound to a MX lock, only the MXUser "wrapper" is * freed. The caller is responsible for calling MX_DestroyLockRec() on * the MX lock before calling this routine. * * Results: - * Lock is destroyed. Don't use the pointer again. + * Lock is destroyed upon correct reference count. Don't use the + * pointer again. * * Side effects: * None @@ -421,15 +426,15 @@ MXUser_CreateRecLock(const char *userName, // IN: *----------------------------------------------------------------------------- */ -void -MXUser_DestroyRecLock(MXUserRecLock *lock) // IN: +static void +MXUserCondDestroyRecLock(MXUserRecLock *lock) // IN: { - if (lock != NULL) { - MXUserStats *stats; - - ASSERT(lock->header.signature == MXUSER_REC_SIGNATURE); + ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE)); + if (Atomic_FetchAndDec(&lock->destroyRefCount) == 1) { if (lock->vmmLock == NULL) { + MXUserStats *stats; + if (MXRecLockCount(&lock->recursiveLock) > 0) { MXUserDumpAndPanic(&lock->header, "%s: Destroy of an acquired recursive lock\n", @@ -459,11 +464,34 @@ MXUser_DestroyRecLock(MXUserRecLock *lock) // IN: } } +void +MXUser_DestroyRecLock(MXUserRecLock *lock) // IN: +{ + if (lock != NULL) { + ASSERT(lock->header.signature == MXUSER_REC_SIGNATURE); + + /* + * May not call destroy on a lock more than once + * + * That the code can get here may only occur if the reference count + * mechanism is used. + */ + + if (Atomic_FetchAndInc(&lock->destroyWasCalled) != 0) { + MXUserDumpAndPanic(&lock->header, + "%s: Destroy of a destroyed recursive lock\n", + __FUNCTION__); + } + + MXUserCondDestroyRecLock(lock); + } +} + /* *----------------------------------------------------------------------------- * - * MXUser_AcquireRecLock -- + * MXUserAcquireRecLock -- * * An acquisition is made (lock is taken) on the specified recursive lock. * @@ -478,8 +506,8 @@ MXUser_DestroyRecLock(MXUserRecLock *lock) // IN: *----------------------------------------------------------------------------- */ -void -MXUser_AcquireRecLock(MXUserRecLock *lock) // IN/OUT: +static void +MXUserAcquireRecLock(MXUserRecLock *lock) // IN/OUT: { ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE)); @@ -522,6 +550,17 @@ MXUser_AcquireRecLock(MXUserRecLock *lock) // IN/OUT: } +void +MXUser_AcquireRecLock(MXUserRecLock *lock) // IN/OUT: +{ + ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE)); + + ASSERT(Atomic_Read(&lock->destroyWasCalled) == 0); + + MXUserAcquireRecLock(lock); +} + + /* *----------------------------------------------------------------------------- * @@ -609,6 +648,10 @@ MXUser_TryAcquireRecLock(MXUserRecLock *lock) // IN/OUT: ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE)); + if (UNLIKELY(Atomic_Read(&lock->destroyWasCalled) != 0)) { + return FALSE; + } + if (lock->vmmLock) { ASSERT(MXUserMX_TryLockRec); success = (*MXUserMX_TryLockRec)(lock->vmmLock); @@ -943,6 +986,91 @@ MXUser_BindMXMutexRec(struct MX_MutexRec *mutex, // IN: } +/* + *----------------------------------------------------------------------------- + * + * MXUser_IncRefRecLock -- + * + * Add a reference to the lock to prevent an immediate destory from + * succeeding. + * + * Results: + * As above + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +MXUser_IncRefRecLock(MXUserRecLock *lock) // IN: +{ + ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE)); + + Atomic_Inc(&lock->destroyRefCount); +} + + +/* + *----------------------------------------------------------------------------- + * + * MXUser_DecRefRecLock -- + * + * Remove a reference to the lock. If the reference count is zero, + * the lock is destroyed. + * + * Results: + * As above + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +MXUser_DecRefRecLock(MXUserRecLock *lock) // IN: +{ + ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE)); + + MXUserCondDestroyRecLock(lock); +} + + +/* + *----------------------------------------------------------------------------- + * + * MXUser_AcquireWeakRefRecLock -- + * + * Acquire a lock only if destroy has not be called on it. This is + * special implementation that will have limited lifetime. Once Poll + * is upgraded to use trylock this implementation will go away. + * + * Results: + * As above + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +Bool +MXUser_AcquireWeakRefRecLock(MXUserRecLock *lock) // IN: +{ + ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE)); + + if (Atomic_Read(&lock->destroyWasCalled) != 0) { + return FALSE; + } else { + MXUserAcquireRecLock(lock); + + return TRUE; + } +} + + #if defined(VMX86_VMX) #include "mutex.h" #include "mutexRankVMX.h"