1.0.23.59: bug 3b has been fixed a while now
[sbcl/tcr.git] / src / runtime / pthread-lutex.c
blob636521403598b1ab534ce9064383c38afb140bd0
1 /* An approximation of Linux futexes implemented using pthread mutexes
2 * and pthread condition variables.
3 */
5 /*
6 * This software is part of the SBCL system. See the README file for
7 * more information.
9 * The software is in the public domain and is provided with
10 * absolutely no warranty. See the COPYING and CREDITS files for more
11 * information.
14 #include "sbcl.h"
16 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
18 #include <errno.h>
19 #include <stdlib.h>
21 #include "runtime.h"
22 #include "arch.h"
23 #include "target-arch-os.h"
24 #include "os.h"
25 #include "pthread-lutex.h"
26 #include "gencgc.h"
28 #include "genesis/lutex.h"
30 #if 1
31 # define lutex_assert(ex) \
32 do { \
33 if (!(ex)) lutex_abort(); \
34 } while (0)
35 # define lutex_assert_verbose(ex, fmt, ...) \
36 do { \
37 if (!(ex)) { \
38 fprintf(stderr, fmt, ## __VA_ARGS__); \
39 lutex_abort(); \
40 } \
41 } while (0)
42 #else
43 # define lutex_assert(ex)
44 # define lutex_assert_verbose(ex, fmt, ...)
45 #endif
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;
53 int
54 lutex_init (tagged_lutex_t tagged_lutex)
56 int ret;
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);
92 return ret;
95 int
96 lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t tagged_mutex_lutex)
98 int ret;
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);
105 return ret;
109 lutex_wake (tagged_lutex_t tagged_lutex, int n)
111 int ret = 0;
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);
119 } else{
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.
125 while (n--) {
126 ret = pthread_cond_signal(lutex->condition_variable);
127 lutex_assert(ret == 0);
131 return ret;
135 lutex_lock (tagged_lutex_t tagged_lutex)
137 int ret = 0;
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...
146 if (ret == EDEADLK)
147 return ret;
148 lutex_assert(ret == 0);
150 return ret;
154 lutex_trylock (tagged_lutex_t tagged_lutex)
156 int ret = 0;
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)
162 return ret;
163 lutex_assert(ret == 0);
165 return ret;
169 lutex_unlock (tagged_lutex_t tagged_lutex)
171 int ret = 0;
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)) */
177 if (ret == EPERM)
178 return ret;
179 lutex_assert(ret == 0);
181 return ret;
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;
195 if (lutex->mutex) {
196 pthread_mutex_destroy(lutex->mutex);
197 free(lutex->mutex);
198 lutex->mutex = NULL;
201 if (lutex->mutexattr) {
202 pthread_mutexattr_destroy(lutex->mutexattr);
203 free(lutex->mutexattr);
204 lutex->mutexattr = NULL;
207 return 0;
209 #endif