1 #ifndef _ASM_IA64_SEMAPHORE_H
2 #define _ASM_IA64_SEMAPHORE_H
3
4 /*
5 * Copyright (C) 1998-2000 Hewlett-Packard Co
6 * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
7 */
8
9 #include <linux/wait.h>
10
11 #include <asm/atomic.h>
12
13 struct semaphore {
14 atomic_t count;
15 int sleepers;
16 wait_queue_head_t wait;
17 #if WAITQUEUE_DEBUG
18 long __magic; /* initialized by __SEM_DEBUG_INIT() */
19 #endif
20 };
21
22 #if WAITQUEUE_DEBUG
23 # define __SEM_DEBUG_INIT(name) , (long) &(name).__magic
24 #else
25 # define __SEM_DEBUG_INIT(name)
26 #endif
27
28 #define __SEMAPHORE_INITIALIZER(name,count) \
29 { \
30 ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
31 __SEM_DEBUG_INIT(name) \
32 }
33
34 #define __MUTEX_INITIALIZER(name) __SEMAPHORE_INITIALIZER(name,1)
35
36 #define __DECLARE_SEMAPHORE_GENERIC(name,count) \
37 struct semaphore name = __SEMAPHORE_INITIALIZER(name, count)
38
39 #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1)
40 #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name, 0)
41
42 static inline void
43 sema_init (struct semaphore *sem, int val)
44 {
45 *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
46 }
47
48 static inline void
49 init_MUTEX (struct semaphore *sem)
50 {
51 sema_init(sem, 1);
52 }
53
54 static inline void
55 init_MUTEX_LOCKED (struct semaphore *sem)
56 {
57 sema_init(sem, 0);
58 }
59
60 extern void __down (struct semaphore * sem);
61 extern int __down_interruptible (struct semaphore * sem);
62 extern int __down_trylock (struct semaphore * sem);
63 extern void __up (struct semaphore * sem);
64
65 extern spinlock_t semaphore_wake_lock;
66
67 /*
68 * Atomically decrement the semaphore's count. If it goes negative,
69 * block the calling thread in the TASK_UNINTERRUPTIBLE state.
70 */
71 static inline void
72 down (struct semaphore *sem)
73 {
74 #if WAITQUEUE_DEBUG
75 CHECK_MAGIC(sem->__magic);
76 #endif
77 if (atomic_dec_return(&sem->count) < 0)
78 __down(sem);
79 }
80
81 /*
82 * Atomically decrement the semaphore's count. If it goes negative,
83 * block the calling thread in the TASK_INTERRUPTIBLE state.
84 */
85 static inline int
86 down_interruptible (struct semaphore * sem)
87 {
88 int ret = 0;
89
90 #if WAITQUEUE_DEBUG
91 CHECK_MAGIC(sem->__magic);
92 #endif
93 if (atomic_dec_return(&sem->count) < 0)
94 ret = __down_interruptible(sem);
95 return ret;
96 }
97
98 static inline int
99 down_trylock (struct semaphore *sem)
100 {
101 int ret = 0;
102
103 #if WAITQUEUE_DEBUG
104 CHECK_MAGIC(sem->__magic);
105 #endif
106 if (atomic_dec_return(&sem->count) < 0)
107 ret = __down_trylock(sem);
108 return ret;
109 }
110
111 static inline void
112 up (struct semaphore * sem)
113 {
114 #if WAITQUEUE_DEBUG
115 CHECK_MAGIC(sem->__magic);
116 #endif
117 if (atomic_inc_return(&sem->count) <= 0)
118 __up(sem);
119 }
120
121 /*
122 * rw mutexes (should that be mutices? =) -- throw rw spinlocks and
123 * semaphores together, and this is what we end up with...
124 *
125 * The lock is initialized to BIAS. This way, a writer subtracts BIAS
126 * ands gets 0 for the case of an uncontended lock. Readers decrement
127 * by 1 and see a positive value when uncontended, negative if there
128 * are writers waiting (in which case it goes to sleep). BIAS must be
129 * chosen such that subtracting BIAS once per CPU will result either
130 * in zero (uncontended case) or in a negative value (contention
131 * case). On the other hand, BIAS must be at least as big as the
132 * number of processes in the system.
133 *
134 * On IA-64, we use a BIAS value of 0x100000000, which supports up to
135 * 2 billion (2^31) processors and 4 billion processes.
136 *
137 * In terms of fairness, when there is heavy use of the lock, we want
138 * to see the lock being passed back and forth between readers and
139 * writers (like in a producer/consumer style of communication).
140 *
141 * -ben (with clarifications & IA-64 comments by davidm)
142 */
143 #define RW_LOCK_BIAS 0x100000000ul
144
145 struct rw_semaphore {
146 volatile long count;
147 volatile __u8 write_bias_granted;
148 volatile __u8 read_bias_granted;
149 __u16 pad1;
150 __u32 pad2;
151 wait_queue_head_t wait;
152 wait_queue_head_t write_bias_wait;
153 #if WAITQUEUE_DEBUG
154 long __magic;
155 atomic_t readers;
156 atomic_t writers;
157 #endif
158 };
159
160 #if WAITQUEUE_DEBUG
161 # define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
162 #else
163 # define __RWSEM_DEBUG_INIT
164 #endif
165
166 #define __RWSEM_INITIALIZER(name,count) \
167 { \
168 (count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
169 __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
170 __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT \
171 }
172
173 #define __DECLARE_RWSEM_GENERIC(name,count) \
174 struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
175
176 #define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS)
177 #define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS - 1)
178 #define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0)
179
180 extern void __down_read_failed (struct rw_semaphore *sem, long count);
181 extern void __down_write_failed (struct rw_semaphore *sem, long count);
182 extern void __rwsem_wake (struct rw_semaphore *sem, long count);
183
184 static inline void
185 init_rwsem (struct rw_semaphore *sem)
186 {
187 sem->count = RW_LOCK_BIAS;
188 sem->read_bias_granted = 0;
189 sem->write_bias_granted = 0;
190 init_waitqueue_head(&sem->wait);
191 init_waitqueue_head(&sem->write_bias_wait);
192 #if WAITQUEUE_DEBUG
193 sem->__magic = (long)&sem->__magic;
194 atomic_set(&sem->readers, 0);
195 atomic_set(&sem->writers, 0);
196 #endif
197 }
198
199 static inline void
200 down_read (struct rw_semaphore *sem)
201 {
202 long count;
203
204 #if WAITQUEUE_DEBUG
205 CHECK_MAGIC(sem->__magic);
206 #endif
207
208 count = ia64_fetch_and_add(-1, &sem->count);
209 if (count < 0)
210 __down_read_failed(sem, count);
211
212 #if WAITQUEUE_DEBUG
213 if (sem->write_bias_granted)
214 BUG();
215 if (atomic_read(&sem->writers))
216 BUG();
217 atomic_inc(&sem->readers);
218 #endif
219 }
220
221 static inline void
222 down_write (struct rw_semaphore *sem)
223 {
224 long old_count, new_count;
225
226 #if WAITQUEUE_DEBUG
227 CHECK_MAGIC(sem->__magic);
228 #endif
229
230 do {
231 old_count = sem->count;
232 new_count = old_count - RW_LOCK_BIAS;
233 } while (cmpxchg_acq(&sem->count, old_count, new_count) != old_count);
234
235 if (new_count != 0)
236 __down_write_failed(sem, new_count);
237 #if WAITQUEUE_DEBUG
238 if (atomic_read(&sem->writers))
239 BUG();
240 if (atomic_read(&sem->readers))
241 BUG();
242 if (sem->read_bias_granted)
243 BUG();
244 if (sem->write_bias_granted)
245 BUG();
246 atomic_inc(&sem->writers);
247 #endif
248 }
249
250 /*
251 * When a reader does a release, the only significant
252 * case is when there was a writer waiting, and we've
253 * bumped the count to 0: we must wake the writer up.
254 */
255 static inline void
256 __up_read (struct rw_semaphore *sem)
257 {
258 long count;
259
260 count = ia64_fetch_and_add(1, &sem->count);
261 if (count == 0)
262 /*
263 * Other processes are blocked already; resolve
264 * contention by letting either a writer or a reader
265 * proceed...
266 */
267 __rwsem_wake(sem, count);
268 }
269
270 /*
271 * Releasing the writer is easy -- just release it and
272 * wake up any sleepers.
273 */
274 static inline void
275 __up_write (struct rw_semaphore *sem)
276 {
277 long old_count, new_count;
278
279 do {
280 old_count = sem->count;
281 new_count = old_count + RW_LOCK_BIAS;
282 } while (cmpxchg_rel(&sem->count, old_count, new_count) != old_count);
283
284 /*
285 * Note: new_count <u RW_LOCK_BIAS <=> old_count < 0 && new_count >= 0.
286 * (where <u is "unsigned less-than").
287 */
288 if ((unsigned long) new_count < RW_LOCK_BIAS)
289 /* someone is blocked already, resolve contention... */
290 __rwsem_wake(sem, new_count);
291 }
292
293 static inline void
294 up_read (struct rw_semaphore *sem)
295 {
296 #if WAITQUEUE_DEBUG
297 if (sem->write_bias_granted)
298 BUG();
299 if (atomic_read(&sem->writers))
300 BUG();
301 atomic_dec(&sem->readers);
302 #endif
303 __up_read(sem);
304 }
305
306 static inline void
307 up_write (struct rw_semaphore *sem)
308 {
309 #if WAITQUEUE_DEBUG
310 if (sem->read_bias_granted)
311 BUG();
312 if (sem->write_bias_granted)
313 BUG();
314 if (atomic_read(&sem->readers))
315 BUG();
316 if (atomic_read(&sem->writers) != 1)
317 BUG();
318 atomic_dec(&sem->writers);
319 #endif
320 __up_write(sem);
321 }
322
323 #endif /* _ASM_IA64_SEMAPHORE_H */
324
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.