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)
23 #include "target-arch-os.h"
25 #include "pthread-lutex.h"
28 #include "genesis/lutex.h"
31 # define lutex_assert(ex) \
33 if (!(ex)) lutex_abort(); \
35 # define lutex_assert_verbose(ex, fmt, ...) \
38 fprintf(stderr, fmt, ## __VA_ARGS__); \
43 # define lutex_assert(ex)
44 # define lutex_assert_verbose(ex, fmt, ...)
47 #define lutex_abort() \
48 lose("Lutex assertion failure, file \"%s\", line %d\n", __FILE__, __LINE__)
51 pthread_mutex_t lutex_register_lock = PTHREAD_MUTEX_INITIALIZER;
54 lutex_init (tagged_lutex_t tagged_lutex)
57 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
59 lutex->mutexattr = malloc(sizeof(pthread_mutexattr_t));
60 lutex_assert(lutex->mutexattr != 0);
62 ret = pthread_mutexattr_init(lutex->mutexattr);
63 lutex_assert(ret == 0);
65 /* The default type of mutex is implementation dependent.
66 * We use PTHREAD_MUTEX_ERRORCHECK so that locking on mutexes
67 * locked by the same thread does not cause deadlocks. */
68 /* FIXME: pthread_mutexattr_settype is available on SUSv2 level
69 * implementations. Can be used without checking? */
70 ret = pthread_mutexattr_settype(lutex->mutexattr,
71 PTHREAD_MUTEX_ERRORCHECK);
72 lutex_assert(ret == 0);
74 lutex->mutex = malloc(sizeof(pthread_mutex_t));
75 lutex_assert(lutex->mutex != 0);
77 ret = pthread_mutex_init(lutex->mutex, lutex->mutexattr);
78 lutex_assert(ret == 0);
80 lutex->condition_variable = malloc(sizeof(pthread_cond_t));
81 lutex_assert(lutex->condition_variable != 0);
83 ret = pthread_cond_init(lutex->condition_variable, NULL);
84 lutex_assert(ret == 0);
86 ret = thread_mutex_lock(&lutex_register_lock); lutex_assert(ret == 0);
88 gencgc_register_lutex(lutex);
90 ret = thread_mutex_unlock(&lutex_register_lock); lutex_assert(ret == 0);
96 lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t tagged_mutex_lutex)
99 struct lutex *queue_lutex = (struct lutex*) native_pointer(tagged_queue_lutex);
100 struct lutex *mutex_lutex = (struct lutex*) native_pointer(tagged_mutex_lutex);
102 ret = pthread_cond_wait(queue_lutex->condition_variable, mutex_lutex->mutex);
103 lutex_assert(ret == 0);
109 lutex_wake (tagged_lutex_t tagged_lutex, int n)
112 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
114 /* The lisp-side code passes N=2**29-1 for a broadcast. */
115 if (n >= ((1 << 29) - 1)) {
116 /* CONDITION-BROADCAST */
117 ret = pthread_cond_broadcast(lutex->condition_variable);
118 lutex_assert(ret == 0);
120 /* We're holding the condition variable mutex, so a thread
121 * we're waking can't re-enter the wait between to calls to
122 * pthread_cond_signal. Thus we'll wake N different threads,
123 * instead of the same thread N times.
126 ret = pthread_cond_signal(lutex->condition_variable);
127 lutex_assert(ret == 0);
135 lutex_lock (tagged_lutex_t tagged_lutex)
138 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
140 ret = thread_mutex_lock(lutex->mutex);
141 /* The mutex is locked by the same thread.
143 * FIXME: Usually when POSIX says that "an error value is returned"
144 * it actually refers to errno...
148 lutex_assert(ret == 0);
154 lutex_trylock (tagged_lutex_t tagged_lutex)
157 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
159 ret = pthread_mutex_trylock(lutex->mutex);
160 /* The mutex is locked */
161 if (ret == EDEADLK || ret == EBUSY)
163 lutex_assert(ret == 0);
169 lutex_unlock (tagged_lutex_t tagged_lutex)
172 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
174 ret = thread_mutex_unlock(lutex->mutex);
175 /* Unlocking unlocked mutex would occur as:
176 * (with-mutex (mutex) (cond-wait cond mutex)) */
179 lutex_assert(ret == 0);
185 lutex_destroy (tagged_lutex_t tagged_lutex)
187 struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
189 if (lutex->condition_variable) {
190 pthread_cond_destroy(lutex->condition_variable);
191 free(lutex->condition_variable);
192 lutex->condition_variable = NULL;
196 pthread_mutex_destroy(lutex->mutex);
201 if (lutex->mutexattr) {
202 pthread_mutexattr_destroy(lutex->mutexattr);
203 free(lutex->mutexattr);
204 lutex->mutexattr = NULL;