Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / arch / parisc / kernel / semaphore.c
1 /*
2  * Semaphore implementation Copyright (c) 2001 Matthew Wilcox, Hewlett-Packard
3  */
4
5 #include <linux/sched.h>
6 #include <linux/spinlock.h>
7 #include <linux/errno.h>
8 #include <linux/init.h>
9
10 /*
11  * Semaphores are complex as we wish to avoid using two variables.
12  * `count' has multiple roles, depending on its value.  If it is positive
13  * or zero, there are no waiters.  The functions here will never be
14  * called; see <asm/semaphore.h>
15  *
16  * When count is -1 it indicates there is at least one task waiting
17  * for the semaphore.
18  *
19  * When count is less than that, there are '- count - 1' wakeups
20  * pending.  ie if it has value -3, there are 2 wakeups pending.
21  *
22  * Note that these functions are only called when there is contention
23  * on the lock, and as such all this is the "non-critical" part of the
24  * whole semaphore business. The critical part is the inline stuff in
25  * <asm/semaphore.h> where we want to avoid any extra jumps and calls.
26  */
27 void __up(struct semaphore *sem)
28 {
29         sem->count--;
30         wake_up(&sem->wait);
31 }
32
33 #define wakers(count) (-1 - count)
34
35 #define DOWN_HEAD                                                       \
36         int ret = 0;                                                    \
37         DECLARE_WAITQUEUE(wait, current);                               \
38                                                                         \
39         /* Note that someone is waiting */                              \
40         if (sem->count == 0)                                            \
41                 sem->count = -1;                                        \
42                                                                         \
43         /* protected by the sentry still -- use unlocked version */     \
44         wait.flags = WQ_FLAG_EXCLUSIVE;                                 \
45         __add_wait_queue_tail(&sem->wait, &wait);                       \
46  lost_race:                                                             \
47         spin_unlock_irq(&sem->sentry);                                  \
48
49 #define DOWN_TAIL                                                       \
50         spin_lock_irq(&sem->sentry);                                    \
51         if (wakers(sem->count) == 0 && ret == 0)                        \
52                 goto lost_race; /* Someone stole our wakeup */          \
53         __remove_wait_queue(&sem->wait, &wait);                         \
54         current->state = TASK_RUNNING;                                  \
55         if (!waitqueue_active(&sem->wait) && (sem->count < 0))          \
56                 sem->count = wakers(sem->count);
57
58 #define UPDATE_COUNT                                                    \
59         sem->count += (sem->count < 0) ? 1 : - 1;
60         
61
62 void __sched __down(struct semaphore * sem)
63 {
64         DOWN_HEAD
65
66         for(;;) {
67                 set_task_state(current, TASK_UNINTERRUPTIBLE);
68                 /* we can _read_ this without the sentry */
69                 if (sem->count != -1)
70                         break;
71                 schedule();
72         }
73
74         DOWN_TAIL
75         UPDATE_COUNT
76 }
77
78 int __sched __down_interruptible(struct semaphore * sem)
79 {
80         DOWN_HEAD
81
82         for(;;) {
83                 set_task_state(current, TASK_INTERRUPTIBLE);
84                 /* we can _read_ this without the sentry */
85                 if (sem->count != -1)
86                         break;
87
88                 if (signal_pending(current)) {
89                         ret = -EINTR;
90                         break;
91                 }
92                 schedule();
93         }
94
95         DOWN_TAIL
96
97         if (!ret) {
98                 UPDATE_COUNT
99         }
100
101         return ret;
102 }