aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipc/sem.c75
1 files changed, 31 insertions, 44 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index cb0070ecf5b..d377b3adfc3 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -403,58 +403,45 @@ undo:
403 */ 403 */
404static void update_queue (struct sem_array * sma) 404static void update_queue (struct sem_array * sma)
405{ 405{
406 int error; 406 struct sem_queue *q, *tq;
407 struct sem_queue * q; 407
408again:
409 list_for_each_entry_safe(q, tq, &sma->sem_pending, list) {
410 int error;
411 int alter;
408 412
409 q = list_entry(sma->sem_pending.next, struct sem_queue, list);
410 while (&q->list != &sma->sem_pending) {
411 error = try_atomic_semop(sma, q->sops, q->nsops, 413 error = try_atomic_semop(sma, q->sops, q->nsops,
412 q->undo, q->pid); 414 q->undo, q->pid);
413 415
414 /* Does q->sleeper still need to sleep? */ 416 /* Does q->sleeper still need to sleep? */
415 if (error <= 0) { 417 if (error > 0)
416 struct sem_queue *n; 418 continue;
417 419
418 /* 420 list_del(&q->list);
419 * Continue scanning. The next operation
420 * that must be checked depends on the type of the
421 * completed operation:
422 * - if the operation modified the array, then
423 * restart from the head of the queue and
424 * check for threads that might be waiting
425 * for semaphore values to become 0.
426 * - if the operation didn't modify the array,
427 * then just continue.
428 * The order of list_del() and reading ->next
429 * is crucial: In the former case, the list_del()
430 * must be done first [because we might be the
431 * first entry in ->sem_pending], in the latter
432 * case the list_del() must be done last
433 * [because the list is invalid after the list_del()]
434 */
435 if (q->alter) {
436 list_del(&q->list);
437 n = list_entry(sma->sem_pending.next,
438 struct sem_queue, list);
439 } else {
440 n = list_entry(q->list.next, struct sem_queue,
441 list);
442 list_del(&q->list);
443 }
444 421
445 /* wake up the waiting thread */ 422 /*
446 q->status = IN_WAKEUP; 423 * The next operation that must be checked depends on the type
424 * of the completed operation:
425 * - if the operation modified the array, then restart from the
426 * head of the queue and check for threads that might be
427 * waiting for semaphore values to become 0.
428 * - if the operation didn't modify the array, then just
429 * continue.
430 */
431 alter = q->alter;
432
433 /* wake up the waiting thread */
434 q->status = IN_WAKEUP;
447 435
448 wake_up_process(q->sleeper); 436 wake_up_process(q->sleeper);
449 /* hands-off: q will disappear immediately after 437 /* hands-off: q will disappear immediately after
450 * writing q->status. 438 * writing q->status.
451 */ 439 */
452 smp_wmb(); 440 smp_wmb();
453 q->status = error; 441 q->status = error;
454 q = n; 442
455 } else { 443 if (alter)
456 q = list_entry(q->list.next, struct sem_queue, list); 444 goto again;
457 }
458 } 445 }
459} 446}
460 447