00ff1b20fbc782ccffa15d0ac2ca4e1068a8d3db
[platform/upstream/glibc.git] / nptl / sysdeps / unix / sysv / linux / sh / lowlevellock.h
1 /* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
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
26 #define SYS_futex               240
27 #define FUTEX_WAIT              0
28 #define FUTEX_WAKE              1
29
30
31 /* Initializer for compatibility lock.  */
32 #define LLL_MUTEX_LOCK_INITIALIZER              (0)
33 #define LLL_MUTEX_LOCK_INITIALIZER_LOCKED       (1)
34 #define LLL_MUTEX_LOCK_INITIALIZER_WAITERS      (2)
35
36 extern int __lll_mutex_lock_wait (int val, int *__futex) attribute_hidden;
37 extern int __lll_mutex_timedlock_wait (int val, int *__futex,
38                                        const struct timespec *abstime)
39      attribute_hidden;
40 extern int __lll_mutex_unlock_wake (int *__futex) attribute_hidden;
41
42
43 #define lll_mutex_trylock(futex) \
44   ({ unsigned char __result; \
45      __asm __volatile ("\
46         .align 2\n\
47         mova 1f,r0\n\
48         nop\n\
49         mov r15,r1\n\
50         mov #-8,r15\n\
51      0: mov.l @%1,r2\n\
52         cmp/eq r2,%3\n\
53         bf 1f\n\
54         mov.l %2,@%1\n\
55      1: mov r1,r15\n\
56         mov #-1,%0\n\
57         negc %0,%0"\
58         : "=r" (__result) \
59         : "r" (&(futex)), \
60           "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), \
61           "r" (LLL_MUTEX_LOCK_INITIALIZER) \
62         : "r0", "r1", "r2", "t", "memory"); \
63      __result; })
64
65 #define lll_mutex_cond_trylock(futex) \
66   ({ unsigned char __result; \
67      __asm __volatile ("\
68         .align 2\n\
69         mova 1f,r0\n\
70         nop\n\
71         mov r15,r1\n\
72         mov #-8,r15\n\
73      0: mov.l @%1,r2\n\
74         cmp/eq r2,%3\n\
75         bf 1f\n\
76         mov.l %2,@%1\n\
77      1: mov r1,r15\n\
78         mov #-1,%0\n\
79         negc %0,%0"\
80         : "=r" (__result) \
81         : "r" (&(futex)), \
82           "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS), \
83           "r" (LLL_MUTEX_LOCK_INITIALIZER) \
84         : "r0", "r1", "r2", "t", "memory"); \
85      __result; })
86
87 #define lll_mutex_lock(futex) \
88   (void) ({ int __result, val, *__futex = &(futex); \
89             __asm __volatile ("\
90                 .align 2\n\
91                 mova 1f,r0\n\
92                 mov r15,r1\n\
93                 mov #-8,r15\n\
94              0: mov.l @%2,%0\n\
95                 tst %0,%0\n\
96                 bf 1f\n\
97                 mov.l %1,@%2\n\
98              1: mov r1,r15"\
99                 : "=&r" (__result) : "r" (1), "r" (__futex) \
100                 : "r0", "r1", "t", "memory"); \
101             if (__result) \
102               __lll_mutex_lock_wait (__result, __futex); })
103
104 /* Special version of lll_mutex_lock which causes the unlock function to
105    always wakeup waiters.  */
106 #define lll_mutex_cond_lock(futex) \
107   (void) ({ int __result, val, *__futex = &(futex); \
108             __asm __volatile ("\
109                 .align 2\n\
110                 mova 1f,r0\n\
111                 mov r15,r1\n\
112                 mov #-8,r15\n\
113              0: mov.l @%2,%0\n\
114                 tst %0,%0\n\
115                 bf 1f\n\
116                 mov.l %1,@%2\n\
117              1: mov r1,r15"\
118                 : "=&r" (__result) : "r" (2), "r" (__futex) \
119                 : "r0", "r1", "t", "memory"); \
120             if (__result) \
121               __lll_mutex_lock_wait (__result, __futex); })
122
123 #define lll_mutex_timedlock(futex, timeout) \
124   ({ int __result, val, *__futex = &(futex); \
125      __asm __volatile ("\
126         .align 2\n\
127         mova 1f,r0\n\
128         mov r15,r1\n\
129         mov #-8,r15\n\
130      0: mov.l @%2,%0\n\
131         tst %0,%0\n\
132         bf 1f\n\
133         mov.l %1,@%2\n\
134      1: mov r1,r15"\
135         : "=&r" (__result) : "r" (1), "r" (__futex) \
136         : "r0", "r1", "t", "memory"); \
137     if (__result) \
138       __result = __lll_mutex_timedlock_wait (__result, __futex, timeout); \
139     __result; })
140
141 #define lll_mutex_unlock(futex) \
142   (void) ({ int __result, *__futex = &(futex); \
143             __asm __volatile ("\
144                 .align 2\n\
145                 mova 1f,r0\n\
146                 mov r15,r1\n\
147                 mov #-6,r15\n\
148              0: mov.l @%1,%0\n\
149                 add #-1,%0\n\
150                 mov.l %0,@%1\n\
151              1: mov r1,r15"\
152                 : "=&r" (__result) : "r" (__futex) \
153                 : "r0", "r1", "memory"); \
154             if (__result) \
155               __lll_mutex_unlock_wake (__futex); })
156
157 #define lll_mutex_islocked(futex) \
158   (futex != 0)
159
160
161 /* We have a separate internal lock implementation which is not tied
162    to binary compatibility.  */
163
164 /* Type for lock object.  */
165 typedef int lll_lock_t;
166
167 /* Initializers for lock.  */
168 #define LLL_LOCK_INITIALIZER            (0)
169 #define LLL_LOCK_INITIALIZER_LOCKED     (1)
170
171
172 # ifdef NEED_SYSCALL_INST_PAD
173 #  define SYSCALL_WITH_INST_PAD "\
174         trapa #0x14; or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0"
175 # else
176 #  define SYSCALL_WITH_INST_PAD "\
177         trapa #0x14"
178 # endif
179
180 #define lll_futex_wait(futex, val) \
181   do {                                                                        \
182     int __ignore;                                                             \
183     register unsigned long __r3 asm ("r3") = SYS_futex;                       \
184     register unsigned long __r4 asm ("r4") = (unsigned long) (futex);         \
185     register unsigned long __r5 asm ("r5") = FUTEX_WAIT;                      \
186     register unsigned long __r6 asm ("r6") = (unsigned long) (val);           \
187     register unsigned long __r7 asm ("r7") = 0;                               \
188     __asm __volatile (SYSCALL_WITH_INST_PAD                                   \
189                       : "=z" (__ignore)                                       \
190                       : "r" (__r3), "r" (__r4), "r" (__r5),                   \
191                         "r" (__r6), "r" (__r7)                                \
192                       : "memory", "t");                                       \
193   } while (0)
194
195
196 #define lll_futex_wake(futex, nr) \
197   do {                                                                        \
198     int __ignore;                                                             \
199     register unsigned long __r3 asm ("r3") = SYS_futex;                       \
200     register unsigned long __r4 asm ("r4") = (unsigned long) (futex);         \
201     register unsigned long __r5 asm ("r5") = FUTEX_WAKE;                      \
202     register unsigned long __r6 asm ("r6") = (unsigned long) (nr);            \
203     register unsigned long __r7 asm ("r7") = 0;                               \
204     __asm __volatile (SYSCALL_WITH_INST_PAD                                   \
205                       : "=z" (__ignore)                                       \
206                       : "r" (__r3), "r" (__r4), "r" (__r5),                   \
207                         "r" (__r6), "r" (__r7)                                \
208                       : "memory", "t");                                       \
209   } while (0)
210
211
212 extern int lll_unlock_wake_cb (int *__futex) attribute_hidden;
213
214
215 /* The states of a lock are:
216     0  -  untaken
217     1  -  taken by one user
218     2  -  taken by more users */
219
220 #define lll_trylock(futex) lll_mutex_trylock (futex)
221 #define lll_lock(futex) lll_mutex_lock (futex)
222 #define lll_unlock(futex) lll_mutex_unlock (futex)
223
224 #define lll_islocked(futex) \
225   (futex != LLL_LOCK_INITIALIZER)
226
227
228 /* The kernel notifies a process with uses CLONE_CLEARTID via futex
229    wakeup when the clone terminates.  The memory location contains the
230    thread ID while the clone is running and is reset to zero
231    afterwards.  */
232
233 extern int __lll_wait_tid (int *tid) attribute_hidden;
234 #define lll_wait_tid(tid) \
235   do {                                                                        \
236     __typeof (tid) *__tid = &(tid);                                           \
237     while (*__tid != 0)                                                       \
238       lll_futex_wait (__tid, *__tid);                                         \
239   } while (0)
240
241 extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
242      attribute_hidden;
243 #define lll_timedwait_tid(tid, abstime) \
244   ({                                                                          \
245     int __result = 0;                                                         \
246     if (tid != 0)                                                             \
247       {                                                                       \
248         if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)           \
249           __result = EINVAL;                                                  \
250         else                                                                  \
251           __result = __lll_timedwait_tid (&tid, abstime);                     \
252       }                                                                       \
253     __result; })
254
255
256 /* Conditional variable handling.  */
257
258 extern void __lll_cond_wait (pthread_cond_t *cond) attribute_hidden;
259 extern int __lll_cond_timedwait (pthread_cond_t *cond,
260                                  const struct timespec *abstime)
261      attribute_hidden;
262 extern void __lll_cond_wake (pthread_cond_t *cond) attribute_hidden;
263 extern void __lll_cond_broadcast (pthread_cond_t *cond) attribute_hidden;
264
265
266 #define lll_cond_wait(cond) \
267   __lll_cond_wait (cond)
268 #define lll_cond_timedwait(cond, abstime) \
269   __lll_cond_timedwait (cond, abstime)
270 #define lll_cond_wake(cond) \
271   __lll_cond_wake (cond)
272 #define lll_cond_broadcast(cond) \
273   __lll_cond_broadcast (cond)
274
275 #endif  /* lowlevellock.h */