Artifact [874c388a9b]
Not logged in

Artifact 874c388a9ba18bbe5f5a1ec9f231ce142b2b8eac1fc2ade697a39cb679a9beee:

Attachment "tclMutexTest.diff" to ticket [893f8cc5db] added by chw 2025-10-06 14:43:27.
Index: generic/tclMutexTest.c
==================================================================
--- generic/tclMutexTest.c
+++ generic/tclMutexTest.c
@@ -27,10 +27,12 @@
 /*
  * Types related to Tcl_Mutex tests.
  */
 
 TCL_DECLARE_MUTEX(testContextMutex)
+TCL_DECLARE_MUTEX(threadStartMutex)
+static Tcl_Condition threadStartCond;
 
 static inline void
 LockTestContext(
     int numRecursions)
 {
@@ -87,13 +89,10 @@
     Tcl_ThreadId threadId;		  /* Only access in creator */
     Tcl_WideUInt numOperations;		  /* Use is dependent on the test */
     Tcl_WideUInt timeouts;		  /* Timeouts on condition variables */
 } MutexThreadContext;
 
-/* Used to track how many test threads running. Also used as trigger */
-static volatile int mutexThreadCount;
-
 static Tcl_ThreadCreateType	CounterThreadProc(void *clientData);
 static int			TestMutexLock(Tcl_Interp *interp,
 				    MutexSharedContext *contextPtr);
 static int			TestConditionVariable(Tcl_Interp *interp,
 				    MutexSharedContext *contextPtr);
@@ -231,12 +230,16 @@
     MutexSharedContext *contextPtr)
 {
     MutexThreadContext *threadContextsPtr = (MutexThreadContext *)
 	    Tcl_Alloc(sizeof(*threadContextsPtr) * contextPtr->numThreads);
 
+    Tcl_MutexLock(&threadStartMutex);
+    /* Inflate threadStartCond for later */
+    Tcl_Time nullTime = { 0, 0 };
+    Tcl_ConditionWait(&threadStartCond, &threadStartMutex, &nullTime);
+
     contextPtr->u.counter = 0;
-    mutexThreadCount = 0;
     for (int i = 0; i < contextPtr->numThreads; i++) {
 	threadContextsPtr[i].sharedContextPtr = contextPtr;
 	threadContextsPtr[i].numOperations = 0; /* Init though not used */
 
 	if (Tcl_CreateThread(&threadContextsPtr[i].threadId,
@@ -243,11 +246,14 @@
 		CounterThreadProc, &threadContextsPtr[i],
 		TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) {
 	    Tcl_Panic("Failed to create %d'th thread\n", i);
 	}
     }
-    mutexThreadCount = contextPtr->numThreads; /* Will fire off all test threads */
+
+    /* Trigger start signal */
+    Tcl_ConditionNotify(&threadStartCond);
+    Tcl_MutexUnlock(&threadStartMutex);
 
     /* Wait for all threads */
     for (int i = 0; i < contextPtr->numThreads; i++) {
 	int threadResult;
 	Tcl_JoinThread(threadContextsPtr[i].threadId, &threadResult);
@@ -279,14 +285,14 @@
     void *clientData)
 {
     MutexThreadContext *threadContextPtr = (MutexThreadContext *)clientData;
     MutexSharedContext *contextPtr = threadContextPtr->sharedContextPtr;
 
-    /* Spin wait until given the run signal */
-    while (mutexThreadCount < contextPtr->numThreads) {
-	YieldToOtherThreads();
-    }
+    /* Wait for start signal */
+    Tcl_MutexLock(&threadStartMutex);
+    Tcl_ConditionWait(&threadStartCond, &threadStartMutex, NULL);
+    Tcl_MutexUnlock(&threadStartMutex);
 
     for (int i = 0; i < contextPtr->numIterations; i++) {
 	LockTestContext(contextPtr->numRecursions);
 	Tcl_WideUInt temp = contextPtr->u.counter;
 	if (contextPtr->yield) {
@@ -344,11 +350,14 @@
     MutexThreadContext *consumerContextsPtr = (MutexThreadContext *)Tcl_Alloc(
 	    sizeof(*consumerContextsPtr) * numConsumers);
     MutexThreadContext *producerContextsPtr = (MutexThreadContext *)Tcl_Alloc(
 	    sizeof(*producerContextsPtr) * numProducers);
 
-    mutexThreadCount = 0;
+    Tcl_MutexLock(&threadStartMutex);
+    /* Inflate threadStartCond for later */
+    Tcl_Time nullTime = { 0, 0 };
+    Tcl_ConditionWait(&threadStartCond, &threadStartMutex, &nullTime);
 
     for (int i = 0; i < numConsumers; i++) {
 	consumerContextsPtr[i].sharedContextPtr = contextPtr;
 	consumerContextsPtr[i].numOperations = 0;
 	consumerContextsPtr[i].timeouts = 0;
@@ -370,11 +379,13 @@
 		TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) {
 	    Tcl_Panic("Failed to create %d'th thread\n", (int) i);
 	}
     }
 
-    mutexThreadCount = contextPtr->numThreads; /* Will trigger all threads */
+    /* Trigger start signal */
+    Tcl_ConditionNotify(&threadStartCond);
+    Tcl_MutexUnlock(&threadStartMutex);
 
     /* Producer total, thread, timeouts, Consumer total, thread, timeouts */
     Tcl_Obj *results[6];
     results[1] = Tcl_NewListObj(numProducers, NULL);
     results[4] = Tcl_NewListObj(numConsumers, NULL);
@@ -439,14 +450,14 @@
 
     /* Limit on total number of operations across all threads */
     Tcl_WideUInt limit;
     limit = contextPtr->numThreads * (Tcl_WideUInt) contextPtr->numIterations;
 
-    /* Spin wait until given the run signal */
-    while (mutexThreadCount < contextPtr->numThreads) {
-	YieldToOtherThreads();
-    }
+    /* Wait for start signal */
+    Tcl_MutexLock(&threadStartMutex);
+    Tcl_ConditionWait(&threadStartCond, &threadStartMutex, NULL);
+    Tcl_MutexUnlock(&threadStartMutex);
 
     LockTestContext(contextPtr->numRecursions);
     while (contextPtr->u.queue.totalEnqueued < limit) {
 	if (contextPtr->u.queue.available == contextPtr->u.queue.capacity) {
 	    Tcl_Time before, after;
@@ -501,14 +512,14 @@
 
     /* Limit on total number of operations across all threads */
     Tcl_WideUInt limit;
     limit = contextPtr->numThreads * (Tcl_WideUInt) contextPtr->numIterations;
 
-    /* Spin wait until given the run signal */
-    while (mutexThreadCount < contextPtr->numThreads) {
-	YieldToOtherThreads();
-    }
+    /* Wait for start signal */
+    Tcl_MutexLock(&threadStartMutex);
+    Tcl_ConditionWait(&threadStartCond, &threadStartMutex, NULL);
+    Tcl_MutexUnlock(&threadStartMutex);
 
     LockTestContext(contextPtr->numRecursions);
     while (contextPtr->u.queue.totalDequeued < limit) {
 	if (contextPtr->u.queue.available == 0) {
 	    Tcl_Time before, after;