|
@@ -241,6 +241,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
|
|
|
key_t key = params->key;
|
|
|
int nsems = params->u.nsems;
|
|
|
int semflg = params->flg;
|
|
|
+ int i;
|
|
|
|
|
|
if (!nsems)
|
|
|
return -EINVAL;
|
|
@@ -273,6 +274,11 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
|
|
|
ns->used_sems += nsems;
|
|
|
|
|
|
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->list_id);
|
|
|
sma->sem_nsems = nsems;
|
|
@@ -419,6 +425,15 @@ static void wake_up_sem_queue(struct sem_queue *q, int error)
|
|
|
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
|
|
|
* looking for tasks that can be completed.
|
|
|
*/
|
|
@@ -438,7 +453,7 @@ again:
|
|
|
if (error > 0)
|
|
|
continue;
|
|
|
|
|
|
- list_del(&q->list);
|
|
|
+ unlink_queue(sma, q);
|
|
|
|
|
|
/*
|
|
|
* 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)
|
|
|
|
|
|
/* Wake up all pending processes and let them fail with EIDRM. */
|
|
|
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);
|
|
|
}
|
|
|
|
|
@@ -1191,6 +1205,19 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
|
|
|
else
|
|
|
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.sleeper = current;
|
|
|
current->state = TASK_INTERRUPTIBLE;
|
|
@@ -1232,7 +1259,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
|
|
|
*/
|
|
|
if (timeout && jiffies_left == 0)
|
|
|
error = -EAGAIN;
|
|
|
- list_del(&queue.list);
|
|
|
+ unlink_queue(sma, &queue);
|
|
|
|
|
|
out_unlock_free:
|
|
|
sem_unlock(sma);
|
|
@@ -1375,7 +1402,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
|
|
|
struct sem_array *sma = it;
|
|
|
|
|
|
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.id,
|
|
|
sma->sem_perm.mode,
|