Add priority inheritance futex support on sparc.
[platform/upstream/glibc.git] / nptl / sysdeps / unix / sysv / linux / sparc / lowlevellock.h
1 /* Copyright (C) 2003-2013 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Jakub Jelinek <jakub@redhat.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, see
17    <http://www.gnu.org/licenses/>.  */
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>
26 #include <kernel-features.h>
27
28
29 #define FUTEX_WAIT              0
30 #define FUTEX_WAKE              1
31 #define FUTEX_REQUEUE           3
32 #define FUTEX_CMP_REQUEUE       4
33 #define FUTEX_WAKE_OP           5
34 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE   ((4 << 24) | 1)
35 #define FUTEX_LOCK_PI           6
36 #define FUTEX_UNLOCK_PI         7
37 #define FUTEX_TRYLOCK_PI        8
38 #define FUTEX_WAIT_BITSET       9
39 #define FUTEX_WAKE_BITSET       10
40 #define FUTEX_WAIT_REQUEUE_PI   11
41 #define FUTEX_CMP_REQUEUE_PI    12
42 #define FUTEX_PRIVATE_FLAG      128
43 #define FUTEX_CLOCK_REALTIME    256
44
45 #define FUTEX_BITSET_MATCH_ANY  0xffffffff
46
47
48 /* Values for 'private' parameter of locking macros.  Yes, the
49    definition seems to be backwards.  But it is not.  The bit will be
50    reversed before passing to the system call.  */
51 #define LLL_PRIVATE     0
52 #define LLL_SHARED      FUTEX_PRIVATE_FLAG
53
54 #ifndef __sparc32_atomic_do_lock
55 /* Delay in spinlock loop.  */
56 extern void __cpu_relax (void);
57 #define BUSY_WAIT_NOP   __cpu_relax ()
58 #endif
59
60 #if !defined NOT_IN_libc || defined IS_IN_rtld
61 /* In libc.so or ld.so all futexes are private.  */
62 # ifdef __ASSUME_PRIVATE_FUTEX
63 #  define __lll_private_flag(fl, private) \
64   ((fl) | FUTEX_PRIVATE_FLAG)
65 # else
66 #  define __lll_private_flag(fl, private) \
67   ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
68 # endif
69 #else
70 # ifdef __ASSUME_PRIVATE_FUTEX
71 #  define __lll_private_flag(fl, private) \
72   (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
73 # else
74 #  define __lll_private_flag(fl, private) \
75   (__builtin_constant_p (private)                                             \
76    ? ((private) == 0                                                          \
77       ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))            \
78       : (fl))                                                                 \
79    : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                                \
80               & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
81 # endif       
82 #endif
83
84
85 #define lll_futex_wait(futexp, val, private) \
86   lll_futex_timed_wait (futexp, val, NULL, private)
87
88 #define lll_futex_timed_wait(futexp, val, timespec, private) \
89   ({                                                                          \
90     INTERNAL_SYSCALL_DECL (__err);                                            \
91     long int __ret;                                                           \
92                                                                               \
93     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                      \
94                               __lll_private_flag (FUTEX_WAIT, private),       \
95                               (val), (timespec));                             \
96     __ret;                                                                    \
97   })
98
99 #define lll_futex_timed_wait_bitset(futexp, val, timespec, clockbit, private) \
100   ({                                                                          \
101     INTERNAL_SYSCALL_DECL (__err);                                            \
102     long int __ret;                                                           \
103     int __op = FUTEX_WAIT_BITSET | clockbit;                                  \
104                                                                               \
105     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                      \
106                               __lll_private_flag (__op, private),             \
107                               (val), (timespec), NULL /* Unused.  */,         \
108                               FUTEX_BITSET_MATCH_ANY);                        \
109     __ret;                                                                    \
110   })
111
112 #define lll_futex_wake(futexp, nr, private) \
113   ({                                                                          \
114     INTERNAL_SYSCALL_DECL (__err);                                            \
115     long int __ret;                                                           \
116                                                                               \
117     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                      \
118                               __lll_private_flag (FUTEX_WAKE, private),       \
119                               (nr), 0);                                       \
120     __ret;                                                                    \
121   })
122
123 /* Returns non-zero if error happened, zero if success.  */
124 #define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
125   ({                                                                          \
126     INTERNAL_SYSCALL_DECL (__err);                                            \
127     long int __ret;                                                           \
128                                                                               \
129     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                      \
130                               __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
131                               (nr_wake), (nr_move), (mutex), (val));          \
132     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                  \
133   })
134
135 #define lll_robust_dead(futexv, private) \
136   do                                                                          \
137     {                                                                         \
138       int *__futexp = &(futexv);                                              \
139       atomic_or (__futexp, FUTEX_OWNER_DIED);                                 \
140       lll_futex_wake (__futexp, 1, private);                                  \
141     }                                                                         \
142   while (0)
143
144 /* Returns non-zero if error happened, zero if success.  */
145 #ifdef __sparc32_atomic_do_lock
146 /* Avoid FUTEX_WAKE_OP if supporting pre-v9 CPUs.  */
147 # define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) 1
148 #else
149 # define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
150   ({                                                                          \
151     INTERNAL_SYSCALL_DECL (__err);                                            \
152     long int __ret;                                                           \
153                                                                               \
154     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                      \
155                               __lll_private_flag (FUTEX_WAKE_OP, private),    \
156                               (nr_wake), (nr_wake2), (futexp2),               \
157                               FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                 \
158     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                  \
159   })
160 #endif
161
162 /* Priority Inheritance support.  */
163 #define lll_futex_wait_requeue_pi(futexp, val, mutex, private) \
164   lll_futex_timed_wait_requeue_pi (futexp, val, NULL, 0, mutex, private)
165
166 #define lll_futex_timed_wait_requeue_pi(futexp, val, timespec, clockbit,      \
167                                         mutex, private)                       \
168   ({                                                                          \
169     INTERNAL_SYSCALL_DECL (__err);                                            \
170     long int __ret;                                                           \
171     int __op = FUTEX_WAIT_REQUEUE_PI | clockbit;                              \
172                                                                               \
173     __ret = INTERNAL_SYSCALL (futex, __err, 5, (futexp),                      \
174                               __lll_private_flag (__op, private),             \
175                               (val), (timespec), mutex);                      \
176     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;                 \
177   })
178
179 #define lll_futex_cmp_requeue_pi(futexp, nr_wake, nr_move, mutex, val, priv)  \
180   ({                                                                          \
181     INTERNAL_SYSCALL_DECL (__err);                                            \
182     long int __ret;                                                           \
183                                                                               \
184     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                      \
185                               __lll_private_flag (FUTEX_CMP_REQUEUE_PI, priv),\
186                               (nr_wake), (nr_move), (mutex), (val));          \
187     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                  \
188   })
189
190 static inline int
191 __attribute__ ((always_inline))
192 __lll_trylock (int *futex)
193 {
194   return atomic_compare_and_exchange_val_24_acq (futex, 1, 0) != 0;
195 }
196 #define lll_trylock(futex) __lll_trylock (&(futex))
197
198 static inline int
199 __attribute__ ((always_inline))
200 __lll_cond_trylock (int *futex)
201 {
202   return atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0;
203 }
204 #define lll_cond_trylock(futex) __lll_cond_trylock (&(futex))
205
206 static inline int
207 __attribute__ ((always_inline))
208 __lll_robust_trylock (int *futex, int id)
209 {
210   return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0;
211 }
212 #define lll_robust_trylock(futex, id) \
213   __lll_robust_trylock (&(futex), id)
214
215
216 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
217 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
218 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
219
220 static inline void
221 __attribute__ ((always_inline))
222 __lll_lock (int *futex, int private)
223 {
224   int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0);
225
226   if (__builtin_expect (val != 0, 0))
227     {
228       if (__builtin_constant_p (private) && private == LLL_PRIVATE)
229         __lll_lock_wait_private (futex);
230       else
231         __lll_lock_wait (futex, private);
232     }
233 }
234 #define lll_lock(futex, private) __lll_lock (&(futex), private)
235
236 static inline int
237 __attribute__ ((always_inline))
238 __lll_robust_lock (int *futex, int id, int private)
239 {
240   int result = 0;
241   if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
242     result = __lll_robust_lock_wait (futex, private);
243   return result;
244 }
245 #define lll_robust_lock(futex, id, private) \
246   __lll_robust_lock (&(futex), id, private)
247
248 static inline void
249 __attribute__ ((always_inline))
250 __lll_cond_lock (int *futex, int private)
251 {
252   int val = atomic_compare_and_exchange_val_24_acq (futex, 2, 0);
253
254   if (__builtin_expect (val != 0, 0))
255     __lll_lock_wait (futex, private);
256 }
257 #define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
258
259 #define lll_robust_cond_lock(futex, id, private) \
260   __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
261
262
263 extern int __lll_timedlock_wait (int *futex, const struct timespec *,
264                                  int private) attribute_hidden;
265 extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
266                                         int private) attribute_hidden;
267
268 static inline int
269 __attribute__ ((always_inline))
270 __lll_timedlock (int *futex, const struct timespec *abstime, int private)
271 {
272   int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0);
273   int result = 0;
274
275   if (__builtin_expect (val != 0, 0))
276     result = __lll_timedlock_wait (futex, abstime, private);
277   return result;
278 }
279 #define lll_timedlock(futex, abstime, private) \
280   __lll_timedlock (&(futex), abstime, private)
281
282 static inline int
283 __attribute__ ((always_inline))
284 __lll_robust_timedlock (int *futex, const struct timespec *abstime,
285                         int id, int private)
286 {
287   int result = 0;
288   if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
289     result = __lll_robust_timedlock_wait (futex, abstime, private);
290   return result;
291 }
292 #define lll_robust_timedlock(futex, abstime, id, private) \
293   __lll_robust_timedlock (&(futex), abstime, id, private)
294
295 #define lll_unlock(lock, private) \
296   ((void) ({                                                                  \
297     int *__futex = &(lock);                                                   \
298     int __val = atomic_exchange_24_rel (__futex, 0);                          \
299     if (__builtin_expect (__val > 1, 0))                                      \
300       lll_futex_wake (__futex, 1, private);                                   \
301   }))
302
303 #define lll_robust_unlock(lock, private) \
304   ((void) ({                                                                  \
305     int *__futex = &(lock);                                                   \
306     int __val = atomic_exchange_rel (__futex, 0);                             \
307     if (__builtin_expect (__val & FUTEX_WAITERS, 0))                          \
308       lll_futex_wake (__futex, 1, private);                                   \
309   }))
310
311 #define lll_islocked(futex) \
312   (futex != 0)
313
314 /* Initializers for lock.  */
315 #define LLL_LOCK_INITIALIZER            (0)
316 #define LLL_LOCK_INITIALIZER_LOCKED     (1)
317
318 /* The kernel notifies a process which uses CLONE_CHILD_CLEARTID via futex
319    wakeup when the clone terminates.  The memory location contains the
320    thread ID while the clone is running and is reset to zero
321    afterwards.  */
322 #define lll_wait_tid(tid) \
323   do                                                    \
324     {                                                   \
325       __typeof (tid) __tid;                             \
326       while ((__tid = (tid)) != 0)                      \
327         lll_futex_wait (&(tid), __tid, LLL_SHARED);     \
328     }                                                   \
329   while (0)
330
331 extern int __lll_timedwait_tid (int *, const struct timespec *)
332      attribute_hidden;
333
334 #define lll_timedwait_tid(tid, abstime) \
335   ({                                                    \
336     int __res = 0;                                      \
337     if ((tid) != 0)                                     \
338       __res = __lll_timedwait_tid (&(tid), (abstime));  \
339     __res;                                              \
340   })
341
342 #endif  /* lowlevellock.h */