OSDN Git Service

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