Bool (*MXUserMX_IsLockedByCurThreadRec)(const struct MX_MutexRec *lock) = NULL;
-#if defined(MXUSER_DEBUG) || defined(MXUSER_STATS)
-/*
- *-----------------------------------------------------------------------------
- *
- * MXUserMaintainMaxTid --
- *
- * Maintain the maximum known thread ID.
- *
- * Results:
- * As Above.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Atomic_uint32 mxMaxThreadID; // implicitly initialized to 0 -- mbellon
+#if defined(MXUSER_DEBUG)
+#define MXUSER_MAX_LOCKS_PER_THREAD (2 * MXUSER_MAX_REC_DEPTH)
-static void
-MXUserMaintainMaxTid(VThreadID tid) // IN:
-{
- while (TRUE) {
- uint32 curValue = Atomic_Read(&mxMaxThreadID);
+typedef struct {
+ uint32 locksHeld;
+ MXUserHeader *lockArray[MXUSER_MAX_LOCKS_PER_THREAD];
+} MXUserPerThread;
- if (tid <= curValue) {
- break;
- }
-
- Atomic_ReadIfEqualWrite(&mxMaxThreadID, curValue, tid);
- }
-}
+static Atomic_Ptr hashTableMem;
/*
*/
MXUserPerThread *
-MXUserGetPerThread(VThreadID tid, // IN: thread ID
+MXUserGetPerThread(void *tid, // IN: native thread ID
Bool mayAlloc) // IN: alloc perThread if not present?
{
- MXUserPerThread *perThread;
-
-#if defined(VMX86_VMX)
- /*
- * Inside the VMX we have a tightly controlled environment with a rigidly
- * controlled maximum number of threads. That being the case, use a simple,
- * low memory usage and *VERY* fast scheme to manage the perThread data.
- */
-
- static Atomic_Ptr perThreadArray[VTHREAD_MAX_THREADS];
-
- if (tid >= VTHREAD_MAX_THREADS) {
- Panic("%s: tid out of bounds (%u)\n", __FUNCTION__, tid);
- }
-
- perThread = Atomic_ReadPtr(&perThreadArray[tid]);
-
- if ((perThread == NULL) && mayAlloc) {
- MXUserPerThread *before;
-
- perThread = Util_SafeCalloc(1, sizeof(MXUserPerThread));
-
- before = Atomic_ReadIfEqualWritePtr(&perThreadArray[tid], NULL,
- (void *) perThread);
-
- if (before) {
- free(perThread);
- }
-
- MXUserMaintainMaxTid(tid); // track the maximum known tid
-
- perThread = Atomic_ReadPtr(&perThreadArray[tid]);
- ASSERT(perThread);
- }
-#else
- /*
- * Outside the VMX there are no controls on the number of threads that can
- * use MXUser locks. Here use an open ended, reasonably fast scheme for
- * managing the perThread data.
- *
- * Use an atomic hash table to manage the perThread data. This avoids a
- * great deal of locking and syncronization overhead.
- */
-
HashTable *hash;
-
- static Atomic_Ptr hashTableMem;
+ MXUserPerThread *perThread;
hash = HashTable_AllocOnce(&hashTableMem, 1024,
HASH_INT_KEY | HASH_FLAG_ATOMIC, NULL);
perThread = NULL;
- if (!HashTable_Lookup(hash, (void *) (uintptr_t) tid,
- (void **) &perThread)) {
+ if (!HashTable_Lookup(hash, tid, (void **) &perThread)) {
/* No entry for this tid was found, allocate one? */
if (mayAlloc) {
* the mess.
*/
- perThread = HashTable_LookupOrInsert(hash, (void *) (uintptr_t) tid,
- newEntry);
+ perThread = HashTable_LookupOrInsert(hash, tid, newEntry);
ASSERT(perThread);
if (perThread != newEntry) {
perThread = NULL;
}
}
-#endif
return perThread;
}
-#endif
-#if defined(MXUSER_DEBUG)
/*
*-----------------------------------------------------------------------------
*
- * MXUser_AnyLocksHeld --
- *
- * Are any MXUser locks held?
- *
- * A tid of VTHREAD_INVALID_ID asks to check locks across all threads
- * (via an linear search over all threads); such a check may return an
- * incorrect or stale result in an active multi-threaded environment.
+ * MXUser_IsCurThreadHoldingLocks --
*
- * A tid other than VTHREAD_INVALID_ID will check locks for the specified
- * thread. The results of this check are always valid for the calling
- * thread but may be incorrect or stale for other threads.
+ * Are any MXUser locks held by the calling thread?
*
* Results:
* TRUE Yes
*/
Bool
-MXUser_AnyLocksHeld(VThreadID tid) // IN:
+MXUser_IsCurThreadHoldingLocks(void)
{
- Bool result;
-
- if (tid == VTHREAD_INVALID_ID) {
- uint32 i;
- uint32 maxThreadID = Atomic_Read(&mxMaxThreadID);
-
- result = FALSE;
-
- for (i = 0; i < maxThreadID; i++) {
- MXUserPerThread *perThread = MXUserGetPerThread(i, FALSE);
-
- if (perThread && (perThread->locksHeld != 0)) {
- result = TRUE;
- break;
- }
- }
- } else {
- MXUserPerThread *perThread = MXUserGetPerThread(tid, FALSE);
-
- result = (perThread == NULL) ? FALSE : (perThread->locksHeld != 0);
- }
+ MXUserPerThread *perThread = MXUserGetPerThread(MXUserGetNativeTID(),
+ FALSE);
- return result;
+ return (perThread == NULL) ? FALSE : (perThread->locksHeld != 0);
}
MXUserAcquisitionTracking(MXUserHeader *header, // IN:
Bool checkRank) // IN:
{
- VThreadID tid = VThread_CurID();
- MXUserPerThread *perThread = MXUserGetPerThread(tid, TRUE);
+ MXUserPerThread *perThread = MXUserGetPerThread(MXUserGetNativeTID(), TRUE);
ASSERT_NOT_IMPLEMENTED(perThread->locksHeld < MXUSER_MAX_LOCKS_PER_THREAD);
{
uint32 i;
uint32 lastEntry;
- VThreadID tid = VThread_CurID();
+ void *tid = MXUserGetNativeTID();
MXUserPerThread *perThread = MXUserGetPerThread(tid, FALSE);
/* MXUserAcquisitionTracking should have already created a perThread */
if (UNLIKELY(perThread == NULL)) {
- MXUserDumpAndPanic(header, "%s: perThread not found! (thread %u)\n",
+ MXUserDumpAndPanic(header, "%s: perThread not found! (thread %p)\n",
__FUNCTION__, tid);
}
/* The argument lock had better be in the perThread */
if (UNLIKELY(i >= perThread->locksHeld)) {
- MXUserDumpAndPanic(header, "%s: lock not found! (thread %u; count %u)\n",
+ MXUserDumpAndPanic(header, "%s: lock not found! (thread %p; count %u)\n",
__FUNCTION__, tid, perThread->locksHeld);
}
MXUserListLocks(void)
{
#if defined(MXUSER_DEBUG)
- MXUserPerThread *perThread = MXUserGetPerThread(VThread_CurID(), FALSE);
+ MXUserPerThread *perThread = MXUserGetPerThread(MXUserGetNativeTID(),
+ FALSE);
if (perThread != NULL) {
uint32 i;
MXThreadID nativeThreadID; // Native thread ID
#if defined(MXUSER_DEBUG)
- VThreadID portableThreadID; // VThreadID, when available
const void *ownerRetAddr; // return address of acquisition routine
#endif
} MXRecLock;
lock->referenceCount = 0;
#if defined(MXUSER_DEBUG)
- lock->portableThreadID = VTHREAD_INVALID_ID;
lock->ownerRetAddr = NULL;
#endif
}
{
if (MXRecLockCount(lock) == 0) {
#if defined(MXUSER_DEBUG)
- ASSERT(lock->portableThreadID == VTHREAD_INVALID_ID);
-
lock->ownerRetAddr = location;
- lock->portableThreadID = VThread_CurID();
#endif
MXRecLockSetOwner(lock);
#if defined(MXUSER_DEBUG)
lock->ownerRetAddr = NULL;
- lock->portableThreadID = VTHREAD_INVALID_ID;
#endif
}
}
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MXUserGetNativeTID --
+ *
+ * Gets a native representation of the thread ID, which can be stored
+ * in a pointer.
+ *
+ * Results:
+ * Native representation of a thread ID.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void *
+MXUserGetNativeTID(void)
+{
+ /* All thread types must fit into a uintptr_t */
+
+#if defined(_WIN32)
+ ASSERT_ON_COMPILE(sizeof(DWORD) <= sizeof (void *));
+ return (void *) (uintptr_t) GetCurrentThreadId();
+#else
+ ASSERT_ON_COMPILE(sizeof(pthread_t) <= sizeof (void *));
+ return (void *) (uintptr_t) pthread_self();
+#endif
+}
+
+
/*
* MXUser header - all MXUser objects start with this
*/
} MXUserHeader;
-/*
- * The per thread information.
- */
-
-#if defined(MXUSER_DEBUG) || defined(MXUSER_STATS)
-#define MXUSER_MAX_LOCKS_PER_THREAD (2 * MXUSER_MAX_REC_DEPTH)
-
-typedef struct {
-#if defined(MXUSER_DEBUG)
- uint32 locksHeld;
- MXUserHeader *lockArray[MXUSER_MAX_LOCKS_PER_THREAD];
-#endif
-
-#if defined(MXUSER_STATS)
- uint64 totalAcquisitions; // total thread lock acquisitions
- uint64 contendedAcquisitions; // contended subset of above
-#endif
-} MXUserPerThread;
-
-MXUserPerThread *MXUserGetPerThread(VThreadID tid,
- Bool mayAlloc);
-#endif
-
/*
* Internal functions
*/