Signed-off-by: Nick Piggin --- ipc/sem.c | 79 +++++++++++++++++++++++++------------------------------------- 1 file changed, 33 insertions(+), 46 deletions(-) Index: linux-2.6/ipc/sem.c =================================================================== --- linux-2.6.orig/ipc/sem.c +++ linux-2.6/ipc/sem.c @@ -402,58 +402,45 @@ undo: */ static void update_queue (struct sem_array * sma) { - int error; - struct sem_queue * q; + struct sem_queue *q, *tq; + +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, q->undo, q->pid); /* Does q->sleeper still need to sleep? */ - if (error <= 0) { - struct sem_queue *n; + if (error > 0) + continue; + + list_del(&q->list); + + /* + * 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 the waiting thread */ + q->status = IN_WAKEUP; + + wake_up_process(q->sleeper); + /* hands-off: q will disappear immediately after + * writing q->status. + */ + smp_wmb(); + q->status = error; - /* - * 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; - - wake_up_process(q->sleeper); - /* hands-off: q will disappear immediately after - * writing q->status. - */ - smp_wmb(); - q->status = error; - q = n; - } else { - q = list_entry(q->list.next, struct sem_queue, list); - } + if (alter) + goto again; } } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/