Upload Tizen:Base source
[external/eglibc.git] / nptl / sysdeps / unix / sysv / linux / sh / lowlevellock.h
1 /* Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009
2    Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
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 #ifndef __ASSEMBLER__
24 #include <time.h>
25 #include <sys/param.h>
26 #include <bits/pthreadtypes.h>
27 #include <kernel-features.h>
28 #endif
29
30 #define SYS_futex               240
31 #define FUTEX_WAIT              0
32 #define FUTEX_WAKE              1
33 #define FUTEX_CMP_REQUEUE       4
34 #define FUTEX_WAKE_OP           5
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 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE   ((4 << 24) | 1)
46
47 /* Values for 'private' parameter of locking macros.  Yes, the
48    definition seems to be backwards.  But it is not.  The bit will be
49    reversed before passing to the system call.  */
50 #define LLL_PRIVATE    0
51 #define LLL_SHARED     FUTEX_PRIVATE_FLAG
52
53
54 #if !defined NOT_IN_libc || defined IS_IN_rtld
55 /* In libc.so or ld.so all futexes are private.  */
56 # ifdef __ASSUME_PRIVATE_FUTEX
57 #  define __lll_private_flag(fl, private) \
58   ((fl) | FUTEX_PRIVATE_FLAG)
59 # else
60 #  define __lll_private_flag(fl, private) \
61   ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
62 # endif
63 #else
64 # ifdef __ASSUME_PRIVATE_FUTEX
65 #  define __lll_private_flag(fl, private) \
66   (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
67 # else
68 #  define __lll_private_flag(fl, private) \
69   (__builtin_constant_p (private)                                             \
70    ? ((private) == 0                                                          \
71       ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))            \
72       : (fl))                                                                 \
73    : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                                \
74               & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
75 # endif       
76 #endif
77
78 #ifndef __ASSEMBLER__
79
80 /* Initializer for compatibility lock.  */
81 #define LLL_LOCK_INITIALIZER            (0)
82 #define LLL_LOCK_INITIALIZER_LOCKED     (1)
83 #define LLL_LOCK_INITIALIZER_WAITERS    (2)
84
85 extern int __lll_lock_wait_private (int val, int *__futex)
86   attribute_hidden;
87 extern int __lll_lock_wait (int val, int *__futex, int private)
88   attribute_hidden;
89 extern int __lll_timedlock_wait (int val, int *__futex,
90                                  const struct timespec *abstime, int private)
91   attribute_hidden;
92 extern int __lll_robust_lock_wait (int val, int *__futex, int private)
93   attribute_hidden;
94 extern int __lll_robust_timedlock_wait (int val, int *__futex,
95                                         const struct timespec *abstime,
96                                         int private)
97   attribute_hidden;
98 extern int __lll_unlock_wake_private (int *__futex) attribute_hidden;
99 extern int __lll_unlock_wake (int *__futex, int private) attribute_hidden;
100
101 #define lll_trylock(futex) \
102   ({ unsigned char __result; \
103      __asm __volatile ("\
104         .align 2\n\
105         mova 1f,r0\n\
106         nop\n\
107         mov r15,r1\n\
108         mov #-8,r15\n\
109      0: mov.l @%1,r2\n\
110         cmp/eq r2,%3\n\
111         bf 1f\n\
112         mov.l %2,@%1\n\
113      1: mov r1,r15\n\
114         mov #-1,%0\n\
115         negc %0,%0"\
116         : "=r" (__result) \
117         : "r" (&(futex)), \
118           "r" (LLL_LOCK_INITIALIZER_LOCKED), \
119           "r" (LLL_LOCK_INITIALIZER) \
120         : "r0", "r1", "r2", "t", "memory"); \
121      __result; })
122
123 #define lll_robust_trylock(futex, id)   \
124   ({ unsigned char __result; \
125      __asm __volatile ("\
126         .align 2\n\
127         mova 1f,r0\n\
128         nop\n\
129         mov r15,r1\n\
130         mov #-8,r15\n\
131      0: mov.l @%1,r2\n\
132         cmp/eq r2,%3\n\
133         bf 1f\n\
134         mov.l %2,@%1\n\
135      1: mov r1,r15\n\
136         mov #-1,%0\n\
137         negc %0,%0"\
138         : "=r" (__result) \
139         : "r" (&(futex)), \
140           "r" (id), \
141           "r" (LLL_LOCK_INITIALIZER) \
142         : "r0", "r1", "r2", "t", "memory"); \
143      __result; })
144
145 #define lll_cond_trylock(futex) \
146   ({ unsigned char __result; \
147      __asm __volatile ("\
148         .align 2\n\
149         mova 1f,r0\n\
150         nop\n\
151         mov r15,r1\n\
152         mov #-8,r15\n\
153      0: mov.l @%1,r2\n\
154         cmp/eq r2,%3\n\
155         bf 1f\n\
156         mov.l %2,@%1\n\
157      1: mov r1,r15\n\
158         mov #-1,%0\n\
159         negc %0,%0"\
160         : "=r" (__result) \
161         : "r" (&(futex)), \
162           "r" (LLL_LOCK_INITIALIZER_WAITERS), \
163           "r" (LLL_LOCK_INITIALIZER) \
164         : "r0", "r1", "r2", "t", "memory"); \
165      __result; })
166
167 #define lll_lock(futex, private) \
168   (void) ({ int __result, *__futex = &(futex); \
169             __asm __volatile ("\
170                 .align 2\n\
171                 mova 1f,r0\n\
172                 nop\n\
173                 mov r15,r1\n\
174                 mov #-8,r15\n\
175              0: mov.l @%2,%0\n\
176                 tst %0,%0\n\
177                 bf 1f\n\
178                 mov.l %1,@%2\n\
179              1: mov r1,r15"\
180                 : "=&r" (__result) : "r" (1), "r" (__futex) \
181                 : "r0", "r1", "t", "memory"); \
182             if (__result) \
183               { \
184                 if (__builtin_constant_p (private) \
185                     && (private) == LLL_PRIVATE) \
186                   __lll_lock_wait_private (__result, __futex); \
187                 else \
188                   __lll_lock_wait (__result, __futex, (private));       \
189               } \
190     })
191
192 #define lll_robust_lock(futex, id, private) \
193   ({ int __result, *__futex = &(futex); \
194      __asm __volatile ("\
195         .align 2\n\
196         mova 1f,r0\n\
197         nop\n\
198         mov r15,r1\n\
199         mov #-8,r15\n\
200       0: mov.l @%2,%0\n\
201         tst %0,%0\n\
202         bf 1f\n\
203         mov.l %1,@%2\n\
204       1: mov r1,r15"\
205         : "=&r" (__result) : "r" (id), "r" (__futex) \
206         : "r0", "r1", "t", "memory"); \
207      if (__result) \
208        __result = __lll_robust_lock_wait (__result, __futex, private); \
209      __result; })
210
211 /* Special version of lll_mutex_lock which causes the unlock function to
212    always wakeup waiters.  */
213 #define lll_cond_lock(futex, private) \
214   (void) ({ int __result, *__futex = &(futex); \
215             __asm __volatile ("\
216                 .align 2\n\
217                 mova 1f,r0\n\
218                 nop\n\
219                 mov r15,r1\n\
220                 mov #-8,r15\n\
221              0: mov.l @%2,%0\n\
222                 tst %0,%0\n\
223                 bf 1f\n\
224                 mov.l %1,@%2\n\
225              1: mov r1,r15"\
226                 : "=&r" (__result) : "r" (2), "r" (__futex) \
227                 : "r0", "r1", "t", "memory"); \
228             if (__result) \
229               __lll_lock_wait (__result, __futex, private); })
230
231 #define lll_robust_cond_lock(futex, id, private) \
232   ({ int __result, *__futex = &(futex); \
233      __asm __volatile ("\
234         .align 2\n\
235         mova 1f,r0\n\
236         nop\n\
237         mov r15,r1\n\
238         mov #-8,r15\n\
239      0: mov.l @%2,%0\n\
240         tst %0,%0\n\
241         bf 1f\n\
242         mov.l %1,@%2\n\
243      1: mov r1,r15"\
244         : "=&r" (__result) : "r" (id | FUTEX_WAITERS), "r" (__futex) \
245         : "r0", "r1", "t", "memory"); \
246       if (__result) \
247         __result = __lll_robust_lock_wait (__result, __futex, private); \
248       __result; })
249
250 #define lll_timedlock(futex, timeout, private) \
251   ({ int __result, *__futex = &(futex); \
252      __asm __volatile ("\
253         .align 2\n\
254         mova 1f,r0\n\
255         nop\n\
256         mov r15,r1\n\
257         mov #-8,r15\n\
258      0: mov.l @%2,%0\n\
259         tst %0,%0\n\
260         bf 1f\n\
261         mov.l %1,@%2\n\
262      1: mov r1,r15"\
263         : "=&r" (__result) : "r" (1), "r" (__futex) \
264         : "r0", "r1", "t", "memory"); \
265     if (__result) \
266       __result = __lll_timedlock_wait (__result, __futex, timeout, private); \
267     __result; })
268
269 #define lll_robust_timedlock(futex, timeout, id, private) \
270   ({ int __result, *__futex = &(futex); \
271      __asm __volatile ("\
272         .align 2\n\
273         mova 1f,r0\n\
274         nop\n\
275         mov r15,r1\n\
276         mov #-8,r15\n\
277      0: mov.l @%2,%0\n\
278         tst %0,%0\n\
279         bf 1f\n\
280         mov.l %1,@%2\n\
281      1: mov r1,r15"\
282         : "=&r" (__result) : "r" (id), "r" (__futex) \
283         : "r0", "r1", "t", "memory"); \
284     if (__result) \
285       __result = __lll_robust_timedlock_wait (__result, __futex, \
286                                               timeout, private); \
287     __result; })
288
289 #define lll_unlock(futex, private) \
290   (void) ({ int __result, *__futex = &(futex); \
291             __asm __volatile ("\
292                 .align 2\n\
293                 mova 1f,r0\n\
294                 mov r15,r1\n\
295                 mov #-6,r15\n\
296              0: mov.l @%1,%0\n\
297                 add #-1,%0\n\
298                 mov.l %0,@%1\n\
299              1: mov r1,r15"\
300                 : "=&r" (__result) : "r" (__futex) \
301                 : "r0", "r1", "memory"); \
302             if (__result) \
303               { \
304                 if (__builtin_constant_p (private) \
305                     && (private) == LLL_PRIVATE) \
306                   __lll_unlock_wake_private (__futex); \
307                 else \
308                   __lll_unlock_wake (__futex, (private)); \
309               } \
310     })
311
312 #define lll_robust_unlock(futex, private) \
313   (void) ({ int __result, *__futex = &(futex); \
314             __asm __volatile ("\
315                 .align 2\n\
316                 mova 1f,r0\n\
317                 mov r15,r1\n\
318                 mov #-6,r15\n\
319              0: mov.l @%1,%0\n\
320                 and %2,%0\n\
321                 mov.l %0,@%1\n\
322              1: mov r1,r15"\
323                 : "=&r" (__result) : "r" (__futex), "r" (FUTEX_WAITERS) \
324                 : "r0", "r1", "memory");        \
325             if (__result) \
326               __lll_unlock_wake (__futex, private); })
327
328 #define lll_robust_dead(futex, private)                \
329   (void) ({ int __ignore, *__futex = &(futex); \
330             __asm __volatile ("\
331                 .align 2\n\
332                 mova 1f,r0\n\
333                 mov r15,r1\n\
334                 mov #-6,r15\n\
335              0: mov.l @%1,%0\n\
336                 or %2,%0\n\
337                 mov.l %0,@%1\n\
338              1: mov r1,r15"\
339                 : "=&r" (__ignore) : "r" (__futex), "r" (FUTEX_OWNER_DIED) \
340                 : "r0", "r1", "memory");        \
341             lll_futex_wake (__futex, 1, private); })
342
343 # ifdef NEED_SYSCALL_INST_PAD
344 #  define SYSCALL_WITH_INST_PAD "\
345         trapa #0x14; or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0"
346 # else
347 #  define SYSCALL_WITH_INST_PAD "\
348         trapa #0x14"
349 # endif
350
351 #define lll_futex_wait(futex, val, private) \
352   lll_futex_timed_wait (futex, val, NULL, private)
353
354
355 #define lll_futex_timed_wait(futex, val, timeout, private) \
356   ({                                                                          \
357     int __status;                                                             \
358     register unsigned long __r3 asm ("r3") = SYS_futex;                       \
359     register unsigned long __r4 asm ("r4") = (unsigned long) (futex);         \
360     register unsigned long __r5 asm ("r5")                                    \
361       = __lll_private_flag (FUTEX_WAIT, private);                             \
362     register unsigned long __r6 asm ("r6") = (unsigned long) (val);           \
363     register unsigned long __r7 asm ("r7") = (timeout);                       \
364     __asm __volatile (SYSCALL_WITH_INST_PAD                                   \
365                       : "=z" (__status)                                       \
366                       : "r" (__r3), "r" (__r4), "r" (__r5),                   \
367                         "r" (__r6), "r" (__r7)                                \
368                       : "memory", "t");                                       \
369     __status;                                                                 \
370   })
371
372
373 #define lll_futex_wake(futex, nr, private) \
374   do {                                                                        \
375     int __ignore;                                                             \
376     register unsigned long __r3 asm ("r3") = SYS_futex;                       \
377     register unsigned long __r4 asm ("r4") = (unsigned long) (futex);         \
378     register unsigned long __r5 asm ("r5")                                    \
379       = __lll_private_flag (FUTEX_WAKE, private);                             \
380     register unsigned long __r6 asm ("r6") = (unsigned long) (nr);            \
381     register unsigned long __r7 asm ("r7") = 0;                               \
382     __asm __volatile (SYSCALL_WITH_INST_PAD                                   \
383                       : "=z" (__ignore)                                       \
384                       : "r" (__r3), "r" (__r4), "r" (__r5),                   \
385                         "r" (__r6), "r" (__r7)                                \
386                       : "memory", "t");                                       \
387   } while (0)
388
389
390 #define lll_islocked(futex) \
391   (futex != LLL_LOCK_INITIALIZER)
392
393 /* The kernel notifies a process with uses CLONE_CLEARTID via futex
394    wakeup when the clone terminates.  The memory location contains the
395    thread ID while the clone is running and is reset to zero
396    afterwards.  */
397
398 #define lll_wait_tid(tid) \
399   do {                                                                        \
400     __typeof (tid) *__tid = &(tid);                                           \
401     while (*__tid != 0)                                                       \
402       lll_futex_wait (__tid, *__tid, LLL_SHARED);                             \
403   } while (0)
404
405 extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
406      attribute_hidden;
407 #define lll_timedwait_tid(tid, abstime) \
408   ({                                                                          \
409     int __result = 0;                                                         \
410     if (tid != 0)                                                             \
411       {                                                                       \
412         if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)           \
413           __result = EINVAL;                                                  \
414         else                                                                  \
415           __result = __lll_timedwait_tid (&tid, abstime);                     \
416       }                                                                       \
417     __result; })
418
419 #endif  /* !__ASSEMBLER__ */
420
421 #endif  /* lowlevellock.h */