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