aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sem.h5
-rw-r--r--ipc/sem.c37
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;
86struct sem { 86struct 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. */
103struct sem_queue { 105struct 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 */
diff --git a/ipc/sem.c b/ipc/sem.c
index eac3f46a5968..4252a8eb77e2 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -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
428static 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
1237out_unlock_free: 1264out_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,