|
|
1.1 root 1: /*
2: * System V Compatible Semaphores
3: *
4: * This module provides System V compatible semaphore operations.
5: *
6: * Author: Allan Cornish.
7: */
8:
9: #include <sys/coherent.h>
10: #include <sys/sched.h>
11: #include <sys/types.h>
12: #include <sys/uproc.h>
13: #include <errno.h>
14: #include <sys/stat.h>
15: #include <sys/con.h>
16: #include <sys/sem.h>
17:
18: #ifndef EIDRM
19: #define EIDRM EDOM
20: #endif
21:
22: /*
23: * Semaphore Information
24: */
25:
26: #define NSEMVAL 32767
27:
28: static
29: struct semid_ds *semids = 0;
30:
31: unsigned NSEMID = 16;
32: unsigned NSEM = 16;
33:
34:
35: /*
36: * Semaphore Initialization.
37: *
38: * Initialize semaphore ids.
39: */
40:
41: seminit()
42: {
43: register struct semid_ds *semidp;
44:
45: if (semids = kalloc(NSEMID * sizeof(struct semid_ds))) {
46: for (semidp = &semids[NSEMID]; --semidp >= semids;)
47: semidp->sem_perm.mode = 0;
48: } else {
49: printf("could not allocate %u semaphore ids\n", NSEMID);
50: NSEMID = 0;
51: }
52: }
53:
54: /*
55: * Semctl - Semaphore Control Operations.
56: */
57: usemctl(semid, semnum, cmd, arg)
58: int semid, cmd;
59: int semnum;
60: union semun {
61: int val;
62: struct semid_ds *buf;
63: unsigned short *array;
64: } arg;
65: {
66: register struct semid_ds *semidp;
67: register struct sem *semp;
68: int nsems, val;
69:
70: /* printf("usemctl() called: semid = %ld semnum = %ld cmd = %d arg = %d",
71: * semid, semnum, cmd, arg);
72: */
73: if (u.u_error)
74: return -1;
75:
76: if (semid >= NSEMID) {
77: u.u_error = EINVAL;
78: return -1;
79: }
80:
81: semidp = &semids[semid];
82: if ((semidp->sem_perm.mode & IPC_ALLOC) == 0) {
83: u.u_error = EINVAL;
84: return -1;
85: }
86:
87: if ((ipcaccess(&semidp->sem_perm) & SEM_R) == 0) { /* can't read */
88: u.u_error = EACCES;
89: return -1;
90: }
91:
92: if (semnum >= semidp->sem_nsems) {
93: u.u_error = EFBIG;
94: return -1;
95: }
96:
97: semp = &semidp->sem_base[semnum];
98:
99: switch (cmd) {
100: case GETVAL: /* Return value of semval */
101: return semp->semval;
102: case SETVAL: /* Set semval */
103: if ((ipcaccess(&semidp->sem_perm) & SEM_A) == 0) {
104: u.u_error = EACCES; /* can't alter */
105: return -1;
106: }
107: if (arg.val < 0) { /* illegal value */
108: u.u_error = ERANGE;
109: return -1;
110: }
111: if (semp->semval = arg.val) {
112:
113: if (semp->semncnt)
114: wakeup(&semp->semncnt);
115: } else {
116: if (semp->semzcnt)
117: wakeup(&semp->semzcnt);
118: }
119: return 0;
120: case GETPID: /* Return value of sempid */
121: return semp->sempid;
122: case GETNCNT: /* Return value of semncnt */
123: return semp->semncnt;
124: case GETZCNT: /* Return value of semzcnt */
125: return semp->semzcnt;
126: case GETALL: /* Return semvals array */
127: nsems = semidp->sem_nsems;
128: semp = semidp->sem_base;
129: while (--nsems >= 0) {
130: putuwd((arg.array)++, (semp++)->semval);
131: if (u.u_error)
132: return -1;
133: }
134: return 0;
135: case SETALL: /* Set semvals array */
136: if ((ipcaccess(&semidp->sem_perm) & SEM_A) == 0) {
137: u.u_error = EACCES;
138: return -1;
139: }
140: nsems = semidp->sem_nsems;
141: semp = semidp->sem_base;
142: while (--nsems >= 0) {
143: if ((val = getuwd(arg.array)) < 0) {
144: if (u.u_error == 0)
145: u.u_error = ERANGE;
146: } else
147: semp->semval = val;
148: arg.array++;
149: semp++;
150: }
151: if (u.u_error)
152: return -1;
153: return 0;
154: case IPC_STAT:
155: kucopy(semidp, arg.buf, sizeof(struct semid_ds));
156: return 0;
157: case IPC_SET:
158: if ((u.u_uid != 0) && (u.u_uid != semidp->sem_perm.uid)) {
159: u.u_error = EPERM;
160: return -1;
161: }
162: semidp->sem_perm.uid = getuwd(&((arg.buf)->sem_perm.uid));
163: semidp->sem_perm.gid = getuwd(&((arg.buf)->sem_perm.gid));
164: semidp->sem_perm.mode =
165: (getuwd(&((arg.buf)->sem_perm.mode))&0777) | IPC_ALLOC;
166: return 0;
167: case IPC_RMID:
168: if ((u.u_uid != 0) && (u.u_uid != semidp->sem_perm.uid)) {
169: u.u_error = EPERM;
170: return -1;
171: }
172: semidp->sem_perm.seq++;
173: semp = &semidp->sem_base[ semidp->sem_nsems ];
174:
175: while (--semp >= semidp->sem_base) {
176: if (semp->semncnt)
177: wakeup(&semp->semncnt);
178: if (semp->semzcnt)
179: wakeup(&semp->semzcnt);
180: }
181: kfree(semidp->sem_base);
182: semidp->sem_perm.mode = 0;
183: return 0;
184: default:
185: u.u_error = EINVAL;
186: return -1;
187: }
188: }
189:
190: /*
191: * Semget - Get set of semaphores
192: */
193:
194: usemget(skey, nsems, semflg)
195: key_t skey;
196: int nsems, semflg;
197: {
198: register struct semid_ds *semidp;
199: register struct sem *semp;
200: struct semid_ds *freeidp = 0;
201:
202: /* printf("usemget called: skey= %x (%d) nsems= %x (%u) semflg= %x (%d)\n",
203: * skey, skey, nsems, nsems, semflg, semflg);
204: *
205: * printf("NSEM is %x (%d)\n", NSEM, NSEM);
206: */
207: if (u.u_error)
208: return -1;
209:
210: if (nsems >= NSEM) {
211: /* printf("usemget(): nsems> NSEM\n"); */
212: u.u_error = EINVAL;
213: return -1;
214: }
215:
216: for (semidp = &semids[NSEMID]; --semidp >= semids;) {
217: if ((semidp->sem_perm.mode & IPC_ALLOC) == 0) {
218: if ((freeidp == 0) ||
219: (freeidp->sem_ctime > semidp->sem_ctime))
220: freeidp = semidp;
221: continue;
222: }
223:
224: #ifdef IPC_PRIVATE
225: if (skey == IPC_PRIVATE)
226: continue;
227: #endif
228:
229: if (skey == semidp->sem_perm.key) { /* found! */
230: if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
231: u.u_error = EEXIST;
232: return -1;
233: }
234: if ((semidp->sem_perm.mode & semflg) != (semflg&0777)) {
235: u.u_error = EACCES;
236: return -1;
237: }
238: if (semidp->sem_nsems < nsems) {
239: u.u_error = EINVAL;
240: return -1;
241: }
242: return semidp - semids;
243: }
244: }
245:
246: if (!(semflg & IPC_CREAT)) {
247: u.u_error = ENOENT;
248: return -1;
249: }
250:
251: if (freeidp == 0) {
252: u.u_error = ENOSPC;
253: return -1;
254: }
255:
256: semidp = freeidp;
257: semidp->sem_base = kalloc(nsems * sizeof(struct sem));
258: if (semidp->sem_base == 0) {
259: u.u_error = ENOSPC;
260: return -1;
261: }
262: semidp->sem_nsems = nsems;
263: semidp->sem_otime = 0;
264: semidp->sem_ctime = timer.t_time;
265:
266: for (semp = &semidp->sem_base[nsems]; --semp >= semidp->sem_base;)
267: semp->semval = semp->sempid = semp->semncnt = semp->semzcnt = 0;
268:
269: semidp->sem_perm.cuid = semidp->sem_perm.uid = u.u_uid;
270: semidp->sem_perm.cgid = semidp->sem_perm.gid = u.u_gid;
271: semidp->sem_perm.mode = (semflg & 0777) | IPC_ALLOC;
272: semidp->sem_perm.key = skey;
273:
274: return semidp - semids;
275: }
276:
277: /*
278: * Semop - Semaphore Operations.
279: */
280:
281: usemop(semid, sops, nsops)
282: int semid;
283: struct sembuf *sops;
284: unsigned nsops;
285: {
286: register struct semid_ds *semidp;
287: register struct sem *semp;
288: struct sembuf *sp;
289: unsigned short n, semnum, semflg;
290: short semop, oval;
291:
292: if (u.u_error)
293: return -1;
294:
295: if (semid >= NSEMID) {
296: u.u_error = EINVAL;
297: return -1;
298: }
299:
300: if (nsops >= NSEM) {
301: u.u_error = E2BIG;
302: return -1;
303: }
304:
305: semidp = &semids[semid];
306:
307: if ((semidp->sem_perm.mode & IPC_ALLOC) == 0) {
308: u.u_error = EINVAL;
309: return -1;
310: }
311:
312: if ((ipcaccess(&semidp->sem_perm) & SEM_A) == 0) {
313: u.u_error = EACCES;
314: return -1;
315: }
316:
317: sp = sops;
318: n = nsops;
319:
320: while (n > 0) { /* do semaphore ops */
321: semnum = getuwd(& (sp->sem_num));
322: semop = getuwd(& (sp->sem_op));
323: semflg = getuwd(& (sp->sem_flg));
324:
325: if ((u.u_error != 0) || (semnum >= semidp->sem_nsems)) {
326: while (--sp >= sops) { /* undo prev semops */
327: semnum = getuwd(&sp->sem_num);
328: semop = getuwd(&sp->sem_op );
329: semp = &semidp->sem_base[ semnum ];
330: semundo(semp, semop);
331: }
332: if (u.u_error == 0)
333: u.u_error = EFBIG;
334: return -1;
335: }
336:
337: semp = &semidp->sem_base[semnum];
338:
339: if ((oval = semdo(semp, semop)) < 0) { /* can't do semop */
340: while (--sp >= sops) { /* undo prev semops */
341: unsigned unnum = getuwd(&sp->sem_num);
342: int unop = getuwd(&sp->sem_op );
343: semundo(&semidp->sem_base[ unnum ], unop);
344: }
345:
346: if (u.u_error)
347: return -1;
348:
349: if (semflg & IPC_NOWAIT) {
350: u.u_error = EAGAIN;
351: return -1;
352: }
353:
354: if (semop < 0) { /* wait for non-zero */
355: if (semwait(semidp, &semp->semncnt) < 0)
356: return -1;
357: } else { /* wait for zero */
358:
359: if (semwait(semidp, &semp->semzcnt) < 0)
360: return -1;
361: }
362:
363: sp = sops; /* retry set of semaphore operations */
364: n = nsops;
365: continue;
366: }
367:
368: ++sp;
369: --n;
370: }
371:
372: for (sp=sops,n=nsops; n > 0; --n,++sp) {/* save pid in each semaphore */
373: semnum = getuwd(&sp->sem_num);
374: semidp->sem_base[ semnum ].sempid = SELF->p_pid;
375: }
376:
377: semidp->sem_otime = timer.t_time; /* ajust operation time */
378: return oval; /* return last prev semval */
379: }
380:
381: /*
382: * Do a Semaphore Operation.
383: *
384: * Input: semp = pointer to semaphore
385: * semop = semaphore operation
386: *
387: * Action: If semop < 0 and semval > semop then add semop to semval.
388: * If semop > 0 then add semop to semval.
389: *
390: * Return: Previous semval.
391: */
392: static
393: semdo(semp, semop)
394: register struct sem * semp;
395: register int semop;
396: {
397: int ret;
398:
399: ret = semp->semval;
400:
401: if (semop < 0) { /* want to decrement semval */
402: semop = -semop;
403:
404: if (semp->semval < semop) /* can't decrement semval */
405: return -1;
406:
407: semp->semval -= semop;
408:
409: if ((semp->semval == 0) && (semp->semzcnt != 0))
410: wakeup(&semp->semzcnt);
411: } else if (semop > 0) { /* want to increment semval */
412: if ((semp->semval + semop) > NSEMVAL) {
413: u.u_error = ERANGE;
414: return -1;
415: }
416:
417: semp->semval += semop;
418:
419: if (semp->semncnt)
420: wakeup(&semp->semncnt);
421: } else /* if (semop == 0) */ {
422: if (semp->semval != 0)
423: return -1;
424: }
425: return ret;
426: }
427:
428: /*
429: * Undo a Semaphore Operation.
430: */
431: static
432: semundo(semp, semop)
433: register struct sem * semp;
434: register int semop;
435: {
436: if (semp->semval -= semop) {
437: if (semp->semncnt)
438: wakeup(&semp->semncnt);
439: } else {
440: if (semp->semzcnt)
441: wakeup(&semp->semzcnt);
442: }
443: }
444:
445: /*
446: * Wait on Semaphore Event
447: *
448: * Input: semidp = pointer to semaphore id structure.
449: * ep = pointer to semncnt or semzcnt event to wait for.
450: *
451: * Action: Sleep on a semaphore event.
452: * If semaphore id has been deleted, error return.
453: * If signal has been received, error return.
454: *
455: * Output: 0 = Status ok.
456: * -1 = Error occurred, errno is set.
457: */
458:
459: static
460: semwait(semidp, ep)
461: register struct semid_ds * semidp;
462: register unsigned short *ep;
463: {
464: unsigned seqn;
465:
466: seqn = semidp->sem_perm.seq;
467: ++(*ep);
468: #ifdef _I386
469: x_sleep(ep, pritty, slpriSigCatch, "semwait");
470: #else
471: v_sleep(ep, CVTTOUT, IVTTOUT, SVTTOUT, "semwait");
472: #endif
473:
474: if (semidp->sem_perm.seq != seqn) { /* semaphore id gone */
475: u.u_error = EIDRM;
476: return -1;
477: }
478:
479: --(*ep);
480:
481: if (SELF->p_ssig && nondsig()) { /* signal received */
482: u.u_error = EINTR;
483: return -1;
484: }
485: return 0;
486: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.