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