|
|
1.1 root 1: /*
2: * File: sem1.c
3: *
4: * Purpose: This module provides System V compatible semaphore operations.
5: *
6: * $Log: sem386.c,v $
7: * Revision 1.2 93/04/20 10:00:32 bin
8: * kernel 77: vlad: sem_undo and other changes
9: *
10: * Revision 1.1 93/04/09 08:48:23 bin
11: * Initial revision
12: *
13: */
14:
15: /*
16: * ----------------------------------------------------------------------
17: * Includes.
18: */
19: #include <sys/coherent.h>
20: #include <sys/sched.h>
21: #if 0
22: #include <sys/proc.h>
23: #endif
24: #include <sys/types.h>
25: #include <sys/uproc.h>
26: #include <errno.h>
27: #include <sys/stat.h>
28: #include <sys/con.h>
29: #include <sys/sem.h>
30:
31: /*
32: * ----------------------------------------------------------------------
33: * Definitions.
34: * Constants.
35: * Macros with argument lists.
36: * Typedefs.
37: * Enums.
38: */
39:
40: /*
41: * ----------------------------------------------------------------------
42: * Functions.
43: * Import Functions.
44: * Export Functions.
45: * Local Functions.
46: */
47: int iSemPerm(); /* Check permissions */
48: int iSanityCheck(); /* Sanity check */
49: int iSemInit(); /* Init semaphores */
50: void vClearAdj(); /* Clear the adjust value */
51: int iSubAdj(); /* Subtract value from the sem adjust */
52: /*
53: * ----------------------------------------------------------------------
54: * Global Data.
55: * Import Variables.
56: * Export Variables.
57: * Local Variables.
58: */
59: /* Patchable values */
60: int SEMMNI = 10; /* max # of the semaphore sets, systemwide */
61: int SEMMNS = 60; /* max # of semaphores, systemwide */
62: int SEMMSL = 25; /* max # of semaphores per set */
63: int SEMVMX = 32767; /* max value of any semaphore */
64:
65: struct semid_ds *semids = NULL; /* Array of semaphore sets */
66: int iSemTotal = 0; /* Total number of semaphores, systemwide */
67: GATE gSemGate; /* Semaphore gate. */
68: unsigned short usSEM_R = 0444; /* Permission definition for read */
69: unsigned short usSEM_A = 0222; /* and alter */
70:
71: /*
72: * ----------------------------------------------------------------------
73: * Code.
74: */
75:
76: /*
77: * Semget gets set of semaphores. Returns semaphore set id on suuccess,
78: * or sets u.u_error on error.
79: */
80: usemget(skey, nsems, semflg)
81: key_t skey; /* Semaphore key */
82: int nsems, /* # of semaphores in the set */
83: semflg; /* Permission flag */
84: {
85: register struct semid_ds *semidp; /* Semaphore set */
86: register struct sem *semp; /* Semaphores */
87: struct semid_ds *freeidp = 0; /* Oldest free set */
88:
89: if (iSanityCheck(nsems))
90: return;
91:
92: /* Allocate memmory on the first semget. This memory (~300 bytes)
93: * will stay alloc up to the next reboot. The alloced unused memory
94: * is smaller than code that will allow to manage it more sophisticated.
95: * Allocaton is used to allow patchability of the semaphores.
96: */
97: if (semids == NULL) {
98: if (iSemInit()) {
99: u.u_error = ENOSPC;
100: return;
101: }
102: }
103: lock(gSemGate); /* Lock semaphore operations */
104:
105: /* Now we will go through all semaphores. */
106: for (semidp = semids; semidp < semids + SEMMNI; semidp++) {
107: /* If set is free look for the oldest */
108: if ((semidp->sem_perm.mode & IPC_ALLOC) == 0) {
109: if ((freeidp == 0) ||
110: (freeidp->sem_ctime > semidp->sem_ctime))
111: freeidp = semidp;
112: continue;
113: }
114:
115: /* Check if a request was for the private set */
116: if (skey == IPC_PRIVATE)
117: continue;
118:
119: if (skey != semidp->sem_perm.key)
120: continue;
121: /* Found */
122: /* Exclusive set cannot be created */
123: if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
124: unlock(gSemGate);
125: u.u_error = EEXIST;
126: return;
127: }
128:
129: /* Check the permissions */
130: if (iSemPerm(semidp, semflg)) {
131: unlock(gSemGate);
132: return;
133: }
134:
135: /* Check the requested number of semaphores */
136: if (semidp->sem_nsems < nsems) {
137: unlock(gSemGate);
138: u.u_error = EINVAL;
139: return;
140: }
141: /* Semaphore set id number is the number of an array element */
142: unlock(gSemGate);
143: return semidp - semids;
144: }
145:
146: /* Set does not exist. So, we have to create it */
147: /* Now nsems should be > 0 */
148: if (nsems < 1) {
149: unlock(gSemGate);
150: u.u_error = EINVAL;
151: return;
152: }
153:
154: /* Check the total number of semaphores */
155: if ((iSemTotal + nsems > SEMMNS)) {
156: unlock(gSemGate);
157: u.u_error = ENOSPC;
158: return;
159: }
160:
161: /* Check if there is the request for creation */
162: if (!(semflg & IPC_CREAT)) {
163: unlock(gSemGate);
164: u.u_error = ENOENT;
165: return;
166: }
167:
168: /* Out of system limits */
169: if (freeidp == 0) {
170: unlock(gSemGate);
171: u.u_error = ENOSPC;
172: return;
173: }
174:
175: /* Now we have to creat a new set. freeidp points to the oldest free
176: * set which we will use.
177: */
178: semidp = freeidp;
179: /* Get space for semaphores */
180: semidp->sem_base = kalloc(nsems * sizeof(struct sem));
181: if (semidp->sem_base == 0) {
182: unlock(gSemGate);
183: u.u_error = ENOSPC;
184: return;
185: }
186:
187: /* Initialize created set */
188: /* ipc_perm */
189: semidp->sem_perm.cuid = semidp->sem_perm.uid = u.u_uid;
190: semidp->sem_perm.cgid = semidp->sem_perm.gid = u.u_gid;
191: semidp->sem_perm.mode = (semflg & 0777) | IPC_ALLOC;
192: semidp->sem_perm.key = skey;
193: semidp->sem_perm.seq = semidp - semids;
194:
195: semidp->sem_nsems = nsems;
196: semidp->sem_otime = 0;
197: semidp->sem_ctime = timer.t_time;
198:
199: /* Increment number of semaphores in used */
200: iSemTotal += nsems;
201:
202: /* Set values of the semaphores to 0.
203: * SVR3 does not do it and suggests set up sem struct using
204: * semctl() call. SVR4 manual says nothing about it.
205: */
206: for (semp = semidp->sem_base; semp < semidp->sem_base + nsems; semp++){
207: semp->semval = semp->sempid = semp->semncnt = semp->semzcnt = 0;
208: }
209: unlock(gSemGate);
210: return semidp - semids;
211: }
212:
213: /*
214: * Semctl provides semaphore control operation as specify by cmd.
215: * On success return value depends on cmd, sets u.u_error on error.
216: */
217: usemctl(semid, semnum, cmd, arg)
218: int semid, /* Semaphore set id */
219: cmd; /* Command */
220: int semnum; /* Semaphore # */
221: union semun {
222: int val; /* Used for SETVAL only */
223: struct semid_ds *buf; /* Used for IPC_STAT and IPC_SET */
224: unsigned short *array; /* Used for IPC_GET_ALL and IPC_SETALL */
225: } arg;
226:
227: {
228: register struct semid_ds *semidp; /* Semaphore set */
229: register struct sem *semp; /* Semaphore */
230: int val; /* Semaphore value */
231: int i; /* Loopindex */
232: unsigned short *pusUserAr; /* User array */
233:
234: if (iSanityCheck(semnum))
235: return;
236:
237: /* Check if there was any successfull semget before.
238: * Problem may be if somebody does semctl() before semids was
239: * alloced.
240: */
241: if (semids == 0) {
242: u.u_error = EINVAL;
243: return;
244: }
245:
246: /* semid cannot be < 0 and more than systemwide limit */
247: if (semid < 0 || semid >= SEMMNI) {
248: u.u_error = EINVAL;
249: return;
250: }
251: semidp = semids + semid;
252:
253: /* Check if the requested set is alloced */
254: if ((semidp->sem_perm.mode & IPC_ALLOC) == 0) {
255: u.u_error = EINVAL;
256: return;
257: }
258:
259: /* Check if semnum is a correct semaphore number.
260: * SV would do it only when there is request for a
261: * single semaphore value, as GETVAL or SETVAL.
262: */
263: if (semnum >= semidp->sem_nsems) {
264: u.u_error = EFBIG;
265: return;
266: }
267:
268: semp = semidp->sem_base + semnum;
269:
270: switch (cmd) {
271: case GETVAL: /* Return value of semval */
272: if (iSemPerm(semidp, usSEM_R)) /* cannot read */
273: return;
274: return semp->semval;
275: case SETVAL: /* Set semval. Clear all semadj values on success. */
276: if (iSemPerm(semidp, usSEM_A)) /* cannot alter */
277: return;
278: /* semval always >= 0 */
279: if (arg.val > SEMVMX || arg.val < 0) { /* illegal value */
280: u.u_error = ERANGE;
281: return;
282: }
283: /* Set semval and wakeup whatever should be */
284: if (semp->semval = arg.val) {
285: if (semp->semncnt)
286: wakeup(&semp->semncnt);
287: } else {
288: if (semp->semzcnt)
289: wakeup(&semp->semzcnt);
290: }
291: semidp->sem_ctime = timer.t_time;
292: /* Clear corresponding adjust value in all processes */
293: vClearAdj(semid, semnum);
294: return 0;
295: case GETPID: /* Return value of sempid */
296: if (iSemPerm(semidp, usSEM_R)) /* cannot read */
297: return;
298: return semp->sempid;
299: case GETNCNT: /* Return value of semncnt */
300: if (iSemPerm(semidp, usSEM_R)) /* cannot read */
301: return;
302: return semp->semncnt;
303: case GETZCNT: /* Return value of semzcnt */
304: if (iSemPerm(semidp, usSEM_R)) /* cannot read */
305: return;
306: return semp->semzcnt;
307: case GETALL: /* Return semvals array */
308: if (iSemPerm(semidp, usSEM_R)) /* cannot read */
309: return;
310: /* Copy all values to user array */
311: semp = semidp->sem_base;
312: pusUserAr = arg.array;
313: for (i = 0; i < semidp->sem_nsems; i++) {
314: putusd(pusUserAr, semp->semval);
315: if (u.u_error)
316: return;
317: semp++;
318: pusUserAr++;
319: }
320: return 0;
321: case SETALL: /* Set semvals array */
322: if (iSemPerm(semidp, SEM_A)) /* cannot alter */
323: return;
324:
325: /* Set semvals accoding to the arg.array */
326: semp = semidp->sem_base;
327: pusUserAr = arg.array;
328: lock(gSemGate);
329: for (i = 0; i < semidp->sem_nsems; i++) {
330: val = getusd(pusUserAr++);
331: if (u.u_error) {
332: unlock(gSemGate);
333: return;
334: }
335: if (val < 0 || val > SEMVMX) {
336: u.u_error = ERANGE;
337: unlock(gSemGate);
338: return;
339: }
340: semp->semval = val;
341: /* Clear corresponding adjust value in all processes. */
342: vClearAdj(semid, i);
343: semp++;
344: }
345: semidp->sem_ctime = timer.t_time;
346: unlock(gSemGate);
347: return 0;
348: case IPC_STAT:
349: if (iSemPerm(semidp, usSEM_R)) /* cannot read */
350: return;
351: kucopy(semidp, arg.buf, sizeof(struct semid_ds));
352: return 0;
353: case IPC_SET:
354: if (iSemPerm(semidp, SEM_A)) /* cannot alter */
355: return;
356: semidp->sem_perm.uid = getusd(&((arg.buf)->sem_perm.uid));
357: semidp->sem_perm.gid = getusd(&((arg.buf)->sem_perm.gid));
358: semidp->sem_perm.mode =
359: (getusd(&((arg.buf)->sem_perm.mode))&0777) | IPC_ALLOC;
360: semidp->sem_ctime = timer.t_time;
361: return 0;
362: case IPC_RMID:
363: if ((u.u_uid != 0) && (u.u_uid != semidp->sem_perm.uid)
364: && u.u_uid != semidp->sem_perm.cuid) {
365: u.u_error = EPERM;
366: return;
367: }
368:
369: /* We have to wake up all waiting proccesses */
370: for (semp = semidp->sem_base; semp < semidp->sem_base +
371: semidp->sem_nsems; semp++) {
372: if (semp->semncnt)
373: wakeup(&semp->semncnt);
374: if (semp->semzcnt)
375: wakeup(&semp->semzcnt);
376: }
377: /* We do not cleane up adjust values here */
378: iSemTotal -= semidp->sem_nsems;
379: semidp->sem_perm.mode = 0;
380: kfree(semidp->sem_base);
381: return 0;
382: default:
383: u.u_error = EINVAL;
384: return;
385: }
386: }
387:
388: /*
389: * Semop - Semaphore Operations.
390: */
391: usemop(iSemId, pstSops, uNsops)
392: int iSemId; /* Semaphore identifier */
393: struct sembuf *pstSops; /* Array of sem. operations */
394: unsigned uNsops; /* # of elements in the array */
395: {
396: register struct semid_ds *rpstSemSet; /* Semaphore set */
397: register struct sem *rpstSem; /* Semaphore */
398: struct sembuf *pstSemBuf; /* Operations */
399: unsigned short usSemNum; /* Semaphore number */
400: short sSemFlg; /* Semaphore flag */
401: short sSemOper; /* Operation */
402: int i; /* Loop index */
403: short change = 0; /* Sem was changed */
404:
405: /* Check if semids was alloced */
406: if (semids == 0) {
407: u.u_error = EINVAL;
408: return;
409: }
410: /* iSemId cannot be < 0 and more than systemwide limit */
411: if (iSemId < 0 || iSemId >= SEMMNI) {
412: u.u_error = EINVAL;
413: return;
414: }
415: if (!useracc(pstSops, sizeof(struct sembuf) * uNsops, 0) || uNsops<1) {
416: u.u_error = EFAULT;
417: return;
418: }
419:
420: rpstSemSet = semids + iSemId; /* Requested set */
421:
422: if ((rpstSemSet->sem_perm.mode & IPC_ALLOC) == 0) {
423: u.u_error = EINVAL;
424: return -1;
425: }
426: TRY_AGAIN: /* Repeat the semaphore set */
427:
428: /* Lock semaphore system */
429: lock(gSemGate);
430:
431: /* do semaphore ops */
432: for (i = 0, pstSemBuf = pstSops; i < uNsops; i++, pstSemBuf++) {
433: usSemNum = getusd(&(pstSemBuf->sem_num));
434: sSemOper = getusd(&(pstSemBuf->sem_op));
435: sSemFlg = getusd(&(pstSemBuf->sem_flg));
436:
437: if (sSemOper < -SEMVMX || sSemOper > SEMVMX) {
438: semundo(rpstSemSet, pstSops, i);
439: u.u_error = E2BIG;
440: unlock(gSemGate);
441: return;
442: }
443: if ((u.u_error != 0) || (usSemNum >= rpstSemSet->sem_nsems)) {
444: /* We have falure here. undo all previous
445: * operations.
446: */
447: semundo(rpstSemSet, pstSops, i);
448: /* If u_error was not set it means that sem_number
449: * is bad. So, set error to EFBIG.
450: */
451: if (u.u_error == 0)
452: u.u_error = EFBIG;
453: unlock(gSemGate);
454: return;
455: }
456:
457: /* Go to proper semaphore */
458: rpstSem = rpstSemSet->sem_base + usSemNum;
459:
460: /* We can have 3 different cases: sSemOper < 0,
461: * sSemOper == 0, & sSemOper > 0.
462: */
463: if (sSemOper < 0) { /* want to decrement semval */
464: /* We do not have to undo anything. If we cannot alter
465: * we did not change any value in the set. But we
466: * have to check here because other requests could be
467: * for read (sSemOper=0)
468: */
469: if (iSemPerm(rpstSemSet, SEM_A)) { /* cannot alter */
470: unlock(gSemGate);
471: return;
472: }
473:
474: /* If we can decrement semval, do it. If
475: * semval becomes 0 wakeup all processes
476: * waiting for semval==0.
477: */
478: if (rpstSem->semval >= -sSemOper) {
479: if (!(rpstSem->semval += sSemOper))
480: if (rpstSem->semzcnt)
481: wakeup(&rpstSem->semzcnt);
482: if (sSemFlg & SEM_UNDO) {
483: if (iSubAdj(iSemId,usSemNum,sSemOper)) {
484: semundo(rpstSemSet, pstSops, i);
485: unlock(gSemGate);
486: return;
487: }
488: }
489: change++;
490: continue;
491: }
492: /* Can't decrement. */
493: semundo(rpstSemSet, pstSops, i);
494: if (sSemFlg & IPC_NOWAIT) {
495: if (u.u_error == 0)
496: u.u_error = EAGAIN;
497: unlock(gSemGate);
498: return;
499: } else {/* Go to sleep */
500: unlock(gSemGate);
501: if (semwait(iSemId, &rpstSem->semncnt) < 0) {
502: return;
503: }
504: /* Now we can retry semaphore set */
505: goto TRY_AGAIN;
506: }
507: }
508: if (sSemOper == 0) {
509: if (iSemPerm(rpstSemSet, SEM_R)) { /* cannot read */
510: /* If somebody cannot read it does not
511: * mean that one couldn't alter.
512: */
513: if (iSemPerm(rpstSemSet, SEM_A))
514: semundo(rpstSemSet, pstSops, i);
515:
516: unlock(gSemGate);
517: return;
518: }
519: if (rpstSem->semval == 0) {
520: continue;
521: }
522: /* Semaphore value isn't 0. Undo all previous
523: * operations.
524: */
525: semundo(rpstSemSet, pstSops, i);
526:
527: if (sSemFlg & IPC_NOWAIT) {
528: if (u.u_error == 0)
529: u.u_error = EAGAIN;
530: unlock(gSemGate);
531: return;
532: }
533:
534: unlock(gSemGate);
535: if (semwait(iSemId, &rpstSem->semzcnt) < 0) {
536: return;
537: }
538: goto TRY_AGAIN;
539: }
540: if (sSemOper > 0) {
541: if (iSemPerm(rpstSemSet, SEM_A)) { /* cannot alter */
542: unlock(gSemGate);
543: return;
544: }
545: if (sSemFlg & SEM_UNDO) {
546: if (iSubAdj(iSemId, usSemNum, sSemOper)) {
547: semundo(rpstSemSet, pstSops, i);
548: unlock(gSemGate);
549: return;
550: }
551: }
552: if (rpstSem->semval > SEMVMX - sSemOper) {
553: semundo(rpstSemSet, pstSops, i);
554: /* semundo would not adjust current semaphore */
555: if (sSemFlg & SEM_UNDO) {
556: iSubAdj(iSemId, usSemNum, -sSemOper);
557: }
558: u.u_error = ERANGE;
559: unlock(gSemGate);
560: return;
561: }
562: rpstSem->semval += sSemOper;
563:
564: /* Wake up waiting processes */
565: if (rpstSem->semncnt)
566: wakeup(&rpstSem->semncnt);
567: change++;
568: continue;
569: }
570: }
571: rpstSemSet->sem_otime = timer.t_time; /* adjust semop time */
572: if (change) /* Semaphore was changed */
573: rpstSemSet->sem_ctime = timer.t_time;
574:
575: /* Go through all set again and set pid of last semop */
576: for (i = 0, pstSemBuf = pstSops; i < uNsops; i++, pstSemBuf++) {
577: usSemNum = getusd(&(pstSemBuf->sem_num));
578: rpstSem = rpstSemSet->sem_base + usSemNum;
579: rpstSem->sempid = SELF->p_pid;
580: }
581: unlock(gSemGate);
582: return 0; /* return last prev semval */
583: }
584:
585: /*
586: * Wait for an event.
587: */
588: semwait(iSemId, usSleepEvent)
589: int iSemId; /* Semaphore set id */
590: unsigned short *usSleepEvent; /* Could be semcnt or semzcnt */
591: {
592: register struct semid_ds *rpstSemSet; /* Semaphore set */
593:
594: (*usSleepEvent)++;
595:
596: rpstSemSet = semids + iSemId;
597:
598: x_sleep(usSleepEvent, pritty, slpriSigCatch, "semwait");
599:
600: if (!(rpstSemSet->sem_perm.mode & IPC_ALLOC)) { /* Semaphore gone */
601: u.u_error = EIDRM;
602: return -1;
603: }
604: (*usSleepEvent)--;
605:
606: if (SELF->p_ssig && nondsig()) { /* Signal received */
607: u.u_error = EINTR;
608: return -1;
609: }
610: return 0;
611: }
612:
613: /*
614: * Undo a Semaphore Operation. It should undo an adjust values too.
615: */
616: semundo(pstSemSet, pstSemOp, iUndo)
617: struct semid_ds *pstSemSet; /* Pointer to the semaphore set */
618: struct sembuf *pstSemOp; /* Pointer to the undo operation */
619: int iUndo; /* Number of semaphores to undo */
620: {
621: register struct sem *rpstSem; /* */
622: register struct sembuf *rpstBuf; /* */
623: register int i; /* Loop index */
624: int iSemId; /* Semaphore id */
625: unsigned short usSemNum; /* Semaphore number */
626: short sSemOper; /* Value to undo */
627: short sSemFlg; /* Semaphore flag */
628:
629: rpstSem = pstSemSet->sem_base;
630: rpstBuf = pstSemOp;
631: iSemId = pstSemSet - semids;
632: for (i = 0; i < iUndo; i++) {
633: usSemNum = getusd( &(rpstBuf->sem_num) );
634: sSemOper = getusd( &(rpstBuf->sem_op) );
635: sSemFlg = getusd( &(rpstBuf->sem_flg) );
636: rpstSem->semval -= sSemOper;
637: if (sSemFlg & SEM_UNDO) {
638: iSubAdj(iSemId, usSemNum, -sSemOper);
639: }
640: rpstBuf++;
641: rpstSem++;
642: }
643: }
644:
645: /*
646: * Check permissions of the semaphore set.
647: * Return 0 on success, -1 and set errno on error.
648: */
649: int iSemPerm(pstSemId, iSemFlg)
650: struct semid_ds *pstSemId; /* Pointer to the semaphor set */
651: int iSemFlg; /* Requested permissions */
652: {
653: int iSemMode;
654:
655: /* Check if resource is alloced */
656: if ((pstSemId->sem_perm.mode & IPC_ALLOC) == 0) {
657: u.u_error = EINVAL;
658: return -1;
659: }
660:
661: /* We need 9 lower order bits. There is a question what we have to do
662: * if someone sets an execute bits on. At this point we just ignore
663: * them.
664: */
665: iSemMode = iSemFlg & 0666;
666:
667: /* For superuser or if mode is 0 */
668: if (u.u_uid == 0 || !iSemMode)
669: return 0;
670:
671: /* For owner or creator */
672: if (u.u_uid == pstSemId->sem_perm.uid || u.u_uid
673: == pstSemId->sem_perm.cuid) {
674: if ((iSemMode & pstSemId->sem_perm.mode) & 0600)
675: return 0;
676: else {
677: u.u_error = EACCES;
678: return -1;
679: }
680: }
681: /* For group */
682: if (u.u_gid == pstSemId->sem_perm.gid
683: || u.u_gid == pstSemId->sem_perm.cgid) {
684: if ((iSemMode & pstSemId->sem_perm.mode) & 060)
685: return 0;
686: else {
687: u.u_error = EACCES;
688: return -1;
689: }
690: }
691: /* For the rest of the world */
692: if ((iSemMode & pstSemId->sem_perm.mode) & 06)
693: return 0;
694: else {
695: u.u_error = EACCES;
696: return -1;
697: }
698: /* We should never come here */
699: u.u_error = EACCES;
700: return -1;
701: }
702:
703: /*
704: * Allocate and clear space for semapohore sets
705: * Return 0 on success, -1 and set errno on error.
706: */
707: iSemInit()
708: {
709: unsigned uSize; /* Size of the alloc memmory */
710:
711: uSize = sizeof(struct semid_ds) * SEMMNI;
712:
713: if ((semids = (struct semid_ds *) kalloc(uSize)) == NULL)
714: return -1;
715: memset((char *) semids, 0, uSize);
716: return 0;
717: }
718:
719: /*
720: * Check if semaphore number is a valid number.
721: */
722: iSanityCheck(iSemNumber)
723: int iSemNumber; /* Requested number of the semaphores in the set */
724: {
725: /* Just to be on safe side */
726: if (u.u_error)
727: return -1;
728:
729: /* Check if we are inside system limits. */
730: if (iSemNumber >= SEMMSL || iSemNumber < 0) {
731: u.u_error = EINVAL;
732: return -1;
733: }
734: return 0;
735: }
736:
737: /*
738: * Subtract iValue from the adjust value for the specified
739: * semaphore for the specified process.
740: */
741: int iSubAdj(iSemId, usSemNum, sValue)
742: int iSemId; /* Semaphore set id */
743: unsigned short usSemNum; /* Semaphore number */
744: short sValue; /* Adjust value */
745: {
746: PROC *pp; /* Current process */
747: struct sem_undo *unPrev, /* Previous and next pointers to */
748: *unNext; /* sem_undo structures link list */
749: int newAdjust; /* New adjust value */
750:
751: pp = SELF; /* Get the current process */
752:
753: /* Look if adjust value for semaphore was set */
754: for (unNext = pp->p_semu; unNext != NULL; unNext = unPrev->un_np) {
755: if (unNext->un_num == usSemNum && unNext->un_id == iSemId) {
756: newAdjust = unNext->un_aoe - sValue;
757: if (newAdjust < -SEMVMX || newAdjust > SEMVMX) {
758: u.u_error = ERANGE;
759: return -1;
760: }
761: unNext->un_aoe = newAdjust; /* Found and adjust */
762: return 0;
763: }
764: unPrev = unNext;
765: }
766: /* There is no adjust value for semaphore.
767: * We have to allocate space and creat a new adjust value.
768: */
769: if ((unNext = kalloc(sizeof(struct sem_undo))) == NULL) {
770: u.u_error = ENOSPC;
771: return -1;
772: }
773: /* Set values for the next entry */
774: unNext->un_np = NULL;
775: unNext->un_aoe -= sValue;
776: unNext->un_num = usSemNum;
777: unNext->un_id = iSemId;
778:
779: /* Put new entry at the end of link list */
780: if (pp->p_semu == NULL)
781: pp->p_semu = unNext; /* New link list */
782: else /* Add entry to the existing list */
783: unPrev->un_np = unNext; /* unPrev is a last entry in the list */
784: return 0;
785: }
786:
787: /*
788: * Clear adjust value for all process.
789: */
790: void vClearAdj(iSemId, usSemNum)
791: int iSemId; /* Semaphore set id */
792: int usSemNum; /* Semaphore number */
793: {
794: PROC *pp; /* process */
795: struct sem_undo *unNext; /* sem_undo structures */
796:
797: /* Go through all processes and zero the proper undo entry */
798: for (pp = &procq; (pp = pp->p_nforw) != &procq; ) {
799: /* Look if adjust value for semaphore was set. */
800: for (unNext = pp->p_semu; unNext != NULL;
801: unNext = unNext->un_np) {
802: if (unNext->un_num == usSemNum
803: && unNext->un_id == iSemId)
804: unNext->un_aoe = 0; /* Found */
805: }
806: }
807: }
808:
809: /*
810: * Adjust all semaphores and remove sem_undo link list.
811: */
812: semAllAdjust(pp)
813: PROC *pp;
814: {
815: struct sem_undo *unPrev, /* Previous and next pointers to */
816: *unNext; /* sem_undo structures link list */
817: struct semid_ds *pstSemSet; /* Semaphore set */
818: struct sem *pstSem; /* Semaphore */
819:
820: if ((unNext = pp->p_semu) == NULL)
821: return;
822:
823: while (unNext != NULL) {
824: pstSemSet = semids + unNext->un_id; /* Requested set */
825: pstSem = pstSemSet->sem_base + unNext->un_num;
826: pstSem->semval += unNext->un_aoe;
827: pstSem->sempid = SELF->p_pid;
828: pstSemSet->sem_ctime = timer.t_time;
829: unPrev = unNext;
830: unNext = unPrev->un_np;
831: kfree(unPrev);
832: }
833: /*kfree(pp->p_semu);*/
834: pp->p_semu = NULL;
835: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.