sysv_sem.c revision 1.40 1 /* $NetBSD: sysv_sem.c,v 1.40 2000/07/22 16:11:02 simonb Exp $ */
2
3 /*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Implementation of SVID semaphores
42 *
43 * Author: Daniel Boulet
44 *
45 * This software is provided ``AS IS'' without any warranties of any kind.
46 */
47
48 #define SYSVSEM
49
50 #include <sys/param.h>
51 #include <sys/kernel.h>
52 #include <sys/sem.h>
53 #include <sys/sysctl.h>
54 #include <sys/mount.h> /* XXX for <sys/syscallargs.h> */
55 #include <sys/syscallargs.h>
56
57 int semtot = 0;
58 struct semid_ds *sema; /* semaphore id pool */
59 struct __sem *sem; /* semaphore pool */
60 struct sem_undo *semu_list; /* list of active undo structures */
61 int *semu; /* undo structure pool */
62
63 #ifdef SEM_DEBUG
64 #define SEM_PRINTF(a) printf a
65 #else
66 #define SEM_PRINTF(a)
67 #endif
68
69 struct sem_undo *semu_alloc __P((struct proc *));
70 int semundo_adjust __P((struct proc *, struct sem_undo **, int, int, int));
71 void semundo_clear __P((int, int));
72
73 /*
74 * XXXSMP Once we go MP, there needs to be a lock for the semaphore system.
75 * Until then, we're saved by being a non-preemptive kernel.
76 */
77
78 void
79 seminit()
80 {
81 int i;
82
83 if (sema == NULL)
84 panic("sema is NULL");
85 if (semu == NULL)
86 panic("semu is NULL");
87
88 for (i = 0; i < seminfo.semmni; i++) {
89 sema[i]._sem_base = 0;
90 sema[i].sem_perm.mode = 0;
91 }
92 for (i = 0; i < seminfo.semmnu; i++) {
93 struct sem_undo *suptr = SEMU(i);
94 suptr->un_proc = NULL;
95 }
96 semu_list = NULL;
97 }
98
99 /*
100 * Placebo.
101 */
102
103 int
104 sys_semconfig(p, v, retval)
105 struct proc *p;
106 void *v;
107 register_t *retval;
108 {
109 *retval = 0;
110 return 0;
111 }
112
113 /*
114 * Allocate a new sem_undo structure for a process
115 * (returns ptr to structure or NULL if no more room)
116 */
117
118 struct sem_undo *
119 semu_alloc(p)
120 struct proc *p;
121 {
122 int i;
123 struct sem_undo *suptr;
124 struct sem_undo **supptr;
125 int attempt;
126
127 /*
128 * Try twice to allocate something.
129 * (we'll purge any empty structures after the first pass so
130 * two passes are always enough)
131 */
132
133 for (attempt = 0; attempt < 2; attempt++) {
134 /*
135 * Look for a free structure.
136 * Fill it in and return it if we find one.
137 */
138
139 for (i = 0; i < seminfo.semmnu; i++) {
140 suptr = SEMU(i);
141 if (suptr->un_proc == NULL) {
142 suptr->un_next = semu_list;
143 semu_list = suptr;
144 suptr->un_cnt = 0;
145 suptr->un_proc = p;
146 return(suptr);
147 }
148 }
149
150 /*
151 * We didn't find a free one, if this is the first attempt
152 * then try to free some structures.
153 */
154
155 if (attempt == 0) {
156 /* All the structures are in use - try to free some */
157 int did_something = 0;
158
159 supptr = &semu_list;
160 while ((suptr = *supptr) != NULL) {
161 if (suptr->un_cnt == 0) {
162 suptr->un_proc = NULL;
163 *supptr = suptr->un_next;
164 did_something = 1;
165 } else
166 supptr = &(suptr->un_next);
167 }
168
169 /* If we didn't free anything then just give-up */
170 if (!did_something)
171 return(NULL);
172 } else {
173 /*
174 * The second pass failed even though we freed
175 * something after the first pass!
176 * This is IMPOSSIBLE!
177 */
178 panic("semu_alloc - second attempt failed");
179 }
180 }
181 return NULL;
182 }
183
184 /*
185 * Adjust a particular entry for a particular proc
186 */
187
188 int
189 semundo_adjust(p, supptr, semid, semnum, adjval)
190 struct proc *p;
191 struct sem_undo **supptr;
192 int semid, semnum;
193 int adjval;
194 {
195 struct sem_undo *suptr;
196 struct undo *sunptr;
197 int i;
198
199 /* Look for and remember the sem_undo if the caller doesn't provide
200 it */
201
202 suptr = *supptr;
203 if (suptr == NULL) {
204 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
205 if (suptr->un_proc == p) {
206 *supptr = suptr;
207 break;
208 }
209 }
210 if (suptr == NULL) {
211 if (adjval == 0)
212 return(0);
213 suptr = semu_alloc(p);
214 if (suptr == NULL)
215 return(ENOSPC);
216 *supptr = suptr;
217 }
218 }
219
220 /*
221 * Look for the requested entry and adjust it (delete if adjval becomes
222 * 0).
223 */
224 sunptr = &suptr->un_ent[0];
225 for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
226 if (sunptr->un_id != semid || sunptr->un_num != semnum)
227 continue;
228 if (adjval == 0)
229 sunptr->un_adjval = 0;
230 else
231 sunptr->un_adjval += adjval;
232 if (sunptr->un_adjval == 0) {
233 suptr->un_cnt--;
234 if (i < suptr->un_cnt)
235 suptr->un_ent[i] =
236 suptr->un_ent[suptr->un_cnt];
237 }
238 return(0);
239 }
240
241 /* Didn't find the right entry - create it */
242 if (adjval == 0)
243 return(0);
244 if (suptr->un_cnt == SEMUME)
245 return(EINVAL);
246
247 sunptr = &suptr->un_ent[suptr->un_cnt];
248 suptr->un_cnt++;
249 sunptr->un_adjval = adjval;
250 sunptr->un_id = semid;
251 sunptr->un_num = semnum;
252 return(0);
253 }
254
255 void
256 semundo_clear(semid, semnum)
257 int semid, semnum;
258 {
259 struct sem_undo *suptr;
260
261 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
262 struct undo *sunptr;
263 int i;
264
265 sunptr = &suptr->un_ent[0];
266 for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
267 if (sunptr->un_id == semid) {
268 if (semnum == -1 || sunptr->un_num == semnum) {
269 suptr->un_cnt--;
270 if (i < suptr->un_cnt) {
271 suptr->un_ent[i] =
272 suptr->un_ent[suptr->un_cnt];
273 i--, sunptr--;
274 }
275 }
276 if (semnum != -1)
277 break;
278 }
279 }
280 }
281 }
282
283 int
284 sys_____semctl13(p, v, retval)
285 struct proc *p;
286 void *v;
287 register_t *retval;
288 {
289 struct sys_____semctl13_args /* {
290 syscallarg(int) semid;
291 syscallarg(int) semnum;
292 syscallarg(int) cmd;
293 syscallarg(union __semun *) arg;
294 } */ *uap = v;
295 struct semid_ds sembuf;
296 int cmd, error;
297 void *pass_arg;
298 union __semun karg;
299
300 cmd = SCARG(uap, cmd);
301
302 switch (cmd) {
303 case IPC_SET:
304 case IPC_STAT:
305 pass_arg = &sembuf;
306 break;
307
308 case GETALL:
309 case SETVAL:
310 case SETALL:
311 pass_arg = &karg;
312 break;
313 default:
314 pass_arg = NULL;
315 break;
316 }
317
318 if (pass_arg) {
319 error = copyin(SCARG(uap, arg), &karg, sizeof(karg));
320 if (error)
321 return error;
322 if (cmd == IPC_SET) {
323 error = copyin(karg.buf, &sembuf, sizeof(sembuf));
324 if (error)
325 return (error);
326 }
327 }
328
329 error = semctl1(p, SCARG(uap, semid), SCARG(uap, semnum), cmd,
330 pass_arg, retval);
331
332 if (error == 0 && cmd == IPC_STAT)
333 error = copyout(&sembuf, karg.buf, sizeof(sembuf));
334
335 return (error);
336 }
337
338 int
339 semctl1(p, semid, semnum, cmd, v, retval)
340 struct proc *p;
341 int semid, semnum, cmd;
342 void *v;
343 register_t *retval;
344 {
345 struct ucred *cred = p->p_ucred;
346 union __semun *arg = v;
347 struct semid_ds *sembuf = v, *semaptr;
348 int i, error, ix;
349
350 SEM_PRINTF(("call to semctl(%d, %d, %d, %p)\n",
351 semid, semnum, cmd, v));
352
353 ix = IPCID_TO_IX(semid);
354 if (ix < 0 || ix >= seminfo.semmsl)
355 return (EINVAL);
356
357 semaptr = &sema[ix];
358 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
359 semaptr->sem_perm._seq != IPCID_TO_SEQ(semid))
360 return (EINVAL);
361
362 switch (cmd) {
363 case IPC_RMID:
364 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M)) != 0)
365 return (error);
366 semaptr->sem_perm.cuid = cred->cr_uid;
367 semaptr->sem_perm.uid = cred->cr_uid;
368 semtot -= semaptr->sem_nsems;
369 for (i = semaptr->_sem_base - sem; i < semtot; i++)
370 sem[i] = sem[i + semaptr->sem_nsems];
371 for (i = 0; i < seminfo.semmni; i++) {
372 if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
373 sema[i]._sem_base > semaptr->_sem_base)
374 sema[i]._sem_base -= semaptr->sem_nsems;
375 }
376 semaptr->sem_perm.mode = 0;
377 semundo_clear(ix, -1);
378 wakeup(semaptr);
379 break;
380
381 case IPC_SET:
382 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
383 return (error);
384 semaptr->sem_perm.uid = sembuf->sem_perm.uid;
385 semaptr->sem_perm.gid = sembuf->sem_perm.gid;
386 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
387 (sembuf->sem_perm.mode & 0777);
388 semaptr->sem_ctime = time.tv_sec;
389 break;
390
391 case IPC_STAT:
392 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
393 return (error);
394 memcpy(sembuf, semaptr, sizeof(struct semid_ds));
395 break;
396
397 case GETNCNT:
398 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
399 return (error);
400 if (semnum < 0 || semnum >= semaptr->sem_nsems)
401 return (EINVAL);
402 *retval = semaptr->_sem_base[semnum].semncnt;
403 break;
404
405 case GETPID:
406 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
407 return (error);
408 if (semnum < 0 || semnum >= semaptr->sem_nsems)
409 return (EINVAL);
410 *retval = semaptr->_sem_base[semnum].sempid;
411 break;
412
413 case GETVAL:
414 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
415 return (error);
416 if (semnum < 0 || semnum >= semaptr->sem_nsems)
417 return (EINVAL);
418 *retval = semaptr->_sem_base[semnum].semval;
419 break;
420
421 case GETALL:
422 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
423 return (error);
424 for (i = 0; i < semaptr->sem_nsems; i++) {
425 error = copyout(&semaptr->_sem_base[i].semval,
426 &arg->array[i], sizeof(arg->array[i]));
427 if (error != 0)
428 break;
429 }
430 break;
431
432 case GETZCNT:
433 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
434 return (error);
435 if (semnum < 0 || semnum >= semaptr->sem_nsems)
436 return (EINVAL);
437 *retval = semaptr->_sem_base[semnum].semzcnt;
438 break;
439
440 case SETVAL:
441 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
442 return (error);
443 if (semnum < 0 || semnum >= semaptr->sem_nsems)
444 return (EINVAL);
445 semaptr->_sem_base[semnum].semval = arg->val;
446 semundo_clear(ix, semnum);
447 wakeup(semaptr);
448 break;
449
450 case SETALL:
451 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
452 return (error);
453 for (i = 0; i < semaptr->sem_nsems; i++) {
454 error = copyin(&arg->array[i],
455 &semaptr->_sem_base[i].semval,
456 sizeof(arg->array[i]));
457 if (error != 0)
458 break;
459 }
460 semundo_clear(ix, -1);
461 wakeup(semaptr);
462 break;
463
464 default:
465 return (EINVAL);
466 }
467
468 return (error);
469 }
470
471 int
472 sys_semget(p, v, retval)
473 struct proc *p;
474 void *v;
475 register_t *retval;
476 {
477 struct sys_semget_args /* {
478 syscallarg(key_t) key;
479 syscallarg(int) nsems;
480 syscallarg(int) semflg;
481 } */ *uap = v;
482 int semid, eval;
483 int key = SCARG(uap, key);
484 int nsems = SCARG(uap, nsems);
485 int semflg = SCARG(uap, semflg);
486 struct ucred *cred = p->p_ucred;
487
488 SEM_PRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
489
490 if (key != IPC_PRIVATE) {
491 for (semid = 0; semid < seminfo.semmni; semid++) {
492 if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
493 sema[semid].sem_perm._key == key)
494 break;
495 }
496 if (semid < seminfo.semmni) {
497 SEM_PRINTF(("found public key\n"));
498 if ((eval = ipcperm(cred, &sema[semid].sem_perm,
499 semflg & 0700)))
500 return(eval);
501 if (nsems > 0 && sema[semid].sem_nsems < nsems) {
502 SEM_PRINTF(("too small\n"));
503 return(EINVAL);
504 }
505 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
506 SEM_PRINTF(("not exclusive\n"));
507 return(EEXIST);
508 }
509 goto found;
510 }
511 }
512
513 SEM_PRINTF(("need to allocate the semid_ds\n"));
514 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
515 if (nsems <= 0 || nsems > seminfo.semmsl) {
516 SEM_PRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
517 seminfo.semmsl));
518 return(EINVAL);
519 }
520 if (nsems > seminfo.semmns - semtot) {
521 SEM_PRINTF(("not enough semaphores left (need %d, got %d)\n",
522 nsems, seminfo.semmns - semtot));
523 return(ENOSPC);
524 }
525 for (semid = 0; semid < seminfo.semmni; semid++) {
526 if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
527 break;
528 }
529 if (semid == seminfo.semmni) {
530 SEM_PRINTF(("no more semid_ds's available\n"));
531 return(ENOSPC);
532 }
533 SEM_PRINTF(("semid %d is available\n", semid));
534 sema[semid].sem_perm._key = key;
535 sema[semid].sem_perm.cuid = cred->cr_uid;
536 sema[semid].sem_perm.uid = cred->cr_uid;
537 sema[semid].sem_perm.cgid = cred->cr_gid;
538 sema[semid].sem_perm.gid = cred->cr_gid;
539 sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
540 sema[semid].sem_perm._seq =
541 (sema[semid].sem_perm._seq + 1) & 0x7fff;
542 sema[semid].sem_nsems = nsems;
543 sema[semid].sem_otime = 0;
544 sema[semid].sem_ctime = time.tv_sec;
545 sema[semid]._sem_base = &sem[semtot];
546 semtot += nsems;
547 memset(sema[semid]._sem_base, 0,
548 sizeof(sema[semid]._sem_base[0])*nsems);
549 SEM_PRINTF(("sembase = %p, next = %p\n", sema[semid]._sem_base,
550 &sem[semtot]));
551 } else {
552 SEM_PRINTF(("didn't find it and wasn't asked to create it\n"));
553 return(ENOENT);
554 }
555
556 found:
557 *retval = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
558 return(0);
559 }
560
561 int
562 sys_semop(p, v, retval)
563 struct proc *p;
564 void *v;
565 register_t *retval;
566 {
567 struct sys_semop_args /* {
568 syscallarg(int) semid;
569 syscallarg(struct sembuf *) sops;
570 syscallarg(size_t) nsops;
571 } */ *uap = v;
572 int semid = SCARG(uap, semid);
573 int nsops = SCARG(uap, nsops);
574 struct sembuf sops[MAX_SOPS];
575 struct semid_ds *semaptr;
576 struct sembuf *sopptr = NULL;
577 struct __sem *semptr = NULL;
578 struct sem_undo *suptr = NULL;
579 struct ucred *cred = p->p_ucred;
580 int i, j, eval;
581 int do_wakeup, do_undos;
582
583 SEM_PRINTF(("call to semop(%d, %p, %d)\n", semid, sops, nsops));
584
585 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */
586
587 if (semid < 0 || semid >= seminfo.semmsl)
588 return(EINVAL);
589
590 semaptr = &sema[semid];
591 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
592 semaptr->sem_perm._seq != IPCID_TO_SEQ(SCARG(uap, semid)))
593 return(EINVAL);
594
595 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
596 SEM_PRINTF(("eval = %d from ipaccess\n", eval));
597 return(eval);
598 }
599
600 if (nsops > MAX_SOPS) {
601 SEM_PRINTF(("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops));
602 return(E2BIG);
603 }
604
605 if ((eval = copyin(SCARG(uap, sops), sops, nsops * sizeof(sops[0])))
606 != 0) {
607 SEM_PRINTF(("eval = %d from copyin(%p, %p, %d)\n", eval,
608 SCARG(uap, sops), &sops, nsops * sizeof(sops[0])));
609 return(eval);
610 }
611
612 /*
613 * Loop trying to satisfy the vector of requests.
614 * If we reach a point where we must wait, any requests already
615 * performed are rolled back and we go to sleep until some other
616 * process wakes us up. At this point, we start all over again.
617 *
618 * This ensures that from the perspective of other tasks, a set
619 * of requests is atomic (never partially satisfied).
620 */
621 do_undos = 0;
622
623 for (;;) {
624 do_wakeup = 0;
625
626 for (i = 0; i < nsops; i++) {
627 sopptr = &sops[i];
628
629 if (sopptr->sem_num >= semaptr->sem_nsems)
630 return(EFBIG);
631
632 semptr = &semaptr->_sem_base[sopptr->sem_num];
633
634 SEM_PRINTF(("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
635 semaptr, semaptr->_sem_base, semptr,
636 sopptr->sem_num, semptr->semval, sopptr->sem_op,
637 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"));
638
639 if (sopptr->sem_op < 0) {
640 if ((int)(semptr->semval +
641 sopptr->sem_op) < 0) {
642 SEM_PRINTF(("semop: can't do it now\n"));
643 break;
644 } else {
645 semptr->semval += sopptr->sem_op;
646 if (semptr->semval == 0 &&
647 semptr->semzcnt > 0)
648 do_wakeup = 1;
649 }
650 if (sopptr->sem_flg & SEM_UNDO)
651 do_undos = 1;
652 } else if (sopptr->sem_op == 0) {
653 if (semptr->semval > 0) {
654 SEM_PRINTF(("semop: not zero now\n"));
655 break;
656 }
657 } else {
658 if (semptr->semncnt > 0)
659 do_wakeup = 1;
660 semptr->semval += sopptr->sem_op;
661 if (sopptr->sem_flg & SEM_UNDO)
662 do_undos = 1;
663 }
664 }
665
666 /*
667 * Did we get through the entire vector?
668 */
669 if (i >= nsops)
670 goto done;
671
672 /*
673 * No ... rollback anything that we've already done
674 */
675 SEM_PRINTF(("semop: rollback 0 through %d\n", i-1));
676 for (j = 0; j < i; j++)
677 semaptr->_sem_base[sops[j].sem_num].semval -=
678 sops[j].sem_op;
679
680 /*
681 * If the request that we couldn't satisfy has the
682 * NOWAIT flag set then return with EAGAIN.
683 */
684 if (sopptr->sem_flg & IPC_NOWAIT)
685 return(EAGAIN);
686
687 if (sopptr->sem_op == 0)
688 semptr->semzcnt++;
689 else
690 semptr->semncnt++;
691
692 SEM_PRINTF(("semop: good night!\n"));
693 eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH,
694 "semwait", 0);
695 SEM_PRINTF(("semop: good morning (eval=%d)!\n", eval));
696
697 suptr = NULL; /* sem_undo may have been reallocated */
698
699 if (eval != 0)
700 return(EINTR);
701 SEM_PRINTF(("semop: good morning!\n"));
702
703 /*
704 * Make sure that the semaphore still exists
705 */
706 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
707 semaptr->sem_perm._seq != IPCID_TO_SEQ(SCARG(uap, semid))) {
708 /* The man page says to return EIDRM. */
709 /* Unfortunately, BSD doesn't define that code! */
710 #ifdef EIDRM
711 return(EIDRM);
712 #else
713 return(EINVAL);
714 #endif
715 }
716
717 /*
718 * The semaphore is still alive. Readjust the count of
719 * waiting processes.
720 */
721 if (sopptr->sem_op == 0)
722 semptr->semzcnt--;
723 else
724 semptr->semncnt--;
725 }
726
727 done:
728 /*
729 * Process any SEM_UNDO requests.
730 */
731 if (do_undos) {
732 for (i = 0; i < nsops; i++) {
733 /*
734 * We only need to deal with SEM_UNDO's for non-zero
735 * op's.
736 */
737 int adjval;
738
739 if ((sops[i].sem_flg & SEM_UNDO) == 0)
740 continue;
741 adjval = sops[i].sem_op;
742 if (adjval == 0)
743 continue;
744 eval = semundo_adjust(p, &suptr, semid,
745 sops[i].sem_num, -adjval);
746 if (eval == 0)
747 continue;
748
749 /*
750 * Oh-Oh! We ran out of either sem_undo's or undo's.
751 * Rollback the adjustments to this point and then
752 * rollback the semaphore ups and down so we can return
753 * with an error with all structures restored. We
754 * rollback the undo's in the exact reverse order that
755 * we applied them. This guarantees that we won't run
756 * out of space as we roll things back out.
757 */
758 for (j = i - 1; j >= 0; j--) {
759 if ((sops[j].sem_flg & SEM_UNDO) == 0)
760 continue;
761 adjval = sops[j].sem_op;
762 if (adjval == 0)
763 continue;
764 if (semundo_adjust(p, &suptr, semid,
765 sops[j].sem_num, adjval) != 0)
766 panic("semop - can't undo undos");
767 }
768
769 for (j = 0; j < nsops; j++)
770 semaptr->_sem_base[sops[j].sem_num].semval -=
771 sops[j].sem_op;
772
773 SEM_PRINTF(("eval = %d from semundo_adjust\n", eval));
774 return(eval);
775 } /* loop through the sops */
776 } /* if (do_undos) */
777
778 /* We're definitely done - set the sempid's */
779 for (i = 0; i < nsops; i++) {
780 sopptr = &sops[i];
781 semptr = &semaptr->_sem_base[sopptr->sem_num];
782 semptr->sempid = p->p_pid;
783 }
784
785 /* Do a wakeup if any semaphore was up'd. */
786 if (do_wakeup) {
787 SEM_PRINTF(("semop: doing wakeup\n"));
788 #ifdef SEM_WAKEUP
789 sem_wakeup((caddr_t)semaptr);
790 #else
791 wakeup((caddr_t)semaptr);
792 #endif
793 SEM_PRINTF(("semop: back from wakeup\n"));
794 }
795 SEM_PRINTF(("semop: done\n"));
796 *retval = 0;
797 return(0);
798 }
799
800 /*
801 * Go through the undo structures for this process and apply the adjustments to
802 * semaphores.
803 */
804 void
805 semexit(p)
806 struct proc *p;
807 {
808 struct sem_undo *suptr;
809 struct sem_undo **supptr;
810
811 /*
812 * Go through the chain of undo vectors looking for one associated with
813 * this process.
814 */
815
816 for (supptr = &semu_list; (suptr = *supptr) != NULL;
817 supptr = &suptr->un_next) {
818 if (suptr->un_proc == p)
819 break;
820 }
821
822 /*
823 * If there is no undo vector, skip to the end.
824 */
825
826 if (suptr == NULL)
827 return;
828
829 /*
830 * We now have an undo vector for this process.
831 */
832
833 SEM_PRINTF(("proc @%p has undo structure with %d entries\n", p,
834 suptr->un_cnt));
835
836 /*
837 * If there are any active undo elements then process them.
838 */
839 if (suptr->un_cnt > 0) {
840 int ix;
841
842 for (ix = 0; ix < suptr->un_cnt; ix++) {
843 int semid = suptr->un_ent[ix].un_id;
844 int semnum = suptr->un_ent[ix].un_num;
845 int adjval = suptr->un_ent[ix].un_adjval;
846 struct semid_ds *semaptr;
847
848 semaptr = &sema[semid];
849 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
850 panic("semexit - semid not allocated");
851 if (semnum >= semaptr->sem_nsems)
852 panic("semexit - semnum out of range");
853
854 SEM_PRINTF(("semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n",
855 suptr->un_proc, suptr->un_ent[ix].un_id,
856 suptr->un_ent[ix].un_num,
857 suptr->un_ent[ix].un_adjval,
858 semaptr->_sem_base[semnum].semval));
859
860 if (adjval < 0 &&
861 semaptr->_sem_base[semnum].semval < -adjval)
862 semaptr->_sem_base[semnum].semval = 0;
863 else
864 semaptr->_sem_base[semnum].semval += adjval;
865
866 #ifdef SEM_WAKEUP
867 sem_wakeup((caddr_t)semaptr);
868 #else
869 wakeup((caddr_t)semaptr);
870 #endif
871 SEM_PRINTF(("semexit: back from wakeup\n"));
872 }
873 }
874
875 /*
876 * Deallocate the undo vector.
877 */
878 SEM_PRINTF(("removing vector\n"));
879 suptr->un_proc = NULL;
880 *supptr = suptr->un_next;
881 }
882