Add Changelog ...
[jlayton/glibc.git] / ports / sysdeps / unix / sysv / linux / m68k / nptl / lowlevellock.h
1 /* Copyright (C) 2010 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
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 /* Borrowed from ARM's version.  */
20
21 #ifndef _LOWLEVELLOCK_H
22 #define _LOWLEVELLOCK_H 1
23
24 #include <time.h>
25 #include <sys/param.h>
26 #include <bits/pthreadtypes.h>
27 #include <atomic.h>
28 #include <kernel-features.h>
29
30 #define FUTEX_WAIT              0
31 #define FUTEX_WAKE              1
32 #define FUTEX_REQUEUE           3
33 #define FUTEX_CMP_REQUEUE       4
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
39 #define FUTEX_WAIT_BITSET       9
40 #define FUTEX_WAKE_BITSET       10
41 #define FUTEX_PRIVATE_FLAG      128
42 #define FUTEX_CLOCK_REALTIME    256
43
44 #define FUTEX_BITSET_MATCH_ANY  0xffffffff
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
53 #if !defined NOT_IN_libc || defined IS_IN_rtld
54 /* In libc.so or ld.so all futexes are private.  */
55 # ifdef __ASSUME_PRIVATE_FUTEX
56 #  define __lll_private_flag(fl, private) \
57   ((fl) | FUTEX_PRIVATE_FLAG)
58 # else
59 #  define __lll_private_flag(fl, private) \
60   ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
61 # endif
62 #else
63 # ifdef __ASSUME_PRIVATE_FUTEX
64 #  define __lll_private_flag(fl, private) \
65   (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
66 # else
67 #  define __lll_private_flag(fl, private) \
68   (__builtin_constant_p (private)                                             \
69    ? ((private) == 0                                                          \
70       ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))            \
71       : (fl))                                                                 \
72    : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                                \
73               & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
74 # endif
75 #endif
76
77
78 #define lll_futex_wait(futexp, val, private) \
79   lll_futex_timed_wait(futexp, val, NULL, private)
80
81 #define lll_futex_timed_wait(futexp, val, timespec, private) \
82   ({                                                                          \
83     INTERNAL_SYSCALL_DECL (__err);                                            \
84     long int __ret;                                                           \
85     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                      \
86                               __lll_private_flag (FUTEX_WAIT, private),       \
87                               (val), (timespec));                             \
88     __ret;                                                                    \
89   })
90
91 #define lll_futex_wake(futexp, nr, private) \
92   ({                                                                          \
93     INTERNAL_SYSCALL_DECL (__err);                                            \
94     long int __ret;                                                           \
95     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                      \
96                               __lll_private_flag (FUTEX_WAKE, private),       \
97                               (nr), 0);                                       \
98     __ret;                                                                    \
99   })
100
101 #define lll_robust_dead(futexv, private) \
102   do                                                                          \
103     {                                                                         \
104       int *__futexp = &(futexv);                                              \
105       atomic_or (__futexp, FUTEX_OWNER_DIED);                                 \
106       lll_futex_wake (__futexp, 1, private);                                  \
107     }                                                                         \
108   while (0)
109
110 /* Returns non-zero if error happened, zero if success.  */
111 #define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
112   ({                                                                          \
113     INTERNAL_SYSCALL_DECL (__err);                                            \
114     long int __ret;                                                           \
115     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                      \
116                               __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
117                               (nr_wake), (nr_move), (mutex), (val));          \
118     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                  \
119   })
120
121 /* Returns non-zero if error happened, zero if success.  */
122 #define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
123   ({                                                                          \
124     INTERNAL_SYSCALL_DECL (__err);                                            \
125     long int __ret;                                                           \
126     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                      \
127                               __lll_private_flag (FUTEX_WAKE_OP, private),    \
128                               (nr_wake), (nr_wake2), (futexp2),               \
129                               FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                 \
130     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                  \
131   })
132
133 #define lll_trylock(lock)                               \
134   atomic_compare_and_exchange_val_acq (&(lock), 1, 0)
135
136 #define lll_cond_trylock(lock)                          \
137   atomic_compare_and_exchange_val_acq (&(lock), 2, 0)
138
139 #define lll_robust_trylock(lock, id)                    \
140   atomic_compare_and_exchange_val_acq (&(lock), id, 0)
141
142 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
143 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
144 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
145
146 #define __lll_lock(futex, private)                                            \
147   ((void) ({                                                                  \
148     int *__futex = (futex);                                                   \
149     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex,       \
150                                                                 1, 0), 0))    \
151       {                                                                       \
152         if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)       \
153           __lll_lock_wait_private (__futex);                                  \
154         else                                                                  \
155           __lll_lock_wait (__futex, private);                                 \
156       }                                                                       \
157   }))
158 #define lll_lock(futex, private) __lll_lock (&(futex), private)
159
160
161 #define __lll_robust_lock(futex, id, private)                                 \
162   ({                                                                          \
163     int *__futex = (futex);                                                   \
164     int __val = 0;                                                            \
165                                                                               \
166     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
167                                                                 0), 0))       \
168       __val = __lll_robust_lock_wait (__futex, private);                      \
169     __val;                                                                    \
170   })
171 #define lll_robust_lock(futex, id, private) \
172   __lll_robust_lock (&(futex), id, private)
173
174
175 #define __lll_cond_lock(futex, private)                                       \
176   ((void) ({                                                                  \
177     int *__futex = (futex);                                                   \
178     if (__builtin_expect (atomic_exchange_acq (__futex, 2), 0))               \
179       __lll_lock_wait (__futex, private);                                     \
180   }))
181 #define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
182
183
184 #define lll_robust_cond_lock(futex, id, private) \
185   __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
186
187
188 extern int __lll_timedlock_wait (int *futex, const struct timespec *,
189                                  int private) attribute_hidden;
190 extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
191                                         int private) attribute_hidden;
192
193 #define __lll_timedlock(futex, abstime, private)                              \
194   ({                                                                          \
195      int *__futex = (futex);                                                  \
196      int __val = 0;                                                           \
197                                                                               \
198      if (__builtin_expect (atomic_exchange_acq (__futex, 1), 0))              \
199        __val = __lll_timedlock_wait (__futex, abstime, private);              \
200      __val;                                                                   \
201   })
202 #define lll_timedlock(futex, abstime, private) \
203   __lll_timedlock (&(futex), abstime, private)
204
205
206 #define __lll_robust_timedlock(futex, abstime, id, private)                   \
207   ({                                                                          \
208     int *__futex = (futex);                                                   \
209     int __val = 0;                                                            \
210                                                                               \
211     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
212                                                                 0), 0))       \
213       __val = __lll_robust_timedlock_wait (__futex, abstime, private);        \
214     __val;                                                                    \
215   })
216 #define lll_robust_timedlock(futex, abstime, id, private) \
217   __lll_robust_timedlock (&(futex), abstime, id, private)
218
219
220 #define __lll_unlock(futex, private) \
221   (void)                                                        \
222     ({ int *__futex = (futex);                                  \
223        int __oldval = atomic_exchange_rel (__futex, 0);         \
224        if (__builtin_expect (__oldval > 1, 0))                  \
225          lll_futex_wake (__futex, 1, private);                  \
226     })
227 #define lll_unlock(futex, private) __lll_unlock(&(futex), private)
228
229
230 #define __lll_robust_unlock(futex, private) \
231   (void)                                                        \
232     ({ int *__futex = (futex);                                  \
233        int __oldval = atomic_exchange_rel (__futex, 0);         \
234        if (__builtin_expect (__oldval & FUTEX_WAITERS, 0))      \
235          lll_futex_wake (__futex, 1, private);                  \
236     })
237 #define lll_robust_unlock(futex, private) \
238   __lll_robust_unlock(&(futex), private)
239
240
241 #define lll_islocked(futex) \
242   (futex != 0)
243
244
245 /* Our internal lock implementation is identical to the binary-compatible
246    mutex implementation. */
247
248 /* Initializers for lock.  */
249 #define LLL_LOCK_INITIALIZER            (0)
250 #define LLL_LOCK_INITIALIZER_LOCKED     (1)
251
252 /* The states of a lock are:
253     0  -  untaken
254     1  -  taken by one user
255    >1  -  taken by more users */
256
257 /* The kernel notifies a process which uses CLONE_CLEARTID via futex
258    wakeup when the clone terminates.  The memory location contains the
259    thread ID while the clone is running and is reset to zero
260    afterwards.  */
261 #define lll_wait_tid(tid) \
262   do {                                                  \
263     __typeof (tid) __tid;                               \
264     while ((__tid = (tid)) != 0)                        \
265       lll_futex_wait (&(tid), __tid, LLL_SHARED);       \
266   } while (0)
267
268 extern int __lll_timedwait_tid (int *, const struct timespec *)
269      attribute_hidden;
270
271 #define lll_timedwait_tid(tid, abstime) \
272   ({                                                    \
273     int __res = 0;                                      \
274     if ((tid) != 0)                                     \
275       __res = __lll_timedwait_tid (&(tid), (abstime));  \
276     __res;                                              \
277   })
278
279 #endif  /* lowlevellock.h */