Import 2.3.18pre1
[davej-history.git] / include / asm-mips / semaphore.h
blob859638f5ad5b46cb63c4008a924036f710766719
1 /* $Id: semaphore.h,v 1.6 1999/06/17 13:30:38 ralf Exp $
3 * SMP- and interrupt-safe semaphores..
5 * This file is subject to the terms and conditions of the GNU General Public
6 * License. See the file "COPYING" in the main directory of this archive
7 * for more details.
9 * (C) Copyright 1996 Linus Torvalds
10 * (C) Copyright 1998, 1999 Ralf Baechle
12 #ifndef __ASM_MIPS_SEMAPHORE_H
13 #define __ASM_MIPS_SEMAPHORE_H
15 #include <asm/system.h>
16 #include <asm/atomic.h>
17 #include <linux/spinlock.h>
18 #include <linux/wait.h>
20 struct semaphore {
21 atomic_t count;
22 atomic_t waking;
23 wait_queue_head_t wait;
24 #if WAITQUEUE_DEBUG
25 long __magic;
26 #endif
29 #if WAITQUEUE_DEBUG
30 # define __SEM_DEBUG_INIT(name) \
31 , (long)&(name).__magic
32 #else
33 # define __SEM_DEBUG_INIT(name)
34 #endif
36 #define __SEMAPHORE_INITIALIZER(name,count) \
37 { ATOMIC_INIT(count), ATOMIC_INIT(0), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
38 __SEM_DEBUG_INIT(name) }
40 #define __MUTEX_INITIALIZER(name) \
41 __SEMAPHORE_INITIALIZER(name,1)
43 #define __DECLARE_SEMAPHORE_GENERIC(name,count) \
44 struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
46 #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
47 #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
49 extern inline void sema_init (struct semaphore *sem, int val)
51 atomic_set(&sem->count, val);
52 atomic_set(&sem->waking, 0);
53 init_waitqueue_head(&sem->wait);
54 #if WAITQUEUE_DEBUG
55 sem->__magic = (long)&sem->__magic;
56 #endif
59 static inline void init_MUTEX (struct semaphore *sem)
61 sema_init(sem, 1);
64 static inline void init_MUTEX_LOCKED (struct semaphore *sem)
66 sema_init(sem, 0);
69 asmlinkage void __down(struct semaphore * sem);
70 asmlinkage int __down_interruptible(struct semaphore * sem);
71 asmlinkage int __down_trylock(struct semaphore * sem);
72 asmlinkage void __up(struct semaphore * sem);
74 extern inline void down(struct semaphore * sem)
76 #if WAITQUEUE_DEBUG
77 CHECK_MAGIC(sem->__magic);
78 #endif
79 if (atomic_dec_return(&sem->count) < 0)
80 __down(sem);
83 extern inline int down_interruptible(struct semaphore * sem)
85 int ret = 0;
87 #if WAITQUEUE_DEBUG
88 CHECK_MAGIC(sem->__magic);
89 #endif
90 if (atomic_dec_return(&sem->count) < 0)
91 ret = __down_interruptible(sem);
92 return ret;
96 * down_trylock returns 0 on success, 1 if we failed to get the lock.
98 * We must manipulate count and waking simultaneously and atomically.
99 * Do this by using ll/sc on the pair of 32-bit words.
101 extern inline int down_trylock(struct semaphore * sem)
103 long ret, tmp, tmp2, sub;
105 #if WAITQUEUE_DEBUG
106 CHECK_MAGIC(sem->__magic);
107 #endif
108 #ifdef __MIPSEB__
109 __asm__ __volatile__("
110 .set mips3
111 0: lld %1, %4
112 dli %3, 0x0000000100000000
113 sltu %0, %1, $0
115 bltz %1, 1f
116 move %3, $0
119 sltu %2, %1, $0
120 and %0, %0, %2
121 bnez %0, 2f
123 subu %0, %3
124 scd %1, %4
126 beqz %1, 0b
129 .set mips0"
130 : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
131 : "m"(*sem)
132 : "memory");
133 #endif
135 #ifdef __MIPSEL__
136 #error "FIXME: down_trylock doesn't support little endian machines yet."
137 #endif
139 return ret;
143 * Note! This is subtle. We jump to wake people up only if
144 * the semaphore was negative (== somebody was waiting on it).
146 extern inline void up(struct semaphore * sem)
148 #if WAITQUEUE_DEBUG
149 CHECK_MAGIC(sem->__magic);
150 #endif
151 if (atomic_inc_return(&sem->count) <= 0)
152 __up(sem);
155 #endif /* __ASM_MIPS_SEMAPHORE_H */