[PATCH] convert signal handling of NODEFER to act like other Unix boxes.
[linux-2.6.git] / arch / m68knommu / kernel / semaphore.c
1 /*
2  *  Generic semaphore code. Buyer beware. Do your own
3  * specific changes in <asm/semaphore-helper.h>
4  */
5
6 #include <linux/config.h>
7 #include <linux/sched.h>
8 #include <linux/err.h>
9 #include <linux/init.h>
10 #include <asm/semaphore-helper.h>
11
12 #ifndef CONFIG_RMW_INSNS
13 spinlock_t semaphore_wake_lock;
14 #endif
15
16 /*
17  * Semaphores are implemented using a two-way counter:
18  * The "count" variable is decremented for each process
19  * that tries to sleep, while the "waking" variable is
20  * incremented when the "up()" code goes to wake up waiting
21  * processes.
22  *
23  * Notably, the inline "up()" and "down()" functions can
24  * efficiently test if they need to do any extra work (up
25  * needs to do something only if count was negative before
26  * the increment operation.
27  *
28  * waking_non_zero() (from asm/semaphore.h) must execute
29  * atomically.
30  *
31  * When __up() is called, the count was negative before
32  * incrementing it, and we need to wake up somebody.
33  *
34  * This routine adds one to the count of processes that need to
35  * wake up and exit.  ALL waiting processes actually wake up but
36  * only the one that gets to the "waking" field first will gate
37  * through and acquire the semaphore.  The others will go back
38  * to sleep.
39  *
40  * Note that these functions are only called when there is
41  * contention on the lock, and as such all this is the
42  * "non-critical" part of the whole semaphore business. The
43  * critical part is the inline stuff in <asm/semaphore.h>
44  * where we want to avoid any extra jumps and calls.
45  */
46 void __up(struct semaphore *sem)
47 {
48         wake_one_more(sem);
49         wake_up(&sem->wait);
50 }
51
52 /*
53  * Perform the "down" function.  Return zero for semaphore acquired,
54  * return negative for signalled out of the function.
55  *
56  * If called from __down, the return is ignored and the wait loop is
57  * not interruptible.  This means that a task waiting on a semaphore
58  * using "down()" cannot be killed until someone does an "up()" on
59  * the semaphore.
60  *
61  * If called from __down_interruptible, the return value gets checked
62  * upon return.  If the return value is negative then the task continues
63  * with the negative value in the return register (it can be tested by
64  * the caller).
65  *
66  * Either form may be used in conjunction with "up()".
67  *
68  */
69
70
71 #define DOWN_HEAD(task_state)                                           \
72                                                                         \
73                                                                         \
74         current->state = (task_state);                                  \
75         add_wait_queue(&sem->wait, &wait);                              \
76                                                                         \
77         /*                                                              \
78          * Ok, we're set up.  sem->count is known to be less than zero  \
79          * so we must wait.                                             \
80          *                                                              \
81          * We can let go the lock for purposes of waiting.              \
82          * We re-acquire it after awaking so as to protect              \
83          * all semaphore operations.                                    \
84          *                                                              \
85          * If "up()" is called before we call waking_non_zero() then    \
86          * we will catch it right away.  If it is called later then     \
87          * we will have to go through a wakeup cycle to catch it.       \
88          *                                                              \
89          * Multiple waiters contend for the semaphore lock to see       \
90          * who gets to gate through and who has to wait some more.      \
91          */                                                             \
92         for (;;) {
93
94 #define DOWN_TAIL(task_state)                   \
95                 current->state = (task_state);  \
96         }                                       \
97         current->state = TASK_RUNNING;          \
98         remove_wait_queue(&sem->wait, &wait);
99
100 void __sched __down(struct semaphore * sem)
101 {
102         DECLARE_WAITQUEUE(wait, current);
103
104         DOWN_HEAD(TASK_UNINTERRUPTIBLE)
105         if (waking_non_zero(sem))
106                 break;
107         schedule();
108         DOWN_TAIL(TASK_UNINTERRUPTIBLE)
109 }
110
111 int __sched __down_interruptible(struct semaphore * sem)
112 {
113         DECLARE_WAITQUEUE(wait, current);
114         int ret = 0;
115
116         DOWN_HEAD(TASK_INTERRUPTIBLE)
117
118         ret = waking_non_zero_interruptible(sem, current);
119         if (ret)
120         {
121                 if (ret == 1)
122                         /* ret != 0 only if we get interrupted -arca */
123                         ret = 0;
124                 break;
125         }
126         schedule();
127         DOWN_TAIL(TASK_INTERRUPTIBLE)
128         return ret;
129 }
130
131 int __down_trylock(struct semaphore * sem)
132 {
133         return waking_non_zero_trylock(sem);
134 }