summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixThrd.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixThrd.c')
-rw-r--r--unix/tclUnixThrd.c51
1 files changed, 49 insertions, 2 deletions
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index f469341..ae81c5f 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 (25)
+#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.
@@ -45,6 +58,13 @@ static pthread_mutex_t allocLock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t *allocLockPtr = &allocLock;
/*
+ * The mutexLock serializes Tcl_MutexLock. This is necessary to prevent
+ * races when finalizing a mutex that some other thread may want to lock.
+ */
+
+static pthread_mutex_t mutexLock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
* These are for the critical sections inside this file.
*/
@@ -421,6 +441,8 @@ Tcl_MutexLock(
{
pthread_mutex_t *pmutexPtr;
+retry:
+
if (*mutexPtr == NULL) {
MASTER_LOCK;
if (*mutexPtr == NULL) {
@@ -435,8 +457,32 @@ Tcl_MutexLock(
}
MASTER_UNLOCK;
}
- pmutexPtr = *((pthread_mutex_t **)mutexPtr);
- pthread_mutex_lock(pmutexPtr);
+ while (1) {
+ pthread_mutex_lock(&mutexLock);
+ pmutexPtr = *((pthread_mutex_t **)mutexPtr);
+ if (pmutexPtr == NULL) {
+ pthread_mutex_unlock(&mutexLock);
+ goto retry;
+ }
+ if (pthread_mutex_trylock(pmutexPtr) == 0) {
+ pthread_mutex_unlock(&mutexLock);
+ return;
+ }
+ pthread_mutex_unlock(&mutexLock);
+ /*
+ * 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.
+ */
+#ifdef HAVE_USLEEP
+ usleep(TCL_MUTEX_LOCK_SLEEP_TIME * 1000);
+#else
+ Tcl_Sleep(TCL_MUTEX_LOCK_SLEEP_TIME);
+#endif
+ }
}
/*
@@ -727,6 +773,7 @@ TclpFreeAllocCache(
*/
TclFreeAllocCache(ptr);
+ pthread_setspecific(key, NULL);
} else if (initialized) {
/*