aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/sem.c
diff options
context:
space:
mode:
authorManfred Spraul <manfred@colorfullife.com>2009-12-15 19:47:33 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 10:20:10 -0500
commit636c6be823870d829b37fc96655bb8820a6a9be9 (patch)
treedc17d73ae77e6921ca7c88e6b019fe3d72bb9790 /ipc/sem.c
parentb97e820ffffbf49e94ed60c9c26f1a54bccae924 (diff)
ipc/sem.c: optimize single semop operations
sysv sem has the concept of semaphore arrays that consist out of multiple semaphores. Atomic operations that affect multiple semaphores are supported. The patch optimizes single semaphore operation calls that affect only one semaphore: It's not necessary to scan all pending operations, it is sufficient to scan the per-semaphore list. The idea is from Nick Piggin version of an ipc sem improvement, the implementation is different: The code tries to keep as much common code as possible. As the result, the patch is simpler, but optimizes fewer cases. Signed-off-by: Manfred Spraul <manfred@colorfullife.com> Cc: Nick Piggin <npiggin@suse.de> Cc: Pierre Peiffer <peifferp@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.c51
1 files changed, 40 insertions, 11 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index 4252a8eb77e2..7eb6f049dd7c 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -434,17 +434,45 @@ static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
434 sma->complex_count--; 434 sma->complex_count--;
435} 435}
436 436
437/* Go through the pending queue for the indicated semaphore 437
438 * looking for tasks that can be completed. 438/**
439 * update_queue(sma, semnum): Look for tasks that can be completed.
440 * @sma: semaphore array.
441 * @semnum: semaphore that was modified.
442 *
443 * update_queue must be called after a semaphore in a semaphore array
444 * was modified. If multiple semaphore were modified, then @semnum
445 * must be set to -1.
439 */ 446 */
440static void update_queue (struct sem_array * sma) 447static void update_queue(struct sem_array *sma, int semnum)
441{ 448{
442 struct sem_queue *q, *tq; 449 struct sem_queue *q;
450 struct list_head *walk;
451 struct list_head *pending_list;
452 int offset;
453
454 /* if there are complex operations around, then knowing the semaphore
455 * that was modified doesn't help us. Assume that multiple semaphores
456 * were modified.
457 */
458 if (sma->complex_count)
459 semnum = -1;
460
461 if (semnum == -1) {
462 pending_list = &sma->sem_pending;
463 offset = offsetof(struct sem_queue, list);
464 } else {
465 pending_list = &sma->sem_base[semnum].sem_pending;
466 offset = offsetof(struct sem_queue, simple_list);
467 }
443 468
444again: 469again:
445 list_for_each_entry_safe(q, tq, &sma->sem_pending, list) { 470 walk = pending_list->next;
446 int error; 471 while (walk != pending_list) {
447 int alter; 472 int error, alter;
473
474 q = (struct sem_queue *)((char *)walk - offset);
475 walk = walk->next;
448 476
449 error = try_atomic_semop(sma, q->sops, q->nsops, 477 error = try_atomic_semop(sma, q->sops, q->nsops,
450 q->undo, q->pid); 478 q->undo, q->pid);
@@ -769,7 +797,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
769 } 797 }
770 sma->sem_ctime = get_seconds(); 798 sma->sem_ctime = get_seconds();
771 /* maybe some queued-up processes were waiting for this */ 799 /* maybe some queued-up processes were waiting for this */
772 update_queue(sma); 800 update_queue(sma, -1);
773 err = 0; 801 err = 0;
774 goto out_unlock; 802 goto out_unlock;
775 } 803 }
@@ -811,7 +839,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
811 curr->sempid = task_tgid_vnr(current); 839 curr->sempid = task_tgid_vnr(current);
812 sma->sem_ctime = get_seconds(); 840 sma->sem_ctime = get_seconds();
813 /* maybe some queued-up processes were waiting for this */ 841 /* maybe some queued-up processes were waiting for this */
814 update_queue(sma); 842 update_queue(sma, semnum);
815 err = 0; 843 err = 0;
816 goto out_unlock; 844 goto out_unlock;
817 } 845 }
@@ -1187,7 +1215,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
1187 error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current)); 1215 error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current));
1188 if (error <= 0) { 1216 if (error <= 0) {
1189 if (alter && error == 0) 1217 if (alter && error == 0)
1190 update_queue (sma); 1218 update_queue(sma, (nsops == 1) ? sops[0].sem_num : -1);
1219
1191 goto out_unlock_free; 1220 goto out_unlock_free;
1192 } 1221 }
1193 1222
@@ -1388,7 +1417,7 @@ void exit_sem(struct task_struct *tsk)
1388 } 1417 }
1389 sma->sem_otime = get_seconds(); 1418 sma->sem_otime = get_seconds();
1390 /* maybe some queued-up processes were waiting for this */ 1419 /* maybe some queued-up processes were waiting for this */
1391 update_queue(sma); 1420 update_queue(sma, -1);
1392 sem_unlock(sma); 1421 sem_unlock(sma);
1393 1422
1394 call_rcu(&un->rcu, free_un); 1423 call_rcu(&un->rcu, free_un);