aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManfred Spraul <manfred@colorfullife.com>2009-12-15 19:47:32 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 10:20:10 -0500
commitb97e820ffffbf49e94ed60c9c26f1a54bccae924 (patch)
tree195146c43d24051aada20a211f2bb146bfebe9d2
parentb6e90822e77cd476c18410f7003197d466e36ac6 (diff)
ipc/sem.c: add a per-semaphore pending list
Based on Nick's findings: sysv sem has the concept of semaphore arrays that consist out of multiple semaphores. Atomic operations that affect multiple semaphores are supported. The patch is the first step for optimizing simple, single semaphore operations: In addition to the global list of all pending operations, a 2nd, per-semaphore list with the simple operations is added. Note: this patch does not make sense by itself, the new list is used nowhere. 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>
-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,