2 * Alpha semaphore implementation.
4 * (C) Copyright 1996 Linus Torvalds
5 * (C) Copyright 1999, 2000 Richard Henderson
8 #include <linux/sched.h>
12 * Semaphores are implemented using a two-way counter:
14 * The "count" variable is decremented for each process that tries to sleep,
15 * while the "waking" variable is incremented when the "up()" code goes to
16 * wake up waiting processes.
18 * Notably, the inline "up()" and "down()" functions can efficiently test
19 * if they need to do any extra work (up needs to do something only if count
20 * was negative before the increment operation.
22 * waking_non_zero() (from asm/semaphore.h) must execute atomically.
24 * When __up() is called, the count was negative before incrementing it,
25 * and we need to wake up somebody.
27 * This routine adds one to the count of processes that need to wake up and
28 * exit. ALL waiting processes actually wake up but only the one that gets
29 * to the "waking" field first will gate through and acquire the semaphore.
30 * The others will go back to sleep.
32 * Note that these functions are only called when there is contention on the
33 * lock, and as such all this is the "non-critical" part of the whole
34 * semaphore business. The critical part is the inline stuff in
35 * <asm/semaphore.h> where we want to avoid any extra jumps and calls.
39 * Perform the "down" function. Return zero for semaphore acquired,
40 * return negative for signalled out of the function.
42 * If called from down, the return is ignored and the wait loop is
43 * not interruptible. This means that a task waiting on a semaphore
44 * using "down()" cannot be killed until someone does an "up()" on
47 * If called from down_interruptible, the return value gets checked
48 * upon return. If the return value is negative then the task continues
49 * with the negative value in the return register (it can be tested by
52 * Either form may be used in conjunction with "up()".
56 __down_failed(struct semaphore *sem)
58 DECLARE_WAITQUEUE(wait, current);
60 #ifdef CONFIG_DEBUG_SEMAPHORE
61 printk("%s(%d): down failed(%p)\n",
62 current->comm, current->pid, sem);
65 current->state = TASK_UNINTERRUPTIBLE;
67 add_wait_queue_exclusive(&sem->wait, &wait);
69 /* At this point we know that sem->count is negative. In order
70 to avoid racing with __up, we must check for wakeup before
71 going to sleep the first time. */
76 /* An atomic conditional decrement of sem->waking. */
87 : "=r"(ret), "=&r"(tmp), "=m"(sem->waking)
94 set_task_state(current, TASK_UNINTERRUPTIBLE);
97 remove_wait_queue(&sem->wait, &wait);
98 current->state = TASK_RUNNING;
100 #ifdef CONFIG_DEBUG_SEMAPHORE
101 printk("%s(%d): down acquired(%p)\n",
102 current->comm, current->pid, sem);
107 __down_failed_interruptible(struct semaphore *sem)
109 DECLARE_WAITQUEUE(wait, current);
112 #ifdef CONFIG_DEBUG_SEMAPHORE
113 printk("%s(%d): down failed(%p)\n",
114 current->comm, current->pid, sem);
117 current->state = TASK_INTERRUPTIBLE;
119 add_wait_queue_exclusive(&sem->wait, &wait);
122 long tmp, tmp2, tmp3;
124 /* We must undo the sem->count down_interruptible decrement
125 simultaneously and atomicly with the sem->waking
126 adjustment, otherwise we can race with __up. This is
127 accomplished by doing a 64-bit ll/sc on two 32-bit words.
129 "Equivalent" C. Note that we have to do this all without
130 (taken) branches in order to be a valid ll/sc sequence.
135 if (tmp >= 0) { // waking >= 0
136 tmp += 0xffffffff00000000; // waking -= 1
140 // count += 1, but since -1 + 1 carries into the
141 // high word, we have to be more careful here.
142 tmp = (tmp & 0xffffffff00000000)
143 | ((tmp + 1) & 0x00000000ffffffff);
150 __asm__ __volatile__(
168 : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2),
169 "=&r"(tmp3), "=m"(*sem)
170 : "r"(signal_pending(current)), "r"(-EINTR),
171 "r"(0xffffffff00000000));
173 /* At this point we have ret
176 -EINTR interrupted */
181 set_task_state(current, TASK_INTERRUPTIBLE);
184 remove_wait_queue(&sem->wait, &wait);
185 current->state = TASK_RUNNING;
188 #ifdef CONFIG_DEBUG_SEMAPHORE
189 printk("%s(%d): down %s(%p)\n",
190 current->comm, current->pid,
191 (ret < 0 ? "interrupted" : "acquired"), sem);
194 /* Convert "got the lock" to 0==success. */
195 return (ret < 0 ? ret : 0);
199 __up_wakeup(struct semaphore *sem)
205 down(struct semaphore *sem)
208 CHECK_MAGIC(sem->__magic);
210 #ifdef CONFIG_DEBUG_SEMAPHORE
211 printk("%s(%d): down(%p) <count=%d> from %p\n",
212 current->comm, current->pid, sem,
213 atomic_read(&sem->count), __builtin_return_address(0));
219 down_interruptible(struct semaphore *sem)
222 CHECK_MAGIC(sem->__magic);
224 #ifdef CONFIG_DEBUG_SEMAPHORE
225 printk("%s(%d): down(%p) <count=%d> from %p\n",
226 current->comm, current->pid, sem,
227 atomic_read(&sem->count), __builtin_return_address(0));
229 return __down_interruptible(sem);
233 down_trylock(struct semaphore *sem)
238 CHECK_MAGIC(sem->__magic);
241 ret = __down_trylock(sem);
243 #ifdef CONFIG_DEBUG_SEMAPHORE
244 printk("%s(%d): down_trylock %s from %p\n",
245 current->comm, current->pid,
246 ret ? "failed" : "acquired",
247 __builtin_return_address(0));
254 up(struct semaphore *sem)
257 CHECK_MAGIC(sem->__magic);
259 #ifdef CONFIG_DEBUG_SEMAPHORE
260 printk("%s(%d): up(%p) <count=%d> from %p\n",
261 current->comm, current->pid, sem,
262 atomic_read(&sem->count), __builtin_return_address(0));