]>
Commit | Line | Data |
---|---|---|
0ecb606c | 1 | /* Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. |
f036e569 UD |
2 | This file is part of the GNU C Library. |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
5 | modify it under the terms of the GNU Lesser General Public | |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
8 | ||
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | Lesser General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU Lesser General Public | |
15 | License along with the GNU C Libr \ary; if not, write to the Free | |
16 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
17 | 02111-1307 USA. */ | |
18 | ||
19 | #ifndef _LOWLEVELLOCK_H | |
20 | #define _LOWLEVELLOCK_H 1 | |
21 | ||
22 | #include <time.h> | |
23 | #include <sys/param.h> | |
24 | #include <bits/pthreadtypes.h> | |
25 | #include <atomic.h> | |
dc927809 | 26 | #include <sysdep.h> |
f036e569 UD |
27 | |
28 | ||
29 | #define __NR_futex 394 | |
30 | #define FUTEX_WAIT 0 | |
31 | #define FUTEX_WAKE 1 | |
32 | #define FUTEX_REQUEUE 3 | |
75fccede | 33 | #define FUTEX_CMP_REQUEUE 4 |
0ecb606c JJ |
34 | #define FUTEX_WAKE_OP 5 |
35 | #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1) | |
36 | #define FUTEX_LOCK_PI 6 | |
37 | #define FUTEX_UNLOCK_PI 7 | |
38 | #define FUTEX_TRYLOCK_PI 8 | |
f036e569 UD |
39 | |
40 | /* Initializer for compatibility lock. */ | |
41 | #define LLL_MUTEX_LOCK_INITIALIZER (0) | |
42 | ||
43 | #define lll_futex_wait(futexp, val) \ | |
44 | ({ \ | |
45 | INTERNAL_SYSCALL_DECL (__err); \ | |
46 | long int __ret; \ | |
47 | __ret = INTERNAL_SYSCALL (futex, __err, 4, \ | |
48 | (futexp), FUTEX_WAIT, (val), 0); \ | |
d810b358 | 49 | INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret; \ |
f036e569 UD |
50 | }) |
51 | ||
52 | #define lll_futex_timed_wait(futexp, val, timespec) \ | |
53 | ({ \ | |
54 | INTERNAL_SYSCALL_DECL (__err); \ | |
55 | long int __ret; \ | |
56 | __ret = INTERNAL_SYSCALL (futex, __err, 4, \ | |
57 | (futexp), FUTEX_WAIT, (val), (timespec)); \ | |
d810b358 | 58 | INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret; \ |
f036e569 UD |
59 | }) |
60 | ||
61 | #define lll_futex_wake(futexp, nr) \ | |
62 | ({ \ | |
63 | INTERNAL_SYSCALL_DECL (__err); \ | |
64 | long int __ret; \ | |
65 | __ret = INTERNAL_SYSCALL (futex, __err, 4, \ | |
66 | (futexp), FUTEX_WAKE, (nr), 0); \ | |
d810b358 | 67 | INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret; \ |
f036e569 UD |
68 | }) |
69 | ||
0ecb606c JJ |
70 | #define lll_robust_mutex_dead(futexv) \ |
71 | do \ | |
72 | { \ | |
73 | int *__futexp = &(futexv); \ | |
74 | atomic_or (__futexp, FUTEX_OWNER_DIED); \ | |
75 | lll_futex_wake (__futexp, 1); \ | |
76 | } \ | |
77 | while (0) | |
78 | ||
75fccede UD |
79 | /* Returns non-zero if error happened, zero if success. */ |
80 | #define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ | |
f036e569 UD |
81 | ({ \ |
82 | INTERNAL_SYSCALL_DECL (__err); \ | |
83 | long int __ret; \ | |
75fccede UD |
84 | __ret = INTERNAL_SYSCALL (futex, __err, 6, \ |
85 | (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ | |
86 | (nr_move), (mutex), (val)); \ | |
87 | INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ | |
f036e569 UD |
88 | }) |
89 | ||
0ecb606c JJ |
90 | /* Returns non-zero if error happened, zero if success. */ |
91 | #define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) \ | |
92 | ({ \ | |
93 | INTERNAL_SYSCALL_DECL (__err); \ | |
94 | long int __ret; \ | |
95 | __ret = INTERNAL_SYSCALL (futex, __err, 6, \ | |
96 | (futexp), FUTEX_WAKE_OP, (nr_wake), \ | |
97 | (nr_wake2), (futexp2), \ | |
98 | FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \ | |
99 | INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ | |
100 | }) | |
101 | ||
102 | ||
103 | ||
f036e569 | 104 | |
dc927809 RH |
105 | static inline int __attribute__((always_inline)) |
106 | __lll_mutex_trylock(int *futex) | |
107 | { | |
108 | return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; | |
109 | } | |
110 | #define lll_mutex_trylock(lock) __lll_mutex_trylock (&(lock)) | |
f036e569 UD |
111 | |
112 | ||
2c0b891a UD |
113 | static inline int __attribute__((always_inline)) |
114 | __lll_mutex_cond_trylock(int *futex) | |
115 | { | |
116 | return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; | |
117 | } | |
118 | #define lll_mutex_cond_trylock(lock) __lll_mutex_cond_trylock (&(lock)) | |
119 | ||
120 | ||
0ecb606c JJ |
121 | static inline int __attribute__((always_inline)) |
122 | __lll_robust_mutex_trylock(int *futex, int id) | |
123 | { | |
124 | return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0; | |
125 | } | |
126 | #define lll_robust_mutex_trylock(lock, id) \ | |
127 | __lll_robust_mutex_trylock (&(lock), id) | |
128 | ||
dc927809 | 129 | extern void __lll_lock_wait (int *futex) attribute_hidden; |
0ecb606c | 130 | extern int __lll_robust_lock_wait (int *futex) attribute_hidden; |
f036e569 | 131 | |
dc927809 RH |
132 | static inline void __attribute__((always_inline)) |
133 | __lll_mutex_lock(int *futex) | |
134 | { | |
135 | if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) | |
136 | __lll_lock_wait (futex); | |
137 | } | |
138 | #define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) | |
f036e569 | 139 | |
f036e569 | 140 | |
0ecb606c JJ |
141 | static inline int __attribute__ ((always_inline)) |
142 | __lll_robust_mutex_lock (int *futex, int id) | |
143 | { | |
144 | int result = 0; | |
145 | if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) | |
146 | result = __lll_robust_lock_wait (futex); | |
147 | return result; | |
148 | } | |
149 | #define lll_robust_mutex_lock(futex, id) \ | |
150 | __lll_robust_mutex_lock (&(futex), id) | |
151 | ||
152 | ||
dc927809 RH |
153 | static inline void __attribute__ ((always_inline)) |
154 | __lll_mutex_cond_lock (int *futex) | |
155 | { | |
156 | if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0) | |
157 | __lll_lock_wait (futex); | |
158 | } | |
159 | #define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) | |
f036e569 | 160 | |
f036e569 | 161 | |
0ecb606c JJ |
162 | #define lll_robust_mutex_cond_lock(futex, id) \ |
163 | __lll_robust_mutex_lock (&(futex), (id) | FUTEX_WAITERS) | |
164 | ||
165 | ||
dc927809 RH |
166 | extern int __lll_timedlock_wait (int *futex, const struct timespec *) |
167 | attribute_hidden; | |
0ecb606c JJ |
168 | extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *) |
169 | attribute_hidden; | |
dc927809 RH |
170 | |
171 | static inline int __attribute__ ((always_inline)) | |
172 | __lll_mutex_timedlock (int *futex, const struct timespec *abstime) | |
173 | { | |
174 | int result = 0; | |
175 | if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) | |
176 | result = __lll_timedlock_wait (futex, abstime); | |
177 | return result; | |
178 | } | |
179 | #define lll_mutex_timedlock(futex, abstime) \ | |
180 | __lll_mutex_timedlock (&(futex), abstime) | |
181 | ||
182 | ||
0ecb606c JJ |
183 | static inline int __attribute__ ((always_inline)) |
184 | __lll_robust_mutex_timedlock (int *futex, const struct timespec *abstime, | |
185 | int id) | |
186 | { | |
187 | int result = 0; | |
188 | if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) | |
189 | result = __lll_robust_timedlock_wait (futex, abstime); | |
190 | return result; | |
191 | } | |
192 | #define lll_robust_mutex_timedlock(futex, abstime, id) \ | |
193 | __lll_robust_mutex_timedlock (&(futex), abstime, id) | |
194 | ||
195 | ||
dc927809 RH |
196 | static inline void __attribute__ ((always_inline)) |
197 | __lll_mutex_unlock (int *futex) | |
198 | { | |
199 | int val = atomic_exchange_rel (futex, 0); | |
200 | if (__builtin_expect (val > 1, 0)) | |
201 | lll_futex_wake (futex, 1); | |
202 | } | |
203 | #define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) | |
204 | ||
205 | ||
0ecb606c JJ |
206 | static inline void __attribute__ ((always_inline)) |
207 | __lll_robust_mutex_unlock (int *futex, int mask) | |
208 | { | |
209 | int val = atomic_exchange_rel (futex, 0); | |
210 | if (__builtin_expect (val & mask, 0)) | |
211 | lll_futex_wake (futex, 1); | |
212 | } | |
213 | #define lll_robust_mutex_unlock(futex) \ | |
214 | __lll_robust_mutex_unlock(&(futex), FUTEX_WAITERS) | |
215 | ||
216 | ||
dc927809 RH |
217 | static inline void __attribute__ ((always_inline)) |
218 | __lll_mutex_unlock_force (int *futex) | |
219 | { | |
220 | (void) atomic_exchange_rel (futex, 0); | |
221 | lll_futex_wake (futex, 1); | |
222 | } | |
223 | #define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) | |
224 | ||
f036e569 UD |
225 | |
226 | #define lll_mutex_islocked(futex) \ | |
227 | (futex != 0) | |
228 | ||
229 | ||
230 | /* Our internal lock implementation is identical to the binary-compatible | |
231 | mutex implementation. */ | |
232 | ||
233 | /* Type for lock object. */ | |
234 | typedef int lll_lock_t; | |
235 | ||
236 | /* Initializers for lock. */ | |
237 | #define LLL_LOCK_INITIALIZER (0) | |
238 | #define LLL_LOCK_INITIALIZER_LOCKED (1) | |
239 | ||
240 | extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; | |
241 | ||
242 | /* The states of a lock are: | |
243 | 0 - untaken | |
244 | 1 - taken by one user | |
245 | >1 - taken by more users */ | |
246 | ||
247 | #define lll_trylock(lock) lll_mutex_trylock (lock) | |
248 | #define lll_lock(lock) lll_mutex_lock (lock) | |
249 | #define lll_unlock(lock) lll_mutex_unlock (lock) | |
250 | #define lll_islocked(lock) lll_mutex_islocked (lock) | |
251 | ||
252 | /* The kernel notifies a process which uses CLONE_CLEARTID via futex | |
253 | wakeup when the clone terminates. The memory location contains the | |
254 | thread ID while the clone is running and is reset to zero | |
255 | afterwards. */ | |
256 | #define lll_wait_tid(tid) \ | |
dc927809 RH |
257 | do { \ |
258 | __typeof (tid) __tid; \ | |
259 | while ((__tid = (tid)) != 0) \ | |
260 | lll_futex_wait (&(tid), __tid); \ | |
f036e569 UD |
261 | } while (0) |
262 | ||
263 | extern int __lll_timedwait_tid (int *, const struct timespec *) | |
264 | attribute_hidden; | |
265 | ||
266 | #define lll_timedwait_tid(tid, abstime) \ | |
dc927809 RH |
267 | ({ \ |
268 | int __res = 0; \ | |
269 | if ((tid) != 0) \ | |
270 | __res = __lll_timedwait_tid (&(tid), (abstime)); \ | |
271 | __res; \ | |
f036e569 UD |
272 | }) |
273 | ||
274 | ||
275 | /* Conditional variable handling. */ | |
276 | ||
277 | extern void __lll_cond_wait (pthread_cond_t *cond) | |
278 | attribute_hidden; | |
279 | extern int __lll_cond_timedwait (pthread_cond_t *cond, | |
280 | const struct timespec *abstime) | |
281 | attribute_hidden; | |
282 | extern void __lll_cond_wake (pthread_cond_t *cond) | |
283 | attribute_hidden; | |
284 | extern void __lll_cond_broadcast (pthread_cond_t *cond) | |
285 | attribute_hidden; | |
286 | ||
287 | #define lll_cond_wait(cond) \ | |
288 | __lll_cond_wait (cond) | |
289 | #define lll_cond_timedwait(cond, abstime) \ | |
290 | __lll_cond_timedwait (cond, abstime) | |
291 | #define lll_cond_wake(cond) \ | |
292 | __lll_cond_wake (cond) | |
293 | #define lll_cond_broadcast(cond) \ | |
294 | __lll_cond_broadcast (cond) | |
295 | ||
296 | #endif /* lowlevellock.h */ |