]>
Commit | Line | Data |
---|---|---|
a88c9263 UD |
1 | /* Copyright (C) 2003 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. | |
3 | Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, write to the Free | |
17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
18 | 02111-1307 USA. */ | |
19 | ||
20 | #ifndef _LOWLEVELLOCK_H | |
21 | #define _LOWLEVELLOCK_H 1 | |
22 | ||
23 | #include <time.h> | |
24 | #include <sys/param.h> | |
25 | #include <bits/pthreadtypes.h> | |
26 | ||
27 | #define SYS_futex 238 | |
28 | #define FUTEX_WAIT 0 | |
29 | #define FUTEX_WAKE 1 | |
284bdc42 | 30 | #define FUTEX_REQUEUE 3 |
a88c9263 UD |
31 | |
32 | /* Initializer for compatibility lock. */ | |
33 | #define LLL_MUTEX_LOCK_INITIALIZER (0) | |
34 | ||
35 | #define lll_futex_wait(futex, val) \ | |
36 | ({ \ | |
37 | register unsigned long int __r2 asm ("2") = (unsigned long int) (futex); \ | |
38 | register unsigned long int __r3 asm ("3") = FUTEX_WAIT; \ | |
39 | register unsigned long int __r4 asm ("4") = (unsigned long int) (val); \ | |
40 | register unsigned long int __r5 asm ("5") = 0ul; \ | |
41 | register unsigned long __result asm ("2"); \ | |
42 | \ | |
43 | __asm __volatile ("svc %b1" \ | |
44 | : "=d" (__result) \ | |
45 | : "i" (SYS_futex), "0" (__r2), "d" (__r3), \ | |
46 | "d" (__r4), "d" (__r5) \ | |
47 | : "cc", "memory" ); \ | |
48 | __result; \ | |
49 | }) | |
50 | ||
51 | ||
52 | #define lll_futex_timed_wait(futex, val, timespec) \ | |
53 | ({ \ | |
54 | register unsigned long int __r2 asm ("2") = (unsigned long int) (futex); \ | |
55 | register unsigned long int __r3 asm ("3") = FUTEX_WAIT; \ | |
56 | register unsigned long int __r4 asm ("4") = (unsigned long int) (val); \ | |
57 | register unsigned long int __r5 asm ("5") = (unsigned long int)(timespec);\ | |
58 | register unsigned long int __result asm ("2"); \ | |
59 | \ | |
60 | __asm __volatile ("svc %b1" \ | |
61 | : "=d" (__result) \ | |
62 | : "i" (SYS_futex), "0" (__r2), "d" (__r3), \ | |
63 | "d" (__r4), "d" (__r5) \ | |
64 | : "cc", "memory" ); \ | |
65 | __result; \ | |
66 | }) | |
67 | ||
68 | ||
69 | #define lll_futex_wake(futex, nr) \ | |
70 | ({ \ | |
71 | register unsigned long int __r2 asm ("2") = (unsigned long int) (futex); \ | |
72 | register unsigned long int __r3 asm ("3") = FUTEX_WAKE; \ | |
73 | register unsigned long int __r4 asm ("4") = (unsigned long int) (nr); \ | |
74 | register unsigned long int __result asm ("2"); \ | |
75 | \ | |
76 | __asm __volatile ("svc %b1" \ | |
77 | : "=d" (__result) \ | |
78 | : "i" (SYS_futex), "0" (__r2), "d" (__r3), "d" (__r4) \ | |
79 | : "cc", "memory" ); \ | |
80 | __result; \ | |
81 | }) | |
82 | ||
83 | ||
284bdc42 UD |
84 | #define lll_futex_requeue(futex, nr_wake, nr_move, mutex) \ |
85 | ({ \ | |
86 | register unsigned long int __r2 asm ("2") = (unsigned long int) (futex); \ | |
87 | register unsigned long int __r3 asm ("3") = FUTEX_REQUEUE; \ | |
88 | register unsigned long int __r4 asm ("4") = (long int) (nr_wake); \ | |
89 | register unsigned long int __r5 asm ("5") = (long int) (nr_move); \ | |
90 | register unsigned long int __r6 asm ("6") = (unsigned long int) (mutex); \ | |
91 | register unsigned long __result asm ("2"); \ | |
92 | \ | |
93 | __asm __volatile ("svc %b1" \ | |
94 | : "=d" (__result) \ | |
95 | : "i" (SYS_futex), "0" (__r2), "d" (__r3), \ | |
96 | "d" (__r4), "d" (__r5), "d" (__r6) \ | |
97 | : "cc", "memory" ); \ | |
98 | __result; \ | |
99 | }) | |
100 | ||
101 | ||
a88c9263 UD |
102 | #define lll_compare_and_swap(futex, oldval, newval, operation) \ |
103 | do { \ | |
104 | __typeof (futex) __futex = (futex); \ | |
105 | __asm __volatile (" l %1,%0\n" \ | |
106 | "0: " operation "\n" \ | |
107 | " cs %1,%2,%0\n" \ | |
108 | " jl 0b\n" \ | |
109 | "1:" \ | |
110 | : "=Q" (*__futex), "=&d" (oldval), "=&d" (newval) \ | |
111 | : "m" (*__futex) : "cc" ); \ | |
112 | } while (0) | |
113 | ||
114 | ||
115 | static inline int | |
116 | __attribute__ ((always_inline)) | |
117 | __lll_mutex_trylock (int *futex) | |
118 | { | |
119 | unsigned int old; | |
120 | ||
121 | __asm __volatile ("cs %0,%3,%1" | |
122 | : "=d" (old), "=Q" (*futex) | |
123 | : "0" (0), "d" (1), "m" (*futex) : "cc" ); | |
124 | return old != 0; | |
125 | } | |
126 | #define lll_mutex_trylock(futex) __lll_mutex_trylock (&(futex)) | |
127 | ||
128 | ||
129 | extern void ___lll_mutex_lock (int *, int) attribute_hidden; | |
130 | ||
131 | ||
132 | static inline void | |
133 | __attribute__ ((always_inline)) | |
134 | __lll_mutex_lock (int *futex) | |
135 | { | |
136 | int oldval; | |
137 | int newval; | |
138 | ||
139 | lll_compare_and_swap (futex, oldval, newval, "lr %2,%1; ahi %2,1"); | |
140 | if (oldval > 0) | |
141 | ___lll_mutex_lock (futex, newval); | |
142 | } | |
143 | #define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) | |
144 | ||
145 | ||
146 | extern int ___lll_mutex_timedlock (int *, const struct timespec *, int) | |
147 | attribute_hidden; | |
148 | ||
149 | ||
150 | static inline int | |
151 | __attribute__ ((always_inline)) | |
152 | __lll_mutex_timedlock (int *futex, struct timespec *abstime) | |
153 | { | |
154 | int oldval; | |
155 | int newval; | |
156 | int result = 0; | |
157 | ||
158 | lll_compare_and_swap (futex, oldval, newval, "lr %2,%1; ahi %2,1"); | |
159 | if (oldval > 0) | |
160 | result = ___lll_mutex_timedlock (futex, abstime, newval); | |
161 | ||
162 | return result; | |
163 | } | |
164 | #define lll_mutex_timedlock(futex, abstime) \ | |
165 | __lll_mutex_timedlock (&(futex), abstime) | |
166 | ||
167 | ||
168 | static inline void | |
169 | __attribute__ ((always_inline)) | |
170 | __lll_mutex_unlock (int *futex) | |
171 | { | |
172 | int oldval; | |
173 | int newval; | |
174 | ||
175 | lll_compare_and_swap (futex, oldval, newval, "slr %2,%2"); | |
176 | if (oldval > 1) | |
177 | lll_futex_wake (futex, 1); | |
178 | } | |
284bdc42 UD |
179 | #define lll_mutex_unlock(futex) \ |
180 | __lll_mutex_unlock(&(futex)) | |
181 | ||
182 | #define lll_mutex_unlock_force(futex) \ | |
183 | lll_futex_wake (&(futex), 1) | |
a88c9263 UD |
184 | |
185 | #define lll_mutex_islocked(futex) \ | |
186 | (futex != 0) | |
187 | ||
188 | ||
189 | /* We have a separate internal lock implementation which is not tied | |
190 | to binary compatibility. */ | |
191 | ||
192 | /* Type for lock object. */ | |
193 | typedef int lll_lock_t; | |
194 | ||
195 | /* Initializers for lock. */ | |
196 | #define LLL_LOCK_INITIALIZER (1) | |
197 | #define LLL_LOCK_INITIALIZER_LOCKED (0) | |
198 | ||
199 | ||
200 | extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; | |
201 | ||
202 | /* The states of a lock are: | |
203 | 1 - untaken | |
204 | 0 - taken by one user | |
205 | <0 - taken by more users */ | |
206 | ||
207 | ||
208 | static inline int | |
209 | __attribute__ ((always_inline)) | |
210 | __lll_trylock (int *futex) | |
211 | { | |
212 | unsigned int old; | |
213 | ||
214 | __asm __volatile ("cs %0,%3,%1" | |
215 | : "=d" (old), "=Q" (*futex) | |
216 | : "0" (1), "d" (0), "m" (*futex) : "cc" ); | |
217 | return old != 1; | |
218 | } | |
219 | #define lll_trylock(futex) __lll_trylock (&(futex)) | |
220 | ||
221 | ||
222 | extern void ___lll_lock (int *, int) attribute_hidden; | |
223 | ||
224 | static inline void | |
225 | __attribute__ ((always_inline)) | |
226 | __lll_lock (int *futex) | |
227 | { | |
228 | int oldval; | |
229 | int newval; | |
230 | ||
231 | lll_compare_and_swap (futex, oldval, newval, "lr %2,%1; ahi %2,-1"); | |
232 | if (newval < 0) | |
233 | ___lll_lock (futex, newval); | |
234 | } | |
235 | #define lll_lock(futex) __lll_lock (&(futex)) | |
236 | ||
237 | ||
238 | static inline void | |
239 | __attribute__ ((always_inline)) | |
240 | __lll_unlock (int *futex) | |
241 | { | |
242 | int oldval; | |
243 | int newval; | |
244 | ||
245 | lll_compare_and_swap (futex, oldval, newval, "lhi %2,1"); | |
246 | if (oldval < 0) | |
247 | lll_futex_wake (futex, 1); | |
248 | } | |
249 | #define lll_unlock(futex) __lll_unlock(&(futex)) | |
250 | ||
251 | ||
252 | #define lll_islocked(futex) \ | |
253 | (futex != 1) | |
254 | ||
255 | ||
256 | /* The kernel notifies a process with uses CLONE_CLEARTID via futex | |
257 | wakeup when the clone terminates. The memory location contains the | |
258 | thread ID while the clone is running and is reset to zero | |
259 | afterwards. */ | |
260 | static inline void | |
261 | __attribute__ ((always_inline)) | |
262 | __lll_wait_tid (int *ptid) | |
263 | { | |
264 | int tid; | |
265 | ||
266 | while ((tid = *ptid) != 0) | |
267 | lll_futex_wait (ptid, tid); | |
268 | } | |
269 | #define lll_wait_tid(tid) __lll_wait_tid(&(tid)) | |
270 | ||
271 | ||
272 | extern int ___lll_timedwait_tid (int *, const struct timespec *) | |
273 | attribute_hidden; | |
274 | static inline int | |
275 | __attribute__ ((always_inline)) | |
276 | __lll_timedwait_tid (int *ptid, const struct timespec *abstime) | |
277 | { | |
278 | if (*ptid == 0) | |
279 | return 0; | |
280 | ||
281 | return ___lll_timedwait_tid (ptid, abstime); | |
282 | } | |
283 | #define lll_timedwait_tid(tid, abstime) __lll_timedwait_tid (&(tid), abstime) | |
284 | ||
285 | ||
a88c9263 UD |
286 | /* Conditional variable handling. */ |
287 | ||
288 | extern void __lll_cond_wait (pthread_cond_t *cond) | |
289 | attribute_hidden; | |
290 | extern int __lll_cond_timedwait (pthread_cond_t *cond, | |
291 | const struct timespec *abstime) | |
292 | attribute_hidden; | |
293 | extern void __lll_cond_wake (pthread_cond_t *cond) | |
294 | attribute_hidden; | |
295 | extern void __lll_cond_broadcast (pthread_cond_t *cond) | |
296 | attribute_hidden; | |
297 | ||
298 | #define lll_cond_wait(cond) \ | |
299 | __lll_cond_wait (cond) | |
300 | #define lll_cond_timedwait(cond, abstime) \ | |
301 | __lll_cond_timedwait (cond, abstime) | |
302 | #define lll_cond_wake(cond) \ | |
303 | __lll_cond_wake (cond) | |
304 | #define lll_cond_broadcast(cond) \ | |
305 | __lll_cond_broadcast (cond) | |
306 | ||
307 | #endif /* lowlevellock.h */ |