|
|
1.1.1.3 root 1: /*
2:
3: * Copyright 1991, 1992 Eric R. Smith
4:
5: * Copyright 1992 Atari Corporation.
6:
7: * All rights reserved.
8:
9: */
10:
11:
12:
1.1 root 13: /*
14:
15: * The rendezvous:
16:
17: * a little bit of message passing with a lot of synchronization.
18:
19: *
20:
21: * Pmsg(mode,mboxid,msgptr);
22:
23: * short mode;
24:
25: * long mboxid;
26:
27: * struct { long msg1, msg2; short pid; } *msgptr;
28:
29: *
30:
31: * 'mode' bits:
32:
33: * 0000 read
34:
35: * 0001 write
36:
37: * 0002 write, then read from mboxid "PDxx" where xx is my pid.
38:
39: *
40:
41: * 8000 OR with this bit to make the operation non-blocking.
42:
43: *
44:
45: * The messages are five words long: two longs and a short, in that order.
46:
47: * The values of the first two longs are totally up to the processes in
48:
49: * question. The value of the short is the PID of the sender. On return
50:
51: * from writes, the short is the PID of the process that read your message.
52:
53: * On return from reads, it's the PID of the writer.
54:
55: *
56:
57: * If the 0x8000 bit is set in the mode, and there is not a reader/writer
58:
59: * for the mboxid already on the WAIT_Q, this call returns -1.
60:
61: *
62:
63: * In mode 2, the writer is declaring that it wants to wait for a reply to
64:
65: * the message. What happens is that the reader gets put on the ready
66:
67: * queue, but the writer is atomically turned into a reader on a mailbox
68:
69: * whose mboxid is (0xFFFF0000 .OR. pid). The idea is that this process
70:
71: * will sleep until awoken at a later time by the process that read the
72:
73: * message. The process reading the original request is guaranteed not to
74:
75: * block when writing the reply.
76:
77: *
78:
79: * There is no provision for a timeout.
80:
81:
82:
83: The flow is as follows:
84:
85:
86:
87: if (you're writing)
88:
89: if (there's somebody waiting to read)
90:
91: (SATISFY THE RENDEZVOUS RIGHT AWAY)
92:
93: copy msg from your data space into his proc structure
94:
95: wake him up
96:
97: if (you're doing a write/read)
98:
99: (TURN AROUND AND BLOCK WAITING TO READ)
100:
101: write mode 0 to your proc struct and change your mbid
102:
103: goto dosleep
104:
105: else
106:
107: fill in his PID in your data space
108:
109: return 0;
110:
111: endif
112:
113: else
114:
115: (YOU HAVE TO BLOCK WAITING FOR A WRITER)
116:
117: copy from your data space to your proc structure
118:
119: goto dosleep
120:
121: endif
122:
123: else (you're reading)
124:
125: if (there's somebody waiting to write)
126:
127: (SATISFY THE RENDEZVOUS RIGHT AWAY)
128:
129: copy msg from his proc to your data space
130:
131: if (he's doing a write/read)
132:
133: (TURN HIM AROUND WAITING FOR A WRITER)
134:
135: change his mode from write/read to read, and his mbid
136:
137: leave him asleep
138:
139: else
140:
141: wake him up
142:
143: endif
144:
145: return 0;
146:
147: else
148:
149: (YOU HAVE TO BLOCK WAITING FOR A READER)
150:
151: write mode 0 to your proc struct
152:
153: goto dosleep
154:
155: endif
156:
157: endif
158:
159:
160:
161: dosleep:
162:
163: if (non-blocking mode) return EWOULDBLOCK;
164:
165: do {
166:
167: sleep(WAIT_Q, WAIT_MB);
168:
169: } until (a rendezvous happens);
170:
171: (when you wake up...)
172:
173: if (you're reading)
174:
175: copy from your proc struct to your data space
176:
177: else
178:
179: copy the writer's PID from your proc struct to your data space
180:
181: endif
182:
183: return 0;
184:
185:
186:
187: * The wait_cond we use is WAIT_MB, and the mbid waited for is another
188:
189: * field in the proc structure, along with the two longs and a short you
190:
191: * need to remember what somebody else wrote to you, and the mode field for
192:
193: * what kind of operation you're doing (read, write, write/read).
194:
195: *
196:
197: * The beauty of this is that mailboxes don't need to be created or
198:
199: * destroyed, and the blocking and turnaround are atomic, and it's a way to
200:
201: * do rendezvous and interprocess communication without lots of system
202:
203: * calls (Pgetpid, Fwrite, Pause, plus synchronization worries about having
204:
205: * the reader get the message and Pkill you before you've Paused).
206:
207: *
208:
209: * Note: Say PID 33 writes in mode 2 to MBXX and it blocks. Then somebody
210:
211: * writes to PD33, and blocks because you're not waiting for it. Then your
212:
213: * write is satisfied, so you become a reader on PD33. We should check to
214:
215: * see if there are any writers on PD33 and satisfy that rendezvous! But
216:
217: * this could go on forever, and it's easier to stop here. So you lose:
218:
219: * this situation is timing sensitive. It shouldn't come up anyway.
220:
221: */
222:
223:
224:
225: #include "mint.h"
226:
227:
228:
1.1.1.2 root 229: long ARGS_ON_STACK
1.1 root 230:
231: p_msg(mode, mbid, ptr)
232:
233: int mode;
234:
235: long mbid;
236:
237: char *ptr;
238:
239: {
240:
241: int noblock;
242:
243: PROC *p;
244:
245:
246:
1.1.1.3 root 247: TRACELOW(("Pmsg(%d,%lx,%lx)",mode,mbid,ptr));
1.1 root 248:
249:
250:
251: noblock = (mode & 0x8000);
252:
253: mode &= ~0x8000;
254:
255:
256:
257: if (mode == 0) {
258:
259: /* read */
260:
261: /* walk the whole process list looking for a writer */
262:
263: for (p = proclist; p; p = p->gl_next) {
264:
265: if ((p->mb_mode == 1 || p->mb_mode == 2) && p->mb_mbid == mbid) {
266:
267: /* this process is trying to write this mbox */
268:
269: goto got_rendezvous;
270:
271: }
272:
273: }
274:
275: /* nobody is writing just now */
276:
277: goto dosleep;
278:
279: }
280:
281: else if (mode == 1 || mode == 2) {
282:
283: /* write, or write/read */
284:
285: /* walk the whole process list looking for a reader */
286:
287: for (p = proclist; p; p = p->gl_next) {
288:
289: if (p->mb_mode == 0 && p->mb_mbid == mbid) {
290:
291: /* this process is reading this mbox */
292:
293: goto got_rendezvous;
294:
295: }
296:
297: }
298:
299: /* nobody is reading just now */
300:
301: curproc->mb_long1 = *(long *)ptr; /* copy the message */
302:
303: curproc->mb_long2 = *(long *)(ptr+4); /* into my proc struct */
304:
305: goto dosleep;
306:
307: }
308:
309: else return EINVFN; /* invalid mode */
310:
311:
312:
313: /*
314:
315: * we get here if we actually have a rendezvous between p and curproc.
316:
317: */
318:
319:
320:
321: got_rendezvous:
322:
323: if (!mode) {
324:
325: /* curproc is reading */
326:
327: *(long *)(ptr) = p->mb_long1; /* copy the message */
328:
329: *(long *)(ptr+4) = p->mb_long2; /* from his proc struct */
330:
331: *(short *)(ptr+8) = p->pid; /* provide the PID */
332:
333:
334:
335: if (p->mb_mode == 2) {
336:
337: /*
338:
339: * The blocked write was in mode 2: writer becomes a reader and
340:
341: * stays on WAIT_Q waiting on WAIT_MB.
342:
343: */
344:
345: p->mb_mbid = 0xFFFF0000L | p->pid;
346:
347: p->mb_mode = 0;
348:
349: }
350:
351: else {
352:
353: /* The blocked write was in mode 1: writer wakes up */
354:
355: p->mb_writer = curproc->pid; /* tell writer reader's pid */
356:
357: p->mb_mode = -1; /* mark rendezvous */
358:
359: p->wait_cond = 0; /* not necessary? */
360:
361: if (p->wait_q != READY_Q) {
362:
1.1.1.3 root 363: short sr = spl7();
364:
1.1 root 365: /* wake up the writer if it is sleeping */
366:
367: rm_q(p->wait_q,p);
368:
369: add_q(READY_Q,p);
370:
1.1.1.3 root 371: spl(sr);
372:
1.1 root 373: }
374:
375: }
376:
377: return 0;
378:
379: }
380:
381: else {
382:
383: /* curproc is writing */
384:
385: p->mb_writer = curproc->pid; /* provide the PID */
386:
387: p->mb_long1 = *(long *)(ptr); /* copy the message */
388:
389: p->mb_long2 = *(long *)(ptr+4);
390:
391: p->mb_mode = -1; /* mark rendezvous */
392:
393: p->wait_cond = 0; /* not necessary? */
394:
395: if (p->wait_q != READY_Q) {
396:
1.1.1.3 root 397: short sr = spl7();
398:
1.1 root 399: /* wake up the reader if it is sleeping */
400:
401: rm_q(p->wait_q,p);
402:
403: add_q(READY_Q,p);
404:
1.1.1.3 root 405: spl(sr);
406:
1.1 root 407: }
408:
409: if (mode == 2) {
410:
411: /* now curproc becomes a reader */
412:
413: mbid = 0xFFFF0000L | curproc->pid;
414:
415: mode = 0;
416:
417: goto dosleep;
418:
419: }
420:
421: else {
422:
423: *(short *)(ptr+8) = p->pid; /* tell reader writer's pid */
424:
425: return 0;
426:
427: }
428:
429: }
430:
431:
432:
433: /*
434:
435: * we get here when a read or write should block because there's nobody
436:
437: * already waiting at the other end.
438:
439: */
440:
441:
442:
443: dosleep:
444:
445: if (noblock) {
446:
447: return -1L;
448:
449: }
450:
451: curproc->mb_mbid = mbid; /* and ID waited for */
452:
453: curproc->mb_mode = mode; /* save mode */
454:
455:
456:
457: /*
458:
459: * OK: now we sleep until a rendezvous has occured. The loop is because we
460:
461: * may be woken up to deal with signals before the rendezvous. The thing
462:
463: * that says the rendezvous actually happened is that mb_mode got changed
464:
465: * to -1.
466:
467: */
468:
469: do {
470:
471: sleep(WAIT_Q, WAIT_MB); /* block */
472:
473: } while (curproc->mb_mode != -1);
474:
475:
476:
477: /*
478:
479: * When we wake up, we transfer the message from our proc struct
480:
481: * into our message pointer space if we were reading, and do
482:
483: * nothing if we were writing. The write/read case is taken care
484:
485: * of without waking this process up at all.
486:
487: *
488:
489: * Check curproc->mode because it may not be the mode we started
490:
491: * with any more.
492:
493: */
494:
495: if (mode == 0) {
496:
497: *(long *)(ptr) = curproc->mb_long1;
498:
499: *(long *)(ptr+4) = curproc->mb_long2;
500:
501: }
502:
503: /* in any case, copy the 'writer' field because that's the PID */
504:
505: /* of the other side of the rendezvous */
506:
507: *(short *)(ptr+8) = curproc->mb_writer;
508:
509: return 0;
510:
511: }
512:
513:
514:
515: /*
516:
517: * more mutex: this time a semaphore.
518:
519: *
520:
521: * long Psemaphore(short mode, long id, long timeout)
522:
523: *
524:
525: * MODE ACTION
526:
527: * 0 Create and get a semaphore with the given ID.
528:
529: * 1 Destroy.
530:
531: * 2 Get (blocks until it's available or destroyed, or timeout).
532:
533: * 3 Release.
534:
535: *
536:
537: * RETURNS
538:
539: *
540:
541: * CODE MEANING
542:
543: * 0 OK. Created/obtained/released/destroyed, depending on mode.
544:
545: * ERROR You asked for a semaphore that you already own.
546:
547: * ERANGE That semaphore doesn't exist (modes 1, 2, 3, 4),
548:
549: * or out of slots for new semaphores (0).
550:
551: * EACCDN That semaphore exists already, so you can't create it (mode 0),
552:
553: * or the semaphore is busy (returned from mode 3 if you lose),
554:
555: * or you don't own it (modes 1 and 4).
556:
557: *
558:
559: * If you create a semaphore you will also own it, so you have to release
560:
561: * it with mode 2 before anybody else can get it. Semaphore ID's are magic
562:
563: * numbers which the creator should make available to the users. You have
564:
565: * to own a semaphore to destroy it. If you block waiting for a semaphore,
566:
567: * and then it gets destroyed, you get ERANGE.
568:
569: *
570:
571: * The timeout argument is ignored except in mode 2. In that mode, 0 means
572:
573: * "return immediately" and, as a special case, -1 means "forever."
574:
575: * Since it is in fact an unsigned long number of milliseconds, -2 means
576:
577: * 49 hours, but here -1 truly means forever.
578:
579: *
580:
581: */
582:
583:
584:
585: #define NSEMAPHORES 10
586:
587:
588:
589: typedef struct sema {
590:
591: struct sema *next;
592:
593: long id;
594:
595: short owner; /* -1 means "available" */
596:
597: } SEMA;
598:
599:
600:
601: static SEMA *semalist;
602:
603:
604:
605: static void unsemame P_((PROC *));
606:
607:
608:
609: static void
610:
611: unsemame(p)
612:
613: PROC *p;
614:
615: {
616:
617: /* take process P off the WAIT_Q and put it on the READY_Q */
618:
1.1.1.2 root 619: TRACE(("semaphore sleep ends for pid %d",p->pid));
1.1 root 620:
621: if (p->wait_q == WAIT_Q) {
622:
1.1.1.3 root 623: short sr = spl7();
624:
1.1 root 625: rm_q(WAIT_Q,p);
626:
627: add_q(READY_Q,p);
628:
1.1.1.3 root 629: spl(sr);
630:
1.1 root 631: }
632:
633: p->wait_cond = 0;
634:
635: }
636:
637:
638:
1.1.1.2 root 639: long ARGS_ON_STACK
1.1 root 640:
641: p_semaphore(mode,id,timeout)
642:
643: int mode;
644:
645: long id;
646:
647: long timeout;
648:
649: {
650:
651: SEMA *s, **q;
652:
653: TIMEOUT *timeout_ptr = NULL;
654:
655:
656:
1.1.1.3 root 657: TRACELOW(("Psemaphore(%d,%lx)",mode,id));
1.1 root 658:
659:
660:
661: switch (mode) {
662:
663: case 0: { /* create */
664:
665: for (s = semalist; s; s = s->next) {
666:
667: if (s->id == id) {
668:
1.1.1.2 root 669: DEBUG(("Psemaphore(%d,%lx): already exists",mode,id));
1.1 root 670:
671: return EACCDN;
672:
673: }
674:
675: }
676:
677: /* get a new one */
678:
1.1.1.2 root 679: if ((s = (SEMA *)kmalloc(sizeof(SEMA))) == 0)
680:
681: return ENSMEM;
1.1 root 682:
683: s->id = id;
684:
685: s->owner = curproc->pid;
686:
687: s->next = semalist;
688:
689: semalist = s;
690:
691: return E_OK;
692:
693: }
694:
695: case 2: { /* get */
696:
697: loop:
698:
699: for (s = semalist; s; s = s->next) {
700:
701: if (s->id == id) {
702:
703: /* found your semaphore */
704:
705: if (s->owner == curproc->pid) {
706:
1.1.1.2 root 707: DEBUG(("Psemaphore(%d,%lx): curproc already owns it!",
1.1 root 708:
1.1.1.2 root 709: mode,id));
1.1 root 710:
711: return ERROR;
712:
713: }
714:
715: if (s->owner == -1) {
716:
717: /* it's free; you get it */
718:
719: s->owner = curproc->pid;
720:
721: if (timeout_ptr) canceltimeout(timeout_ptr);
722:
723: return 0;
724:
725: }
726:
727: else {
728:
729: /* not free */
730:
731: if (timeout == 0) {
732:
733: /* non-blocking mode */
734:
735: return EACCDN;
736:
737: }
738:
739: else {
740:
741: if (timeout != -1 && !timeout_ptr) {
742:
743: /* schedule a timeout */
744:
745: timeout_ptr = addtimeout(timeout,unsemame);
746:
747: }
748:
749: /* block until it's released, then try again */
750:
751: sleep(WAIT_Q,WAIT_SEMA);
752:
753: if (curproc->wait_cond != WAIT_SEMA) {
754:
1.1.1.2 root 755: TRACE(("Psemaphore(%d,%lx) timed out",mode,id));
1.1 root 756:
757: return EACCDN;
758:
759: }
760:
761: goto loop;
762:
763: }
764:
765: }
766:
767: }
768:
769: }
770:
771: /* no such semaphore (possibly deleted while we were waiting) */
772:
773: if (timeout_ptr) canceltimeout(timeout_ptr);
774:
1.1.1.2 root 775: DEBUG(("Psemaphore(%d,%lx): no such semaphore",mode,id));
1.1 root 776:
777: return ERANGE;
778:
779: }
780:
781: case 3: /* release */
782:
783: case 1: { /* destroy */
784:
785: /*
786:
787: * Style note: this is a handy way to chain down a linked list.
788:
789: * q follows along behind s pointing at the "next" field of the
790:
791: * previous list element. To start, q points to the semalist
792:
793: * variable itself. At all times, then, *q is the place to
794:
795: * write s->next when you want to remove an element 's' from
796:
797: * the list.
798:
799: */
800:
801: for (s = *(q = &semalist); s; s = *(q = &s->next)) {
802:
803: if (s->id == id) {
804:
805: /* found your semaphore */
806:
807: if (s->owner != curproc->pid) {
808:
1.1.1.2 root 809: DEBUG(("Psemaphore(%d,%lx): you don't own it",mode,id));
1.1 root 810:
811: return EACCDN;
812:
813: }
814:
815: else {
816:
1.1.1.4 ! root 817: if (mode == 3) {
1.1 root 818:
1.1.1.4 ! root 819: s->owner = -1; /* make it free, or */
1.1 root 820:
1.1.1.4 ! root 821: } else {
1.1 root 822:
1.1.1.4 ! root 823: *q = s->next; /* delete from list */
! 824:
! 825: kfree(s); /* and free it */
! 826:
! 827: }
1.1 root 828:
829: /* wake up anybody who's waiting for a semaphore */
830:
831: wake(WAIT_Q,WAIT_SEMA);
832:
833: return E_OK;
834:
835: }
836:
837: }
838:
839: }
840:
841: /* no such semaphore */
842:
1.1.1.2 root 843: DEBUG(("Psemaphore(%d,%lx): no such semaphore",mode,id));
1.1 root 844:
845: return ERANGE;
846:
847: }
848:
849: default: { /* invalid mode argument */
850:
1.1.1.2 root 851: DEBUG(("Psemaphore(%d,%lx): invalid mode",mode,id));
1.1 root 852:
853: return EINVFN;
854:
855: }
856:
857: }
858:
859: }
860:
861:
862:
863: /*
864:
865: * Release all semaphores owned by the process with process id "pid".
866:
867: * The semaphores are only released, not destroyed. This function
868:
869: * is called from terminate() in dos_mem.c during process termination.
870:
871: */
872:
873:
874:
875: void
876:
877: free_semaphores(pid)
878:
879: int pid;
880:
881: {
882:
1.1.1.2 root 883: SEMA *s;
1.1 root 884:
885: int didsomething = 0; /* did any semaphores get freed? */
886:
887:
888:
1.1.1.2 root 889: for (s = semalist; s; s = s->next) {
1.1 root 890:
891: if (s->owner == pid) {
892:
893: s->owner = -1; /* mark the semaphore as free */
894:
895: didsomething = 1;
896:
897: }
898:
899: }
900:
901: if (didsomething) {
902:
903: /* wake up anybody waiting for a semaphore, in case it's one of
904:
905: * the ones we just freed
906:
907: */
908:
909: wake(WAIT_Q, WAIT_SEMA);
910:
911: }
912:
913: }
914:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.