Update.
[platform/upstream/glibc.git] / nptl / sysdeps / unix / sysv / linux / powerpc / lowlevellock.h
1 /* Copyright (C) 2003, 2004 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 Libr    \ary; 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
28
29 #define __NR_futex              221
30 #define FUTEX_WAIT              0
31 #define FUTEX_WAKE              1
32 #define FUTEX_REQUEUE           3
33 #define FUTEX_CMP_REQUEUE       4
34
35 /* Initializer for compatibility lock.  */
36 #define LLL_MUTEX_LOCK_INITIALIZER (0)
37
38 #define lll_futex_wait(futexp, val) \
39   ({                                                                          \
40     INTERNAL_SYSCALL_DECL (__err);                                            \
41     long int __ret;                                                           \
42                                                                               \
43     __ret = INTERNAL_SYSCALL (futex, __err, 4,                                \
44                               (futexp), FUTEX_WAIT, (val), 0);                \
45     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;                 \
46   })
47
48 #define lll_futex_timed_wait(futexp, val, timespec) \
49   ({                                                                          \
50     INTERNAL_SYSCALL_DECL (__err);                                            \
51     long int __ret;                                                           \
52                                                                               \
53     __ret = INTERNAL_SYSCALL (futex, __err, 4,                                \
54                               (futexp), FUTEX_WAIT, (val), (timespec));       \
55     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;                 \
56   })
57
58 #define lll_futex_wake(futexp, nr) \
59   ({                                                                          \
60     INTERNAL_SYSCALL_DECL (__err);                                            \
61     long int __ret;                                                           \
62                                                                               \
63     __ret = INTERNAL_SYSCALL (futex, __err, 4,                                \
64                               (futexp), FUTEX_WAKE, (nr), 0);                 \
65     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;                 \
66   })
67
68 /* Returns non-zero if error happened, zero if success.  */
69 #define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \
70   ({                                                                          \
71     INTERNAL_SYSCALL_DECL (__err);                                            \
72     long int __ret;                                                           \
73                                                                               \
74     __ret = INTERNAL_SYSCALL (futex, __err, 6,                                \
75                               (futexp), FUTEX_CMP_REQUEUE, (nr_wake),         \
76                               (nr_move), (mutex), (val));                     \
77     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                  \
78   })
79
80 #ifdef UP
81 # define __lll_acq_instr        ""
82 # define __lll_rel_instr        ""
83 #else
84 # define __lll_acq_instr        "isync"
85 # define __lll_rel_instr        "sync"
86 #endif
87
88 /* Set *futex to 1 if it is 0, atomically.  Returns the old value */
89 #define __lll_trylock(futex) \
90   ({ int __val;                                                               \
91      __asm __volatile ("1:      lwarx   %0,0,%2\n"                            \
92                        "        cmpwi   0,%0,0\n"                             \
93                        "        bne     2f\n"                                 \
94                        "        stwcx.  %3,0,%2\n"                            \
95                        "        bne-    1b\n"                                 \
96                        "2:      " __lll_acq_instr                             \
97                        : "=&r" (__val), "=m" (*futex)                         \
98                        : "r" (futex), "r" (1), "m" (*futex)                   \
99                        : "cr0", "memory");                                    \
100      __val;                                                                   \
101   })
102
103 #define lll_mutex_trylock(lock) __lll_trylock (&(lock))
104
105 /* Set *futex to 2 if it is 0, atomically.  Returns the old value */
106 #define __lll_cond_trylock(futex) \
107   ({ int __val;                                                               \
108      __asm __volatile ("1:      lwarx   %0,0,%2\n"                            \
109                        "        cmpwi   0,%0,0\n"                             \
110                        "        bne     2f\n"                                 \
111                        "        stwcx.  %3,0,%2\n"                            \
112                        "        bne-    1b\n"                                 \
113                        "2:      " __lll_acq_instr                             \
114                        : "=&r" (__val), "=m" (*futex)                         \
115                        : "r" (futex), "r" (2), "m" (*futex)                   \
116                        : "cr0", "memory");                                    \
117      __val;                                                                   \
118   })
119 #define lll_mutex_cond_trylock(lock)    __lll_cond_trylock (&(lock))
120
121
122 extern void __lll_lock_wait (int *futex) attribute_hidden;
123
124 #define lll_mutex_lock(lock) \
125   (void) ({                                                                   \
126     int *__futex = &(lock);                                                   \
127     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\
128                           0) != 0)                                            \
129       __lll_lock_wait (__futex);                                              \
130   })
131
132 #define lll_mutex_cond_lock(lock) \
133   (void) ({                                                                   \
134     int *__futex = &(lock);                                                   \
135     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 2, 0),\
136                           0) != 0)                                            \
137       __lll_lock_wait (__futex);                                              \
138   })
139
140 extern int __lll_timedlock_wait
141   (int *futex, const struct timespec *) attribute_hidden;
142
143 #define lll_mutex_timedlock(lock, abstime) \
144   ({                                                                          \
145     int *__futex = &(lock);                                                   \
146     int __val = 0;                                                            \
147     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\
148                           0) != 0)                                            \
149       __val = __lll_timedlock_wait (__futex, abstime);                        \
150     __val;                                                                    \
151   })
152
153 #define lll_mutex_unlock(lock) \
154   ((void) ({                                                                  \
155     int *__futex = &(lock);                                                   \
156     int __val = atomic_exchange_rel (__futex, 0);                             \
157     if (__builtin_expect (__val > 1, 0))                                      \
158       lll_futex_wake (__futex, 1);                                            \
159   }))
160
161 #define lll_mutex_unlock_force(lock) \
162   ((void) ({                                                                  \
163     int *__futex = &(lock);                                                   \
164     *__futex = 0;                                                             \
165     __asm __volatile (__lll_rel_instr ::: "memory");                          \
166     lll_futex_wake (__futex, 1);                                              \
167   }))
168
169 #define lll_mutex_islocked(futex) \
170   (futex != 0)
171
172
173 /* Our internal lock implementation is identical to the binary-compatible
174    mutex implementation. */
175
176 /* Type for lock object.  */
177 typedef int lll_lock_t;
178
179 /* Initializers for lock.  */
180 #define LLL_LOCK_INITIALIZER            (0)
181 #define LLL_LOCK_INITIALIZER_LOCKED     (1)
182
183 extern int lll_unlock_wake_cb (int *__futex) attribute_hidden;
184
185 /* The states of a lock are:
186     0  -  untaken
187     1  -  taken by one user
188    >1  -  taken by more users */
189
190 #define lll_trylock(lock)       lll_mutex_trylock (lock)
191 #define lll_lock(lock)          lll_mutex_lock (lock)
192 #define lll_unlock(lock)        lll_mutex_unlock (lock)
193 #define lll_islocked(lock)      lll_mutex_islocked (lock)
194
195 /* The kernel notifies a process which uses CLONE_CLEARTID via futex
196    wakeup when the clone terminates.  The memory location contains the
197    thread ID while the clone is running and is reset to zero
198    afterwards.  */
199 #define lll_wait_tid(tid) \
200   do {                                                                        \
201     __typeof (tid) __tid;                                                     \
202     while ((__tid = (tid)) != 0)                                              \
203       lll_futex_wait (&(tid), __tid);                                         \
204   } while (0)
205
206 extern int __lll_timedwait_tid (int *, const struct timespec *)
207      attribute_hidden;
208
209 #define lll_timedwait_tid(tid, abstime) \
210   ({                                                                          \
211     int __res = 0;                                                            \
212     if ((tid) != 0)                                                           \
213       __res = __lll_timedwait_tid (&(tid), (abstime));                        \
214     __res;                                                                    \
215   })
216
217
218 /* Conditional variable handling.  */
219
220 extern void __lll_cond_wait (pthread_cond_t *cond)
221      attribute_hidden;
222 extern int __lll_cond_timedwait (pthread_cond_t *cond,
223                                  const struct timespec *abstime)
224      attribute_hidden;
225 extern void __lll_cond_wake (pthread_cond_t *cond)
226      attribute_hidden;
227 extern void __lll_cond_broadcast (pthread_cond_t *cond)
228      attribute_hidden;
229
230 #define lll_cond_wait(cond) \
231   __lll_cond_wait (cond)
232 #define lll_cond_timedwait(cond, abstime) \
233   __lll_cond_timedwait (cond, abstime)
234 #define lll_cond_wake(cond) \
235   __lll_cond_wake (cond)
236 #define lll_cond_broadcast(cond) \
237   __lll_cond_broadcast (cond)
238
239 #endif  /* lowlevellock.h */