| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | } |