Annotation of sys/kern/sysv_sem.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sysv_sem.c,v 1.33 2006/08/10 17:03:48 millert Exp $ */
2: /* $NetBSD: sysv_sem.c,v 1.26 1996/02/09 19:00:25 christos Exp $ */
3:
4: /*
5: * Copyright (c) 2002,2003 Todd C. Miller <Todd.Miller@courtesan.com>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: *
19: * Sponsored in part by the Defense Advanced Research Projects
20: * Agency (DARPA) and Air Force Research Laboratory, Air Force
21: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22: */
23: /*
24: * Implementation of SVID semaphores
25: *
26: * Author: Daniel Boulet
27: *
28: * This software is provided ``AS IS'' without any warranties of any kind.
29: */
30:
31: #include <sys/param.h>
32: #include <sys/systm.h>
33: #include <sys/kernel.h>
34: #include <sys/proc.h>
35: #include <sys/sem.h>
36: #include <sys/sysctl.h>
37: #include <sys/malloc.h>
38: #include <sys/pool.h>
39:
40: #include <sys/mount.h>
41: #include <sys/syscallargs.h>
42:
43: /* SVID defines EIDRM but BSD does not */
44: #ifndef EIDRM
45: #define EIDRM EINVAL
46: #endif
47:
48: #ifdef SEM_DEBUG
49: #define DPRINTF(x) printf x
50: #else
51: #define DPRINTF(x)
52: #endif
53:
54: int semtot = 0;
55: int semutot = 0;
56: struct semid_ds **sema; /* semaphore id list */
57: SLIST_HEAD(, sem_undo) semu_list; /* list of undo structures */
58: struct pool sema_pool; /* pool for struct semid_ds */
59: struct pool semu_pool; /* pool for struct sem_undo (SEMUSZ) */
60: unsigned short *semseqs; /* array of sem sequence numbers */
61:
62: struct sem_undo *semu_alloc(struct proc *);
63: int semundo_adjust(struct proc *, struct sem_undo **, int, int, int);
64: void semundo_clear(int, int);
65:
66: void
67: seminit(void)
68: {
69:
70: pool_init(&sema_pool, sizeof(struct semid_ds), 0, 0, 0, "semapl",
71: &pool_allocator_nointr);
72: pool_init(&semu_pool, SEMUSZ, 0, 0, 0, "semupl",
73: &pool_allocator_nointr);
74: sema = malloc(seminfo.semmni * sizeof(struct semid_ds *),
75: M_SEM, M_WAITOK);
76: bzero(sema, seminfo.semmni * sizeof(struct semid_ds *));
77: semseqs = malloc(seminfo.semmni * sizeof(unsigned short),
78: M_SEM, M_WAITOK);
79: bzero(semseqs, seminfo.semmni * sizeof(unsigned short));
80: SLIST_INIT(&semu_list);
81: }
82:
83: /*
84: * Allocate a new sem_undo structure for a process
85: * (returns ptr to structure or NULL if no more room)
86: */
87: struct sem_undo *
88: semu_alloc(struct proc *p)
89: {
90: struct sem_undo *suptr, *sutmp;
91:
92: if (semutot == seminfo.semmnu)
93: return (NULL); /* no space */
94:
95: /*
96: * Allocate a semu w/o waiting if possible.
97: * If we do have to wait, we must check to verify that a semu
98: * with un_proc == p has not been allocated in the meantime.
99: */
100: semutot++;
101: if ((suptr = pool_get(&semu_pool, 0)) == NULL) {
102: sutmp = pool_get(&semu_pool, PR_WAITOK);
103: SLIST_FOREACH(suptr, &semu_list, un_next) {
104: if (suptr->un_proc == p) {
105: pool_put(&semu_pool, sutmp);
106: semutot--;
107: return (suptr);
108: }
109: }
110: suptr = sutmp;
111: }
112: suptr->un_cnt = 0;
113: suptr->un_proc = p;
114: SLIST_INSERT_HEAD(&semu_list, suptr, un_next);
115: return (suptr);
116: }
117:
118: /*
119: * Adjust a particular entry for a particular proc
120: */
121: int
122: semundo_adjust(struct proc *p, struct sem_undo **supptr, int semid, int semnum,
123: int adjval)
124: {
125: struct sem_undo *suptr;
126: struct undo *sunptr;
127: int i;
128:
129: /*
130: * Look for and remember the sem_undo if the caller doesn't provide it.
131: */
132: suptr = *supptr;
133: if (suptr == NULL) {
134: SLIST_FOREACH(suptr, &semu_list, un_next) {
135: if (suptr->un_proc == p) {
136: *supptr = suptr;
137: break;
138: }
139: }
140: if (suptr == NULL) {
141: if (adjval == 0)
142: return (0);
143: suptr = semu_alloc(p);
144: if (suptr == NULL)
145: return (ENOSPC);
146: *supptr = suptr;
147: }
148: }
149:
150: /*
151: * Look for the requested entry and adjust it
152: * (delete if adjval becomes 0).
153: */
154: sunptr = &suptr->un_ent[0];
155: for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
156: if (sunptr->un_id != semid || sunptr->un_num != semnum)
157: continue;
158: if (adjval == 0)
159: sunptr->un_adjval = 0;
160: else
161: sunptr->un_adjval += adjval;
162: if (sunptr->un_adjval != 0)
163: return (0);
164:
165: if (--suptr->un_cnt == 0) {
166: SLIST_REMOVE(&semu_list, suptr, sem_undo, un_next);
167: pool_put(&semu_pool, suptr);
168: semutot--;
169: } else if (i < suptr->un_cnt)
170: suptr->un_ent[i] =
171: suptr->un_ent[suptr->un_cnt];
172: return (0);
173: }
174:
175: /* Didn't find the right entry - create it */
176: if (adjval == 0)
177: return (0);
178: if (suptr->un_cnt == SEMUME)
179: return (EINVAL);
180:
181: sunptr = &suptr->un_ent[suptr->un_cnt];
182: suptr->un_cnt++;
183: sunptr->un_adjval = adjval;
184: sunptr->un_id = semid;
185: sunptr->un_num = semnum;
186: return (0);
187: }
188:
189: void
190: semundo_clear(int semid, int semnum)
191: {
192: struct sem_undo *suptr = SLIST_FIRST(&semu_list);
193: struct sem_undo *suprev = SLIST_END(&semu_list);
194: struct undo *sunptr;
195: int i;
196:
197: while (suptr != SLIST_END(&semu_list)) {
198: sunptr = &suptr->un_ent[0];
199: for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
200: if (sunptr->un_id == semid) {
201: if (semnum == -1 || sunptr->un_num == semnum) {
202: suptr->un_cnt--;
203: if (i < suptr->un_cnt) {
204: suptr->un_ent[i] =
205: suptr->un_ent[suptr->un_cnt];
206: i--, sunptr--;
207: }
208: }
209: if (semnum != -1)
210: break;
211: }
212: }
213: if (suptr->un_cnt == 0) {
214: struct sem_undo *sutmp = suptr;
215:
216: if (suptr == SLIST_FIRST(&semu_list))
217: SLIST_REMOVE_HEAD(&semu_list, un_next);
218: else
219: SLIST_REMOVE_NEXT(&semu_list, suprev, un_next);
220: suptr = SLIST_NEXT(suptr, un_next);
221: pool_put(&semu_pool, sutmp);
222: semutot--;
223: } else {
224: suprev = suptr;
225: suptr = SLIST_NEXT(suptr, un_next);
226: }
227: }
228: }
229:
230: int
231: sys___semctl(struct proc *p, void *v, register_t *retval)
232: {
233: struct sys___semctl_args /* {
234: syscallarg(int) semid;
235: syscallarg(int) semnum;
236: syscallarg(int) cmd;
237: syscallarg(union semun *) arg;
238: } */ *uap = v;
239: union semun arg;
240: int error = 0, cmd = SCARG(uap, cmd);
241:
242: switch (cmd) {
243: case IPC_SET:
244: case IPC_STAT:
245: case GETALL:
246: case SETVAL:
247: case SETALL:
248: error = copyin(SCARG(uap, arg), &arg, sizeof(arg));
249: break;
250: }
251: if (error == 0) {
252: error = semctl1(p, SCARG(uap, semid), SCARG(uap, semnum),
253: cmd, &arg, retval, copyin, copyout);
254: }
255: return (error);
256: }
257:
258: int
259: semctl1(struct proc *p, int semid, int semnum, int cmd, union semun *arg,
260: register_t *retval, int (*ds_copyin)(const void *, void *, size_t),
261: int (*ds_copyout)(const void *, void *, size_t))
262: {
263: struct ucred *cred = p->p_ucred;
264: int i, ix, error = 0;
265: struct semid_ds sbuf;
266: struct semid_ds *semaptr;
267:
268: DPRINTF(("call to semctl(%d, %d, %d, %p)\n", semid, semnum, cmd, arg));
269:
270: ix = IPCID_TO_IX(semid);
271: if (ix < 0 || ix >= seminfo.semmni)
272: return (EINVAL);
273:
274: if ((semaptr = sema[ix]) == NULL ||
275: semaptr->sem_perm.seq != IPCID_TO_SEQ(semid))
276: return (EINVAL);
277:
278: switch (cmd) {
279: case IPC_RMID:
280: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M)) != 0)
281: return (error);
282: semaptr->sem_perm.cuid = cred->cr_uid;
283: semaptr->sem_perm.uid = cred->cr_uid;
284: semtot -= semaptr->sem_nsems;
285: free(semaptr->sem_base, M_SEM);
286: pool_put(&sema_pool, semaptr);
287: sema[ix] = NULL;
288: semundo_clear(ix, -1);
289: wakeup(&sema[ix]);
290: break;
291:
292: case IPC_SET:
293: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
294: return (error);
295: if ((error = ds_copyin(arg->buf, &sbuf, sizeof(sbuf))) != 0)
296: return (error);
297: semaptr->sem_perm.uid = sbuf.sem_perm.uid;
298: semaptr->sem_perm.gid = sbuf.sem_perm.gid;
299: semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
300: (sbuf.sem_perm.mode & 0777);
301: semaptr->sem_ctime = time_second;
302: break;
303:
304: case IPC_STAT:
305: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
306: return (error);
307: error = ds_copyout(semaptr, arg->buf, sizeof(struct semid_ds));
308: break;
309:
310: case GETNCNT:
311: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
312: return (error);
313: if (semnum < 0 || semnum >= semaptr->sem_nsems)
314: return (EINVAL);
315: *retval = semaptr->sem_base[semnum].semncnt;
316: break;
317:
318: case GETPID:
319: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
320: return (error);
321: if (semnum < 0 || semnum >= semaptr->sem_nsems)
322: return (EINVAL);
323: *retval = semaptr->sem_base[semnum].sempid;
324: break;
325:
326: case GETVAL:
327: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
328: return (error);
329: if (semnum < 0 || semnum >= semaptr->sem_nsems)
330: return (EINVAL);
331: *retval = semaptr->sem_base[semnum].semval;
332: break;
333:
334: case GETALL:
335: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
336: return (error);
337: for (i = 0; i < semaptr->sem_nsems; i++) {
338: error = ds_copyout(&semaptr->sem_base[i].semval,
339: &arg->array[i], sizeof(arg->array[0]));
340: if (error != 0)
341: break;
342: }
343: break;
344:
345: case GETZCNT:
346: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
347: return (error);
348: if (semnum < 0 || semnum >= semaptr->sem_nsems)
349: return (EINVAL);
350: *retval = semaptr->sem_base[semnum].semzcnt;
351: break;
352:
353: case SETVAL:
354: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
355: return (error);
356: if (semnum < 0 || semnum >= semaptr->sem_nsems)
357: return (EINVAL);
358: semaptr->sem_base[semnum].semval = arg->val;
359: semundo_clear(ix, semnum);
360: wakeup(&sema[ix]);
361: break;
362:
363: case SETALL:
364: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
365: return (error);
366: for (i = 0; i < semaptr->sem_nsems; i++) {
367: error = ds_copyin(&arg->array[i],
368: &semaptr->sem_base[i].semval,
369: sizeof(arg->array[0]));
370: if (error != 0)
371: break;
372: }
373: semundo_clear(ix, -1);
374: wakeup(&sema[ix]);
375: break;
376:
377: default:
378: return (EINVAL);
379: }
380:
381: return (error);
382: }
383:
384: int
385: sys_semget(struct proc *p, void *v, register_t *retval)
386: {
387: struct sys_semget_args /* {
388: syscallarg(key_t) key;
389: syscallarg(int) nsems;
390: syscallarg(int) semflg;
391: } */ *uap = v;
392: int semid, error;
393: int key = SCARG(uap, key);
394: int nsems = SCARG(uap, nsems);
395: int semflg = SCARG(uap, semflg);
396: struct semid_ds *semaptr, *semaptr_new = NULL;
397: struct ucred *cred = p->p_ucred;
398:
399: DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
400:
401: /*
402: * Preallocate space for the new semaphore. If we are going
403: * to sleep, we want to sleep now to eliminate any race
404: * condition in allocating a semaphore with a specific key.
405: */
406: if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
407: if (nsems <= 0 || nsems > seminfo.semmsl) {
408: DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
409: seminfo.semmsl));
410: return (EINVAL);
411: }
412: if (nsems > seminfo.semmns - semtot) {
413: DPRINTF(("not enough semaphores left (need %d, got %d)\n",
414: nsems, seminfo.semmns - semtot));
415: return (ENOSPC);
416: }
417: semaptr_new = pool_get(&sema_pool, PR_WAITOK);
418: semaptr_new->sem_base = malloc(nsems * sizeof(struct sem),
419: M_SEM, M_WAITOK);
420: bzero(semaptr_new->sem_base, nsems * sizeof(struct sem));
421: }
422:
423: if (key != IPC_PRIVATE) {
424: for (semid = 0, semaptr = NULL; semid < seminfo.semmni; semid++) {
425: if ((semaptr = sema[semid]) != NULL &&
426: semaptr->sem_perm.key == key) {
427: DPRINTF(("found public key\n"));
428: if ((error = ipcperm(cred, &semaptr->sem_perm,
429: semflg & 0700)))
430: goto error;
431: if (nsems > 0 && semaptr->sem_nsems < nsems) {
432: DPRINTF(("too small\n"));
433: error = EINVAL;
434: goto error;
435: }
436: if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
437: DPRINTF(("not exclusive\n"));
438: error = EEXIST;
439: goto error;
440: }
441: goto found;
442: }
443: }
444: }
445:
446: DPRINTF(("need to allocate the semid_ds\n"));
447: if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
448: for (semid = 0; semid < seminfo.semmni; semid++) {
449: if ((semaptr = sema[semid]) == NULL)
450: break;
451: }
452: if (semid == seminfo.semmni) {
453: DPRINTF(("no more semid_ds's available\n"));
454: error = ENOSPC;
455: goto error;
456: }
457: DPRINTF(("semid %d is available\n", semid));
458: semaptr_new->sem_perm.key = key;
459: semaptr_new->sem_perm.cuid = cred->cr_uid;
460: semaptr_new->sem_perm.uid = cred->cr_uid;
461: semaptr_new->sem_perm.cgid = cred->cr_gid;
462: semaptr_new->sem_perm.gid = cred->cr_gid;
463: semaptr_new->sem_perm.mode = (semflg & 0777);
464: semaptr_new->sem_perm.seq = semseqs[semid] =
465: (semseqs[semid] + 1) & 0x7fff;
466: semaptr_new->sem_nsems = nsems;
467: semaptr_new->sem_otime = 0;
468: semaptr_new->sem_ctime = time_second;
469: sema[semid] = semaptr_new;
470: semtot += nsems;
471: } else {
472: DPRINTF(("didn't find it and wasn't asked to create it\n"));
473: return (ENOENT);
474: }
475:
476: found:
477: *retval = IXSEQ_TO_IPCID(semid, sema[semid]->sem_perm);
478: return (0);
479: error:
480: if (semaptr_new != NULL) {
481: free(semaptr_new->sem_base, M_SEM);
482: pool_put(&sema_pool, semaptr_new);
483: }
484: return (error);
485: }
486:
487: int
488: sys_semop(struct proc *p, void *v, register_t *retval)
489: {
490: struct sys_semop_args /* {
491: syscallarg(int) semid;
492: syscallarg(struct sembuf *) sops;
493: syscallarg(size_t) nsops;
494: } */ *uap = v;
495: #define NSOPS 8
496: struct sembuf sopbuf[NSOPS];
497: int semid = SCARG(uap, semid);
498: size_t nsops = SCARG(uap, nsops);
499: struct sembuf *sops;
500: struct semid_ds *semaptr;
501: struct sembuf *sopptr = NULL;
502: struct sem *semptr = NULL;
503: struct sem_undo *suptr = NULL;
504: struct ucred *cred = p->p_ucred;
505: size_t i, j;
506: int do_wakeup, do_undos, error;
507:
508: DPRINTF(("call to semop(%d, %p, %lu)\n", semid, SCARG(uap, sops),
509: (u_long)nsops));
510:
511: semid = IPCID_TO_IX(semid); /* Convert back to zero origin */
512:
513: if (semid < 0 || semid >= seminfo.semmni)
514: return (EINVAL);
515:
516: if ((semaptr = sema[semid]) == NULL ||
517: semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid)))
518: return (EINVAL);
519:
520: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
521: DPRINTF(("error = %d from ipaccess\n", error));
522: return (error);
523: }
524:
525: if (nsops == 0) {
526: *retval = 0;
527: return (0);
528: } else if (nsops > (size_t)seminfo.semopm) {
529: DPRINTF(("too many sops (max=%d, nsops=%lu)\n", seminfo.semopm,
530: (u_long)nsops));
531: return (E2BIG);
532: }
533:
534: if (nsops <= NSOPS)
535: sops = sopbuf;
536: else
537: sops = malloc(nsops * sizeof(struct sembuf), M_SEM, M_WAITOK);
538: error = copyin(SCARG(uap, sops), sops, nsops * sizeof(struct sembuf));
539: if (error != 0) {
540: DPRINTF(("error = %d from copyin(%p, %p, %u)\n", error,
541: SCARG(uap, sops), &sops, nsops * sizeof(struct sembuf)));
542: goto done2;
543: }
544:
545: /*
546: * Loop trying to satisfy the vector of requests.
547: * If we reach a point where we must wait, any requests already
548: * performed are rolled back and we go to sleep until some other
549: * process wakes us up. At this point, we start all over again.
550: *
551: * This ensures that from the perspective of other tasks, a set
552: * of requests is atomic (never partially satisfied).
553: */
554: do_undos = 0;
555:
556: for (;;) {
557: do_wakeup = 0;
558:
559: for (i = 0; i < nsops; i++) {
560: sopptr = &sops[i];
561:
562: if (sopptr->sem_num >= semaptr->sem_nsems) {
563: error = EFBIG;
564: goto done2;
565: }
566:
567: semptr = &semaptr->sem_base[sopptr->sem_num];
568:
569: DPRINTF(("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
570: semaptr, semaptr->sem_base, semptr,
571: sopptr->sem_num, semptr->semval, sopptr->sem_op,
572: (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"));
573:
574: if (sopptr->sem_op < 0) {
575: if ((int)(semptr->semval +
576: sopptr->sem_op) < 0) {
577: DPRINTF(("semop: can't do it now\n"));
578: break;
579: } else {
580: semptr->semval += sopptr->sem_op;
581: if (semptr->semval == 0 &&
582: semptr->semzcnt > 0)
583: do_wakeup = 1;
584: }
585: if (sopptr->sem_flg & SEM_UNDO)
586: do_undos = 1;
587: } else if (sopptr->sem_op == 0) {
588: if (semptr->semval > 0) {
589: DPRINTF(("semop: not zero now\n"));
590: break;
591: }
592: } else {
593: if (semptr->semncnt > 0)
594: do_wakeup = 1;
595: semptr->semval += sopptr->sem_op;
596: if (sopptr->sem_flg & SEM_UNDO)
597: do_undos = 1;
598: }
599: }
600:
601: /*
602: * Did we get through the entire vector?
603: */
604: if (i >= nsops)
605: goto done;
606:
607: /*
608: * No ... rollback anything that we've already done
609: */
610: DPRINTF(("semop: rollback 0 through %d\n", i - 1));
611: for (j = 0; j < i; j++)
612: semaptr->sem_base[sops[j].sem_num].semval -=
613: sops[j].sem_op;
614:
615: /*
616: * If the request that we couldn't satisfy has the
617: * NOWAIT flag set then return with EAGAIN.
618: */
619: if (sopptr->sem_flg & IPC_NOWAIT) {
620: error = EAGAIN;
621: goto done2;
622: }
623:
624: if (sopptr->sem_op == 0)
625: semptr->semzcnt++;
626: else
627: semptr->semncnt++;
628:
629: DPRINTF(("semop: good night!\n"));
630: error = tsleep(&sema[semid], PLOCK | PCATCH,
631: "semwait", 0);
632: DPRINTF(("semop: good morning (error=%d)!\n", error));
633:
634: suptr = NULL; /* sem_undo may have been reallocated */
635:
636: /*
637: * Make sure that the semaphore still exists
638: */
639: if (sema[semid] == NULL ||
640: semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))) {
641: error = EIDRM;
642: goto done2;
643: }
644:
645: /*
646: * The semaphore is still alive. Readjust the count of
647: * waiting processes.
648: */
649: if (sopptr->sem_op == 0)
650: semptr->semzcnt--;
651: else
652: semptr->semncnt--;
653:
654: /*
655: * Is it really morning, or was our sleep interrupted?
656: * (Delayed check of tsleep() return code because we
657: * need to decrement sem[nz]cnt either way.)
658: */
659: if (error != 0) {
660: error = EINTR;
661: goto done2;
662: }
663: DPRINTF(("semop: good morning!\n"));
664: }
665:
666: done:
667: /*
668: * Process any SEM_UNDO requests.
669: */
670: if (do_undos) {
671: for (i = 0; i < nsops; i++) {
672: /*
673: * We only need to deal with SEM_UNDO's for non-zero
674: * op's.
675: */
676: int adjval;
677:
678: if ((sops[i].sem_flg & SEM_UNDO) == 0)
679: continue;
680: adjval = sops[i].sem_op;
681: if (adjval == 0)
682: continue;
683: error = semundo_adjust(p, &suptr, semid,
684: sops[i].sem_num, -adjval);
685: if (error == 0)
686: continue;
687:
688: /*
689: * Uh-Oh! We ran out of either sem_undo's or undo's.
690: * Rollback the adjustments to this point and then
691: * rollback the semaphore ups and down so we can return
692: * with an error with all structures restored. We
693: * rollback the undo's in the exact reverse order that
694: * we applied them. This guarantees that we won't run
695: * out of space as we roll things back out.
696: */
697: if (i != 0) {
698: for (j = i - 1; j >= 0; j--) {
699: if ((sops[j].sem_flg & SEM_UNDO) == 0)
700: continue;
701: adjval = sops[j].sem_op;
702: if (adjval == 0)
703: continue;
704: if (semundo_adjust(p, &suptr, semid,
705: sops[j].sem_num, adjval) != 0)
706: panic("semop - can't undo undos");
707: }
708: }
709:
710: for (j = 0; j < nsops; j++)
711: semaptr->sem_base[sops[j].sem_num].semval -=
712: sops[j].sem_op;
713:
714: DPRINTF(("error = %d from semundo_adjust\n", error));
715: goto done2;
716: } /* loop through the sops */
717: } /* if (do_undos) */
718:
719: /* We're definitely done - set the sempid's */
720: for (i = 0; i < nsops; i++) {
721: sopptr = &sops[i];
722: semptr = &semaptr->sem_base[sopptr->sem_num];
723: semptr->sempid = p->p_pid;
724: }
725:
726: /* Do a wakeup if any semaphore was up'd. */
727: if (do_wakeup) {
728: DPRINTF(("semop: doing wakeup\n"));
729: wakeup(&sema[semid]);
730: DPRINTF(("semop: back from wakeup\n"));
731: }
732: DPRINTF(("semop: done\n"));
733: *retval = 0;
734: done2:
735: if (sops != sopbuf)
736: free(sops, M_SEM);
737: return (error);
738: }
739:
740: /*
741: * Go through the undo structures for this process and apply the adjustments to
742: * semaphores.
743: */
744: void
745: semexit(struct proc *p)
746: {
747: struct sem_undo *suptr;
748: struct sem_undo **supptr;
749:
750: /*
751: * Go through the chain of undo vectors looking for one associated with
752: * this process.
753: */
754: SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, un_next) {
755: if (suptr->un_proc == p)
756: break;
757: }
758:
759: /*
760: * If there is no undo vector, skip to the end.
761: */
762: if (suptr == NULL)
763: return;
764:
765: /*
766: * We now have an undo vector for this process.
767: */
768: DPRINTF(("proc @%p has undo structure with %d entries\n", p,
769: suptr->un_cnt));
770:
771: /*
772: * If there are any active undo elements then process them.
773: */
774: if (suptr->un_cnt > 0) {
775: int ix;
776:
777: for (ix = 0; ix < suptr->un_cnt; ix++) {
778: int semid = suptr->un_ent[ix].un_id;
779: int semnum = suptr->un_ent[ix].un_num;
780: int adjval = suptr->un_ent[ix].un_adjval;
781: struct semid_ds *semaptr;
782:
783: if ((semaptr = sema[semid]) == NULL)
784: panic("semexit - semid not allocated");
785: if (semnum >= semaptr->sem_nsems)
786: panic("semexit - semnum out of range");
787:
788: DPRINTF(("semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n",
789: suptr->un_proc, suptr->un_ent[ix].un_id,
790: suptr->un_ent[ix].un_num,
791: suptr->un_ent[ix].un_adjval,
792: semaptr->sem_base[semnum].semval));
793:
794: if (adjval < 0 &&
795: semaptr->sem_base[semnum].semval < -adjval)
796: semaptr->sem_base[semnum].semval = 0;
797: else
798: semaptr->sem_base[semnum].semval += adjval;
799:
800: wakeup(&sema[semid]);
801: DPRINTF(("semexit: back from wakeup\n"));
802: }
803: }
804:
805: /*
806: * Deallocate the undo vector.
807: */
808: DPRINTF(("removing vector\n"));
809: *supptr = SLIST_NEXT(suptr, un_next);
810: pool_put(&semu_pool, suptr);
811: semutot--;
812: }
813:
814: /*
815: * Userland access to struct seminfo.
816: */
817: int
818: sysctl_sysvsem(int *name, u_int namelen, void *oldp, size_t *oldlenp,
819: void *newp, size_t newlen)
820: {
821: int error, val;
822: struct semid_ds **sema_new;
823: unsigned short *newseqs;
824:
825: if (namelen != 2) {
826: switch (name[0]) {
827: case KERN_SEMINFO_SEMMNI:
828: case KERN_SEMINFO_SEMMNS:
829: case KERN_SEMINFO_SEMMNU:
830: case KERN_SEMINFO_SEMMSL:
831: case KERN_SEMINFO_SEMOPM:
832: case KERN_SEMINFO_SEMUME:
833: case KERN_SEMINFO_SEMUSZ:
834: case KERN_SEMINFO_SEMVMX:
835: case KERN_SEMINFO_SEMAEM:
836: break;
837: default:
838: return (ENOTDIR); /* overloaded */
839: }
840: }
841:
842: switch (name[0]) {
843: case KERN_SEMINFO_SEMMNI:
844: val = seminfo.semmni;
845: if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) ||
846: val == seminfo.semmni)
847: return (error);
848:
849: if (val < seminfo.semmni || val > 0xffff)
850: return (EINVAL);
851:
852: /* Expand semsegs and semseqs arrays */
853: sema_new = malloc(val * sizeof(struct semid_ds *),
854: M_SEM, M_WAITOK);
855: bcopy(sema, sema_new,
856: seminfo.semmni * sizeof(struct semid_ds *));
857: bzero(sema_new + seminfo.semmni,
858: (val - seminfo.semmni) * sizeof(struct semid_ds *));
859: newseqs = malloc(val * sizeof(unsigned short), M_SEM, M_WAITOK);
860: bcopy(semseqs, newseqs,
861: seminfo.semmni * sizeof(unsigned short));
862: bzero(newseqs + seminfo.semmni,
863: (val - seminfo.semmni) * sizeof(unsigned short));
864: free(sema, M_SEM);
865: free(semseqs, M_SEM);
866: sema = sema_new;
867: semseqs = newseqs;
868: seminfo.semmni = val;
869: return (0);
870: case KERN_SEMINFO_SEMMNS:
871: val = seminfo.semmns;
872: if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) ||
873: val == seminfo.semmns)
874: return (error);
875: if (val < seminfo.semmns || val > 0xffff)
876: return (EINVAL); /* can't decrease semmns */
877: seminfo.semmns = val;
878: return (0);
879: case KERN_SEMINFO_SEMMNU:
880: val = seminfo.semmnu;
881: if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) ||
882: val == seminfo.semmnu)
883: return (error);
884: if (val < seminfo.semmnu)
885: return (EINVAL); /* can't decrease semmnu */
886: seminfo.semmnu = val;
887: return (0);
888: case KERN_SEMINFO_SEMMSL:
889: val = seminfo.semmsl;
890: if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) ||
891: val == seminfo.semmsl)
892: return (error);
893: if (val < seminfo.semmsl || val > 0xffff)
894: return (EINVAL); /* can't decrease semmsl */
895: seminfo.semmsl = val;
896: return (0);
897: case KERN_SEMINFO_SEMOPM:
898: val = seminfo.semopm;
899: if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) ||
900: val == seminfo.semopm)
901: return (error);
902: if (val <= 0)
903: return (EINVAL); /* semopm must be >= 1 */
904: seminfo.semopm = val;
905: return (0);
906: case KERN_SEMINFO_SEMUME:
907: return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semume));
908: case KERN_SEMINFO_SEMUSZ:
909: return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semusz));
910: case KERN_SEMINFO_SEMVMX:
911: return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semvmx));
912: case KERN_SEMINFO_SEMAEM:
913: return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semaem));
914: default:
915: return (EOPNOTSUPP);
916: }
917: /* NOTREACHED */
918: }
CVSweb