|
|
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: 817: if (mode == 3) s->owner = -1; /* make it free, or */ 818: 819: else *q = s->next; /* delete from list */ 820: 821: 822: 823: /* wake up anybody who's waiting for a semaphore */ 824: 825: wake(WAIT_Q,WAIT_SEMA); 826: 827: return E_OK; 828: 829: } 830: 831: } 832: 833: } 834: 835: /* no such semaphore */ 836: 1.1.1.2 root 837: DEBUG(("Psemaphore(%d,%lx): no such semaphore",mode,id)); 1.1 root 838: 839: return ERANGE; 840: 841: } 842: 843: default: { /* invalid mode argument */ 844: 1.1.1.2 root 845: DEBUG(("Psemaphore(%d,%lx): invalid mode",mode,id)); 1.1 root 846: 847: return EINVFN; 848: 849: } 850: 851: } 852: 853: } 854: 855: 856: 857: /* 858: 859: * Release all semaphores owned by the process with process id "pid". 860: 861: * The semaphores are only released, not destroyed. This function 862: 863: * is called from terminate() in dos_mem.c during process termination. 864: 865: */ 866: 867: 868: 869: void 870: 871: free_semaphores(pid) 872: 873: int pid; 874: 875: { 876: 1.1.1.2 root 877: SEMA *s; 1.1 root 878: 879: int didsomething = 0; /* did any semaphores get freed? */ 880: 881: 882: 1.1.1.2 root 883: for (s = semalist; s; s = s->next) { 1.1 root 884: 885: if (s->owner == pid) { 886: 887: s->owner = -1; /* mark the semaphore as free */ 888: 889: didsomething = 1; 890: 891: } 892: 893: } 894: 895: if (didsomething) { 896: 897: /* wake up anybody waiting for a semaphore, in case it's one of 898: 899: * the ones we just freed 900: 901: */ 902: 903: wake(WAIT_Q, WAIT_SEMA); 904: 905: } 906: 907: } 908:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.