1 #ifndef _I386_SEMAPHORE_H
2 #define _I386_SEMAPHORE_H
3
4 #include <linux/linkage.h>
5
6 #ifdef __KERNEL__
7
8 /*
9 * SMP- and interrupt-safe semaphores..
10 *
11 * (C) Copyright 1996 Linus Torvalds
12 *
13 * Modified 1996-12-23 by Dave Grothe <dave@gcom.com> to fix bugs in
14 * the original code and to make semaphore waits
15 * interruptible so that processes waiting on
16 * semaphores can be killed.
17 * Modified 1999-02-14 by Andrea Arcangeli, split the sched.c helper
18 * functions in asm/sempahore-helper.h while fixing a
19 * potential and subtle race discovered by Ulrich Schmid
20 * in down_interruptible(). Since I started to play here I
21 * also implemented the `trylock' semaphore operation.
22 * 1999-07-02 Artur Skawina <skawina@geocities.com>
23 * Optimized "0(ecx)" -> "(ecx)" (the assembler does not
24 * do this). Changed calling sequences from push/jmp to
25 * traditional call/ret.
26 * Modified 2001-01-01 Andreas Franck <afranck@gmx.de>
27 * Some hacks to ensure compatibility with recent
28 * GCC snapshots, to avoid stack corruption when compiling
29 * with -fomit-frame-pointer. It's not sure if this will
30 * be fixed in GCC, as our previous implementation was a
31 * bit dubious.
32 *
33 * If you would like to see an analysis of this implementation, please
34 * ftp to gcom.com and download the file
35 * /pub/linux/src/semaphore/semaphore-2.0.24.tar.gz.
36 *
37 */
38
39 #include <asm/system.h>
40 #include <asm/atomic.h>
41 #include <asm/rwlock.h>
42 #include <linux/wait.h>
43
44 struct semaphore {
45 atomic_t count;
46 int sleepers;
47 wait_queue_head_t wait;
48 #if WAITQUEUE_DEBUG
49 long __magic;
50 #endif
51 };
52
53 #if WAITQUEUE_DEBUG
54 # define __SEM_DEBUG_INIT(name) \
55 , (int)&(name).__magic
56 #else
57 # define __SEM_DEBUG_INIT(name)
58 #endif
59
60 #define __SEMAPHORE_INITIALIZER(name,count) \
61 { ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
62 __SEM_DEBUG_INIT(name) }
63
64 #define __MUTEX_INITIALIZER(name) \
65 __SEMAPHORE_INITIALIZER(name,1)
66
67 #define __DECLARE_SEMAPHORE_GENERIC(name,count) \
68 struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
69
70 #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
71 #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
72
73 static inline void sema_init (struct semaphore *sem, int val)
74 {
75 /*
76 * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
77 *
78 * i'd rather use the more flexible initialization above, but sadly
79 * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well.
80 */
81 atomic_set(&sem->count, val);
82 sem->sleepers = 0;
83 init_waitqueue_head(&sem->wait);
84 #if WAITQUEUE_DEBUG
85 sem->__magic = (int)&sem->__magic;
86 #endif
87 }
88
89 static inline void init_MUTEX (struct semaphore *sem)
90 {
91 sema_init(sem, 1);
92 }
93
94 static inline void init_MUTEX_LOCKED (struct semaphore *sem)
95 {
96 sema_init(sem, 0);
97 }
98
99 asmlinkage void __down_failed(void /* special register calling convention */);
100 asmlinkage int __down_failed_interruptible(void /* params in registers */);
101 asmlinkage int __down_failed_trylock(void /* params in registers */);
102 asmlinkage void __up_wakeup(void /* special register calling convention */);
103
104 asmlinkage void __down(struct semaphore * sem);
105 asmlinkage int __down_interruptible(struct semaphore * sem);
106 asmlinkage int __down_trylock(struct semaphore * sem);
107 asmlinkage void __up(struct semaphore * sem);
108
109 /*
110 * This is ugly, but we want the default case to fall through.
111 * "__down_failed" is a special asm handler that calls the C
112 * routine that actually waits. See arch/i386/kernel/semaphore.c
113 */
114 static inline void down(struct semaphore * sem)
115 {
116 #if WAITQUEUE_DEBUG
117 CHECK_MAGIC(sem->__magic);
118 #endif
119
120 __asm__ __volatile__(
121 "# atomic down operation\n\t"
122 LOCK "decl %0\n\t" /* --sem->count */
123 "js 2f\n"
124 "1:\n"
125 ".section .text.lock,\"ax\"\n"
126 "2:\tcall __down_failed\n\t"
127 "jmp 1b\n"
128 ".previous"
129 :"=m" (sem->count)
130 :"c" (sem)
131 :"memory");
132 }
133
134 static inline int down_interruptible(struct semaphore * sem)
135 {
136 int result;
137
138 #if WAITQUEUE_DEBUG
139 CHECK_MAGIC(sem->__magic);
140 #endif
141
142 __asm__ __volatile__(
143 "# atomic interruptible down operation\n\t"
144 LOCK "decl %1\n\t" /* --sem->count */
145 "js 2f\n\t"
146 "xorl %0,%0\n"
147 "1:\n"
148 ".section .text.lock,\"ax\"\n"
149 "2:\tcall __down_failed_interruptible\n\t"
150 "jmp 1b\n"
151 ".previous"
152 :"=a" (result), "=m" (sem->count)
153 :"c" (sem)
154 :"memory");
155 return result;
156 }
157
158 static inline int down_trylock(struct semaphore * sem)
159 {
160 int result;
161
162 #if WAITQUEUE_DEBUG
163 CHECK_MAGIC(sem->__magic);
164 #endif
165
166 __asm__ __volatile__(
167 "# atomic interruptible down operation\n\t"
168 LOCK "decl %1\n\t" /* --sem->count */
169 "js 2f\n\t"
170 "xorl %0,%0\n"
171 "1:\n"
172 ".section .text.lock,\"ax\"\n"
173 "2:\tcall __down_failed_trylock\n\t"
174 "jmp 1b\n"
175 ".previous"
176 :"=a" (result), "=m" (sem->count)
177 :"c" (sem)
178 :"memory");
179 return result;
180 }
181
182 /*
183 * Note! This is subtle. We jump to wake people up only if
184 * the semaphore was negative (== somebody was waiting on it).
185 * The default case (no contention) will result in NO
186 * jumps for both down() and up().
187 */
188 static inline void up(struct semaphore * sem)
189 {
190 #if WAITQUEUE_DEBUG
191 CHECK_MAGIC(sem->__magic);
192 #endif
193 __asm__ __volatile__(
194 "# atomic up operation\n\t"
195 LOCK "incl %0\n\t" /* ++sem->count */
196 "jle 2f\n"
197 "1:\n"
198 ".section .text.lock,\"ax\"\n"
199 "2:\tcall __up_wakeup\n\t"
200 "jmp 1b\n"
201 ".previous"
202 :"=m" (sem->count)
203 :"c" (sem)
204 :"memory");
205 }
206
207 /* rw mutexes (should that be mutices? =) -- throw rw
208 * spinlocks and semaphores together, and this is what we
209 * end up with...
210 *
211 * The lock is initialized to BIAS. This way, a writer
212 * subtracts BIAS ands gets 0 for the case of an uncontended
213 * lock. Readers decrement by 1 and see a positive value
214 * when uncontended, negative if there are writers waiting
215 * (in which case it goes to sleep).
216 *
217 * The value 0x01000000 supports up to 128 processors and
218 * lots of processes. BIAS must be chosen such that subl'ing
219 * BIAS once per CPU will result in the long remaining
220 * negative.
221 *
222 * In terms of fairness, this should result in the lock
223 * flopping back and forth between readers and writers
224 * under heavy use.
225 *
226 * -ben
227 */
228 struct rw_semaphore {
229 atomic_t count;
230 volatile unsigned char write_bias_granted;
231 volatile unsigned char read_bias_granted;
232 volatile unsigned char pad1;
233 volatile unsigned char pad2;
234 wait_queue_head_t wait;
235 wait_queue_head_t write_bias_wait;
236 #if WAITQUEUE_DEBUG
237 long __magic;
238 atomic_t readers;
239 atomic_t writers;
240 #endif
241 };
242
243 #if WAITQUEUE_DEBUG
244 #define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
245 #else
246 #define __RWSEM_DEBUG_INIT /* */
247 #endif
248
249 #define __RWSEM_INITIALIZER(name,count) \
250 { ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
251 __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
252 __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
253
254 #define __DECLARE_RWSEM_GENERIC(name,count) \
255 struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
256
257 #define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
258 #define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
259 #define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
260
261 static inline void init_rwsem(struct rw_semaphore *sem)
262 {
263 atomic_set(&sem->count, RW_LOCK_BIAS);
264 sem->read_bias_granted = 0;
265 sem->write_bias_granted = 0;
266 init_waitqueue_head(&sem->wait);
267 init_waitqueue_head(&sem->write_bias_wait);
268 #if WAITQUEUE_DEBUG
269 sem->__magic = (long)&sem->__magic;
270 atomic_set(&sem->readers, 0);
271 atomic_set(&sem->writers, 0);
272 #endif
273 }
274
275 /* we use FASTCALL convention for the helpers */
276 extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem));
277 extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem));
278 extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem));
279
280 static inline void down_read(struct rw_semaphore *sem)
281 {
282 #if WAITQUEUE_DEBUG
283 if (sem->__magic != (long)&sem->__magic)
284 BUG();
285 #endif
286 __build_read_lock(sem, "__down_read_failed");
287 #if WAITQUEUE_DEBUG
288 if (sem->write_bias_granted)
289 BUG();
290 if (atomic_read(&sem->writers))
291 BUG();
292 atomic_inc(&sem->readers);
293 #endif
294 }
295
296 static inline void down_write(struct rw_semaphore *sem)
297 {
298 #if WAITQUEUE_DEBUG
299 if (sem->__magic != (long)&sem->__magic)
300 BUG();
301 #endif
302 __build_write_lock(sem, "__down_write_failed");
303 #if WAITQUEUE_DEBUG
304 if (atomic_read(&sem->writers))
305 BUG();
306 if (atomic_read(&sem->readers))
307 BUG();
308 if (sem->read_bias_granted)
309 BUG();
310 if (sem->write_bias_granted)
311 BUG();
312 atomic_inc(&sem->writers);
313 #endif
314 }
315
316 /* When a reader does a release, the only significant
317 * case is when there was a writer waiting, and we've
318 * bumped the count to 0: we must wake the writer up.
319 */
320 static inline void __up_read(struct rw_semaphore *sem)
321 {
322 __asm__ __volatile__(
323 "# up_read\n\t"
324 LOCK "incl %0\n\t"
325 "jz 2f\n" /* only do the wake if result == 0 (ie, a writer) */
326 "1:\n\t"
327 ".section .text.lock,\"ax\"\n"
328 "2:\tcall __rwsem_wake\n\t"
329 "jmp 1b\n"
330 ".previous"
331 :"=m" (sem->count)
332 :"a" (sem)
333 :"memory"
334 );
335 }
336
337 /* releasing the writer is easy -- just release it and
338 * wake up any sleepers.
339 */
340 static inline void __up_write(struct rw_semaphore *sem)
341 {
342 __asm__ __volatile__(
343 "# up_write\n\t"
344 LOCK "addl $" RW_LOCK_BIAS_STR ",%0\n"
345 "jc 2f\n" /* only do the wake if the result was -'ve to 0/+'ve */
346 "1:\n\t"
347 ".section .text.lock,\"ax\"\n"
348 "2:\tcall __rwsem_wake\n\t"
349 "jmp 1b\n"
350 ".previous"
351 :"=m" (sem->count)
352 :"a" (sem)
353 :"memory"
354 );
355 }
356
357 static inline void up_read(struct rw_semaphore *sem)
358 {
359 #if WAITQUEUE_DEBUG
360 if (sem->write_bias_granted)
361 BUG();
362 if (atomic_read(&sem->writers))
363 BUG();
364 atomic_dec(&sem->readers);
365 #endif
366 __up_read(sem);
367 }
368
369 static inline void up_write(struct rw_semaphore *sem)
370 {
371 #if WAITQUEUE_DEBUG
372 if (sem->read_bias_granted)
373 BUG();
374 if (sem->write_bias_granted)
375 BUG();
376 if (atomic_read(&sem->readers))
377 BUG();
378 if (atomic_read(&sem->writers) != 1)
379 BUG();
380 atomic_dec(&sem->writers);
381 #endif
382 __up_write(sem);
383 }
384
385 #endif
386 #endif
387
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.