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

