Skip to content

Commit

Permalink
ipc/sem.c: Fix missing wakeups in do_smart_update_queue()
Browse files Browse the repository at this point in the history
do_smart_update_queue() is called when an operation (semop,
semctl(SETVAL), semctl(SETALL), ...) modified the array.  It must check
which of the sleeping tasks can proceed.

do_smart_update_queue() missed a few wakeups:
 - if a sleeping complex op was completed, then all per-semaphore queues
   must be scanned - not only those that were modified by *sops
 - if a sleeping simple op proceeded, then the global queue must be
   scanned again

And:
 - the test for "|sops == NULL) before scanning the global queue is not
   required: If the global queue is empty, then it doesn't need to be
   scanned - regardless of the reason for calling do_smart_update_queue()

The patch is not optimized, i.e.  even completing a wait-for-zero
operation causes a rescan.  This is done to keep the patch as simple as
possible.

Signed-off-by: Manfred Spraul <[email protected]>
Acked-by: Davidlohr Bueso <[email protected]>
Cc: Rik van Riel <[email protected]>
Cc: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
manfred-colorfu authored and torvalds committed May 26, 2013
1 parent 89ff778 commit ab465df
Showing 1 changed file with 22 additions and 5 deletions.
27 changes: 22 additions & 5 deletions ipc/sem.c
Original file line number Diff line number Diff line change
Expand Up @@ -752,28 +752,45 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop
int otime, struct list_head *pt)
{
int i;
int progress;

if (sma->complex_count || sops == NULL) {
if (update_queue(sma, -1, pt))
progress = 1;
retry_global:
if (sma->complex_count) {
if (update_queue(sma, -1, pt)) {
progress = 1;
otime = 1;
sops = NULL;
}
}
if (!progress)
goto done;

if (!sops) {
/* No semops; something special is going on. */
for (i = 0; i < sma->sem_nsems; i++) {
if (update_queue(sma, i, pt))
if (update_queue(sma, i, pt)) {
otime = 1;
progress = 1;
}
}
goto done;
goto done_checkretry;
}

/* Check the semaphores that were modified. */
for (i = 0; i < nsops; i++) {
if (sops[i].sem_op > 0 ||
(sops[i].sem_op < 0 &&
sma->sem_base[sops[i].sem_num].semval == 0))
if (update_queue(sma, sops[i].sem_num, pt))
if (update_queue(sma, sops[i].sem_num, pt)) {
otime = 1;
progress = 1;
}
}
done_checkretry:
if (progress) {
progress = 0;
goto retry_global;
}
done:
if (otime)
Expand Down

0 comments on commit ab465df

Please sign in to comment.