|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Implementation of SVID semaphores
24: *
25: * Author: Daniel Boulet
26: *
27: * This software is provided ``AS IS'' without any warranties of any kind.
28: */
29:
30: #include <sys/param.h>
31: #include <sys/systm.h>
32: #include <sys/sysproto.h>
33: #include <sys/kernel.h>
34: #include <sys/proc.h>
35: #include <sys/sem.h>
36: #include <sys/sysent.h>
37:
38: static void seminit __P((void *));
39: SYSINIT(sysv_sem, SI_SUB_SYSV_SEM, SI_ORDER_FIRST, seminit, NULL)
40:
41: #ifndef _SYS_SYSPROTO_H_
42: struct __semctl_args;
43: int __semctl __P((struct proc *p, struct __semctl_args *uap));
44: struct semget_args;
45: int semget __P((struct proc *p, struct semget_args *uap));
46: struct semop_args;
47: int semop __P((struct proc *p, struct semop_args *uap));
48: struct semconfig_args;
49: int semconfig __P((struct proc *p, struct semconfig_args *uap));
50: #endif
51:
52: static struct sem_undo *semu_alloc __P((struct proc *p));
53: static int semundo_adjust __P((struct proc *p, struct sem_undo **supptr,
54: int semid, int semnum, int adjval));
55: static void semundo_clear __P((int semid, int semnum));
56:
57: /* XXX casting to (sy_call_t *) is bogus, as usual. */
58: static sy_call_t *semcalls[] = {
59: (sy_call_t *)__semctl, (sy_call_t *)semget,
60: (sy_call_t *)semop, (sy_call_t *)semconfig
61: };
62:
63: static int semtot = 0;
64: struct semid_ds *sema; /* semaphore id pool */
65: struct sem *sem; /* semaphore pool */
66: static struct sem_undo *semu_list; /* list of active undo structures */
67: int *semu; /* undo structure pool */
68:
69: static struct proc *semlock_holder = NULL;
70:
71: void
72: seminit(dummy)
73: void *dummy;
74: {
75: register int i;
76:
77: if (sema == NULL)
78: panic("sema is NULL");
79: if (semu == NULL)
80: panic("semu is NULL");
81:
82: for (i = 0; i < seminfo.semmni; i++) {
83: sema[i].sem_base = 0;
84: sema[i].sem_perm.mode = 0;
85: }
86: for (i = 0; i < seminfo.semmnu; i++) {
87: register struct sem_undo *suptr = SEMU(i);
88: suptr->un_proc = NULL;
89: }
90: semu_list = NULL;
91: }
92:
93: /*
94: * Entry point for all SEM calls
95: */
96: int
97: semsys(p, uap)
98: struct proc *p;
99: /* XXX actually varargs. */
100: struct semsys_args /* {
101: u_int which;
102: int a2;
103: int a3;
104: int a4;
105: int a5;
106: } */ *uap;
107: {
108:
109: while (semlock_holder != NULL && semlock_holder != p)
110: (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "semsys", 0);
111:
112: if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
113: return (EINVAL);
114: return ((*semcalls[uap->which])(p, &uap->a2));
115: }
116:
117: /*
118: * Lock or unlock the entire semaphore facility.
119: *
120: * This will probably eventually evolve into a general purpose semaphore
121: * facility status enquiry mechanism (I don't like the "read /dev/kmem"
122: * approach currently taken by ipcs and the amount of info that we want
123: * to be able to extract for ipcs is probably beyond what the capability
124: * of the getkerninfo facility.
125: *
126: * At the time that the current version of semconfig was written, ipcs is
127: * the only user of the semconfig facility. It uses it to ensure that the
128: * semaphore facility data structures remain static while it fishes around
129: * in /dev/kmem.
130: */
131:
132: #ifndef _SYS_SYSPROTO_H_
133: struct semconfig_args {
134: semconfig_ctl_t flag;
135: };
136: #endif
137:
138: int
139: semconfig(p, uap)
140: struct proc *p;
141: struct semconfig_args *uap;
142: {
143: int eval = 0;
144:
145: switch (uap->flag) {
146: case SEM_CONFIG_FREEZE:
147: semlock_holder = p;
148: break;
149:
150: case SEM_CONFIG_THAW:
151: semlock_holder = NULL;
152: wakeup((caddr_t)&semlock_holder);
153: break;
154:
155: default:
156: printf("semconfig: unknown flag parameter value (%d) - ignored\n",
157: uap->flag);
158: eval = EINVAL;
159: break;
160: }
161:
162: p->p_retval[0] = 0;
163: return(eval);
164: }
165:
166: /*
167: * Allocate a new sem_undo structure for a process
168: * (returns ptr to structure or NULL if no more room)
169: */
170:
171: static struct sem_undo *
172: semu_alloc(p)
173: struct proc *p;
174: {
175: register int i;
176: register struct sem_undo *suptr;
177: register struct sem_undo **supptr;
178: int attempt;
179:
180: /*
181: * Try twice to allocate something.
182: * (we'll purge any empty structures after the first pass so
183: * two passes are always enough)
184: */
185:
186: for (attempt = 0; attempt < 2; attempt++) {
187: /*
188: * Look for a free structure.
189: * Fill it in and return it if we find one.
190: */
191:
192: for (i = 0; i < seminfo.semmnu; i++) {
193: suptr = SEMU(i);
194: if (suptr->un_proc == NULL) {
195: suptr->un_next = semu_list;
196: semu_list = suptr;
197: suptr->un_cnt = 0;
198: suptr->un_proc = p;
199: return(suptr);
200: }
201: }
202:
203: /*
204: * We didn't find a free one, if this is the first attempt
205: * then try to free some structures.
206: */
207:
208: if (attempt == 0) {
209: /* All the structures are in use - try to free some */
210: int did_something = 0;
211:
212: supptr = &semu_list;
213: while ((suptr = *supptr) != NULL) {
214: if (suptr->un_cnt == 0) {
215: suptr->un_proc = NULL;
216: *supptr = suptr->un_next;
217: did_something = 1;
218: } else
219: supptr = &(suptr->un_next);
220: }
221:
222: /* If we didn't free anything then just give-up */
223: if (!did_something)
224: return(NULL);
225: } else {
226: /*
227: * The second pass failed even though we freed
228: * something after the first pass!
229: * This is IMPOSSIBLE!
230: */
231: panic("semu_alloc - second attempt failed");
232: }
233: }
234: return (NULL);
235: }
236:
237: /*
238: * Adjust a particular entry for a particular proc
239: */
240:
241: static int
242: semundo_adjust(p, supptr, semid, semnum, adjval)
243: register struct proc *p;
244: struct sem_undo **supptr;
245: int semid, semnum;
246: int adjval;
247: {
248: register struct sem_undo *suptr;
249: register struct undo *sunptr;
250: int i;
251:
252: /* Look for and remember the sem_undo if the caller doesn't provide
253: it */
254:
255: suptr = *supptr;
256: if (suptr == NULL) {
257: for (suptr = semu_list; suptr != NULL;
258: suptr = suptr->un_next) {
259: if (suptr->un_proc == p) {
260: *supptr = suptr;
261: break;
262: }
263: }
264: if (suptr == NULL) {
265: if (adjval == 0)
266: return(0);
267: suptr = semu_alloc(p);
268: if (suptr == NULL)
269: return(ENOSPC);
270: *supptr = suptr;
271: }
272: }
273:
274: /*
275: * Look for the requested entry and adjust it (delete if adjval becomes
276: * 0).
277: */
278: sunptr = &suptr->un_ent[0];
279: for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
280: if (sunptr->un_id != semid || sunptr->un_num != semnum)
281: continue;
282: if (adjval == 0)
283: sunptr->un_adjval = 0;
284: else
285: sunptr->un_adjval += adjval;
286: if (sunptr->un_adjval == 0) {
287: suptr->un_cnt--;
288: if (i < suptr->un_cnt)
289: suptr->un_ent[i] =
290: suptr->un_ent[suptr->un_cnt];
291: }
292: return(0);
293: }
294:
295: /* Didn't find the right entry - create it */
296: if (adjval == 0)
297: return(0);
298: if (suptr->un_cnt != seminfo.semume) {
299: sunptr = &suptr->un_ent[suptr->un_cnt];
300: suptr->un_cnt++;
301: sunptr->un_adjval = adjval;
302: sunptr->un_id = semid; sunptr->un_num = semnum;
303: } else
304: return(EINVAL);
305: return(0);
306: }
307:
308: static void
309: semundo_clear(semid, semnum)
310: int semid, semnum;
311: {
312: register struct sem_undo *suptr;
313:
314: for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
315: register struct undo *sunptr = &suptr->un_ent[0];
316: register int i = 0;
317:
318: while (i < suptr->un_cnt) {
319: if (sunptr->un_id == semid) {
320: if (semnum == -1 || sunptr->un_num == semnum) {
321: suptr->un_cnt--;
322: if (i < suptr->un_cnt) {
323: suptr->un_ent[i] =
324: suptr->un_ent[suptr->un_cnt];
325: continue;
326: }
327: }
328: if (semnum != -1)
329: break;
330: }
331: i++, sunptr++;
332: }
333: }
334: }
335:
336: /*
337: * Note that the user-mode half of this passes a union, not a pointer
338: */
339: #ifndef _SYS_SYSPROTO_H_
340: struct __semctl_args {
341: int semid;
342: int semnum;
343: int cmd;
344: union semun *arg;
345: };
346: #endif
347:
348: int
349: __semctl(p, uap)
350: struct proc *p;
351: register struct __semctl_args *uap;
352: {
353: int semid = uap->semid;
354: int semnum = uap->semnum;
355: int cmd = uap->cmd;
356: union semun *arg = uap->arg;
357: union semun real_arg;
358: struct ucred *cred = p->p_ucred;
359: int i, rval, eval;
360: struct semid_ds sbuf;
361: register struct semid_ds *semaptr;
362:
363: #ifdef SEM_DEBUG
364: printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg);
365: #endif
366:
367: semid = IPCID_TO_IX(semid);
368: if (semid < 0 || semid >= seminfo.semmsl)
369: return(EINVAL);
370:
371: semaptr = &sema[semid];
372: if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
373: semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
374: return(EINVAL);
375:
376: eval = 0;
377: rval = 0;
378:
379: switch (cmd) {
380: case IPC_RMID:
381: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
382: return(eval);
383: semaptr->sem_perm.cuid = cred->cr_uid;
384: semaptr->sem_perm.uid = cred->cr_uid;
385: semtot -= semaptr->sem_nsems;
386: for (i = semaptr->sem_base - sem; i < semtot; i++)
387: sem[i] = sem[i + semaptr->sem_nsems];
388: for (i = 0; i < seminfo.semmni; i++) {
389: if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
390: sema[i].sem_base > semaptr->sem_base)
391: sema[i].sem_base -= semaptr->sem_nsems;
392: }
393: semaptr->sem_perm.mode = 0;
394: semundo_clear(semid, -1);
395: wakeup((caddr_t)semaptr);
396: break;
397:
398: case IPC_SET:
399: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
400: return(eval);
401: if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
402: return(eval);
403: if ((eval = copyin(real_arg.buf, (caddr_t)&sbuf,
404: sizeof(sbuf))) != 0)
405: return(eval);
406: semaptr->sem_perm.uid = sbuf.sem_perm.uid;
407: semaptr->sem_perm.gid = sbuf.sem_perm.gid;
408: semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
409: (sbuf.sem_perm.mode & 0777);
410: semaptr->sem_ctime = time_second;
411: break;
412:
413: case IPC_STAT:
414: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
415: return(eval);
416: if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
417: return(eval);
418: eval = copyout((caddr_t)semaptr, real_arg.buf,
419: sizeof(struct semid_ds));
420: break;
421:
422: case GETNCNT:
423: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
424: return(eval);
425: if (semnum < 0 || semnum >= semaptr->sem_nsems)
426: return(EINVAL);
427: rval = semaptr->sem_base[semnum].semncnt;
428: break;
429:
430: case GETPID:
431: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
432: return(eval);
433: if (semnum < 0 || semnum >= semaptr->sem_nsems)
434: return(EINVAL);
435: rval = semaptr->sem_base[semnum].sempid;
436: break;
437:
438: case GETVAL:
439: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
440: return(eval);
441: if (semnum < 0 || semnum >= semaptr->sem_nsems)
442: return(EINVAL);
443: rval = semaptr->sem_base[semnum].semval;
444: break;
445:
446: case GETALL:
447: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
448: return(eval);
449: if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
450: return(eval);
451: for (i = 0; i < semaptr->sem_nsems; i++) {
452: eval = copyout((caddr_t)&semaptr->sem_base[i].semval,
453: &real_arg.array[i], sizeof(real_arg.array[0]));
454: if (eval != 0)
455: break;
456: }
457: break;
458:
459: case GETZCNT:
460: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
461: return(eval);
462: if (semnum < 0 || semnum >= semaptr->sem_nsems)
463: return(EINVAL);
464: rval = semaptr->sem_base[semnum].semzcnt;
465: break;
466:
467: case SETVAL:
468: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
469: return(eval);
470: if (semnum < 0 || semnum >= semaptr->sem_nsems)
471: return(EINVAL);
472: if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
473: return(eval);
474: semaptr->sem_base[semnum].semval = real_arg.val;
475: semundo_clear(semid, semnum);
476: wakeup((caddr_t)semaptr);
477: break;
478:
479: case SETALL:
480: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
481: return(eval);
482: if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
483: return(eval);
484: for (i = 0; i < semaptr->sem_nsems; i++) {
485: eval = copyin(&real_arg.array[i],
486: (caddr_t)&semaptr->sem_base[i].semval,
487: sizeof(real_arg.array[0]));
488: if (eval != 0)
489: break;
490: }
491: semundo_clear(semid, -1);
492: wakeup((caddr_t)semaptr);
493: break;
494:
495: default:
496: return(EINVAL);
497: }
498:
499: if (eval == 0)
500: p->p_retval[0] = rval;
501: return(eval);
502: }
503:
504: #ifndef _SYS_SYSPROTO_H_
505: struct semget_args {
506: key_t key;
507: int nsems;
508: int semflg;
509: };
510: #endif
511:
512: int
513: semget(p, uap)
514: struct proc *p;
515: register struct semget_args *uap;
516: {
517: int semid, eval;
518: int key = uap->key;
519: int nsems = uap->nsems;
520: int semflg = uap->semflg;
521: struct ucred *cred = p->p_ucred;
522:
523: #ifdef SEM_DEBUG
524: printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
525: #endif
526:
527: if (key != IPC_PRIVATE) {
528: for (semid = 0; semid < seminfo.semmni; semid++) {
529: if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
530: sema[semid].sem_perm.key == key)
531: break;
532: }
533: if (semid < seminfo.semmni) {
534: #ifdef SEM_DEBUG
535: printf("found public key\n");
536: #endif
537: if ((eval = ipcperm(cred, &sema[semid].sem_perm,
538: semflg & 0700)))
539: return(eval);
540: if (nsems > 0 && sema[semid].sem_nsems < nsems) {
541: #ifdef SEM_DEBUG
542: printf("too small\n");
543: #endif
544: return(EINVAL);
545: }
546: if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
547: #ifdef SEM_DEBUG
548: printf("not exclusive\n");
549: #endif
550: return(EEXIST);
551: }
552: goto found;
553: }
554: }
555:
556: #ifdef SEM_DEBUG
557: printf("need to allocate the semid_ds\n");
558: #endif
559: if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
560: if (nsems <= 0 || nsems > seminfo.semmsl) {
561: #ifdef SEM_DEBUG
562: printf("nsems out of range (0<%d<=%d)\n", nsems,
563: seminfo.semmsl);
564: #endif
565: return(EINVAL);
566: }
567: if (nsems > seminfo.semmns - semtot) {
568: #ifdef SEM_DEBUG
569: printf("not enough semaphores left (need %d, got %d)\n",
570: nsems, seminfo.semmns - semtot);
571: #endif
572: return(ENOSPC);
573: }
574: for (semid = 0; semid < seminfo.semmni; semid++) {
575: if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
576: break;
577: }
578: if (semid == seminfo.semmni) {
579: #ifdef SEM_DEBUG
580: printf("no more semid_ds's available\n");
581: #endif
582: return(ENOSPC);
583: }
584: #ifdef SEM_DEBUG
585: printf("semid %d is available\n", semid);
586: #endif
587: sema[semid].sem_perm.key = key;
588: sema[semid].sem_perm.cuid = cred->cr_uid;
589: sema[semid].sem_perm.uid = cred->cr_uid;
590: sema[semid].sem_perm.cgid = cred->cr_gid;
591: sema[semid].sem_perm.gid = cred->cr_gid;
592: sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
593: sema[semid].sem_perm.seq =
594: (sema[semid].sem_perm.seq + 1) & 0x7fff;
595: sema[semid].sem_nsems = nsems;
596: sema[semid].sem_otime = 0;
597: sema[semid].sem_ctime = time_second;
598: sema[semid].sem_base = &sem[semtot];
599: semtot += nsems;
600: bzero(sema[semid].sem_base,
601: sizeof(sema[semid].sem_base[0])*nsems);
602: #ifdef SEM_DEBUG
603: printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
604: &sem[semtot]);
605: #endif
606: } else {
607: #ifdef SEM_DEBUG
608: printf("didn't find it and wasn't asked to create it\n");
609: #endif
610: return(ENOENT);
611: }
612:
613: found:
614: p->p_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
615: return(0);
616: }
617:
618: #ifndef _SYS_SYSPROTO_H_
619: struct semop_args {
620: int semid;
621: struct sembuf *sops;
622: int nsops;
623: };
624: #endif
625:
626: int
627: semop(p, uap)
628: struct proc *p;
629: register struct semop_args *uap;
630: {
631: int semid = uap->semid;
632: int nsops = uap->nsops;
633: struct sembuf sops[MAX_SOPS];
634: register struct semid_ds *semaptr;
635: register struct sembuf *sopptr;
636: register struct sem *semptr;
637: struct sem_undo *suptr = NULL;
638: struct ucred *cred = p->p_ucred;
639: int i, j, eval;
640: int do_wakeup, do_undos;
641:
642: #ifdef SEM_DEBUG
643: printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops);
644: #endif
645:
646: semid = IPCID_TO_IX(semid); /* Convert back to zero origin */
647:
648: if (semid < 0 || semid >= seminfo.semmsl)
649: return(EINVAL);
650:
651: semaptr = &sema[semid];
652: if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
653: return(EINVAL);
654: if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
655: return(EINVAL);
656:
657: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
658: #ifdef SEM_DEBUG
659: printf("eval = %d from ipaccess\n", eval);
660: #endif
661: return(eval);
662: }
663:
664: if (nsops > MAX_SOPS) {
665: #ifdef SEM_DEBUG
666: printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops);
667: #endif
668: return(E2BIG);
669: }
670:
671: if ((eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) {
672: #ifdef SEM_DEBUG
673: printf("eval = %d from copyin(%08x, %08x, %d)\n", eval,
674: uap->sops, &sops, nsops * sizeof(sops[0]));
675: #endif
676: return(eval);
677: }
678:
679: /*
680: * Loop trying to satisfy the vector of requests.
681: * If we reach a point where we must wait, any requests already
682: * performed are rolled back and we go to sleep until some other
683: * process wakes us up. At this point, we start all over again.
684: *
685: * This ensures that from the perspective of other tasks, a set
686: * of requests is atomic (never partially satisfied).
687: */
688: do_undos = 0;
689:
690: for (;;) {
691: do_wakeup = 0;
692:
693: for (i = 0; i < nsops; i++) {
694: sopptr = &sops[i];
695:
696: if (sopptr->sem_num >= semaptr->sem_nsems)
697: return(EFBIG);
698:
699: semptr = &semaptr->sem_base[sopptr->sem_num];
700:
701: #ifdef SEM_DEBUG
702: printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
703: semaptr, semaptr->sem_base, semptr,
704: sopptr->sem_num, semptr->semval, sopptr->sem_op,
705: (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
706: #endif
707:
708: if (sopptr->sem_op < 0) {
709: if (semptr->semval + sopptr->sem_op < 0) {
710: #ifdef SEM_DEBUG
711: printf("semop: can't do it now\n");
712: #endif
713: break;
714: } else {
715: semptr->semval += sopptr->sem_op;
716: if (semptr->semval == 0 &&
717: semptr->semzcnt > 0)
718: do_wakeup = 1;
719: }
720: if (sopptr->sem_flg & SEM_UNDO)
721: do_undos = 1;
722: } else if (sopptr->sem_op == 0) {
723: if (semptr->semval > 0) {
724: #ifdef SEM_DEBUG
725: printf("semop: not zero now\n");
726: #endif
727: break;
728: }
729: } else {
730: if (semptr->semncnt > 0)
731: do_wakeup = 1;
732: semptr->semval += sopptr->sem_op;
733: if (sopptr->sem_flg & SEM_UNDO)
734: do_undos = 1;
735: }
736: }
737:
738: /*
739: * Did we get through the entire vector?
740: */
741: if (i >= nsops)
742: goto done;
743:
744: /*
745: * No ... rollback anything that we've already done
746: */
747: #ifdef SEM_DEBUG
748: printf("semop: rollback 0 through %d\n", i-1);
749: #endif
750: for (j = 0; j < i; j++)
751: semaptr->sem_base[sops[j].sem_num].semval -=
752: sops[j].sem_op;
753:
754: /*
755: * If the request that we couldn't satisfy has the
756: * NOWAIT flag set then return with EAGAIN.
757: */
758: if (sopptr->sem_flg & IPC_NOWAIT)
759: return(EAGAIN);
760:
761: if (sopptr->sem_op == 0)
762: semptr->semzcnt++;
763: else
764: semptr->semncnt++;
765:
766: #ifdef SEM_DEBUG
767: printf("semop: good night!\n");
768: #endif
769: eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH,
770: "semwait", 0);
771: #ifdef SEM_DEBUG
772: printf("semop: good morning (eval=%d)!\n", eval);
773: #endif
774:
775: suptr = NULL; /* sem_undo may have been reallocated */
776:
777: if (eval != 0)
778: return(EINTR);
779: #ifdef SEM_DEBUG
780: printf("semop: good morning!\n");
781: #endif
782:
783: /*
784: * Make sure that the semaphore still exists
785: */
786: if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
787: semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
788: /* The man page says to return EIDRM. */
789: /* Unfortunately, BSD doesn't define that code! */
790: #ifdef EIDRM
791: return(EIDRM);
792: #else
793: return(EINVAL);
794: #endif
795: }
796:
797: /*
798: * The semaphore is still alive. Readjust the count of
799: * waiting processes.
800: */
801: if (sopptr->sem_op == 0)
802: semptr->semzcnt--;
803: else
804: semptr->semncnt--;
805: }
806:
807: done:
808: /*
809: * Process any SEM_UNDO requests.
810: */
811: if (do_undos) {
812: for (i = 0; i < nsops; i++) {
813: /*
814: * We only need to deal with SEM_UNDO's for non-zero
815: * op's.
816: */
817: int adjval;
818:
819: if ((sops[i].sem_flg & SEM_UNDO) == 0)
820: continue;
821: adjval = sops[i].sem_op;
822: if (adjval == 0)
823: continue;
824: eval = semundo_adjust(p, &suptr, semid,
825: sops[i].sem_num, -adjval);
826: if (eval == 0)
827: continue;
828:
829: /*
830: * Oh-Oh! We ran out of either sem_undo's or undo's.
831: * Rollback the adjustments to this point and then
832: * rollback the semaphore ups and down so we can return
833: * with an error with all structures restored. We
834: * rollback the undo's in the exact reverse order that
835: * we applied them. This guarantees that we won't run
836: * out of space as we roll things back out.
837: */
838: for (j = i - 1; j >= 0; j--) {
839: if ((sops[j].sem_flg & SEM_UNDO) == 0)
840: continue;
841: adjval = sops[j].sem_op;
842: if (adjval == 0)
843: continue;
844: if (semundo_adjust(p, &suptr, semid,
845: sops[j].sem_num, adjval) != 0)
846: panic("semop - can't undo undos");
847: }
848:
849: for (j = 0; j < nsops; j++)
850: semaptr->sem_base[sops[j].sem_num].semval -=
851: sops[j].sem_op;
852:
853: #ifdef SEM_DEBUG
854: printf("eval = %d from semundo_adjust\n", eval);
855: #endif
856: return(eval);
857: } /* loop through the sops */
858: } /* if (do_undos) */
859:
860: /* We're definitely done - set the sempid's */
861: for (i = 0; i < nsops; i++) {
862: sopptr = &sops[i];
863: semptr = &semaptr->sem_base[sopptr->sem_num];
864: semptr->sempid = p->p_pid;
865: }
866:
867: /* Do a wakeup if any semaphore was up'd. */
868: if (do_wakeup) {
869: #ifdef SEM_DEBUG
870: printf("semop: doing wakeup\n");
871: #ifdef SEM_WAKEUP
872: sem_wakeup((caddr_t)semaptr);
873: #else
874: wakeup((caddr_t)semaptr);
875: #endif
876: printf("semop: back from wakeup\n");
877: #else
878: wakeup((caddr_t)semaptr);
879: #endif
880: }
881: #ifdef SEM_DEBUG
882: printf("semop: done\n");
883: #endif
884: p->p_retval[0] = 0;
885: return(0);
886: }
887:
888: /*
889: * Go through the undo structures for this process and apply the adjustments to
890: * semaphores.
891: */
892: void
893: semexit(p)
894: struct proc *p;
895: {
896: register struct sem_undo *suptr;
897: register struct sem_undo **supptr;
898: int did_something;
899:
900: /*
901: * If somebody else is holding the global semaphore facility lock
902: * then sleep until it is released.
903: */
904: while (semlock_holder != NULL && semlock_holder != p) {
905: #ifdef SEM_DEBUG
906: printf("semaphore facility locked - sleeping ...\n");
907: #endif
908: (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "semext", 0);
909: }
910:
911: did_something = 0;
912:
913: /*
914: * Go through the chain of undo vectors looking for one
915: * associated with this process.
916: */
917:
918: for (supptr = &semu_list; (suptr = *supptr) != NULL;
919: supptr = &suptr->un_next) {
920: if (suptr->un_proc == p)
921: break;
922: }
923:
924: if (suptr == NULL)
925: goto unlock;
926:
927: #ifdef SEM_DEBUG
928: printf("proc @%08x has undo structure with %d entries\n", p,
929: suptr->un_cnt);
930: #endif
931:
932: /*
933: * If there are any active undo elements then process them.
934: */
935: if (suptr->un_cnt > 0) {
936: int ix;
937:
938: for (ix = 0; ix < suptr->un_cnt; ix++) {
939: int semid = suptr->un_ent[ix].un_id;
940: int semnum = suptr->un_ent[ix].un_num;
941: int adjval = suptr->un_ent[ix].un_adjval;
942: struct semid_ds *semaptr;
943:
944: semaptr = &sema[semid];
945: if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
946: panic("semexit - semid not allocated");
947: if (semnum >= semaptr->sem_nsems)
948: panic("semexit - semnum out of range");
949:
950: #ifdef SEM_DEBUG
951: printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
952: suptr->un_proc, suptr->un_ent[ix].un_id,
953: suptr->un_ent[ix].un_num,
954: suptr->un_ent[ix].un_adjval,
955: semaptr->sem_base[semnum].semval);
956: #endif
957:
958: if (adjval < 0) {
959: if (semaptr->sem_base[semnum].semval < -adjval)
960: semaptr->sem_base[semnum].semval = 0;
961: else
962: semaptr->sem_base[semnum].semval +=
963: adjval;
964: } else
965: semaptr->sem_base[semnum].semval += adjval;
966:
967: #ifdef SEM_WAKEUP
968: sem_wakeup((caddr_t)semaptr);
969: #else
970: wakeup((caddr_t)semaptr);
971: #endif
972: #ifdef SEM_DEBUG
973: printf("semexit: back from wakeup\n");
974: #endif
975: }
976: }
977:
978: /*
979: * Deallocate the undo vector.
980: */
981: #ifdef SEM_DEBUG
982: printf("removing vector\n");
983: #endif
984: suptr->un_proc = NULL;
985: *supptr = suptr->un_next;
986:
987: unlock:
988: /*
989: * If the exiting process is holding the global semaphore facility
990: * lock then release it.
991: */
992: if (semlock_holder == p) {
993: semlock_holder = NULL;
994: wakeup((caddr_t)&semlock_holder);
995: }
996: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.