2 * SMP- and interrupt-safe semaphores..
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
8 * (C) Copyright 1996 Linus Torvalds
9 * (C) Copyright 1998, 99, 2000, 01 Ralf Baechle
10 * (C) Copyright 1999, 2000 Silicon Graphics, Inc.
11 * Copyright (C) 2000, 01 MIPS Technologies, Inc. All rights reserved.
13 #ifndef _ASM_SEMAPHORE_H
14 #define _ASM_SEMAPHORE_H
16 #include <asm/system.h>
17 #include <asm/atomic.h>
18 #include <linux/spinlock.h>
19 #include <linux/wait.h>
20 #include <linux/config.h>
21 #include <linux/rwsem.h>
31 wait_queue_head_t wait;
35 } __attribute__((aligned(8)));
38 # define __SEM_DEBUG_INIT(name) \
39 , (long)&(name).__magic
41 # define __SEM_DEBUG_INIT(name)
45 #define __SEMAPHORE_INITIALIZER(name,count) \
46 { ATOMIC_INIT(count), ATOMIC_INIT(0), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
47 __SEM_DEBUG_INIT(name) }
49 #define __SEMAPHORE_INITIALIZER(name,count) \
50 { ATOMIC_INIT(0), ATOMIC_INIT(count), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
51 __SEM_DEBUG_INIT(name) }
54 #define __MUTEX_INITIALIZER(name) \
55 __SEMAPHORE_INITIALIZER(name,1)
57 #define __DECLARE_SEMAPHORE_GENERIC(name,count) \
58 struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
60 #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
61 #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
63 static inline void sema_init (struct semaphore *sem, int val)
65 atomic_set(&sem->count, val);
66 atomic_set(&sem->waking, 0);
67 init_waitqueue_head(&sem->wait);
69 sem->__magic = (long)&sem->__magic;
73 static inline void init_MUTEX (struct semaphore *sem)
78 static inline void init_MUTEX_LOCKED (struct semaphore *sem)
83 asmlinkage void __down(struct semaphore * sem);
84 asmlinkage int __down_interruptible(struct semaphore * sem);
85 asmlinkage int __down_trylock(struct semaphore * sem);
86 asmlinkage void __up(struct semaphore * sem);
88 static inline void down(struct semaphore * sem)
91 CHECK_MAGIC(sem->__magic);
93 if (atomic_dec_return(&sem->count) < 0)
98 * Interruptible try to acquire a semaphore. If we obtained
99 * it, return zero. If we were interrupted, returns -EINTR
101 static inline int down_interruptible(struct semaphore * sem)
106 CHECK_MAGIC(sem->__magic);
108 if (atomic_dec_return(&sem->count) < 0)
109 ret = __down_interruptible(sem);
113 #ifndef CONFIG_CPU_HAS_LLDSCD
116 * Non-blockingly attempt to down() a semaphore.
117 * Returns zero if we acquired it
119 static inline int down_trylock(struct semaphore * sem)
122 if (atomic_dec_return(&sem->count) < 0)
123 ret = __down_trylock(sem);
130 * down_trylock returns 0 on success, 1 if we failed to get the lock.
132 * We must manipulate count and waking simultaneously and atomically.
133 * Here, we do this by using lld/scd on the pair of 32-bit words. This
134 * won't work on MIPS32 platforms, however, and must be rewritten.
138 * Decrement(sem->count)
139 * If(sem->count >=0) {
140 * Return(SUCCESS) // resource is free
142 * If(sem->waking <= 0) { // if no wakeup pending
143 * Increment(sem->count) // undo decrement
146 * Decrement(sem->waking) // otherwise "steal" wakeup
151 static inline int down_trylock(struct semaphore * sem)
153 long ret, tmp, tmp2, sub;
156 CHECK_MAGIC(sem->__magic);
159 __asm__ __volatile__(
160 ".set\tmips3\t\t\t# down_trylock\n"
161 "0:\tlld\t%1, %4\n\t"
162 "dli\t%3, 0x0000000100000000\n\t"
168 "daddiu\t%1, %1, -1\n\t"
170 "1:\tdaddu\t%1, %1, %3\n"
172 "2:\tscd\t%1, %4\n\t"
175 : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
182 #endif /* CONFIG_CPU_HAS_LLDSCD */
185 * Note! This is subtle. We jump to wake people up only if
186 * the semaphore was negative (== somebody was waiting on it).
188 static inline void up(struct semaphore * sem)
191 CHECK_MAGIC(sem->__magic);
193 if (atomic_inc_return(&sem->count) <= 0)
197 static inline int sem_getcount(struct semaphore *sem)
199 return atomic_read(&sem->count);
202 #endif /* _ASM_SEMAPHORE_H */