OSDN Git Service

2c2557d56586230160e10a58ee853d3f0d6e0bf2
[uclinux-h8/uClibc.git] / libpthread / nptl / sysdeps / unix / sysv / linux / powerpc / lowlevellock.h
1 /* Copyright (C) 2003, 2004, 2006-2008, 2009 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Paul Mackerras <paulus@au.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 #include <atomic.h>
27 #include <bits/kernel-features.h>
28 #include <sysdep.h>
29
30 #ifndef __NR_futex
31 # define __NR_futex             221
32 #endif
33 #define FUTEX_WAIT              0
34 #define FUTEX_WAKE              1
35 #define FUTEX_REQUEUE           3
36 #define FUTEX_CMP_REQUEUE       4
37 #define FUTEX_WAKE_OP           5
38 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE   ((4 << 24) | 1)
39 #define FUTEX_LOCK_PI           6
40 #define FUTEX_UNLOCK_PI         7
41 #define FUTEX_TRYLOCK_PI        8
42 #define FUTEX_WAIT_BITSET       9
43 #define FUTEX_WAKE_BITSET       10
44 #define FUTEX_PRIVATE_FLAG      128
45 #define FUTEX_CLOCK_REALTIME    256
46
47 #define FUTEX_BITSET_MATCH_ANY  0xffffffff
48
49 /* Values for 'private' parameter of locking macros.  Yes, the
50    definition seems to be backwards.  But it is not.  The bit will be
51    reversed before passing to the system call.  */
52 #define LLL_PRIVATE     0
53 #define LLL_SHARED      FUTEX_PRIVATE_FLAG
54
55 #if !defined NOT_IN_libc || defined IS_IN_rtld
56 /* In libc.so or ld.so all futexes are private.  */
57 # ifdef __ASSUME_PRIVATE_FUTEX
58 #  define __lll_private_flag(fl, private) \
59   ((fl) | FUTEX_PRIVATE_FLAG)
60 # else
61 #  define __lll_private_flag(fl, private) \
62   ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
63 # endif
64 #else
65 # ifdef __ASSUME_PRIVATE_FUTEX
66 #  define __lll_private_flag(fl, private) \
67   (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
68 # else
69 #  define __lll_private_flag(fl, private) \
70   (__builtin_constant_p (private)                                             \
71    ? ((private) == 0                                                          \
72       ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))            \
73       : (fl))                                                                 \
74    : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                                \
75               & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
76 # endif
77 #endif
78
79 #define lll_futex_wait(futexp, val, private) \
80   lll_futex_timed_wait (futexp, val, NULL, private)
81
82 #define lll_futex_timed_wait(futexp, val, timespec, private) \
83   ({                                                                          \
84     INTERNAL_SYSCALL_DECL (__err);                                            \
85     long int __ret;                                                           \
86                                                                               \
87     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                      \
88                               __lll_private_flag (FUTEX_WAIT, private),       \
89                               (val), (timespec));                             \
90     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;                 \
91   })
92
93 #define lll_futex_wake(futexp, nr, private) \
94   ({                                                                          \
95     INTERNAL_SYSCALL_DECL (__err);                                            \
96     long int __ret;                                                           \
97                                                                               \
98     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                      \
99                               __lll_private_flag (FUTEX_WAKE, private),       \
100                               (nr), 0);                                       \
101     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;                 \
102   })
103
104 #define lll_robust_dead(futexv, private) \
105   do                                                                          \
106     {                                                                         \
107       INTERNAL_SYSCALL_DECL (__err);                                          \
108       int *__futexp = &(futexv);                                              \
109                                                                               \
110       atomic_or (__futexp, FUTEX_OWNER_DIED);                                 \
111       INTERNAL_SYSCALL (futex, __err, 4, __futexp,                            \
112                         __lll_private_flag (FUTEX_WAKE, private), 1, 0);      \
113     }                                                                         \
114   while (0)
115
116 /* Returns non-zero if error happened, zero if success.  */
117 #define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
118   ({                                                                          \
119     INTERNAL_SYSCALL_DECL (__err);                                            \
120     long int __ret;                                                           \
121                                                                               \
122     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                      \
123                               __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
124                               (nr_wake), (nr_move), (mutex), (val));          \
125     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                  \
126   })
127
128 /* Returns non-zero if error happened, zero if success.  */
129 #define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
130   ({                                                                          \
131     INTERNAL_SYSCALL_DECL (__err);                                            \
132     long int __ret;                                                           \
133                                                                               \
134     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                      \
135                               __lll_private_flag (FUTEX_WAKE_OP, private),    \
136                               (nr_wake), (nr_wake2), (futexp2),               \
137                               FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                 \
138     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                  \
139   })
140
141
142 #ifdef UP
143 # define __lll_acq_instr        ""
144 # define __lll_rel_instr        ""
145 #else
146 # define __lll_acq_instr        "isync"
147 # ifdef _ARCH_PWR4
148 /*
149  * Newer powerpc64 processors support the new "light weight" sync (lwsync)
150  * So if the build is using -mcpu=[power4,power5,power5+,970] we can
151  * safely use lwsync.
152  */
153 #  define __lll_rel_instr       "lwsync"
154 # else
155 /*
156  * Older powerpc32 processors don't support the new "light weight"
157  * sync (lwsync).  So the only safe option is to use normal sync
158  * for all powerpc32 applications.
159  */
160 #  define __lll_rel_instr       "sync"
161 # endif
162 #endif
163
164 /* Set *futex to ID if it is 0, atomically.  Returns the old value */
165 #define __lll_robust_trylock(futex, id) \
166   ({ int __val;                                                               \
167      __asm__ __volatile__ ("1:  lwarx   %0,0,%2" MUTEX_HINT_ACQ "\n"          \
168                        "        cmpwi   0,%0,0\n"                             \
169                        "        bne     2f\n"                                 \
170                        "        stwcx.  %3,0,%2\n"                            \
171                        "        bne-    1b\n"                                 \
172                        "2:      " __lll_acq_instr                             \
173                        : "=&r" (__val), "=m" (*futex)                         \
174                        : "r" (futex), "r" (id), "m" (*futex)                  \
175                        : "cr0", "memory");                                    \
176      __val;                                                                   \
177   })
178
179 #define lll_robust_trylock(lock, id) __lll_robust_trylock (&(lock), id)
180
181 /* Set *futex to 1 if it is 0, atomically.  Returns the old value */
182 #define __lll_trylock(futex) __lll_robust_trylock (futex, 1)
183
184 #define lll_trylock(lock)       __lll_trylock (&(lock))
185
186 /* Set *futex to 2 if it is 0, atomically.  Returns the old value */
187 #define __lll_cond_trylock(futex) __lll_robust_trylock (futex, 2)
188
189 #define lll_cond_trylock(lock)  __lll_cond_trylock (&(lock))
190
191
192 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
193 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
194 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
195
196 #define lll_lock(lock, private) \
197   (void) ({                                                                   \
198     int *__futex = &(lock);                                                   \
199     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\
200                           0) != 0)                                            \
201       {                                                                       \
202         if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)       \
203           __lll_lock_wait_private (__futex);                                  \
204         else                                                                  \
205           __lll_lock_wait (__futex, private);                                 \
206       }                                                                       \
207   })
208
209 #define lll_robust_lock(lock, id, private) \
210   ({                                                                          \
211     int *__futex = &(lock);                                                   \
212     int __val = 0;                                                            \
213     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
214                                                                 0), 0))       \
215       __val = __lll_robust_lock_wait (__futex, private);                      \
216     __val;                                                                    \
217   })
218
219 #define lll_cond_lock(lock, private) \
220   (void) ({                                                                   \
221     int *__futex = &(lock);                                                   \
222     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 2, 0),\
223                           0) != 0)                                            \
224       __lll_lock_wait (__futex, private);                                     \
225   })
226
227 #define lll_robust_cond_lock(lock, id, private) \
228   ({                                                                          \
229     int *__futex = &(lock);                                                   \
230     int __val = 0;                                                            \
231     int __id = id | FUTEX_WAITERS;                                            \
232     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, __id,\
233                                                                 0), 0))       \
234       __val = __lll_robust_lock_wait (__futex, private);                      \
235     __val;                                                                    \
236   })
237
238
239 extern int __lll_timedlock_wait
240   (int *futex, const struct timespec *, int private) attribute_hidden;
241 extern int __lll_robust_timedlock_wait
242   (int *futex, const struct timespec *, int private) attribute_hidden;
243
244 #define lll_timedlock(lock, abstime, private) \
245   ({                                                                          \
246     int *__futex = &(lock);                                                   \
247     int __val = 0;                                                            \
248     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\
249                           0) != 0)                                            \
250       __val = __lll_timedlock_wait (__futex, abstime, private);               \
251     __val;                                                                    \
252   })
253
254 #define lll_robust_timedlock(lock, abstime, id, private) \
255   ({                                                                          \
256     int *__futex = &(lock);                                                   \
257     int __val = 0;                                                            \
258     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
259                                                                 0), 0))       \
260       __val = __lll_robust_timedlock_wait (__futex, abstime, private);        \
261     __val;                                                                    \
262   })
263
264 #define lll_unlock(lock, private) \
265   ((void) ({                                                                  \
266     int *__futex = &(lock);                                                   \
267     int __val = atomic_exchange_rel (__futex, 0);                             \
268     if (__builtin_expect (__val > 1, 0))                                      \
269       lll_futex_wake (__futex, 1, private);                                   \
270   }))
271
272 #define lll_robust_unlock(lock, private) \
273   ((void) ({                                                                  \
274     int *__futex = &(lock);                                                   \
275     int __val = atomic_exchange_rel (__futex, 0);                             \
276     if (__builtin_expect (__val & FUTEX_WAITERS, 0))                          \
277       lll_futex_wake (__futex, 1, private);                                   \
278   }))
279
280 #define lll_islocked(futex) \
281   (futex != 0)
282
283
284 /* Initializers for lock.  */
285 #define LLL_LOCK_INITIALIZER            (0)
286 #define LLL_LOCK_INITIALIZER_LOCKED     (1)
287
288 /* The states of a lock are:
289     0  -  untaken
290     1  -  taken by one user
291    >1  -  taken by more users */
292
293 /* The kernel notifies a process which uses CLONE_CLEARTID via futex
294    wakeup when the clone terminates.  The memory location contains the
295    thread ID while the clone is running and is reset to zero
296    afterwards.  */
297 #define lll_wait_tid(tid) \
298   do {                                                                        \
299     __typeof (tid) __tid;                                                     \
300     while ((__tid = (tid)) != 0)                                              \
301       lll_futex_wait (&(tid), __tid, LLL_SHARED);                             \
302   } while (0)
303
304 extern int __lll_timedwait_tid (int *, const struct timespec *)
305      attribute_hidden;
306
307 #define lll_timedwait_tid(tid, abstime) \
308   ({                                                                          \
309     int __res = 0;                                                            \
310     if ((tid) != 0)                                                           \
311       __res = __lll_timedwait_tid (&(tid), (abstime));                        \
312     __res;                                                                    \
313   })
314
315 #endif  /* lowlevellock.h */