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"
26 #include "genesis/lutex.h"
28 typedef unsigned long tagged_lutex_t
;
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
;