diff options
author | Manfred Spraul <manfred@colorfullife.com> | 2013-05-26 05:08:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-26 18:14:51 -0400 |
commit | ab465df9dda42a997f7537c875127eeb6a88158c (patch) | |
tree | 28a1ec28c15f1b59c938b7757c8f56eed0de0ecd /ipc/sem.c | |
parent | 89ff77837a67994e4a4a20bb648687fbcc3083f2 (diff) |
ipc/sem.c: Fix missing wakeups in do_smart_update_queue()
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 <manfred@colorfullife.com>
Acked-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc/sem.c')
-rw-r--r-- | ipc/sem.c | 27 |
1 files changed, 22 insertions, 5 deletions
@@ -752,19 +752,29 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop | |||
752 | int otime, struct list_head *pt) | 752 | int otime, struct list_head *pt) |
753 | { | 753 | { |
754 | int i; | 754 | int i; |
755 | int progress; | ||
755 | 756 | ||
756 | if (sma->complex_count || sops == NULL) { | 757 | progress = 1; |
757 | if (update_queue(sma, -1, pt)) | 758 | retry_global: |
759 | if (sma->complex_count) { | ||
760 | if (update_queue(sma, -1, pt)) { | ||
761 | progress = 1; | ||
758 | otime = 1; | 762 | otime = 1; |
763 | sops = NULL; | ||
764 | } | ||
759 | } | 765 | } |
766 | if (!progress) | ||
767 | goto done; | ||
760 | 768 | ||
761 | if (!sops) { | 769 | if (!sops) { |
762 | /* No semops; something special is going on. */ | 770 | /* No semops; something special is going on. */ |
763 | for (i = 0; i < sma->sem_nsems; i++) { | 771 | for (i = 0; i < sma->sem_nsems; i++) { |
764 | if (update_queue(sma, i, pt)) | 772 | if (update_queue(sma, i, pt)) { |
765 | otime = 1; | 773 | otime = 1; |
774 | progress = 1; | ||
775 | } | ||
766 | } | 776 | } |
767 | goto done; | 777 | goto done_checkretry; |
768 | } | 778 | } |
769 | 779 | ||
770 | /* Check the semaphores that were modified. */ | 780 | /* Check the semaphores that were modified. */ |
@@ -772,8 +782,15 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop | |||
772 | if (sops[i].sem_op > 0 || | 782 | if (sops[i].sem_op > 0 || |
773 | (sops[i].sem_op < 0 && | 783 | (sops[i].sem_op < 0 && |
774 | sma->sem_base[sops[i].sem_num].semval == 0)) | 784 | sma->sem_base[sops[i].sem_num].semval == 0)) |
775 | if (update_queue(sma, sops[i].sem_num, pt)) | 785 | if (update_queue(sma, sops[i].sem_num, pt)) { |
776 | otime = 1; | 786 | otime = 1; |
787 | progress = 1; | ||
788 | } | ||
789 | } | ||
790 | done_checkretry: | ||
791 | if (progress) { | ||
792 | progress = 0; | ||
793 | goto retry_global; | ||
777 | } | 794 | } |
778 | done: | 795 | done: |
779 | if (otime) | 796 | if (otime) |