aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/sem.c
diff options
context:
space:
mode:
authorManfred Spraul <manfred@colorfullife.com>2014-06-06 17:37:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-06 19:08:15 -0400
commitb220c57aeccf903ec6550b30c52cc0248ddb26bf (patch)
treef0fa284d5819e16f9071ed525d93e40cd1800b7a /ipc/sem.c
parented247b7ca0d20b4528eec362f8435594818d7601 (diff)
ipc/sem.c: make semctl(,,{GETNCNT,GETZCNT}) standard compliant
SUSv4 clearly defines how semncnt and semzcnt must be calculated: A task waits on exactly one semaphore: The semaphore from the first operation in the sop array that cannot proceed. The Linux implementation never followed the standard, it tried to count all semaphores that might be the reason why a task sleeps. This patch fixes that. Note: a) The implementation assumes that GETNCNT and GETZCNT are rare operations, therefore the code counts them only on demand. (If they wouldn't be rare, then the non-compliance would have been found earlier) b) compared to the initial version of the patch, the BUG_ONs were removed and it was clarified that the new behavior conforms to SUS. Back-compatibility concerns: Manfred: : - there is no application in Fedora that uses GETNCNT or GETZCNT. : : - application that use only single-sop semop() are also safe, the : difference only affects complex apps. : : - portable application are also safe, the new behavior is standard : compliant. : : But that's it. The old behavior existed in Linux from 0.99.something : until now. Michael: : * These operations seem to be very little used. Grepping the public : source that is contained Fedora 20 source DVD, there appear to be no : uses. Of course, this says nothing about uses in private / : non-mainstream FOSS code, but it seems likely that the same pattern : is followed there. : : * The existing behavior is hard enough to understand that I suspect : that no one understood it well enough to rely on it anyway : (especially as that behavior contradicted both man page and POSIX). : : So, there's a chance of breakage, but I estimate that it's minute. Signed-off-by: Manfred Spraul <manfred@colorfullife.com> Cc: Davidlohr Bueso <davidlohr.bueso@hp.com> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Signed-off-by: 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.c34
1 files changed, 13 insertions, 21 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index d61362b31f1e..910c7a3865c8 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -993,38 +993,30 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop
993} 993}
994 994
995/* 995/*
996 * check_qop: Test how often a queued operation sleeps on the semaphore semnum 996 * check_qop: Test if a queued operation sleeps on the semaphore semnum
997 */ 997 */
998static int check_qop(struct sem_array *sma, int semnum, struct sem_queue *q, 998static int check_qop(struct sem_array *sma, int semnum, struct sem_queue *q,
999 bool count_zero) 999 bool count_zero)
1000{ 1000{
1001 struct sembuf *sops = q->sops; 1001 struct sembuf *sop = q->blocking;
1002 int nsops = q->nsops;
1003 int i, semcnt;
1004 1002
1005 semcnt = 0; 1003 if (sop->sem_num != semnum)
1004 return 0;
1006 1005
1007 for (i = 0; i < nsops; i++) { 1006 if (count_zero && sop->sem_op == 0)
1008 if (sops[i].sem_num != semnum) 1007 return 1;
1009 continue; 1008 if (!count_zero && sop->sem_op < 0)
1010 if (sops[i].sem_flg & IPC_NOWAIT) 1009 return 1;
1011 continue; 1010
1012 if (count_zero && sops[i].sem_op == 0) 1011 return 0;
1013 semcnt++;
1014 if (!count_zero && sops[i].sem_op < 0)
1015 semcnt++;
1016 }
1017 return semcnt;
1018} 1012}
1019 1013
1020/* The following counts are associated to each semaphore: 1014/* The following counts are associated to each semaphore:
1021 * semncnt number of tasks waiting on semval being nonzero 1015 * semncnt number of tasks waiting on semval being nonzero
1022 * semzcnt number of tasks waiting on semval being zero 1016 * semzcnt number of tasks waiting on semval being zero
1023 * This model assumes that a task waits on exactly one semaphore. 1017 *
1024 * Since semaphore operations are to be performed atomically, tasks actually 1018 * Per definition, a task waits only on the semaphore of the first semop
1025 * wait on a whole sequence of semaphores simultaneously. 1019 * that cannot proceed, even if additional operation would block, too.
1026 * The counts we return here are a rough approximation, but still
1027 * warrant that semncnt+semzcnt>0 if the task is on the pending queue.
1028 */ 1020 */
1029static int count_semcnt(struct sem_array *sma, ushort semnum, 1021static int count_semcnt(struct sem_array *sma, ushort semnum,
1030 bool count_zero) 1022 bool count_zero)