MXUserHeader *lockArray[MXUSER_MAX_LOCKS_PER_THREAD];
} MXUserPerThread;
+#if defined(_WIN32) && !defined(VMX86_VMX)
+static Atomic_Ptr hashLockMem;
+#endif
+
static Atomic_Ptr hashTableMem;
Bool mayAlloc) // IN: alloc perThread if not present?
{
HashTable *hash;
- MXUserPerThread *perThread;
+ MXUserPerThread *perThread = NULL;
+
+#if defined(_WIN32) && !defined(VMX86_VMX)
+ MXRecLock *hashLock = MXUserInternalSingleton(&hashLockMem);
+
+ ASSERT(hashLock);
+
+ hash = HashTable_AllocOnce(&hashTableMem, 1024, HASH_INT_KEY, NULL);
+ MXRecLockAcquire(hashLock);
+#else
hash = HashTable_AllocOnce(&hashTableMem, 1024,
HASH_INT_KEY | HASH_FLAG_ATOMIC, NULL);
-
- perThread = NULL;
+#endif
if (!HashTable_Lookup(hash, tid, (void **) &perThread)) {
/* No entry for this tid was found, allocate one? */
sizeof(MXUserPerThread));
/*
- * Attempt to (racey) insert a perThread on behalf of the specified
- * thread. If yet another thread takes care of this first, clean up
- * the mess.
+ * Attempt to insert a perThread on behalf of the specified thread.
+ * If another thread has taken care of this first, clean up the mess.
*/
perThread = HashTable_LookupOrInsert(hash, tid, newEntry);
}
}
+#if defined(_WIN32) && !defined(VMX86_VMX)
+ MXRecLockRelease(hashLock);
+#endif
+
return perThread;
}
perThread->lockArray[lastEntry] = NULL; // tidy up memory
perThread->locksHeld--;
+
+#if defined(_WIN32) && !defined(VMX86_VMX)
+ /*
+ * On Windows thread IDs aren't greedily recycled. If a process creates and
+ * destroys many threads this can cause a memory leak of perThread data
+ * (and its overhead). We avoid this by atomically (via a lock) creating
+ * (upon first lock acquired) and deleting (upon last lock release) a
+ * perThread.
+ *
+ * Yes, this is a performance cost but it only affects Windows debug
+ * builds and then not by very much - we tend to run for a long time
+ * with either no locks held or at least one lock held.
+ */
+
+ if (perThread->locksHeld == 0) {
+ HashTable *hash = Atomic_ReadPtr(&hashTableMem);
+ MXRecLock *hashLock = MXUserInternalSingleton(&hashLockMem);
+
+ ASSERT(hash);
+ ASSERT(hashLock);
+
+ MXRecLockAcquire(hashLock);
+ HashTable_Delete(hash, tid);
+ MXRecLockRelease(hashLock);
+
+ free(perThread);
+ }
+#endif
}
Warning("\tcount %u\n", lock->recursiveLock.referenceCount);
- Warning("\towner 0x%p\n",
+ Warning("\tnative threadID 0x%p\n",
(void *)(uintptr_t)lock->recursiveLock.nativeThreadID);
+ Warning("\tVThreadID %u\n", lock->recursiveLock.vmwThreadID);
+
if (stats && (stats->holder != NULL)) {
Warning("\tholder %p\n", stats->holder);
}
int referenceCount; // Acquisition count
MXThreadID nativeThreadID; // Native thread ID
+ VThreadID vmwThreadID; // VMW thread ID
} MXRecLock;
MXRecLockSetNoOwner(MXRecLock *lock) // IN:
{
lock->nativeThreadID = MXUSER_INVALID_OWNER;
+ lock->vmwThreadID = VTHREAD_INVALID_ID;
}
MXRecLockSetOwner(MXRecLock *lock) // IN/OUT:
{
lock->nativeThreadID = GetCurrentThreadId();
+ lock->vmwThreadID = VThread_CurID();
}
{
/* a hack but it works portably */
memset((void *) &lock->nativeThreadID, 0xFF, sizeof(lock->nativeThreadID));
+ lock->vmwThreadID = VTHREAD_INVALID_ID;
}
MXRecLockSetOwner(MXRecLock *lock) // IN:
{
lock->nativeThreadID = pthread_self();
+ lock->vmwThreadID = VThread_CurID();
}
/* All thread types must fit into a uintptr_t */
ASSERT_ON_COMPILE(sizeof(VThreadID) <= sizeof (void *));
- return (void *) (uintptr_t) VThread_CurID();
+
+ /*
+ * We must use native (OS provided) thread IDs which are guaranteed to
+ * always be unique. Any ID system that could possibly alias, under
+ * an circumstances, is unacceptable.
+ */
+
+#if defined(_WIN32)
+ return (void *) (uintptr_t) GetCurrentThreadId();
+#else
+ return (void *) (uintptr_t) pthread_self();
+#endif
}
Warning("\tcount %u\n", lock->recursiveLock.referenceCount);
- Warning("\towner 0x%p\n",
+ Warning("\tnative threadID 0x%p\n",
(void *)(uintptr_t)lock->recursiveLock.nativeThreadID);
+ Warning("\tVThreadID %u\n", lock->recursiveLock.vmwThreadID);
+
if (stats && (stats->holder != NULL)) {
Warning("\tholder %p\n", stats->holder);
}