1 /* An approximation of Linux futexes implemented using pthread mutexes
2 * and pthread condition variables.
6 * This software is part of the SBCL system. See the README file for
9 * The software is in the public domain and is provided with
10 * absolutely no warranty. See the COPYING and CREDITS files for more
16 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
22 #include "target-arch-os.h"
25 #include "genesis/lutex.h"
27 typedef unsigned long tagged_lutex_t;
30 # define lutex_assert(ex) \
32 if (!(ex)) lutex_abort(); \
34 # define lutex_assert_verbose(ex, fmt, ...) \
37 fprintf(stderr, fmt, ## __VA_ARGS__); \
42 # define lutex_assert(ex)
43 # define lutex_assert_verbose(ex, fmt, ...)
46 #define lutex_abort() \
47 lose("Lutex assertion failure, file \"%s\", line %d\n", __FILE__, __LINE__)
50 pthread_mutex_t lutex_register_lock = PTHREAD_MUTEX_INITIALIZER;
53 lutex_init (tagged_lutex_t tagged_lutex)
56 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
58 lutex->mutex = malloc(sizeof(pthread_mutex_t));
59 lutex_assert(lutex->mutex != 0);
61 ret = pthread_mutex_init(lutex->mutex, NULL);
62 lutex_assert(ret == 0);
64 lutex->condition_variable = malloc(sizeof(pthread_cond_t));
65 lutex_assert(lutex->condition_variable != 0);
67 ret = pthread_cond_init(lutex->condition_variable, NULL);
68 lutex_assert(ret == 0);
70 ret = thread_mutex_lock(&lutex_register_lock); lutex_assert(ret == 0);
72 gencgc_register_lutex(lutex);
74 ret = thread_mutex_unlock(&lutex_register_lock); lutex_assert(ret == 0);
80 lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t tagged_mutex_lutex)
83 struct lutex *queue_lutex = (struct lutex*) native_pointer(tagged_queue_lutex);
84 struct lutex *mutex_lutex = (struct lutex*) native_pointer(tagged_mutex_lutex);
86 ret = pthread_cond_wait(queue_lutex->condition_variable, mutex_lutex->mutex);
87 lutex_assert(ret == 0);
93 lutex_wake (tagged_lutex_t tagged_lutex, int n)
96 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
98 /* The lisp-side code passes N=2**29-1 for a broadcast. */
99 if (n >= ((1 << 29) - 1)) {
100 /* CONDITION-BROADCAST */
101 ret = pthread_cond_broadcast(lutex->condition_variable);
102 lutex_assert(ret == 0);
104 /* We're holding the condition variable mutex, so a thread
105 * we're waking can't re-enter the wait between to calls to
106 * pthread_cond_signal. Thus we'll wake N different threads,
107 * instead of the same thread N times.
110 ret = pthread_cond_signal(lutex->condition_variable);
111 lutex_assert(ret == 0);
119 lutex_lock (tagged_lutex_t tagged_lutex)
122 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
124 ret = thread_mutex_lock(lutex->mutex);
125 lutex_assert(ret == 0);
131 lutex_unlock (tagged_lutex_t tagged_lutex)
134 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
136 ret = thread_mutex_unlock(lutex->mutex);
137 lutex_assert(ret == 0);
143 lutex_destroy (tagged_lutex_t tagged_lutex)
145 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
147 if (lutex->condition_variable) {
148 pthread_cond_destroy(lutex->condition_variable);
149 free(lutex->condition_variable);
150 lutex->condition_variable = NULL;
154 pthread_mutex_destroy(lutex->mutex);