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