summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixThrd.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixThrd.c')
-rw-r--r--unix/tclUnixThrd.c119
1 files changed, 116 insertions, 3 deletions
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index c33640f..e2f3a77 100644
--- a/unix/tclUnixThrd.c
+++ b/unix/tclUnixThrd.c
@@ -12,7 +12,9 @@
*/
#include "tclInt.h"
+#ifdef HAVE_STDATOMIC_H
#include <stdatomic.h>
+#endif /* HAVE_STDATOMIC_H */
#if TCL_THREADS
@@ -69,6 +71,9 @@
typedef struct PMutex {
pthread_mutex_t mutex;
+#if defined(HAVE_PTHREAD_SPIN_LOCK) && !defined(HAVE_STDATOMIC_H)
+ pthread_spinlock_t lock;
+#endif
volatile pthread_t thread;
volatile int counter;
} PMutex;
@@ -77,6 +82,9 @@ static void
PMutexInit(
PMutex *pmutexPtr)
{
+#if defined(HAVE_PTHREAD_SPIN_LOCK) && !defined(HAVE_STDATOMIC_H)
+ pthread_spin_init(&pmutexPtr->lock, PTHREAD_PROCESS_PRIVATE);
+#endif
pthread_mutex_init(&pmutexPtr->mutex, NULL);
pmutexPtr->thread = 0;
pmutexPtr->counter = 0;
@@ -87,8 +95,13 @@ PMutexDestroy(
PMutex *pmutexPtr)
{
pthread_mutex_destroy(&pmutexPtr->mutex);
+#if defined(HAVE_PTHREAD_SPIN_LOCK) && !defined(HAVE_STDATOMIC_H)
+ pthread_spin_destroy(&pmutexPtr->lock);
+#endif
}
+#ifdef HAVE_STDATOMIC_H
+
static void
PMutexLock(
PMutex *pmutexPtr)
@@ -97,19 +110,19 @@ PMutexLock(
if (__atomic_load_n(&pmutexPtr->counter, __ATOMIC_RELAXED) == 0) {
pthread_mutex_lock(&pmutexPtr->mutex);
__atomic_store_n(&pmutexPtr->thread, mythread, __ATOMIC_RELAXED);
- } else if (__atomic_load_n (&pmutexPtr->thread, __ATOMIC_RELAXED) != mythread) {
+ } else if (__atomic_load_n(&pmutexPtr->thread, __ATOMIC_RELAXED) != mythread) {
pthread_mutex_lock(&pmutexPtr->mutex);
__atomic_store_n(&pmutexPtr->thread, mythread, __ATOMIC_RELAXED);
__atomic_store_n(&pmutexPtr->counter, 0, __ATOMIC_RELAXED);
}
- __atomic_fetch_add(&pmutexPtr->counter, 1, __ATOMIC_RELAXED);
+ __atomic_add_fetch(&pmutexPtr->counter, 1, __ATOMIC_RELAXED);
}
static void
PMutexUnlock(
PMutex *pmutexPtr)
{
- if (__atomic_fetch_add(&pmutexPtr->counter, -1, __ATOMIC_RELAXED) == 1) {
+ if (__atomic_sub_fetch(&pmutexPtr->counter, 1, __ATOMIC_RELAXED) == 0) {
__atomic_store_n(&pmutexPtr->thread, 0, __ATOMIC_RELAXED);
pthread_mutex_unlock(&pmutexPtr->mutex);
}
@@ -139,6 +152,106 @@ PCondTimedWait(
__atomic_store_n(&pmutexPtr->thread, pthread_self(), __ATOMIC_RELAXED);
__atomic_store_n(&pmutexPtr->counter, counter, __ATOMIC_RELAXED);
}
+
+#else /* HAVE_STDATOMIC_H */
+
+static void
+PMutexLock(
+ PMutex *pmutexPtr)
+{
+ bool do_lock;
+
+#ifdef HAVE_PTHREAD_SPIN_LOCK
+ pthread_spin_lock(&pmutexPtr->lock);
+#endif
+ do_lock = (pmutexPtr->thread != pthread_self() || pmutexPtr->counter == 0);
+#ifdef HAVE_PTHREAD_SPIN_LOCK
+ pthread_spin_unlock(&pmutexPtr->lock);
+#endif
+
+ if (do_lock) {
+ pthread_mutex_lock(&pmutexPtr->mutex);
+ pmutexPtr->thread = pthread_self();
+ pmutexPtr->counter = 0;
+ }
+ pmutexPtr->counter++;
+}
+
+static void
+PMutexUnlock(
+ PMutex *pmutexPtr)
+{
+#ifdef HAVE_PTHREAD_SPIN_LOCK
+ bool is_owned;
+
+ pthread_spin_lock(&pmutexPtr->lock);
+ is_owned = (pmutexPtr->thread == pthread_self());
+ pthread_spin_unlock(&pmutexPtr->lock);
+
+ if (!is_owned) {
+ Tcl_Panic("mutex not owned");
+ }
+#endif
+
+ pmutexPtr->counter--;
+ if (pmutexPtr->counter == 0) {
+ pmutexPtr->thread = 0;
+ pthread_mutex_unlock(&pmutexPtr->mutex);
+ }
+}
+
+static void
+PCondWait(
+ pthread_cond_t *pcondPtr,
+ PMutex *pmutexPtr)
+{
+ int counter;
+#ifdef HAVE_PTHREAD_SPIN_LOCK
+ bool is_owned;
+
+ pthread_spin_lock(&pmutexPtr->lock);
+ is_owned = (pmutexPtr->thread == pthread_self());
+ pthread_spin_unlock(&pmutexPtr->lock);
+
+ if (!is_owned) {
+ Tcl_Panic("mutex not owned");
+ }
+#endif
+ counter = pmutexPtr->counter;
+ pmutexPtr->counter = 0;
+ pmutexPtr->thread = 0;
+ pthread_cond_wait(pcondPtr, &pmutexPtr->mutex);
+ pmutexPtr->thread = pthread_self();
+ pmutexPtr->counter = counter;
+}
+
+static void
+PCondTimedWait(
+ pthread_cond_t *pcondPtr,
+ PMutex *pmutexPtr,
+ struct timespec *ptime)
+{
+ int counter;
+#ifdef HAVE_PTHREAD_SPIN_LOCK
+ bool is_owned;
+
+ pthread_spin_lock(&pmutexPtr->lock);
+ is_owned = (pmutexPtr->thread == pthread_self());
+ pthread_spin_unlock(&pmutexPtr->lock);
+
+ if (!is_owned) {
+ Tcl_Panic("mutex not owned");
+ }
+#endif
+ counter = pmutexPtr->counter;
+ pmutexPtr->counter = 0;
+ pmutexPtr->thread = 0;
+ pthread_cond_timedwait(pcondPtr, &pmutexPtr->mutex, ptime);
+ pmutexPtr->thread = pthread_self();
+ pmutexPtr->counter = counter;
+}
+
+#endif /* HAVE_STDATOMIC_H */
/*
* globalLock is used to serialize creation of mutexes, condition variables,