diff options
Diffstat (limited to 'ipc/sem.c')
-rw-r--r-- | ipc/sem.c | 51 |
1 files changed, 40 insertions, 11 deletions
@@ -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 | */ |
440 | static void update_queue (struct sem_array * sma) | 447 | static 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 | ||
444 | again: | 469 | again: |
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); |