diff options
Diffstat (limited to 'ipc/sem.c')
| -rw-r--r-- | ipc/sem.c | 37 |
1 files changed, 32 insertions, 5 deletions
| @@ -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, |
