|
|
1.1 root 1: /* $Header: /kernel/kersrc/io.286/sem.c,v 1.1 92/07/17 15:24:44 bin Exp Locker: bin $
2: *
3: * The information contained herein is a trade secret of INETCO
4: * Systems, and is confidential information. It is provided under
5: * a license agreement, and may be copied or disclosed only under
6: * the terms of that agreement. Any reproduction or disclosure of
7: * this material without the express written authorization of
8: * INETCO Systems or persuant to the license agreement is unlawful.
9: *
10: * Copyright (c) 1985
11: * An unpublished work by INETCO Systems, Ltd.
12: * All rights reserved.
13: */
14:
15: /*
16: * System V Compatible Semaphores
17: *
18: * This module provides System V compatible semaphore operations.
19: *
20: * Author: Allan Cornish, INETCO Systems Ltd., Sep 1984
21: *
22: * $Log: sem.c,v $
23: * Revision 1.1 92/07/17 15:24:44 bin
24: * Initial revision
25: *
26: * Revision 2.1 88/09/03 13:11:37 src
27: * *** empty log message ***
28: *
29: * Revision 1.1 88/03/24 17:06:22 src
30: * Initial revision
31: *
32: * 85/08/06 Allan Cornish
33: * Sem.c split into configuration (semcon.c) and implementation (sem.c).
34: * Semload() renamed to seminit().
35: *
36: * 85/07/22 Allan Cornish
37: * Semctl, semget, semop now return immediately if u.u_error is set.
38: *
39: * 85/07/03 Allan Cornish
40: * Replaced use of EDOM with EIDRM.
41: * Eliminated semlock() and semunlock() functions.
42: * Replaced semaccess() by calls to ipcaccess(), increasing shared ipc code.
43: */
44:
45: #include <coherent.h>
46: #include <sched.h>
47: #include <types.h>
48: #include <errno.h>
49: #include <stat.h>
50: #include <con.h>
51: #include <sem.h>
52:
53: #ifndef EIDRM
54: #define EIDRM EDOM
55: #endif
56:
57: /*
58: * Semaphore Information
59: */
60:
61: #define NSEMVAL 32767
62:
63: static
64: struct semid_ds *semids = 0;
65:
66: unsigned NSEMID = 16;
67: unsigned NSEM = 16;
68:
69: /*
70: * Semaphore Initialization.
71: *
72: * Initialize semaphore ids.
73: */
74:
75: seminit()
76: {
77: register struct semid_ds *semidp;
78:
79: if ( semids = kalloc( NSEMID * sizeof(struct semid_ds) ) ) {
80:
81: for ( semidp = &semids[NSEMID]; --semidp >= semids; )
82: semidp->sem_perm.mode = 0;
83: }
84: else {
85: printf("could not allocate %u semaphore ids\n", NSEMID);
86: NSEMID = 0;
87: }
88: }
89:
90: /*
91: * Semctl - Semaphore Control Operations.
92: */
93:
94: usemctl( semid, semnum, cmd, arg )
95:
96: unsigned semid;
97: unsigned semnum;
98: int cmd;
99: union semun {
100: int val;
101: struct semid_ds *buf;
102: unsigned short *array;
103: } arg;
104:
105: {
106: register struct semid_ds *semidp;
107: register struct sem *semp;
108: int nsems, val;
109:
110: if ( u.u_error )
111: return -1;
112:
113: if ( semid >= NSEMID ) {
114: u.u_error = EINVAL;
115: return -1;
116: }
117:
118: semidp = &semids[semid];
119:
120: if ( (semidp->sem_perm.mode & IPC_ALLOC) == 0 ) {
121: u.u_error = EINVAL;
122: return -1;
123: }
124:
125: if ((ipcaccess( &semidp->sem_perm ) & SEM_R) == 0) { /* can't read */
126: u.u_error = EACCES;
127: return -1;
128: }
129:
130: if ( semnum >= semidp->sem_nsems ) {
131: u.u_error = EFBIG;
132: return -1;
133: }
134:
135: semp = &semidp->sem_base[semnum];
136:
137: switch ( cmd ) {
138:
139: case GETVAL: /* Return value of semval */
140: return semp->semval;
141:
142: case SETVAL: /* Set semval */
143: if ((ipcaccess( &semidp->sem_perm ) & SEM_A) == 0) {
144: u.u_error = EACCES; /* can't alter */
145: return -1;
146: }
147:
148: if ( arg.val < 0 ) { /* illegal value */
149: u.u_error = ERANGE;
150: return -1;
151: }
152:
153: if ( semp->semval = arg.val ) {
154:
155: if ( semp->semncnt )
156: wakeup( &semp->semncnt );
157: }
158: else {
159: if ( semp->semzcnt )
160: wakeup( &semp->semzcnt );
161: }
162:
163: return 0;
164:
165: case GETPID: /* Return value of sempid */
166: return semp->sempid;
167:
168: case GETNCNT: /* Return value of semncnt */
169: return semp->semncnt;
170:
171: case GETZCNT: /* Return value of semzcnt */
172: return semp->semzcnt;
173:
174: case GETALL: /* Return semvals array */
175: nsems = semidp->sem_nsems;
176: semp = semidp->sem_base;
177:
178: while ( --nsems >= 0 ) {
179:
180: putuwd( (arg.array)++, (semp++)->semval );
181:
182: if ( u.u_error )
183: return -1;
184: }
185: return 0;
186:
187: case SETALL: /* Set semvals array */
188: if ( (ipcaccess( &semidp->sem_perm ) & SEM_A) == 0 ) {
189: u.u_error = EACCES;
190: return -1;
191: }
192: nsems = semidp->sem_nsems;
193: semp = semidp->sem_base;
194:
195: while ( --nsems >= 0 ) {
196:
197: if ( (val = getuwd( arg.array )) < 0 ) {
198:
199: if ( u.u_error == 0 )
200: u.u_error = ERANGE;
201: }
202: else
203: semp->semval = val;
204: arg.array++;
205: semp++;
206: }
207: if ( u.u_error )
208: return -1;
209: return 0;
210:
211: case IPC_STAT:
212: kucopy( semidp, arg.buf, sizeof(struct semid_ds) );
213: return 0;
214:
215: case IPC_SET:
216: if ( (u.u_uid != 0) && (u.u_uid != semidp->sem_perm.uid) ) {
217: u.u_error = EPERM;
218: return -1;
219: }
220: semidp->sem_perm.uid = getuwd( &((arg.buf)->sem_perm.uid ) );
221: semidp->sem_perm.gid = getuwd( &((arg.buf)->sem_perm.gid ) );
222: semidp->sem_perm.mode =
223: (getuwd(&((arg.buf)->sem_perm.mode))&0777) | IPC_ALLOC;
224: return 0;
225:
226: case IPC_RMID:
227: if ( (u.u_uid != 0) && (u.u_uid != semidp->sem_perm.uid) ) {
228: u.u_error = EPERM;
229: return -1;
230: }
231: semidp->sem_perm.seq++;
232: semp = &semidp->sem_base[ semidp->sem_nsems ];
233:
234: while ( --semp >= semidp->sem_base ) {
235:
236: if ( semp->semncnt )
237: wakeup( &semp->semncnt );
238: if ( semp->semzcnt )
239: wakeup( &semp->semzcnt );
240: }
241:
242: kfree( semidp->sem_base );
243: semidp->sem_perm.mode = 0;
244: return 0;
245:
246: default:
247: u.u_error = EINVAL;
248: return -1;
249: }
250: }
251:
252: /*
253: * Semget - Get set of semaphores
254: */
255:
256: usemget( skey, nsems, semflg )
257:
258: key_t skey;
259: unsigned nsems;
260: int semflg;
261:
262: {
263: register struct semid_ds *semidp;
264: register struct sem *semp;
265: struct semid_ds *freeidp = 0;
266:
267: if ( u.u_error )
268: return -1;
269:
270: if ( nsems >= NSEM ) {
271: u.u_error = EINVAL;
272: return -1;
273: }
274:
275: for ( semidp = &semids[NSEMID]; --semidp >= semids; ) {
276:
277: if ( (semidp->sem_perm.mode & IPC_ALLOC) == 0 ) {
278:
279: if ((freeidp == 0) ||
280: (freeidp->sem_ctime > semidp->sem_ctime))
281: freeidp = semidp;
282: continue;
283: }
284:
285: #ifdef IPC_PRIVATE
286: if (skey == IPC_PRIVATE)
287: continue;
288: #endif
289:
290: if (skey == semidp->sem_perm.key) { /* found! */
291:
292: if ( (semflg & IPC_CREAT) && (semflg & IPC_EXCL) ) {
293: u.u_error = EEXIST;
294: return -1;
295: }
296:
297: if ((semidp->sem_perm.mode & semflg) != (semflg&0777)) {
298: u.u_error = EACCES;
299: return -1;
300: }
301:
302: if ( semidp->sem_nsems < nsems ) {
303: u.u_error = EINVAL;
304: return -1;
305: }
306:
307: return semidp - semids;
308: }
309: }
310:
311: if ( !(semflg & IPC_CREAT) ) {
312: u.u_error = ENOENT;
313: return -1;
314: }
315:
316: if ( freeidp == 0 ) {
317: u.u_error = ENOSPC;
318: return -1;
319: }
320:
321: semidp = freeidp;
322: semidp->sem_base = kalloc( nsems * sizeof(struct sem) );
323:
324: if (semidp->sem_base == 0 ) {
325: u.u_error = ENOSPC;
326: return -1;
327: }
328:
329: semidp->sem_nsems = nsems;
330: semidp->sem_otime = 0;
331: semidp->sem_ctime = timer.t_time;
332:
333: for ( semp = &semidp->sem_base[nsems]; --semp >= semidp->sem_base; )
334: semp->semval = semp->sempid = semp->semncnt = semp->semzcnt = 0;
335:
336: semidp->sem_perm.cuid = semidp->sem_perm.uid = u.u_uid;
337: semidp->sem_perm.cgid = semidp->sem_perm.gid = u.u_gid;
338: semidp->sem_perm.mode = (semflg & 0777) | IPC_ALLOC;
339: semidp->sem_perm.key = skey;
340:
341: return semidp - semids;
342: }
343:
344: /*
345: * Semop - Semaphore Operations.
346: */
347:
348: usemop( semid, sops, nsops )
349:
350: unsigned semid;
351: struct sembuf *sops;
352: unsigned nsops;
353:
354: {
355: register struct semid_ds *semidp;
356: register struct sem *semp;
357: struct sembuf *sp;
358: unsigned n, semnum, semflg;
359: int semop, oval;
360:
361: if ( u.u_error )
362: return -1;
363:
364: if ( semid >= NSEMID ) {
365: u.u_error = EINVAL;
366: return -1;
367: }
368:
369: if ( nsops >= NSEM ) {
370: u.u_error = E2BIG;
371: return -1;
372: }
373:
374: semidp = &semids[semid];
375:
376: if ( (semidp->sem_perm.mode & IPC_ALLOC) == 0 ) {
377: u.u_error = EINVAL;
378: return -1;
379: }
380:
381: if ( (ipcaccess( &semidp->sem_perm ) & SEM_A) == 0 ) {
382: u.u_error = EACCES;
383: return -1;
384: }
385:
386: sp = sops;
387: n = nsops;
388:
389: while ( n > 0 ) { /* do semaphore ops */
390:
391: semnum = getuwd( & (sp->sem_num) );
392: semop = getuwd( & (sp->sem_op ) );
393: semflg = getuwd( & (sp->sem_flg) );
394:
395: if ( (u.u_error != 0) || (semnum >= semidp->sem_nsems) ) {
396:
397: while ( --sp >= sops ) { /* undo prev semops */
398:
399: semnum = getuwd( &sp->sem_num );
400: semop = getuwd( &sp->sem_op );
401: semp = &semidp->sem_base[ semnum ];
402: semundo( semp, semop );
403: }
404:
405: if ( u.u_error == 0 )
406: u.u_error = EFBIG;
407: return -1;
408: }
409:
410: semp = &semidp->sem_base[semnum];
411:
412: if ( (oval = semdo( semp, semop )) < 0 ) { /* can't do semop */
413:
414: while ( --sp >= sops ) { /* undo prev semops */
415:
416: unsigned unnum = getuwd( &sp->sem_num );
417: int unop = getuwd( &sp->sem_op );
418: semundo( &semidp->sem_base[ unnum ], unop);
419: }
420:
421: if ( u.u_error )
422: return -1;
423:
424: if ( semflg & IPC_NOWAIT ) {
425: u.u_error = EAGAIN;
426: return -1;
427: }
428:
429: if ( semop < 0 ) { /* wait for non-zero */
430:
431: if (semwait( semidp, &semp->semncnt ) < 0 )
432: return -1;
433: }
434: else { /* wait for zero */
435:
436: if ( semwait( semidp, &semp->semzcnt ) < 0 )
437: return -1;
438: }
439:
440: sp = sops; /* retry set of semaphore operations */
441: n = nsops;
442: continue;
443: }
444:
445: ++sp;
446: --n;
447: }
448:
449: for (sp=sops,n=nsops; n > 0; --n,++sp) {/* save pid in each semaphore */
450:
451: semnum = getuwd( &sp->sem_num );
452: semidp->sem_base[ semnum ].sempid = SELF->p_pid;
453: }
454:
455: semidp->sem_otime = timer.t_time; /* ajust operation time */
456: return oval; /* return last prev semval */
457: }
458:
459: /*
460: * Do a Semaphore Operation.
461: *
462: * Input: semp = pointer to semaphore
463: * semop = semaphore operation
464: *
465: * Action: If semop < 0 and semval > semop then add semop to semval.
466: * If semop > 0 then add semop to semval.
467: *
468: * Return: Previous semval.
469: */
470:
471: static
472: semdo( semp, semop )
473:
474: register struct sem * semp;
475: register int semop;
476:
477: {
478: int ret;
479:
480: ret = semp->semval;
481:
482: if ( semop < 0 ) { /* want to decrement semval */
483:
484: semop = -semop;
485:
486: if ( semp->semval < semop ) /* can't decrement semval */
487: return -1;
488:
489: semp->semval -= semop;
490:
491: if ( (semp->semval == 0) && (semp->semzcnt != 0) )
492: wakeup( &semp->semzcnt );
493: }
494: else if ( semop > 0 ) { /* want to increment semval */
495:
496: if ( (semp->semval + semop) > NSEMVAL) {
497:
498: u.u_error = ERANGE;
499: return -1;
500: }
501:
502: semp->semval += semop;
503:
504: if ( semp->semncnt )
505: wakeup( &semp->semncnt );
506: }
507: else /* if ( semop == 0 ) */ {
508:
509: if ( semp->semval != 0 )
510: return -1;
511: }
512: return ret;
513: }
514:
515: /*
516: * Undo a Semaphore Operation.
517: */
518:
519: static
520: semundo( semp, semop )
521:
522: register struct sem * semp;
523: register int semop;
524:
525: {
526: if ( semp->semval -= semop ) {
527:
528: if ( semp->semncnt )
529: wakeup( &semp->semncnt );
530: }
531: else {
532: if ( semp->semzcnt )
533: wakeup( &semp->semzcnt );
534: }
535: }
536:
537: /*
538: * Wait on Semaphore Event
539: *
540: * Input: semidp = pointer to semaphore id structure.
541: * ep = pointer to semncnt or semzcnt event to wait for.
542: *
543: * Action: Sleep on a semaphore event.
544: * If semaphore id has been deleted, error return.
545: * If signal has been received, error return.
546: *
547: * Output: 0 = Status ok.
548: * -1 = Error occurred, errno is set.
549: */
550:
551: static
552: semwait( semidp, ep )
553:
554: register struct semid_ds * semidp;
555: register unsigned short *ep;
556: {
557: unsigned seqn;
558:
559: seqn = semidp->sem_perm.seq;
560: ++(*ep);
561: sleep( ep, CVTTOUT, IVTTOUT, SVTTOUT );
562:
563: if (semidp->sem_perm.seq != seqn ) { /* semaphore id gone */
564: u.u_error = EIDRM;
565: return -1;
566: }
567:
568: --(*ep);
569:
570: if ( SELF->p_ssig && nondsig() ) { /* signal received */
571: u.u_error = EINTR;
572: return -1;
573: }
574: return 0;
575: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.