|
|
1.1 root 1: /*
2: * System V Compatible Messaging
3: *
4: * This module provides System V compatible messaging 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/seg.h>
17: #include <sys/msg.h>
18: #include <stdlib.h>
19:
20: #ifndef EIDRM
21: #define EIDRM EDOM
22: #endif
23:
24: /*
25: * Extended message queue id data structure.
26: * - extended to support System V.3 compatible polls.
27: */
28: struct xmsqid_ds {
29: struct msqid_ds msq;
30: struct event ipolls;
31: struct event opolls;
32: };
33:
34: /*
35: * Message Information
36: */
37:
38: struct xmsqid_ds *msqs = 0; /* Pointer to array of message queues */
39: /* (first queue contains free message list) */
40:
41: struct msg * msgs = 0; /* Pointer to array of message headers */
42:
43: #ifdef _I386
44: char *msgsp;
45: #else
46: static SEG * msgsp;
47: #define msgsel FP_SEL(msgsp->s_faddr)
48: #endif
49:
50: /*
51: * Global Message Parameters
52: */
53:
54: unsigned NMSQID = 9; /* allocated number of message queues */
55: unsigned NMSQB = 2048; /* default maximum queue size in bytes */
56: unsigned NMSG = 10; /* allocated messages: (NMSG * NMSC) < 2^16 */
57: unsigned NMSC = 640; /* maximum message text size */
58:
59:
60: /*
61: * Message Device Initialization.
62: *
63: * Initialize message ids.
64: */
65:
66: msginit()
67: {
68: register struct xmsqid_ds *qp;
69: register struct msg *mp;
70: long wanted;
71: int i;
72:
73: if ( NMSG == 0 )
74: NMSQID = 0;
75: if ( NMSC == 0 )
76: NMSQID = 0;
77: if ( NMSQID == 0 )
78: return 0;
79:
80: if ( NMSQID > 128 )
81: NMSQID = 128;
82:
83: /*
84: * Allocate message queues and message headers.
85: */
86: wanted = (NMSQID * (long) sizeof(struct xmsqid_ds)) +
87: (NMSG * (long) sizeof(struct msg));
88: if (wanted > 16384) {
89: printf("invalid NMSQID or NMSG kernel variable\n");
90: NMSQID=0;
91: return;
92: }
93:
94: /* allocate memory for the headers, msqs points to headers */
95:
96: if ( msqs = kalloc( (unsigned) wanted) ) {
97:
98: /*
99: * Ensure allocated space is cleared.
100: */
101: #ifndef _I386
102: memset( msqs, 0, (unsigned) wanted );
103: #else
104: kclear(msqs, (size_t) wanted);
105: #endif
106: /*
107: * Message headers are contiguous to message queues.
108: */
109: msgs = (struct msg *) (&msqs[NMSQID]); /* msgs points to
110: * LAST header.
111: */
112: /*
113: * Allocate message buffers.
114: */
115: wanted = (long) NMSG * NMSC;
116:
117: if ( wanted > 0xFFFFL ) {
118: printf("invalid NMSG or NMSC kernel variable\n");
119: kfree( msqs );
120: NMSQID = 0;
121: msqs = 0;
122: return;
123: }
124:
125: #ifdef _I386
126: msgsp = kalloc( (size_t) wanted );
127: #else
128: msgsp = salloc( (size_t) wanted, SFHIGH|SFNSWP|SFNCLR);
129: #endif
130: if ( msgsp == 0 ) {
131: printf("could not kalloc %u messages\n", NMSG);
132: kfree( msqs );
133: NMSQID = 0;
134: msqs = 0;
135: return;
136: }
137:
138: kclear(msgsp, (size_t) wanted);
139:
140: /*
141: * Initialize message queues.
142: */
143: for ( qp = msqs, i = 0; i < NMSQID; i++, qp++ ) {
144:
145: qp->msq.msg_perm.seq = i * 256;
146:
147: qp->ipolls.e_dnext =
148: qp->ipolls.e_dlast = &qp->ipolls;
149:
150: qp->opolls.e_dnext =
151: qp->opolls.e_dlast = &qp->opolls;
152: }
153:
154: /*
155: * Initialize message headers, place on free queue.
156: */
157: for ( qp = msqs, mp = &msgs[NMSG]; --mp >= msgs; ) {
158: wanted -= NMSC; /* offset for message text */
159: mp->msg_spot = wanted;
160: mp->msg_next = qp->msq.msg_first;
161: qp->msq.msg_first = mp;
162: }
163: }
164: else {
165: printf("could not kalloc %u message ids\n", NMSQID);
166: NMSQID = 0;
167: }
168:
169: }
170:
171:
172: /*
173: * Msgctl - Message Control Operations.
174: */
175:
176: umsgctl( qid, cmd, buf )
177:
178: int qid;
179: int cmd;
180: struct msqid_ds *buf;
181:
182: {
183: register struct xmsqid_ds *qp;
184: register struct msg *mp;
185: unsigned n;
186:
187: /*
188: * Validate queue identifier.
189: */
190: if ( (qid <= 0) || (qid/256 >= NMSQID) || (msqs == 0) ) {
191: u.u_error = EINVAL;
192: return -1;
193: }
194:
195: qp = &msqs[ qid / 256 ];
196:
197: /*
198: * Validate queue existence.
199: */
200: if ( (qp == 0) || ((qp->msq.msg_perm.mode & IPC_ALLOC) == 0) ) {
201: u.u_error = EINVAL;
202: return -1;
203: }
204:
205: /*
206: * Validate qid for all commands except for IPC_STAT.
207: */
208: if ( (cmd != IPC_STAT) && (qp->msq.msg_perm.seq != qid) ) {
209: u.u_error = EINVAL;
210: return -1;
211: }
212:
213: switch ( cmd ) {
214:
215: case IPC_STAT:
216: /*
217: * Validate access authority.
218: */
219: if ( (ipcaccess(&qp->msq.msg_perm) & MSG_R) == 0 ) {
220: u.u_error = EACCES;
221: break;
222: }
223:
224: /*
225: * Copy queue info to user.
226: */
227: kucopy( qp, buf, sizeof(struct msqid_ds) );
228:
229: /*
230: * Include input polls in receive waiting.
231: */
232: if ( (qp->ipolls.e_dnext != NULL)
233: && (qp->ipolls.e_dnext != &qp->ipolls) ) {
234: putuwd( &buf->msg_perm.mode,
235: getuwd( &buf->msg_perm.mode ) | MSG_RWAIT );
236: }
237:
238: /*
239: * Include output polls in write waiting.
240: */
241: if ( (qp->opolls.e_dnext != NULL)
242: && (qp->opolls.e_dnext != &qp->opolls) ) {
243: putuwd( &buf->msg_perm.mode,
244: getuwd( &buf->msg_perm.mode ) | MSG_WWAIT );
245: }
246:
247: /*
248: * Validate qid.
249: * Doing it now lets user get info on message queue.
250: */
251: if ( qp->msq.msg_perm.seq != qid )
252: u.u_error = EINVAL;
253: break;
254:
255: case IPC_SET:
256: /*
257: * Validate modify authority.
258: */
259: if ( (u.u_uid != 0) && (u.u_uid != qp->msq.msg_perm.uid) ) {
260: u.u_error = EPERM;
261: break;
262: }
263:
264: /*
265: * Get desired queue size.
266: */
267: n = getuwd( &(buf->msg_qbytes) );
268: if (u.u_error)
269: break;
270:
271: /*
272: * Only super-user can increase queue size.
273: */
274: if ( (u.u_uid != 0) && (n > qp->msq.msg_qbytes) ) {
275: u.u_error = EPERM;
276: break;
277: }
278:
279: /*
280: * Set queue parameters.
281: */
282: qp->msq.msg_perm.uid = getuwd( &(buf->msg_perm.uid ) );
283: qp->msq.msg_perm.gid = getuwd( &(buf->msg_perm.gid ) );
284: qp->msq.msg_perm.mode &= ~0777;
285: qp->msq.msg_perm.mode |= getuwd( &(buf->msg_perm.mode) ) & 0777;
286: qp->msq.msg_qbytes = n;
287: break;
288:
289: case IPC_RMID:
290: /*
291: * Validate removal authority.
292: */
293: if ( (u.u_uid != 0) && (u.u_uid != qp->msq.msg_perm.uid) ) {
294: u.u_error = EPERM;
295: break;
296: }
297: /*
298: * Free all messages on the queue being removed.
299: */
300: while ( mp = qp->msq.msg_first ) {
301: qp->msq.msg_first = mp->msg_next;
302: mp->msg_next = msqs->msq.msg_first;
303: msqs->msq.msg_first = mp;
304: }
305:
306: /*
307: * Wakeup processes waiting for free message buffers.
308: */
309: if ( msqs->msq.msg_perm.mode & MSG_RWAIT ) {
310: msqs->msq.msg_perm.mode &= ~MSG_RWAIT;
311: wakeup( msqs );
312: }
313: if ( msqs->ipolls.e_procp )
314: pollwake( &msqs->ipolls );
315:
316: /*
317: * Initialize queue parameters.
318: */
319: qp->msq.msg_last = 0;
320: qp->msq.msg_qnum = 0;
321: qp->msq.msg_cbytes = 0;
322: if ( (qp->msq.msg_perm.seq & 0x00FF) == 0x00FF )
323: qp->msq.msg_perm.seq &= 0x7F00;
324: qp->msq.msg_perm.seq++;
325:
326:
327: /*
328: * Wakeup processes sleeping on the removed message queue.
329: */
330: if ( qp->msq.msg_perm.mode & (MSG_RWAIT|MSG_WWAIT) )
331: wakeup( qp );
332: if ( qp->ipolls.e_procp )
333: pollwake( &qp->ipolls );
334: if ( qp->opolls.e_procp )
335: pollwake( &qp->opolls );
336:
337: qp->msq.msg_perm.mode = 0;
338: break;
339:
340: default:
341: u.u_error = EINVAL;
342: }
343:
344: if ( u.u_error )
345: return -1;
346:
347: return 0;
348: }
349:
350: /*
351: * Msgget - Get set of messages
352: */
353:
354: umsgget( mykey, msgflg )
355:
356: key_t mykey;
357: int msgflg;
358:
359: {
360: register struct xmsqid_ds *qp;
361: register struct xmsqid_ds *freeidp = 0;
362: int rwmode;
363:
364: if ( msqs == 0 ) {
365:
366: msginit();
367:
368: if ( msqs == 0 ) {
369: u.u_error = ENOMEM;
370: return;
371: }
372: }
373:
374: /*
375: * Extract desired access mode from flags.
376: */
377: rwmode = msgflg & 0777;
378:
379: /*
380: * Search for desired message queue [also for first free queue].
381: */
382: for ( qp = &msqs[NMSQID]; --qp > msqs; ) {
383:
384: if ( (qp->msq.msg_perm.mode & IPC_ALLOC) == 0 ) {
385:
386: if ((freeidp == 0) ||
387: (freeidp->msq.msg_ctime > qp->msq.msg_ctime))
388: freeidp = qp;
389: continue;
390: }
391:
392: if (mykey == IPC_PRIVATE)
393: continue;
394:
395: if ( mykey == qp->msq.msg_perm.key ) { /* found! */
396:
397: if ( (msgflg & IPC_CREAT) && (msgflg & IPC_EXCL) ) {
398: u.u_error = EEXIST;
399: return -1;
400: }
401:
402: if ( (qp->msq.msg_perm.mode & rwmode) != rwmode ) {
403: u.u_error = EACCES;
404: return -1;
405: }
406:
407: return qp->msq.msg_perm.seq;
408: }
409: }
410:
411: if ( ! (msgflg & IPC_CREAT) ) {
412: u.u_error = ENOENT;
413: return -1;
414: }
415:
416: if ( (qp = freeidp) == 0 ) {
417: u.u_error = ENOSPC;
418: return -1;
419: }
420:
421: qp->msq.msg_first = 0;
422: qp->msq.msg_last = 0;
423: qp->msq.msg_cbytes = 0;
424: qp->msq.msg_qnum = 0;
425: qp->msq.msg_qbytes = NMSQB;
426: qp->msq.msg_lspid = 0;
427: qp->msq.msg_lrpid = 0;
428: qp->msq.msg_stime = 0;
429: qp->msq.msg_rtime = 0;
430: qp->msq.msg_ctime = timer.t_time;
431:
432: qp->msq.msg_perm.cuid = qp->msq.msg_perm.uid = u.u_uid;
433: qp->msq.msg_perm.cgid = qp->msq.msg_perm.gid = u.u_gid;
434: qp->msq.msg_perm.mode = rwmode | IPC_ALLOC;
435: qp->msq.msg_perm.key = mykey;
436:
437: return qp->msq.msg_perm.seq;
438: }
439:
440: /*
441: * Send a Message
442: */
443:
444: umsgsnd( qid, bufp, msgsz, msgflg )
445: int qid;
446: struct msgbuf *bufp;
447: int msgsz, msgflg;
448:
449: {
450: register struct xmsqid_ds * qp;
451: register struct msg * mp;
452:
453: /*
454: * Validate queue identifier.
455: */
456:
457:
458: if ((qid <= 0) || (qid/256 >= NMSQID) || (msgsz > NMSC) || (msqs==0)) {
459: u.u_error = EINVAL;
460: return -1;
461: }
462:
463: qp = &msqs[ qid / 256 ];
464:
465: /*
466: * Validate queue existence.
467: */
468: if ( (qp->msq.msg_perm.seq != qid)
469: || ((qp->msq.msg_perm.mode & IPC_ALLOC) == 0) ) {
470: u.u_error = EINVAL;
471: return -1;
472: }
473:
474: if ((ipcaccess(&qp->msq.msg_perm) & MSG_W) == 0){ /* can't send mesg */
475: u.u_error = EACCES;
476: return -1;
477: }
478:
479: /*
480: * Wait for a free message buffer
481: */
482:
483: while ( (msqs->msq.msg_first == 0)
484: || (qp->msq.msg_qbytes <= qp->msq.msg_cbytes)) {
485:
486: if ( msgflg & IPC_NOWAIT ) {
487: u.u_error = EAGAIN;
488: return -1;
489: }
490:
491: if (qp->msq.msg_qbytes <= qp->msq.msg_cbytes) {
492: qp->msq.msg_perm.mode |= MSG_WWAIT;
493: sleep( qp, CVTTOUT, IVTTOUT, SVTTOUT );
494: }
495: else {
496: msqs->msq.msg_perm.mode |= MSG_RWAIT;
497: sleep( msqs, CVTTOUT, IVTTOUT, SVTTOUT );
498: }
499:
500: /*
501: * Abort if a signal was received
502: */
503: if (SELF->p_ssig && nondsig() ) {
504: u.u_error = EINTR;
505: return -1;
506: }
507:
508: /*
509: * Abort if the message queue was removed.
510: */
511: if ( qid != qp->msq.msg_perm.seq ) {
512: u.u_error = EIDRM;
513: return -1;
514: }
515: }
516:
517: /*
518: * Use first message on free message queue
519: */
520: mp = msqs->msq.msg_first;
521: mp->msg_ts = msgsz;
522:
523: /*
524: * Transfer the message type and text.
525: */
526:
527: ukcopy( &(bufp->mtype), &(mp->msg_type), sizeof(mp->msg_type) );
528: #ifdef _I386
529: if ( ukcopy( &bufp->mtext[0],(msgsp + mp->msg_spot), msgsz ) != msgsz )
530: #else
531: if ( ufcopy( &bufp->mtext[0],mp->msg_spot, msgsel, msgsz ) != msgsz )
532: #endif
533: u.u_error = EFAULT;
534:
535: /*
536: * Abort if address fault occured during transfer.
537: */
538: if ( u.u_error )
539: return -1;
540:
541: /*
542: * Move the message to the desired queue.
543: */
544:
545:
546: msqs->msq.msg_first = mp->msg_next;
547: mp->msg_next = 0;
548:
549: if ( qp->msq.msg_last )
550: qp->msq.msg_last->msg_next = mp;
551: else
552: qp->msq.msg_first = mp;
553: qp->msq.msg_last = mp;
554:
555: /*
556: * Update queue statistics.
557: */
558:
559: qp->msq.msg_cbytes += msgsz;
560: qp->msq.msg_qnum++;
561: qp->msq.msg_lspid = SELF->p_pid;
562: qp->msq.msg_stime = timer.t_time;
563:
564: /*
565: * Wake processes waiting to receive.
566: */
567:
568:
569: if ( qp->msq.msg_perm.mode & MSG_RWAIT ) {
570: qp->msq.msg_perm.mode &= ~MSG_RWAIT;
571: wakeup( qp );
572: }
573: if ( qp->ipolls.e_procp )
574: pollwake( &qp->ipolls );
575:
576: return 0;
577: }
578:
579: /*
580: * Receive A Message
581: */
582:
583: umsgrcv( qid, bufp, msgsz, msgtyp, msgflg )
584:
585: int qid;
586: struct msgbuf *bufp;
587: int msgsz;
588: long msgtyp;
589: int msgflg;
590:
591: {
592: register struct xmsqid_ds *qp;
593: register struct msg *mp;
594: register struct msg *prev;
595:
596:
597: /*
598: * Validate queue identifier.
599: */
600:
601: if ( (qid <= 0) || (qid/256 >= NMSQID) || (msqs == 0) ) {
602: u.u_error = EINVAL;
603: return -1;
604: }
605:
606: qp = &msqs[ qid / 256 ];
607:
608: /*
609: * Validate queue existence.
610: */
611: if ( (qp->msq.msg_perm.seq != qid)
612: || ((qp->msq.msg_perm.mode & IPC_ALLOC) == 0) ) {
613: u.u_error = EINVAL;
614: return -1;
615: }
616:
617: /*
618: * Permission denied
619: */
620: if ( (ipcaccess(&qp->msq.msg_perm) & MSG_R) == 0 ) {
621: u.u_error = EACCES;
622: return -1;
623: }
624:
625: /*
626: * Wait for message
627: */
628: for (;;) {
629:
630: mp = qp->msq.msg_first;
631: prev = 0;
632:
633: /*
634: * Find mesg of type <= abs(msgtyp)
635: */
636:
637: if ( msgtyp < 0 ) {
638:
639: struct msg *xp, *xprev;
640:
641: xp = 0;
642: xprev = 0;
643: msgtyp = -msgtyp;
644:
645: for ( ; mp != 0 ; prev = mp, mp = mp->msg_next ) {
646:
647: if (mp->msg_type > msgtyp)
648: continue;
649:
650: if ((xp==0) || (mp->msg_type < xp->msg_type)) {
651: xp = mp;
652: xprev = prev;
653: }
654: }
655: mp = xp;
656: prev = xprev;
657: msgtyp = -msgtyp;
658: }
659:
660: /*
661: * Find message of type == msgtyp
662: */
663: else if ( msgtyp > 0 ) {
664:
665: while ( (mp != 0) && (mp->msg_type != msgtyp) ) {
666: prev = mp;
667: mp = mp->msg_next;
668: }
669: }
670:
671: /*
672: * Else take first message
673: */
674:
675: if ( mp )
676: break;
677:
678: /*
679: * Can't wait to receive mesg
680: */
681: if ( msgflg & IPC_NOWAIT ) {
682: u.u_error = EAGAIN;
683: return -1;
684: }
685:
686: qp->msq.msg_perm.mode |= MSG_RWAIT;
687: sleep( qp, CVTTOUT, IVTTOUT, SVTTOUT );
688:
689: /*
690: * Signal received
691: */
692: if ( SELF->p_ssig && nondsig() ) {
693: u.u_error = EINTR;
694: return -1;
695: }
696:
697: /*
698: * Not same q anymore
699: */
700: if ( qid != qp->msq.msg_perm.seq ) {
701: u.u_error = EIDRM;
702: return -1;
703: }
704: }
705:
706: /*
707: * Ensure entire message can be transferred, or MSG_NOERROR asserted.
708: */
709:
710: if ( (msgsz < mp->msg_ts) && ((msgflg & MSG_NOERROR) == 0) ) {
711: u.u_error = E2BIG;
712: return -1;
713: }
714:
715: /*
716: * Transfer message data
717: */
718: if ( msgsz > mp->msg_ts )
719: msgsz = mp->msg_ts;
720:
721: kucopy( &(mp->msg_type), &(bufp->mtype), sizeof(mp->msg_type) );
722: #ifdef _I386
723: if (kucopy( (msgsp + mp->msg_spot), &(bufp->mtext[0]), msgsz ) != msgsz)
724: #else
725: if (fucopy( mp->msg_spot, msgsel, &(bufp->mtext[0]), msgsz ) != msgsz)
726: #endif
727: u.u_error = EFAULT;
728:
729: /*
730: * Abort if address fault occurred during transfer.
731: */
732: if ( u.u_error )
733: return -1;
734:
735: /*
736: * Remove message from queue
737: */
738: if ( prev )
739: prev->msg_next = mp->msg_next;
740: else
741: qp->msq.msg_first = mp->msg_next;
742:
743: if ( qp->msq.msg_last == mp )
744: qp->msq.msg_last = prev;
745:
746:
747: /*
748: * Update queue statistics
749: */
750: qp->msq.msg_cbytes -= mp->msg_ts;
751: qp->msq.msg_qnum--;
752: qp->msq.msg_lrpid = SELF->p_pid;
753: qp->msq.msg_rtime = timer.t_time;
754:
755: /*
756: * Wakeup processes waiting to send.
757: */
758:
759: if (qp->msq.msg_perm.mode & MSG_WWAIT) {
760: qp->msq.msg_perm.mode &= ~MSG_WWAIT;
761: wakeup( qp );
762: }
763: if ( qp->opolls.e_procp )
764: pollwake( &qp->opolls );
765:
766:
767: /*
768: * Place message buffer on free message queue
769: */
770: qp = msqs;
771: mp->msg_next = qp->msq.msg_first;
772: qp->msq.msg_first = mp;
773:
774: /*
775: * Wakeup processes waiting for empty message buffer
776: */
777: if ( qp->msq.msg_perm.mode & MSG_RWAIT ) {
778: qp->msq.msg_perm.mode &= ~MSG_RWAIT;
779: wakeup( qp );
780: }
781: if ( msqs->ipolls.e_procp )
782: pollwake( &msqs->ipolls );
783:
784:
785: return msgsz;
786: }
787:
788: /*
789: * Msgpoll - Message Queue Polling.
790: */
791: msgpoll( qid, ev, msec )
792: int qid;
793: int ev;
794: int msec;
795: {
796: register struct xmsqid_ds * qp;
797:
798: /*
799: * Validate queue identifier.
800: */
801: if ( (qid <= 0) || (qid/256 >= NMSQID) || (msqs == 0) )
802: return POLLNVAL;
803:
804: qp = &msqs[ qid / 256 ];
805:
806: /*
807: * Validate queue existence.
808: */
809: if ( ((qp->msq.msg_perm.mode & IPC_ALLOC) == 0)
810: || (qp->msq.msg_perm.seq != qid) )
811: return POLLHUP;
812:
813: /*
814: * Priority polls not supported.
815: */
816: ev &= ~POLLPRI;
817:
818: /*
819: * Input poll.
820: */
821: if ( ev & POLLIN ) {
822:
823: /*
824: * No messages on queue.
825: */
826: if ( qp->msq.msg_qnum == 0 ) {
827: /*
828: * Enable input monitor.
829: */
830: if ( msec != 0 )
831: pollopen( &qp->ipolls );
832: ev &= ~POLLIN;
833: }
834:
835: /*
836: * Prevent output monitor.
837: */
838: else
839: msec = 0;
840: }
841:
842: /*
843: * Output poll.
844: */
845: if ( ev & POLLOUT ) {
846:
847: /*
848: * Queue full.
849: */
850: if ( qp->msq.msg_cbytes >= qp->msq.msg_qbytes ) {
851: if ( msec != 0 )
852: pollopen( &qp->opolls );
853: ev &= ~POLLOUT;
854: }
855:
856: /*
857: * No free message buffers.
858: */
859: else if ( msqs->msq.msg_first == NULL ) {
860: if ( msec != 0 )
861: pollopen( &msqs->ipolls );
862: ev &= ~POLLOUT;
863: }
864: }
865:
866: return ev;
867: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.