diff options
-rw-r--r-- | include/linux/sem.h | 5 | ||||
-rw-r--r-- | ipc/sem.c | 37 |
2 files changed, 36 insertions, 6 deletions
diff --git a/include/linux/sem.h b/include/linux/sem.h index 1b191c176bcd..8a4adbef8a0f 100644 --- a/include/linux/sem.h +++ b/include/linux/sem.h | |||
@@ -86,6 +86,7 @@ struct task_struct; | |||
86 | struct sem { | 86 | struct sem { |
87 | int semval; /* current value */ | 87 | int semval; /* current value */ |
88 | int sempid; /* pid of last operation */ | 88 | int sempid; /* pid of last operation */ |
89 | struct list_head sem_pending; /* pending single-sop operations */ | ||
89 | }; | 90 | }; |
90 | 91 | ||
91 | /* One sem_array data structure for each set of semaphores in the system. */ | 92 | /* One sem_array data structure for each set of semaphores in the system. */ |
@@ -96,11 +97,13 @@ struct sem_array { | |||
96 | struct sem *sem_base; /* ptr to first semaphore in array */ | 97 | struct sem *sem_base; /* ptr to first semaphore in array */ |
97 | struct list_head sem_pending; /* pending operations to be processed */ | 98 | struct list_head sem_pending; /* pending operations to be processed */ |
98 | struct list_head list_id; /* undo requests on this array */ | 99 | struct list_head list_id; /* undo requests on this array */ |
99 | unsigned long sem_nsems; /* no. of semaphores in array */ | 100 | int sem_nsems; /* no. of semaphores in array */ |
101 | int complex_count; /* pending complex operations */ | ||
100 | }; | 102 | }; |
101 | 103 | ||
102 | /* One queue for each sleeping process in the system. */ | 104 | /* One queue for each sleeping process in the system. */ |
103 | struct sem_queue { | 105 | struct sem_queue { |
106 | struct list_head simple_list; /* queue of pending operations */ | ||
104 | struct list_head list; /* queue of pending operations */ | 107 | struct list_head list; /* queue of pending operations */ |
105 | struct task_struct *sleeper; /* this process */ | 108 | struct task_struct *sleeper; /* this process */ |
106 | struct sem_undo *undo; /* undo structure */ | 109 | struct sem_undo *undo; /* undo structure */ |
@@ -241,6 +241,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
241 | key_t key = params->key; | 241 | key_t key = params->key; |
242 | int nsems = params->u.nsems; | 242 | int nsems = params->u.nsems; |
243 | int semflg = params->flg; | 243 | int semflg = params->flg; |
244 | int i; | ||
244 | 245 | ||
245 | if (!nsems) | 246 | if (!nsems) |
246 | return -EINVAL; | 247 | return -EINVAL; |
@@ -273,6 +274,11 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
273 | ns->used_sems += nsems; | 274 | ns->used_sems += nsems; |
274 | 275 | ||
275 | sma->sem_base = (struct sem *) &sma[1]; | 276 | sma->sem_base = (struct sem *) &sma[1]; |
277 | |||
278 | for (i = 0; i < nsems; i++) | ||
279 | INIT_LIST_HEAD(&sma->sem_base[i].sem_pending); | ||
280 | |||
281 | sma->complex_count = 0; | ||
276 | INIT_LIST_HEAD(&sma->sem_pending); | 282 | INIT_LIST_HEAD(&sma->sem_pending); |
277 | INIT_LIST_HEAD(&sma->list_id); | 283 | INIT_LIST_HEAD(&sma->list_id); |
278 | sma->sem_nsems = nsems; | 284 | sma->sem_nsems = nsems; |
@@ -419,6 +425,15 @@ static void wake_up_sem_queue(struct sem_queue *q, int error) | |||
419 | preempt_enable(); | 425 | preempt_enable(); |
420 | } | 426 | } |
421 | 427 | ||
428 | static void unlink_queue(struct sem_array *sma, struct sem_queue *q) | ||
429 | { | ||
430 | list_del(&q->list); | ||
431 | if (q->nsops == 1) | ||
432 | list_del(&q->simple_list); | ||
433 | else | ||
434 | sma->complex_count--; | ||
435 | } | ||
436 | |||
422 | /* Go through the pending queue for the indicated semaphore | 437 | /* Go through the pending queue for the indicated semaphore |
423 | * looking for tasks that can be completed. | 438 | * looking for tasks that can be completed. |
424 | */ | 439 | */ |
@@ -438,7 +453,7 @@ again: | |||
438 | if (error > 0) | 453 | if (error > 0) |
439 | continue; | 454 | continue; |
440 | 455 | ||
441 | list_del(&q->list); | 456 | unlink_queue(sma, q); |
442 | 457 | ||
443 | /* | 458 | /* |
444 | * The next operation that must be checked depends on the type | 459 | * The next operation that must be checked depends on the type |
@@ -532,8 +547,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) | |||
532 | 547 | ||
533 | /* Wake up all pending processes and let them fail with EIDRM. */ | 548 | /* Wake up all pending processes and let them fail with EIDRM. */ |
534 | list_for_each_entry_safe(q, tq, &sma->sem_pending, list) { | 549 | list_for_each_entry_safe(q, tq, &sma->sem_pending, list) { |
535 | list_del(&q->list); | 550 | unlink_queue(sma, q); |
536 | |||
537 | wake_up_sem_queue(q, -EIDRM); | 551 | wake_up_sem_queue(q, -EIDRM); |
538 | } | 552 | } |
539 | 553 | ||
@@ -1191,6 +1205,19 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
1191 | else | 1205 | else |
1192 | list_add(&queue.list, &sma->sem_pending); | 1206 | list_add(&queue.list, &sma->sem_pending); |
1193 | 1207 | ||
1208 | if (nsops == 1) { | ||
1209 | struct sem *curr; | ||
1210 | curr = &sma->sem_base[sops->sem_num]; | ||
1211 | |||
1212 | if (alter) | ||
1213 | list_add_tail(&queue.simple_list, &curr->sem_pending); | ||
1214 | else | ||
1215 | list_add(&queue.simple_list, &curr->sem_pending); | ||
1216 | } else { | ||
1217 | INIT_LIST_HEAD(&queue.simple_list); | ||
1218 | sma->complex_count++; | ||
1219 | } | ||
1220 | |||
1194 | queue.status = -EINTR; | 1221 | queue.status = -EINTR; |
1195 | queue.sleeper = current; | 1222 | queue.sleeper = current; |
1196 | current->state = TASK_INTERRUPTIBLE; | 1223 | current->state = TASK_INTERRUPTIBLE; |
@@ -1232,7 +1259,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
1232 | */ | 1259 | */ |
1233 | if (timeout && jiffies_left == 0) | 1260 | if (timeout && jiffies_left == 0) |
1234 | error = -EAGAIN; | 1261 | error = -EAGAIN; |
1235 | list_del(&queue.list); | 1262 | unlink_queue(sma, &queue); |
1236 | 1263 | ||
1237 | out_unlock_free: | 1264 | out_unlock_free: |
1238 | sem_unlock(sma); | 1265 | sem_unlock(sma); |
@@ -1375,7 +1402,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it) | |||
1375 | struct sem_array *sma = it; | 1402 | struct sem_array *sma = it; |
1376 | 1403 | ||
1377 | return seq_printf(s, | 1404 | return seq_printf(s, |
1378 | "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n", | 1405 | "%10d %10d %4o %10u %5u %5u %5u %5u %10lu %10lu\n", |
1379 | sma->sem_perm.key, | 1406 | sma->sem_perm.key, |
1380 | sma->sem_perm.id, | 1407 | sma->sem_perm.id, |
1381 | sma->sem_perm.mode, | 1408 | sma->sem_perm.mode, |