diff -urN 2.3.15-pre1/kernel/sched.c 2.3.15-pre1-wakeonesem1/kernel/sched.c --- 2.3.15-pre1/kernel/sched.c Fri Aug 20 17:43:24 1999 +++ 2.3.15-pre1-wakeonesem1/kernel/sched.c Sat Aug 21 16:42:30 1999 @@ -863,6 +863,14 @@ * * Either form may be used in conjunction with "up()". * + * NOTE NOTE: The tasks that are sleeping on a semaphore will be + * wakenup in a FIFO wake-one behaviour. For this reason + * waking_non_zero_interruptible() _must_ first check if it + * can grab the semaphore, and if so it must return successfully. + * _Only_ if the seamphore is still busy it can then check if + * there is a signal pending and fail _only_ in such case. + * All architectures must enforce this rule to avoid deadlocking + * with the wake-one wakeup. */ #define DOWN_VAR \ @@ -871,10 +879,7 @@ init_waitqueue_entry(&wait, tsk); #define DOWN_HEAD(task_state) \ - \ - \ - tsk->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ + add_wait_queue_exclusive(&sem->wait, &wait); \ \ /* \ * Ok, we're set up. sem->count is known to be less than zero \ @@ -891,10 +896,11 @@ * Multiple waiters contend for the semaphore lock to see \ * who gets to gate through and who has to wait some more. \ */ \ - for (;;) { + for (;;) { \ + tsk->state = (task_state); -#define DOWN_TAIL(task_state) \ - tsk->state = (task_state); \ +#define DOWN_TAIL() \ + schedule(); \ } \ tsk->state = TASK_RUNNING; \ remove_wait_queue(&sem->wait, &wait); @@ -902,18 +908,19 @@ void __down(struct semaphore * sem) { DOWN_VAR - DOWN_HEAD(TASK_UNINTERRUPTIBLE) + DOWN_HEAD(TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE) + if (waking_non_zero(sem)) break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) + + DOWN_TAIL() } int __down_interruptible(struct semaphore * sem) { int ret = 0; DOWN_VAR - DOWN_HEAD(TASK_INTERRUPTIBLE) + DOWN_HEAD(TASK_INTERRUPTIBLE|TASK_EXCLUSIVE) ret = waking_non_zero_interruptible(sem, tsk); if (ret) @@ -923,8 +930,8 @@ ret = 0; break; } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) + + DOWN_TAIL() return ret; }