source: svn/trunk/newcon3bcm2_21bu/toolchain/mips-linux-uclibc/include/asm/semaphore.h

Last change on this file was 2, checked in by phkim, 11 years ago

1.phkim

  1. revision copy newcon3sk r27
  • Property svn:executable set to *
File size: 6.5 KB
Line 
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1996  Linus Torvalds
7 * Copyright (C) 1998, 99, 2000, 01  Ralf Baechle
8 * Copyright (C) 1999, 2000, 01  Silicon Graphics, Inc.
9 * Copyright (C) 2000, 01 MIPS Technologies, Inc.
10 */
11#ifndef _ASM_SEMAPHORE_H
12#define _ASM_SEMAPHORE_H
13
14#include <asm/atomic.h>
15#include <linux/wait.h>
16
17struct semaphore {
18#ifdef __MIPSEB__
19        atomic_t count;
20        atomic_t waking;
21#else
22        atomic_t waking;
23        atomic_t count;
24#endif
25        wait_queue_head_t wait;
26#if WAITQUEUE_DEBUG
27        long __magic;
28#endif
29} __attribute__((aligned(8)));
30
31#if WAITQUEUE_DEBUG
32# define __SEM_DEBUG_INIT(name) , .__magic = (long)&(name).__magic
33#else
34# define __SEM_DEBUG_INIT(name)
35#endif
36
37#define __SEMAPHORE_INITIALIZER(name,_count) {                          \
38        .count  = ATOMIC_INIT(_count),                                  \
39        .waking = ATOMIC_INIT(0),                                       \
40        .wait   = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)            \
41        __SEM_DEBUG_INIT(name)                                          \
42}
43
44#define __MUTEX_INITIALIZER(name) __SEMAPHORE_INITIALIZER(name, 1)
45
46#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
47        struct semaphore name = __SEMAPHORE_INITIALIZER(name, count)
48
49#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1)
50#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
51
52static inline void sema_init (struct semaphore *sem, int val)
53{
54        atomic_set(&sem->count, val);
55        atomic_set(&sem->waking, 0);
56        init_waitqueue_head(&sem->wait);
57#if WAITQUEUE_DEBUG
58        sem->__magic = (long)&sem->__magic;
59#endif
60}
61
62static inline void init_MUTEX (struct semaphore *sem)
63{
64        sema_init(sem, 1);
65}
66
67static inline void init_MUTEX_LOCKED (struct semaphore *sem)
68{
69        sema_init(sem, 0);
70}
71
72#ifndef CONFIG_CPU_HAS_LLDSCD
73/*
74 * On machines without lld/scd we need a spinlock to make the manipulation of
75 * sem->count and sem->waking atomic.
76 */
77extern spinlock_t semaphore_lock;
78#endif
79
80extern void __down_failed(struct semaphore * sem);
81extern int  __down_failed_interruptible(struct semaphore * sem);
82extern void __up_wakeup(struct semaphore * sem);
83
84static inline void down(struct semaphore * sem)
85{
86        int count;
87
88#if WAITQUEUE_DEBUG
89        CHECK_MAGIC(sem->__magic);
90#endif
91        might_sleep();
92        count = atomic_dec_return(&sem->count);
93        if (unlikely(count < 0))
94                __down_failed(sem);
95}
96
97/*
98 * Interruptible try to acquire a semaphore.  If we obtained
99 * it, return zero.  If we were interrupted, returns -EINTR
100 */
101static inline int down_interruptible(struct semaphore * sem)
102{
103        int count;
104
105#if WAITQUEUE_DEBUG
106        CHECK_MAGIC(sem->__magic);
107#endif
108        might_sleep();
109        count = atomic_dec_return(&sem->count);
110        if (unlikely(count < 0))
111                return __down_failed_interruptible(sem);
112
113        return 0;
114}
115
116#ifdef CONFIG_CPU_HAS_LLDSCD
117
118/*
119 * down_trylock returns 0 on success, 1 if we failed to get the lock.
120 *
121 * We must manipulate count and waking simultaneously and atomically.
122 * Here, we do this by using lld/scd on the pair of 32-bit words.
123 *
124 * Pseudocode:
125 *
126 *   Decrement(sem->count)
127 *   If(sem->count >=0) {
128 *      Return(SUCCESS)                 // resource is free
129 *   } else {
130 *      If(sem->waking <= 0) {          // if no wakeup pending
131 *         Increment(sem->count)        // undo decrement
132 *         Return(FAILURE)
133 *      } else {
134 *         Decrement(sem->waking)       // otherwise "steal" wakeup
135 *         Return(SUCCESS)
136 *      }
137 *   }
138 */
139static inline int down_trylock(struct semaphore * sem)
140{
141        long ret, tmp, tmp2, sub;
142
143#if WAITQUEUE_DEBUG
144        CHECK_MAGIC(sem->__magic);
145#endif
146
147        __asm__ __volatile__(
148        "       .set    mips3                   # down_trylock          \n"
149        "0:     lld     %1, %4                                          \n"
150        "       dli     %3, 0x0000000100000000  # count -= 1            \n"
151        "       dsubu   %1, %3                                          \n"
152        "       li      %0, 0                   # ret = 0               \n"
153        "       bgez    %1, 2f                  # if count >= 0         \n"
154        "       sll     %2, %1, 0               # extract waking        \n"
155        "       blez    %2, 1f                  # if waking < 0 -> 1f   \n"
156        "       daddiu  %1, %1, -1              # waking -= 1           \n"
157        "       b       2f                                              \n"
158        "1:     daddu   %1, %1, %3              # count += 1            \n"
159        "       li      %0, 1                   # ret = 1               \n"
160        "2:     scd     %1, %4                                          \n"
161        "       beqz    %1, 0b                                          \n"
162        "       sync                                                    \n"
163        "       .set    mips0                                           \n"
164        : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
165        : "m"(*sem)
166        : "memory");
167
168        return ret;
169}
170
171/*
172 * Note! This is subtle. We jump to wake people up only if
173 * the semaphore was negative (== somebody was waiting on it).
174 */
175static inline void up(struct semaphore * sem)
176{
177        unsigned long tmp, tmp2;
178        int count;
179
180#if WAITQUEUE_DEBUG
181        CHECK_MAGIC(sem->__magic);
182#endif
183        /*
184         * We must manipulate count and waking simultaneously and atomically.
185         * Otherwise we have races between up and __down_failed_interruptible
186         * waking up on a signal.
187         */
188
189        __asm__ __volatile__(
190        "       .set    mips3                                   \n"
191        "       sync                    # up                    \n"
192        "1:     lld     %1, %3                                  \n"
193        "       dsra32  %0, %1, 0       # extract count to %0   \n"
194        "       daddiu  %0, 1           # count += 1            \n"
195        "       slti    %2, %0, 1       # %3 = (%0 <= 0)        \n"
196        "       daddu   %1, %2          # waking += %3          \n"
197        "       dsll32 %1, %1, 0        # zero-extend %1        \n"
198        "       dsrl32 %1, %1, 0                                \n"
199        "       dsll32  %2, %0, 0       # Reassemble union      \n"
200        "       or      %1, %2          # from count and waking \n"
201        "       scd     %1, %3                                  \n"
202        "       beqz    %1, 1b                                  \n"
203        "       .set    mips0                                   \n"
204        : "=&r"(count), "=&r"(tmp), "=&r"(tmp2), "+m"(*sem)
205        :
206        : "memory");
207
208        if (unlikely(count <= 0))
209                __up_wakeup(sem);
210}
211
212#else
213
214/*
215 * Non-blockingly attempt to down() a semaphore.
216 * Returns zero if we acquired it
217 */
218static inline int down_trylock(struct semaphore * sem)
219{
220        unsigned long flags;
221        int count, waking;
222        int ret = 0;
223
224#if WAITQUEUE_DEBUG
225        CHECK_MAGIC(sem->__magic);
226#endif
227
228        spin_lock_irqsave(&semaphore_lock, flags);
229        count = atomic_read(&sem->count) - 1;
230        atomic_set(&sem->count, count);
231        if (unlikely(count < 0)) {
232                waking = atomic_read(&sem->waking);
233                if (waking <= 0) {
234                        atomic_set(&sem->count, count + 1);
235                        ret = 1;
236                } else {
237                        atomic_set(&sem->waking, waking - 1);
238                        ret = 0;
239                }
240        }
241        spin_unlock_irqrestore(&semaphore_lock, flags);
242
243        return ret;
244}
245
246/*
247 * Note! This is subtle. We jump to wake people up only if
248 * the semaphore was negative (== somebody was waiting on it).
249 */
250static inline void up(struct semaphore * sem)
251{
252        unsigned long flags;
253        int count, waking;
254
255#if WAITQUEUE_DEBUG
256        CHECK_MAGIC(sem->__magic);
257#endif
258        /*
259         * We must manipulate count and waking simultaneously and atomically.
260         * Otherwise we have races between up and __down_failed_interruptible
261         * waking up on a signal.
262         */
263
264        spin_lock_irqsave(&semaphore_lock, flags);
265        count = atomic_read(&sem->count) + 1;
266        waking = atomic_read(&sem->waking);
267        if (count <= 0)
268                waking++;
269        atomic_set(&sem->count, count);
270        atomic_set(&sem->waking, waking);
271        spin_unlock_irqrestore(&semaphore_lock, flags);
272
273        if (unlikely(count <= 0))
274                __up_wakeup(sem);
275}
276
277#endif /* CONFIG_CPU_HAS_LLDSCD */
278
279#endif /* _ASM_SEMAPHORE_H */
Note: See TracBrowser for help on using the repository browser.