forked from Minki/linux
ipc/sem.c: sem use list operations
Replace the handcoded list operations in update_queue() with the standard list_for_each_entry macros. list_for_each_entry_safe() must be used, because list entries can disappear immediately uppon the wakeup event. Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Manfred Spraul <manfred@colorfullife.com> Cc: Pierre Peiffer <peifferp@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
bf17bb7177
commit
9cad200c76
75
ipc/sem.c
75
ipc/sem.c
@ -403,58 +403,45 @@ undo:
|
|||||||
*/
|
*/
|
||||||
static void update_queue (struct sem_array * sma)
|
static void update_queue (struct sem_array * sma)
|
||||||
{
|
{
|
||||||
int error;
|
struct sem_queue *q, *tq;
|
||||||
struct sem_queue * q;
|
|
||||||
|
again:
|
||||||
|
list_for_each_entry_safe(q, tq, &sma->sem_pending, list) {
|
||||||
|
int error;
|
||||||
|
int alter;
|
||||||
|
|
||||||
q = list_entry(sma->sem_pending.next, struct sem_queue, list);
|
|
||||||
while (&q->list != &sma->sem_pending) {
|
|
||||||
error = try_atomic_semop(sma, q->sops, q->nsops,
|
error = try_atomic_semop(sma, q->sops, q->nsops,
|
||||||
q->undo, q->pid);
|
q->undo, q->pid);
|
||||||
|
|
||||||
/* Does q->sleeper still need to sleep? */
|
/* Does q->sleeper still need to sleep? */
|
||||||
if (error <= 0) {
|
if (error > 0)
|
||||||
struct sem_queue *n;
|
continue;
|
||||||
|
|
||||||
/*
|
list_del(&q->list);
|
||||||
* Continue scanning. The next operation
|
|
||||||
* that must be checked depends on the type of the
|
|
||||||
* completed operation:
|
|
||||||
* - if the operation modified the array, then
|
|
||||||
* restart from the head of the queue and
|
|
||||||
* check for threads that might be waiting
|
|
||||||
* for semaphore values to become 0.
|
|
||||||
* - if the operation didn't modify the array,
|
|
||||||
* then just continue.
|
|
||||||
* The order of list_del() and reading ->next
|
|
||||||
* is crucial: In the former case, the list_del()
|
|
||||||
* must be done first [because we might be the
|
|
||||||
* first entry in ->sem_pending], in the latter
|
|
||||||
* case the list_del() must be done last
|
|
||||||
* [because the list is invalid after the list_del()]
|
|
||||||
*/
|
|
||||||
if (q->alter) {
|
|
||||||
list_del(&q->list);
|
|
||||||
n = list_entry(sma->sem_pending.next,
|
|
||||||
struct sem_queue, list);
|
|
||||||
} else {
|
|
||||||
n = list_entry(q->list.next, struct sem_queue,
|
|
||||||
list);
|
|
||||||
list_del(&q->list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* wake up the waiting thread */
|
/*
|
||||||
q->status = IN_WAKEUP;
|
* The next operation that must be checked depends on the type
|
||||||
|
* of the completed operation:
|
||||||
|
* - if the operation modified the array, then restart from the
|
||||||
|
* head of the queue and check for threads that might be
|
||||||
|
* waiting for semaphore values to become 0.
|
||||||
|
* - if the operation didn't modify the array, then just
|
||||||
|
* continue.
|
||||||
|
*/
|
||||||
|
alter = q->alter;
|
||||||
|
|
||||||
wake_up_process(q->sleeper);
|
/* wake up the waiting thread */
|
||||||
/* hands-off: q will disappear immediately after
|
q->status = IN_WAKEUP;
|
||||||
* writing q->status.
|
|
||||||
*/
|
wake_up_process(q->sleeper);
|
||||||
smp_wmb();
|
/* hands-off: q will disappear immediately after
|
||||||
q->status = error;
|
* writing q->status.
|
||||||
q = n;
|
*/
|
||||||
} else {
|
smp_wmb();
|
||||||
q = list_entry(q->list.next, struct sem_queue, list);
|
q->status = error;
|
||||||
}
|
|
||||||
|
if (alter)
|
||||||
|
goto again;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user