Commit b97e820f authored by Manfred Spraul's avatar Manfred Spraul Committed by Linus Torvalds

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: default avatarManfred Spraul <manfred@colorfullife.com>
Cc: Nick Piggin <npiggin@suse.de>
Cc: Pierre Peiffer <peifferp@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b6e90822
...@@ -86,6 +86,7 @@ struct task_struct; ...@@ -86,6 +86,7 @@ struct task_struct;
struct sem { struct sem {
int semval; /* current value */ int semval; /* current value */
int sempid; /* pid of last operation */ int sempid; /* pid of last operation */
struct list_head sem_pending; /* pending single-sop operations */
}; };
/* One sem_array data structure for each set of semaphores in the system. */ /* One sem_array data structure for each set of semaphores in the system. */
...@@ -96,11 +97,13 @@ struct sem_array { ...@@ -96,11 +97,13 @@ struct sem_array {
struct sem *sem_base; /* ptr to first semaphore in array */ struct sem *sem_base; /* ptr to first semaphore in array */
struct list_head sem_pending; /* pending operations to be processed */ struct list_head sem_pending; /* pending operations to be processed */
struct list_head list_id; /* undo requests on this array */ struct list_head list_id; /* undo requests on this array */
unsigned long sem_nsems; /* no. of semaphores in array */ int sem_nsems; /* no. of semaphores in array */
int complex_count; /* pending complex operations */
}; };
/* One queue for each sleeping process in the system. */ /* One queue for each sleeping process in the system. */
struct sem_queue { struct sem_queue {
struct list_head simple_list; /* queue of pending operations */
struct list_head list; /* queue of pending operations */ struct list_head list; /* queue of pending operations */
struct task_struct *sleeper; /* this process */ struct task_struct *sleeper; /* this process */
struct sem_undo *undo; /* undo structure */ struct sem_undo *undo; /* undo structure */
......
...@@ -241,6 +241,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) ...@@ -241,6 +241,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
key_t key = params->key; key_t key = params->key;
int nsems = params->u.nsems; int nsems = params->u.nsems;
int semflg = params->flg; int semflg = params->flg;
int i;
if (!nsems) if (!nsems)
return -EINVAL; return -EINVAL;
...@@ -273,6 +274,11 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) ...@@ -273,6 +274,11 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
ns->used_sems += nsems; ns->used_sems += nsems;
sma->sem_base = (struct sem *) &sma[1]; sma->sem_base = (struct sem *) &sma[1];
for (i = 0; i < nsems; i++)
INIT_LIST_HEAD(&sma->sem_base[i].sem_pending);
sma->complex_count = 0;
INIT_LIST_HEAD(&sma->sem_pending); INIT_LIST_HEAD(&sma->sem_pending);
INIT_LIST_HEAD(&sma->list_id); INIT_LIST_HEAD(&sma->list_id);
sma->sem_nsems = nsems; sma->sem_nsems = nsems;
...@@ -419,6 +425,15 @@ static void wake_up_sem_queue(struct sem_queue *q, int error) ...@@ -419,6 +425,15 @@ static void wake_up_sem_queue(struct sem_queue *q, int error)
preempt_enable(); preempt_enable();
} }
static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
{
list_del(&q->list);
if (q->nsops == 1)
list_del(&q->simple_list);
else
sma->complex_count--;
}
/* Go through the pending queue for the indicated semaphore /* Go through the pending queue for the indicated semaphore
* looking for tasks that can be completed. * looking for tasks that can be completed.
*/ */
...@@ -438,7 +453,7 @@ again: ...@@ -438,7 +453,7 @@ again:
if (error > 0) if (error > 0)
continue; continue;
list_del(&q->list); unlink_queue(sma, q);
/* /*
* The next operation that must be checked depends on the type * 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,8 +547,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
/* Wake up all pending processes and let them fail with EIDRM. */ /* Wake up all pending processes and let them fail with EIDRM. */
list_for_each_entry_safe(q, tq, &sma->sem_pending, list) { list_for_each_entry_safe(q, tq, &sma->sem_pending, list) {
list_del(&q->list); unlink_queue(sma, q);
wake_up_sem_queue(q, -EIDRM); wake_up_sem_queue(q, -EIDRM);
} }
...@@ -1191,6 +1205,19 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, ...@@ -1191,6 +1205,19 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
else else
list_add(&queue.list, &sma->sem_pending); list_add(&queue.list, &sma->sem_pending);
if (nsops == 1) {
struct sem *curr;
curr = &sma->sem_base[sops->sem_num];
if (alter)
list_add_tail(&queue.simple_list, &curr->sem_pending);
else
list_add(&queue.simple_list, &curr->sem_pending);
} else {
INIT_LIST_HEAD(&queue.simple_list);
sma->complex_count++;
}
queue.status = -EINTR; queue.status = -EINTR;
queue.sleeper = current; queue.sleeper = current;
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
...@@ -1232,7 +1259,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, ...@@ -1232,7 +1259,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
*/ */
if (timeout && jiffies_left == 0) if (timeout && jiffies_left == 0)
error = -EAGAIN; error = -EAGAIN;
list_del(&queue.list); unlink_queue(sma, &queue);
out_unlock_free: out_unlock_free:
sem_unlock(sma); sem_unlock(sma);
...@@ -1375,7 +1402,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it) ...@@ -1375,7 +1402,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
struct sem_array *sma = it; struct sem_array *sma = it;
return seq_printf(s, return seq_printf(s,
"%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n", "%10d %10d %4o %10u %5u %5u %5u %5u %10lu %10lu\n",
sma->sem_perm.key, sma->sem_perm.key,
sma->sem_perm.id, sma->sem_perm.id,
sma->sem_perm.mode, sma->sem_perm.mode,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment