summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Mistachkin <joe@mistachkin.com>2015-05-17 22:13:39 (GMT)
committerJoe Mistachkin <joe@mistachkin.com>2015-05-17 22:13:39 (GMT)
commitbeea2ed90e5ef5ef3f760f1697e207d493813a0d (patch)
tree4e4355a066d0f52d57167288aae475eb521391f3
parentcf546fcc60e29ae9c2f87f51580c1da4bf18b448 (diff)
downloadtcl-beea2ed90e5ef5ef3f760f1697e207d493813a0d.zip
tcl-beea2ed90e5ef5ef3f760f1697e207d493813a0d.tar.gz
tcl-beea2ed90e5ef5ef3f760f1697e207d493813a0d.tar.bz2
This should completely fix the race conditions at the cost of more complexity. Also, on Unix, a more reliable means than Tcl_Sleep() of sleeping for a short time is needed.
-rw-r--r--unix/tclUnixThrd.c41
-rw-r--r--win/tclWinThrd.c30
2 files changed, 57 insertions, 14 deletions
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index 3a59624..11df5ee 100644
--- a/unix/tclUnixThrd.c
+++ b/unix/tclUnixThrd.c
@@ -22,6 +22,19 @@ typedef struct ThreadSpecificData {
static Tcl_ThreadDataKey dataKey;
/*
+ * This is the number of milliseconds to wait between internal retries in
+ * the Tcl_MutexLock function. This value must be greater than zero and
+ * should be a suitable value for the given platform.
+ *
+ * TODO: This may need to be dynamically determined, based on the relative
+ * performance of the running process.
+ */
+
+#ifndef TCL_MUTEX_LOCK_SLEEP_TIME
+# define TCL_MUTEX_LOCK_SLEEP_TIME (0)
+#endif
+
+/*
* masterLock is used to serialize creation of mutexes, condition variables,
* and thread local storage. This is the only place that can count on the
* ability to statically initialize the mutex.
@@ -496,14 +509,28 @@ retry:
}
MASTER_UNLOCK;
}
- TclpMutexLock();
- pmutexPtr = *((pthread_mutex_t **)mutexPtr);
- if (pmutexPtr == NULL) {
- TclpMutexUnlock();
- goto retry;
+ while (1) {
+ TclpMutexLock();
+ pmutexPtr = *((pthread_mutex_t **)mutexPtr);
+ if (pmutexPtr == NULL) {
+ TclpMutexUnlock();
+ goto retry;
+ }
+ if (pthread_mutex_trylock(pmutexPtr) == 0) {
+ TclpMutexUnlock();
+ return;
+ }
+ TclpMutexUnlock();
+ /*
+ * BUGBUG: All core and Thread package tests pass when usleep()
+ * is used; however, the Thread package tests hang at
+ * various places when Tcl_Sleep() is used, typically
+ * while running test "thread-17.8", "thread-17.9", or
+ * "thread-17.11a". Really, what we want here is just
+ * to yield to other threads for a while.
+ */
+ Tcl_Sleep(TCL_MUTEX_LOCK_SLEEP_TIME);
}
- TclpMutexUnlock();
- pthread_mutex_lock(pmutexPtr);
}
/*
diff --git a/win/tclWinThrd.c b/win/tclWinThrd.c
index ef42a83..7fd5ff5 100644
--- a/win/tclWinThrd.c
+++ b/win/tclWinThrd.c
@@ -24,6 +24,16 @@ _CRTIMP unsigned int __cdecl _controlfp (unsigned int unNew, unsigned int unMask
#endif
/*
+ * This is the number of milliseconds to wait between internal retries in
+ * the Tcl_MutexLock function. This value must be greater than or equal
+ * to zero and should be a suitable value for the given platform.
+ */
+
+#ifndef TCL_MUTEX_LOCK_SLEEP_TIME
+# define TCL_MUTEX_LOCK_SLEEP_TIME (0)
+#endif
+
+/*
* This is the master lock used to serialize access to other serialization
* data structures.
*/
@@ -641,14 +651,20 @@ retry:
}
MASTER_UNLOCK;
}
- TclpMutexLock();
- csPtr = *((CRITICAL_SECTION **)mutexPtr);
- if (csPtr == NULL) {
- TclpMutexUnlock();
- goto retry;
+ while (1) {
+ TclpMutexLock();
+ csPtr = *((CRITICAL_SECTION **)mutexPtr);
+ if (csPtr == NULL) {
+ TclpMutexUnlock();
+ goto retry;
+ }
+ if (TryEnterCriticalSection(csPtr)) {
+ TclpMutexUnlock();
+ return;
+ }
+ TclpMutexUnlock();
+ Tcl_Sleep(TCL_MUTEX_LOCK_SLEEP_TIME);
}
- TclpMutexUnlock();
- EnterCriticalSection(csPtr);
}
/*