285891b6595f0283a4218ac917f5965c12a2a5e6
[sbcl.git] / src / runtime / pthread-lutex.c
1 /* An approximation of Linux futexes implemented using pthread mutexes
2  * and pthread condition variables.
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
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.
12  */
13
14 #include "sbcl.h"
15
16 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
17
18 #include <stdlib.h>
19
20 #include "runtime.h"
21 #include "arch.h"
22 #include "target-arch-os.h"
23 #include "os.h"
24
25 #include "genesis/lutex.h"
26
27 typedef unsigned long tagged_lutex_t;
28
29 #if 1
30 # define lutex_assert(ex)                                              \
31 do {                                                                   \
32     if (!(ex)) lutex_abort();                                          \
33 } while (0)
34 # define lutex_assert_verbose(ex, fmt, ...)                            \
35 do {                                                                   \
36     if (!(ex)) {                                                       \
37         fprintf(stderr, fmt, ## __VA_ARGS__);                          \
38         lutex_abort();                                                 \
39     }                                                                  \
40 } while (0)
41 #else
42 # define lutex_assert(ex)
43 # define lutex_assert_verbose(ex, fmt, ...)
44 #endif
45
46 #define lutex_abort()                                                  \
47   lose("Lutex assertion failure, file \"%s\", line %d\n", __FILE__, __LINE__)
48
49
50 pthread_mutex_t lutex_register_lock = PTHREAD_MUTEX_INITIALIZER;
51
52 int
53 lutex_init (tagged_lutex_t tagged_lutex)
54 {
55     int ret;
56     struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
57
58     lutex->mutex = malloc(sizeof(pthread_mutex_t));
59     lutex_assert(lutex->mutex != 0);
60
61     ret = pthread_mutex_init(lutex->mutex, NULL);
62     lutex_assert(ret == 0);
63
64     lutex->condition_variable = malloc(sizeof(pthread_cond_t));
65     lutex_assert(lutex->condition_variable != 0);
66
67     ret = pthread_cond_init(lutex->condition_variable, NULL);
68     lutex_assert(ret == 0);
69
70     ret = thread_mutex_lock(&lutex_register_lock); lutex_assert(ret == 0);
71
72     gencgc_register_lutex(lutex);
73
74     ret = thread_mutex_unlock(&lutex_register_lock); lutex_assert(ret == 0);
75
76     return ret;
77 }
78
79 int
80 lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t tagged_mutex_lutex)
81 {
82     int ret;
83     struct lutex *queue_lutex = (struct lutex*) native_pointer(tagged_queue_lutex);
84     struct lutex *mutex_lutex = (struct lutex*) native_pointer(tagged_mutex_lutex);
85
86     ret = pthread_cond_wait(queue_lutex->condition_variable, mutex_lutex->mutex);
87     lutex_assert(ret == 0);
88
89     return ret;
90 }
91
92 int
93 lutex_wake (tagged_lutex_t tagged_lutex, int n)
94 {
95     int ret = 0;
96     struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
97
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);
103     } else{
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.
108          */
109         while (n--) {
110             ret = pthread_cond_signal(lutex->condition_variable);
111             lutex_assert(ret == 0);
112         }
113     }
114
115     return ret;
116 }
117
118 int
119 lutex_lock (tagged_lutex_t tagged_lutex)
120 {
121     int ret = 0;
122     struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
123
124     ret = thread_mutex_lock(lutex->mutex);
125     lutex_assert(ret == 0);
126
127     return ret;
128 }
129
130 int
131 lutex_unlock (tagged_lutex_t tagged_lutex)
132 {
133     int ret = 0;
134     struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
135
136     ret = thread_mutex_unlock(lutex->mutex);
137     lutex_assert(ret == 0);
138
139     return ret;
140 }
141
142 int
143 lutex_destroy (tagged_lutex_t tagged_lutex)
144 {
145     struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
146
147     if (lutex->condition_variable) {
148         pthread_cond_destroy(lutex->condition_variable);
149         free(lutex->condition_variable);
150         lutex->condition_variable = NULL;
151     }
152
153     if (lutex->mutex) {
154         pthread_mutex_destroy(lutex->mutex);
155         free(lutex->mutex);
156         lutex->mutex = NULL;
157     }
158
159     return 0;
160 }
161 #endif