|
|
1.1 ! root 1: /* ! 2: ! 3: Copyright 1990,1991,1992 Eric R. Smith. All rights reserved. ! 4: ! 5: */ ! 6: ! 7: ! 8: ! 9: /* ! 10: ! 11: * GEMDOS emulation routines: these are for the GEMDOS system calls ! 12: ! 13: * concerning allocating/freeing memory, including Pexec() (since ! 14: ! 15: * this allocates memory) and Pterm() (since this, implicitly, frees ! 16: ! 17: * it). ! 18: ! 19: */ ! 20: ! 21: ! 22: ! 23: #include "mint.h" ! 24: ! 25: ! 26: ! 27: int procdate, proctime; /* set when any processes are created/destroyed */ ! 28: ! 29: ! 30: ! 31: static long do_vfork P_((int)); ! 32: ! 33: ! 34: ! 35: /* ! 36: ! 37: * new call for TT TOS, for the user to inform DOS of alternate memory ! 38: ! 39: * FIXME: we really shouldn't trust the user so completely ! 40: ! 41: */ ! 42: ! 43: ! 44: ! 45: long ! 46: ! 47: m_addalt(start, size) ! 48: ! 49: long start, size; ! 50: ! 51: { ! 52: ! 53: if (!add_region(alt, start, size, M_ALT)) ! 54: ! 55: return EINTRN; ! 56: ! 57: else ! 58: ! 59: return 0; ! 60: ! 61: } ! 62: ! 63: ! 64: ! 65: /* ! 66: ! 67: * internal routine for doing Malloc on a particular memory map ! 68: ! 69: */ ! 70: ! 71: ! 72: ! 73: long ! 74: ! 75: _do_malloc(map, size, mode) ! 76: ! 77: MMAP map; ! 78: ! 79: long size; ! 80: ! 81: int mode; ! 82: ! 83: { ! 84: ! 85: virtaddr v; ! 86: ! 87: MEMREGION *m; ! 88: ! 89: long maxsize, mleft; ! 90: ! 91: ! 92: ! 93: if (size == -1L) { ! 94: ! 95: maxsize = max_rsize(map); ! 96: ! 97: if (curproc->maxmem) { ! 98: ! 99: mleft = curproc->maxmem - memused(curproc); ! 100: ! 101: if (maxsize > mleft) ! 102: ! 103: maxsize = mleft; ! 104: ! 105: if (maxsize < 0) ! 106: ! 107: maxsize = 0; ! 108: ! 109: } ! 110: ! 111: /* make sure to round down */ ! 112: ! 113: return maxsize & ~MASKBITS; ! 114: ! 115: } ! 116: ! 117: ! 118: ! 119: /* special case: Malloc(0) should always return 0 */ ! 120: ! 121: if (size == 0) ! 122: ! 123: return 0; ! 124: ! 125: ! 126: ! 127: if (curproc->maxmem) { /* memory limit? */ ! 128: ! 129: if (size > curproc->maxmem - memused(curproc)) { ! 130: ! 131: DEBUG("malloc: memory request would exceed limit"); ! 132: ! 133: return 0; ! 134: ! 135: } ! 136: ! 137: } ! 138: ! 139: ! 140: ! 141: m = get_region(map, size); ! 142: ! 143: if (!m) { ! 144: ! 145: DEBUG("malloc: out of memory"); ! 146: ! 147: return 0; ! 148: ! 149: } ! 150: ! 151: v = attach_region(curproc, m); ! 152: ! 153: if (!v) { ! 154: ! 155: m->links = 0; ! 156: ! 157: free_region(m); ! 158: ! 159: return 0; ! 160: ! 161: } ! 162: ! 163: /* NOTE: get_region returns a region with link count 1; since attach_region ! 164: ! 165: * increments the link count, we have to remember to decrement the count ! 166: ! 167: * to correct for this. ! 168: ! 169: */ ! 170: ! 171: m->links--; ! 172: ! 173: if ((mode & F_KEEP)) { /* request for permanent memory */ ! 174: ! 175: m->mflags |= M_KEEP; ! 176: ! 177: } ! 178: ! 179: return (long)v; ! 180: ! 181: } ! 182: ! 183: ! 184: ! 185: long ! 186: ! 187: m_xalloc(size, mode) ! 188: ! 189: long size; ! 190: ! 191: int mode; ! 192: ! 193: { ! 194: ! 195: long r, r1; ! 196: ! 197: ! 198: ! 199: TRACE("Mxalloc(%ld,%x)",size,mode); ! 200: ! 201: if ( (mode & 8) ) { ! 202: ! 203: DEBUG("Unsupported Mxalloc mode"); ! 204: ! 205: return 0; /* future expansion */ ! 206: ! 207: } ! 208: ! 209: if ( (mode&3) == 0) ! 210: ! 211: return _do_malloc(core, size, mode); ! 212: ! 213: else if ( (mode&3) == 1) ! 214: ! 215: return _do_malloc(alt, size, mode); ! 216: ! 217: else if (size == -1) { ! 218: ! 219: /* modes 2 and 3 are the same for for size -1 */ ! 220: ! 221: r = _do_malloc(core, -1L, mode); ! 222: ! 223: r1 = _do_malloc(alt, -1L, mode); ! 224: ! 225: if (r > r1) return r; ! 226: ! 227: else return r1; ! 228: ! 229: } ! 230: ! 231: else if ( (mode&3) == 2) { ! 232: ! 233: r = _do_malloc(core, size, mode); ! 234: ! 235: if (r == 0) return _do_malloc(alt, size, mode); ! 236: ! 237: else return r; ! 238: ! 239: } ! 240: ! 241: else /* if ( (mode&3) == 3) */ { ! 242: ! 243: r = _do_malloc(alt, size, mode); ! 244: ! 245: if (r == 0) return _do_malloc(core, size, mode); ! 246: ! 247: else return r; ! 248: ! 249: } ! 250: ! 251: ! 252: ! 253: DEBUG("Mxalloc: bad request??"); ! 254: ! 255: return 0; ! 256: ! 257: } ! 258: ! 259: ! 260: ! 261: long ! 262: ! 263: m_alloc(size) ! 264: ! 265: long size; ! 266: ! 267: { ! 268: ! 269: long r; ! 270: ! 271: ! 272: ! 273: TRACE("Malloc(%lx)", size); ! 274: ! 275: if (curproc->memflags & F_ALTALLOC) ! 276: ! 277: r = m_xalloc(size, 3); ! 278: ! 279: else ! 280: ! 281: r = m_xalloc(size, 0); ! 282: ! 283: TRACE("Malloc: returning %lx", r); ! 284: ! 285: return r; ! 286: ! 287: } ! 288: ! 289: ! 290: ! 291: long ! 292: ! 293: m_free(block) ! 294: ! 295: virtaddr block; ! 296: ! 297: { ! 298: ! 299: MEMREGION *m; ! 300: ! 301: int i; ! 302: ! 303: ! 304: ! 305: TRACE("Mfree(%lx)", block); ! 306: ! 307: if (!block) { ! 308: ! 309: DEBUG("Mfree: null pointer"); ! 310: ! 311: return EIMBA; ! 312: ! 313: } ! 314: ! 315: ! 316: ! 317: /* search backwards so that most recently allocated incarnations of ! 318: ! 319: shared memory blocks are freed first (this doesn't matter very often) ! 320: ! 321: */ ! 322: ! 323: ! 324: ! 325: for (i = curproc->num_reg - 1; i >= 0; i--) { ! 326: ! 327: if (curproc->addr[i] == block) { ! 328: ! 329: m = curproc->mem[i]; ! 330: ! 331: assert(m != NULL); ! 332: ! 333: assert(m->loc == (long)block); ! 334: ! 335: curproc->mem[i] = 0; ! 336: ! 337: curproc->addr[i] = 0; ! 338: ! 339: m->links--; ! 340: ! 341: if (m->links == 0) { ! 342: ! 343: free_region(m); ! 344: ! 345: } ! 346: ! 347: return 0; ! 348: ! 349: } ! 350: ! 351: } ! 352: ! 353: ! 354: ! 355: /* hmmm... if we didn't find the region, perhaps it's a global ! 356: ! 357: * one (with the M_KEEP flag set) belonging to a process that ! 358: ! 359: * terminated ! 360: ! 361: */ ! 362: ! 363: for (i = rootproc->num_reg - 1; i >= 0; i--) { ! 364: ! 365: if (rootproc->addr[i] == block) { ! 366: ! 367: m = rootproc->mem[i]; ! 368: ! 369: assert(m != NULL); ! 370: ! 371: assert(m->loc == (long)block); ! 372: ! 373: if (!(m->mflags & M_KEEP)) ! 374: ! 375: continue; ! 376: ! 377: rootproc->mem[i] = 0; ! 378: ! 379: rootproc->addr[i] = 0; ! 380: ! 381: m->links--; ! 382: ! 383: if (m->links == 0) { ! 384: ! 385: free_region(m); ! 386: ! 387: } ! 388: ! 389: return 0; ! 390: ! 391: } ! 392: ! 393: } ! 394: ! 395: ! 396: ! 397: ! 398: ! 399: DEBUG("Mfree: bad address %lx", block); ! 400: ! 401: return EIMBA; ! 402: ! 403: } ! 404: ! 405: ! 406: ! 407: long ! 408: ! 409: m_shrink(dummy, block, size) ! 410: ! 411: int dummy; ! 412: ! 413: virtaddr block; ! 414: ! 415: long size; ! 416: ! 417: { ! 418: ! 419: MEMREGION *m; ! 420: ! 421: int i; ! 422: ! 423: ! 424: ! 425: TRACE("Mshrink: %lx to %ld", block, size); ! 426: ! 427: if (!block) { ! 428: ! 429: DEBUG("Mshrink: null pointer"); ! 430: ! 431: return EIMBA; ! 432: ! 433: } ! 434: ! 435: ! 436: ! 437: for (i = 0; i < curproc->num_reg; i++) { ! 438: ! 439: if (curproc->addr[i] == block) { ! 440: ! 441: m = curproc->mem[i]; ! 442: ! 443: assert(m != NULL); ! 444: ! 445: assert(m->loc == (long)block); ! 446: ! 447: return shrink_region(m, size); ! 448: ! 449: } ! 450: ! 451: } ! 452: ! 453: DEBUG("Mshrink: bad address (%lx)", block); ! 454: ! 455: return EIMBA; ! 456: ! 457: } ! 458: ! 459: ! 460: ! 461: long ! 462: ! 463: p_exec(mode, ptr1, ptr2, ptr3) ! 464: ! 465: int mode; ! 466: ! 467: void *ptr1, *ptr2, *ptr3; ! 468: ! 469: { ! 470: ! 471: MEMREGION *base, *env = 0; /* assignment suppress spurious warning */ ! 472: ! 473: PROC *p = 0; ! 474: ! 475: long r, flags = 0; ! 476: ! 477: int i; ! 478: ! 479: char mkbase = 0, mkload = 0, mkgo = 0, mkwait = 0, mkfree = 0; ! 480: ! 481: char overlay = 0; ! 482: ! 483: char thread = 0; ! 484: ! 485: char mkname = 0, *newname, *lastslash; ! 486: ! 487: char localname[PNAMSIZ+1]; ! 488: ! 489: XATTR xattr; ! 490: ! 491: ! 492: ! 493: switch(mode) { ! 494: ! 495: case 0: ! 496: ! 497: mkwait = 1; /* fall through */ ! 498: ! 499: case 100: ! 500: ! 501: mkload = mkgo = mkfree = 1; ! 502: ! 503: mkname = 1; ! 504: ! 505: TRACE("Pexec(%d,%s,\"%s\")", mode, ptr1, ptr2); ! 506: ! 507: break; ! 508: ! 509: case 200: /* overlay current process */ ! 510: ! 511: mkload = mkgo = 1; ! 512: ! 513: overlay = mkname = 1; ! 514: ! 515: TRACE("Pexec(%d,%s,\"%s\")", mode, ptr1, ptr2); ! 516: ! 517: break; ! 518: ! 519: case 3: ! 520: ! 521: mkload = 1; ! 522: ! 523: TRACE("Pexec(%d,%s,\"%s\")", mode, ptr1, ptr2); ! 524: ! 525: break; ! 526: ! 527: case 6: ! 528: ! 529: mkfree = 1; ! 530: ! 531: /* fall through */ ! 532: ! 533: case 4: ! 534: ! 535: mkwait = mkgo = 1; ! 536: ! 537: TRACE("Pexec(%d,%lx)", mode, ptr2); ! 538: ! 539: break; ! 540: ! 541: case 106: ! 542: ! 543: mkfree = 1; /* fall through */ ! 544: ! 545: case 104: ! 546: ! 547: thread = (mode == 104); ! 548: ! 549: mkgo = 1; ! 550: ! 551: mkname = (ptr1 != 0); ! 552: ! 553: TRACE("Pexec(%d,%s,%lx)", mode, ptr1, ptr2); ! 554: ! 555: break; ! 556: ! 557: case 7: ! 558: ! 559: flags = (long)ptr1; /* set program flags */ ! 560: ! 561: /* and fall through */ ! 562: ! 563: case 5: ! 564: ! 565: mkbase = 1; ! 566: ! 567: TRACE("Pexec(%d,%lx,\"%s\")", mode, ptr1, ptr2); ! 568: ! 569: break; ! 570: ! 571: default: ! 572: ! 573: DEBUG("Pexec: bad mode %d", mode); ! 574: ! 575: return EINVFN; ! 576: ! 577: } ! 578: ! 579: ! 580: ! 581: /* in most cases, we'll want a process struct to exist, ! 582: ! 583: * so make sure one is around. Note that we must be ! 584: ! 585: * careful to free it later! ! 586: ! 587: */ ! 588: ! 589: ! 590: ! 591: p = 0; ! 592: ! 593: if (!overlay) { ! 594: ! 595: p = new_proc(); ! 596: ! 597: if (!p) { ! 598: ! 599: DEBUG("Pexec: couldn't get a PROC struct"); ! 600: ! 601: return ENSMEM; ! 602: ! 603: } ! 604: ! 605: } ! 606: ! 607: ! 608: ! 609: ! 610: ! 611: if (mkload || mkbase) { ! 612: ! 613: env = create_env((char *)ptr3); ! 614: ! 615: if (!env) { ! 616: ! 617: DEBUG("Pexec: unable to create environment"); ! 618: ! 619: if (p) dispose_proc(p); ! 620: ! 621: return ENSMEM; ! 622: ! 623: } ! 624: ! 625: } ! 626: ! 627: ! 628: ! 629: if (mkbase) { ! 630: ! 631: base = create_base((char *)ptr2, env, flags, 0L); ! 632: ! 633: if (!base) { ! 634: ! 635: DEBUG("Pexec: unable to create basepage"); ! 636: ! 637: detach_region(curproc, env); ! 638: ! 639: if (p) dispose_proc(p); ! 640: ! 641: return ENSMEM; ! 642: ! 643: } ! 644: ! 645: } ! 646: ! 647: else if (mkload) { ! 648: ! 649: base = load_region((char *)ptr1, env, (char *)ptr2, &xattr); ! 650: ! 651: if (!base) { ! 652: ! 653: DEBUG("Pexec: load_region failed"); ! 654: ! 655: detach_region(curproc, env); ! 656: ! 657: if (p) dispose_proc(p); ! 658: ! 659: return mint_errno; ! 660: ! 661: } ! 662: ! 663: } ! 664: ! 665: else { /* mode == 4 or 6 or 104 or 106 -- just go */ ! 666: ! 667: base = addr2mem((virtaddr)ptr2); ! 668: ! 669: if (base) ! 670: ! 671: env = addr2mem(*(void **)(base->loc + 0x2c)); ! 672: ! 673: else ! 674: ! 675: env = 0; ! 676: ! 677: if (!env) { ! 678: ! 679: if (p) dispose_proc(p); ! 680: ! 681: return EIMBA; ! 682: ! 683: } ! 684: ! 685: } ! 686: ! 687: ! 688: ! 689: /* make a local copy of the name, in case we are overlaying the current ! 690: ! 691: * process ! 692: ! 693: */ ! 694: ! 695: if (mkname) { ! 696: ! 697: lastslash = 0; ! 698: ! 699: newname = ptr1; ! 700: ! 701: while (*newname) { ! 702: ! 703: if (*newname == '\\' || *newname == '/') ! 704: ! 705: lastslash = newname; ! 706: ! 707: ++newname; ! 708: ! 709: } ! 710: ! 711: if (!lastslash) ! 712: ! 713: lastslash = ptr1; ! 714: ! 715: else ! 716: ! 717: lastslash++; ! 718: ! 719: ! 720: ! 721: i = 0; newname = localname; ! 722: ! 723: while (i++ < PNAMSIZ) { ! 724: ! 725: if (*lastslash == '.' || *lastslash == 0) { ! 726: ! 727: *newname = 0; break; ! 728: ! 729: } ! 730: ! 731: else ! 732: ! 733: *newname++ = *lastslash++; ! 734: ! 735: } ! 736: ! 737: *newname = 0; ! 738: ! 739: } ! 740: ! 741: ! 742: ! 743: if (p) { ! 744: ! 745: /* free the PROC struct so fork_proc will succeed */ ! 746: ! 747: dispose_proc(p); ! 748: ! 749: p = 0; ! 750: ! 751: } ! 752: ! 753: ! 754: ! 755: if (mkgo) { ! 756: ! 757: BASEPAGE *b; ! 758: ! 759: ! 760: ! 761: if (overlay) { ! 762: ! 763: p = curproc; ! 764: ! 765: /* make sure that exec_region doesn't free the base and env */ ! 766: ! 767: base->links++; ! 768: ! 769: env->links++; ! 770: ! 771: } ! 772: ! 773: else { ! 774: ! 775: p = fork_proc(); ! 776: ! 777: } ! 778: ! 779: if (!p) { ! 780: ! 781: if (mkbase) { ! 782: ! 783: detach_region(curproc, base); ! 784: ! 785: detach_region(curproc, env); ! 786: ! 787: } ! 788: ! 789: return mint_errno; ! 790: ! 791: } ! 792: ! 793: ! 794: ! 795: if (mkload && mkgo) { /* setuid/setgid is OK */ ! 796: ! 797: if (xattr.mode & S_ISUID) ! 798: ! 799: p->euid = xattr.uid; ! 800: ! 801: if (xattr.mode & S_ISGID) ! 802: ! 803: p->egid = xattr.gid; ! 804: ! 805: } ! 806: ! 807: (void)exec_region(p, base, thread); ! 808: ! 809: attach_region(p, env); ! 810: ! 811: attach_region(p, base); ! 812: ! 813: ! 814: ! 815: /* tell the child who the parent was */ ! 816: ! 817: b = (BASEPAGE *)base->loc; ! 818: ! 819: if (!overlay) ! 820: ! 821: b->p_parent = (BASEPAGE *)curproc->base; ! 822: ! 823: ! 824: ! 825: if (mkname) { ! 826: ! 827: /* interesting coincidence -- if a process needs a name, it usually ! 828: ! 829: * needs to have its domain reset to DOM_TOS. Doing it this way ! 830: ! 831: * (instead of doing it in exec_region) means that Pexec(4,...) ! 832: ! 833: * can be used to create new threads of execution which retain ! 834: ! 835: * the same domain. ! 836: ! 837: */ ! 838: ! 839: if (!thread) ! 840: ! 841: p->domain = DOM_TOS; ! 842: ! 843: ! 844: ! 845: /* put in the new process name we saved above */ ! 846: ! 847: strcpy(p->name, localname); ! 848: ! 849: } ! 850: ! 851: ! 852: ! 853: /* set the time/date stamp of u:\proc */ ! 854: ! 855: proctime = timestamp; ! 856: ! 857: procdate = datestamp; ! 858: ! 859: ! 860: ! 861: if (overlay) { ! 862: ! 863: /* correct for temporary increase in links (see above) */ ! 864: ! 865: base->links--; ! 866: ! 867: env->links--; ! 868: ! 869: /* let our parent run, if it Vfork'd() */ ! 870: ! 871: if ( (p = pid2proc(curproc->ppid)) != 0 ) { ! 872: ! 873: if (p->wait_q == WAIT_Q && ! 874: ! 875: p->wait_cond == (long)curproc) { ! 876: ! 877: rm_q(WAIT_Q, p); ! 878: ! 879: add_q(READY_Q, p); ! 880: ! 881: } ! 882: ! 883: } ! 884: ! 885: ! 886: ! 887: /* OK, let's run our new code */ ! 888: ! 889: /* we guarantee ourselves at least 2 timeslices to do an Mshrink */ ! 890: ! 891: assert(curproc->magic == CTXT_MAGIC); ! 892: ! 893: fresh_slices(2); ! 894: ! 895: leave_kernel(); ! 896: ! 897: restore_context(&(curproc->ctxt[CURRENT])); ! 898: ! 899: } ! 900: ! 901: else { ! 902: ! 903: /* we want this process to run ASAP */ ! 904: ! 905: /* so we temporarily give it high priority and put it first on the ! 906: ! 907: * run queue ! 908: ! 909: */ ! 910: ! 911: run_next(p, 2); ! 912: ! 913: } ! 914: ! 915: } ! 916: ! 917: ! 918: ! 919: if (mkfree) { ! 920: ! 921: detach_region(curproc, base); ! 922: ! 923: detach_region(curproc, env); ! 924: ! 925: } ! 926: ! 927: ! 928: ! 929: if (mkwait) { ! 930: ! 931: long oldsigint, oldsigquit; ! 932: ! 933: ! 934: ! 935: oldsigint = curproc->sighandle[SIGINT]; ! 936: ! 937: oldsigquit = curproc->sighandle[SIGQUIT]; ! 938: ! 939: curproc->sighandle[SIGINT] = ! 940: ! 941: curproc->sighandle[SIGQUIT] = SIG_IGN; ! 942: ! 943: ! 944: ! 945: i = p->pid; ! 946: ! 947: for(;;) { ! 948: ! 949: r = p_wait3(0, (long *)0); ! 950: ! 951: if (r < 0) { ! 952: ! 953: ALERT("p_exec: wait error"); ! 954: ! 955: return EINTRN; ! 956: ! 957: } ! 958: ! 959: if ( i == ((r&0xffff0000) >> 16) ) { ! 960: ! 961: TRACE("leaving Pexec with child return code"); ! 962: ! 963: r = r & 0x0000ffff; ! 964: ! 965: break; ! 966: ! 967: } ! 968: ! 969: if (curproc->pid) ! 970: ! 971: DEBUG("Pexec: wrong child found"); ! 972: ! 973: } ! 974: ! 975: curproc->sighandle[SIGINT] = oldsigint; ! 976: ! 977: curproc->sighandle[SIGQUIT] = oldsigquit; ! 978: ! 979: return r; ! 980: ! 981: } ! 982: ! 983: else if (mkgo) { ! 984: ! 985: yield(); /* let the new process run */ ! 986: ! 987: return p->pid; ! 988: ! 989: } else { ! 990: ! 991: TRACE("leaving Pexec with basepage address %lx", base->loc); ! 992: ! 993: return base->loc; ! 994: ! 995: } ! 996: ! 997: } ! 998: ! 999: ! 1000: ! 1001: /* ! 1002: ! 1003: * terminate a process, with return code "code". If que == ZOMBIE_Q, free ! 1004: ! 1005: * all resources attached to the child; if que == TSR_Q, free everything ! 1006: ! 1007: * but memory ! 1008: ! 1009: */ ! 1010: ! 1011: ! 1012: ! 1013: long ! 1014: ! 1015: terminate(code, que) ! 1016: ! 1017: int code, que; ! 1018: ! 1019: { ! 1020: ! 1021: extern PROC *dlockproc[]; /* in dosdir.c */ ! 1022: ! 1023: PROC *p; ! 1024: ! 1025: FILEPTR *fp; ! 1026: ! 1027: MEMREGION *m; ! 1028: ! 1029: int i, wakemint = 0; ! 1030: ! 1031: extern short bconbsiz; /* in bios.c */ ! 1032: ! 1033: ! 1034: ! 1035: if (bconbsiz) ! 1036: ! 1037: (void) bflush(); ! 1038: ! 1039: ! 1040: ! 1041: assert(que == ZOMBIE_Q || que == TSR_Q); ! 1042: ! 1043: ! 1044: ! 1045: if (curproc->pid == 0) { ! 1046: ! 1047: FATAL("attempt to terminate MiNT"); ! 1048: ! 1049: } ! 1050: ! 1051: ! 1052: ! 1053: /* cancel all pending timeouts for this process */ ! 1054: ! 1055: cancelalltimeouts(); ! 1056: ! 1057: /* cancel alarm clock */ ! 1058: ! 1059: curproc->alarmtim = 0; ! 1060: ! 1061: ! 1062: ! 1063: /* release any drives locked by Dlock */ ! 1064: ! 1065: for(i = 0; i < NUM_DRIVES; i++) { ! 1066: ! 1067: if (dlockproc[i] == curproc) { ! 1068: ! 1069: dlockproc[i] = 0; ! 1070: ! 1071: changedrv(i); ! 1072: ! 1073: } ! 1074: ! 1075: } ! 1076: ! 1077: ! 1078: ! 1079: /* release the controlling terminal, if we're a process group leader */ ! 1080: ! 1081: fp = curproc->handle[-1]; ! 1082: ! 1083: if (fp && is_terminal(fp) && curproc->pgrp == curproc->pid) { ! 1084: ! 1085: struct tty *tty = (struct tty *)fp->devinfo; ! 1086: ! 1087: if (curproc->pgrp == tty->pgrp) ! 1088: ! 1089: tty->pgrp = 0; ! 1090: ! 1091: } ! 1092: ! 1093: ! 1094: ! 1095: /* close all files */ ! 1096: ! 1097: for (i = MIN_HANDLE; i < MAX_OPEN; i++) { ! 1098: ! 1099: if ((fp = curproc->handle[i])) ! 1100: ! 1101: do_close(fp); ! 1102: ! 1103: curproc->handle[i] = 0; ! 1104: ! 1105: } ! 1106: ! 1107: ! 1108: ! 1109: /* close any unresolved Fsfirst/Fsnext directory searches */ ! 1110: ! 1111: for (i = 0; i < NUM_SEARCH; i++) { ! 1112: ! 1113: if (curproc->srchdta[i]) { ! 1114: ! 1115: DIR *dirh = &curproc->srchdir[i]; ! 1116: ! 1117: (*dirh->fc.fs->closedir)(dirh); ! 1118: ! 1119: } ! 1120: ! 1121: } ! 1122: ! 1123: ! 1124: ! 1125: /* release all semaphores owned by this process */ ! 1126: ! 1127: free_semaphores(curproc->pid); ! 1128: ! 1129: ! 1130: ! 1131: /* free all memory */ ! 1132: ! 1133: if (que == ZOMBIE_Q) { ! 1134: ! 1135: for (i = curproc->num_reg - 1; i >=0; i--) { ! 1136: ! 1137: m = curproc->mem[i]; ! 1138: ! 1139: curproc->mem[i] = 0; curproc->addr[i] = 0; ! 1140: ! 1141: if (m) { ! 1142: ! 1143: /* don't free specially allocated memory */ ! 1144: ! 1145: if (m->mflags & M_KEEP) { ! 1146: ! 1147: if (curproc != rootproc) ! 1148: ! 1149: attach_region(rootproc, m); ! 1150: ! 1151: } ! 1152: ! 1153: m->links--; ! 1154: ! 1155: if (m->links == 0) { ! 1156: ! 1157: free_region(m); ! 1158: ! 1159: } ! 1160: ! 1161: } ! 1162: ! 1163: } ! 1164: ! 1165: kfree(curproc->mem); kfree(curproc->addr); ! 1166: ! 1167: curproc->mem = 0; ! 1168: ! 1169: curproc->addr = 0; ! 1170: ! 1171: curproc->num_reg = 0; ! 1172: ! 1173: } ! 1174: ! 1175: /* else ! 1176: ! 1177: make TSR process non-swappable */ ! 1178: ! 1179: ! 1180: ! 1181: /* ! 1182: ! 1183: * make sure that any open files that refer to this process are ! 1184: ! 1185: * closed ! 1186: ! 1187: */ ! 1188: ! 1189: changedrv(PROC_BASE_DEV | curproc->pid); ! 1190: ! 1191: ! 1192: ! 1193: /* find our parent (if parent not found, then use process 0 as parent ! 1194: ! 1195: * since that process is constantly in a wait loop) ! 1196: ! 1197: */ ! 1198: ! 1199: ! 1200: ! 1201: p = pid2proc(curproc->ppid); ! 1202: ! 1203: if (!p) { ! 1204: ! 1205: TRACE("terminate: parent not found"); ! 1206: ! 1207: p = pid2proc(0); ! 1208: ! 1209: } ! 1210: ! 1211: ! 1212: ! 1213: /* NOTE: normally just post_sig is sufficient for sending a signal; but ! 1214: ! 1215: * in this particular case, we have to worry about processes that are ! 1216: ! 1217: * blocking all signals because they Vfork'd and are waiting for us to ! 1218: ! 1219: * finish (which is indicated by a wait_cond matching our PROC ! 1220: ! 1221: * structure), and also processes that are ignoring SIGCHLD but are ! 1222: ! 1223: * waiting for us. ! 1224: ! 1225: */ ! 1226: ! 1227: if (p->wait_q == WAIT_Q && ! 1228: ! 1229: (p->wait_cond == (long)curproc || p->wait_cond == (long)&p_wait3) ) { ! 1230: ! 1231: TRACE("terminate: waking up parent"); ! 1232: ! 1233: rm_q(WAIT_Q, p); ! 1234: ! 1235: add_q(READY_Q, p); ! 1236: ! 1237: } ! 1238: ! 1239: post_sig(p, SIGCHLD); /* inform of process termination */ ! 1240: ! 1241: ! 1242: ! 1243: /* find our children, and orphan them */ ! 1244: ! 1245: i = curproc->pid; ! 1246: ! 1247: for (p = proclist; p; p = p->gl_next) { ! 1248: ! 1249: if (p->ppid == i) { ! 1250: ! 1251: p->ppid = 0; /* have the system adopt it */ ! 1252: ! 1253: if (p->wait_q == ZOMBIE_Q) ! 1254: ! 1255: wakemint = 1; /* we need to wake proc. 0 */ ! 1256: ! 1257: } ! 1258: ! 1259: } ! 1260: ! 1261: ! 1262: ! 1263: if (wakemint) { ! 1264: ! 1265: p = rootproc; /* pid 0 */ ! 1266: ! 1267: if (p->wait_q == WAIT_Q) { ! 1268: ! 1269: rm_q(WAIT_Q, p); ! 1270: ! 1271: add_q(READY_Q, p); ! 1272: ! 1273: } ! 1274: ! 1275: } ! 1276: ! 1277: ! 1278: ! 1279: /* this makes sure that our children are inherited by the system; ! 1280: ! 1281: * plus, it may help avoid problems if somehow a signal gets ! 1282: ! 1283: * through to us ! 1284: ! 1285: */ ! 1286: ! 1287: for(i = 0; i < NSIG; i++) ! 1288: ! 1289: curproc->sighandle[i] = SIG_IGN; ! 1290: ! 1291: ! 1292: ! 1293: /* finally, reset the time/date stamp for u:\proc */ ! 1294: ! 1295: proctime = timestamp; ! 1296: ! 1297: procdate = datestamp; ! 1298: ! 1299: ! 1300: ! 1301: for(;;) { ! 1302: ! 1303: sleep(que, (long)(unsigned)code); ! 1304: ! 1305: /* we shouldn't ever get here */ ! 1306: ! 1307: FATAL("terminate: sleep woke up when it shouldn't have"); ! 1308: ! 1309: } ! 1310: ! 1311: return 0; /* fake */ ! 1312: ! 1313: } ! 1314: ! 1315: ! 1316: ! 1317: /* ! 1318: ! 1319: * TOS process termination entry points: ! 1320: ! 1321: * p_term terminates the process with extreme prejuidice ! 1322: ! 1323: * p_termres lets the process hang around resident in memory, after ! 1324: ! 1325: * shrinking its transient program area to "save" bytes ! 1326: ! 1327: */ ! 1328: ! 1329: ! 1330: ! 1331: long ! 1332: ! 1333: p_term(code) ! 1334: ! 1335: int code; ! 1336: ! 1337: { ! 1338: ! 1339: CONTEXT *syscall; ! 1340: ! 1341: ! 1342: ! 1343: TRACE("Pterm(%d)", code); ! 1344: ! 1345: /* call the process termination vector */ ! 1346: ! 1347: syscall = &curproc->ctxt[SYSCALL]; ! 1348: ! 1349: ! 1350: ! 1351: if (syscall->term_vec != (long)rts) { ! 1352: ! 1353: TRACE("term_vec: user has something to do"); ! 1354: ! 1355: /* ! 1356: ! 1357: * we handle the termination vector just like Supexec(), by ! 1358: ! 1359: * sending signal 0 to the process. See supexec() in xbios.c for details. ! 1360: ! 1361: * Note that we _always_ want to unwind the signal stack, hence the ! 1362: ! 1363: * curproc->sigmask setting here. ! 1364: ! 1365: */ ! 1366: ! 1367: curproc->sigmask |= 1L; ! 1368: ! 1369: (void)supexec((Func)syscall->term_vec, 0L, 0L, 0L, 0L, ! 1370: ! 1371: (long)code); ! 1372: ! 1373: /* ! 1374: ! 1375: * if we arrive here, continue with the termination... ! 1376: ! 1377: */ ! 1378: ! 1379: } ! 1380: ! 1381: return terminate(code, ZOMBIE_Q); ! 1382: ! 1383: } ! 1384: ! 1385: ! 1386: ! 1387: long ! 1388: ! 1389: p_term0() ! 1390: ! 1391: { ! 1392: ! 1393: return p_term(0); ! 1394: ! 1395: } ! 1396: ! 1397: ! 1398: ! 1399: long ! 1400: ! 1401: p_termres(save, code) ! 1402: ! 1403: long save; ! 1404: ! 1405: int code; ! 1406: ! 1407: { ! 1408: ! 1409: MEMREGION *m; ! 1410: ! 1411: ! 1412: ! 1413: TRACE("Ptermres(%ld, %d)", save, code); ! 1414: ! 1415: m = curproc->mem[1]; /* should be the basepage (0 is env.) */ ! 1416: ! 1417: if (m) { ! 1418: ! 1419: (void)shrink_region(m, save); ! 1420: ! 1421: } ! 1422: ! 1423: return terminate(code, TSR_Q); ! 1424: ! 1425: } ! 1426: ! 1427: ! 1428: ! 1429: /* ! 1430: ! 1431: * routine for waiting for children to die. Return has the pid of the ! 1432: ! 1433: * found child in the high word, and the child's exit code in ! 1434: ! 1435: * the low word. If no children exist, return "File Not Found". ! 1436: ! 1437: * If (nohang & 1) is nonzero, then return a 0 immediately if we have ! 1438: ! 1439: * no dead children but some living ones that we still have to wait ! 1440: ! 1441: * for. If (nohang & 2) is nonzero, then we return any stopped ! 1442: ! 1443: * children; otherwise, only children that have exited or are stopped ! 1444: ! 1445: * due to a trace trap are returned. ! 1446: ! 1447: * If "rusage" is non-zero and a child is found, put the child's ! 1448: ! 1449: * resource usage into it (currently only the user and system time are ! 1450: ! 1451: * sent back) ! 1452: ! 1453: */ ! 1454: ! 1455: ! 1456: ! 1457: long ! 1458: ! 1459: p_wait3(nohang, rusage) ! 1460: ! 1461: int nohang; ! 1462: ! 1463: long *rusage; ! 1464: ! 1465: { ! 1466: ! 1467: long r; ! 1468: ! 1469: PROC *p, *q; ! 1470: ! 1471: int ourpid; ! 1472: ! 1473: int found; ! 1474: ! 1475: ! 1476: ! 1477: TRACE("Pwait3"); ! 1478: ! 1479: ourpid = curproc->pid; ! 1480: ! 1481: ! 1482: ! 1483: /* if there are terminated children, clean up and return their info; ! 1484: ! 1485: * if there are children, but still running, wait for them; ! 1486: ! 1487: * if there are no children, return an error ! 1488: ! 1489: */ ! 1490: ! 1491: ! 1492: ! 1493: do { ! 1494: ! 1495: /* look for any children */ ! 1496: ! 1497: found = 0; ! 1498: ! 1499: for (p = proclist; p; p = p->gl_next) { ! 1500: ! 1501: if (p->ppid == ourpid) { ! 1502: ! 1503: found++; ! 1504: ! 1505: if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q) ! 1506: ! 1507: break; ! 1508: ! 1509: ! 1510: ! 1511: /* p->wait_cond == 0 if a stopped process has already been waited for */ ! 1512: ! 1513: if (p->wait_q == STOP_Q && p->wait_cond) { ! 1514: ! 1515: if ((nohang & 2) || ! 1516: ! 1517: ((p->wait_cond&0x1f00) == SIGTRAP<<8)) ! 1518: ! 1519: break; ! 1520: ! 1521: } ! 1522: ! 1523: } ! 1524: ! 1525: } ! 1526: ! 1527: if (!p) { ! 1528: ! 1529: if (found) { ! 1530: ! 1531: if (nohang & 1) ! 1532: ! 1533: return 0; ! 1534: ! 1535: if (curproc->pid) ! 1536: ! 1537: TRACE("Pwait3: going to sleep"); ! 1538: ! 1539: sleep(WAIT_Q, (long)&p_wait3); ! 1540: ! 1541: } ! 1542: ! 1543: else { ! 1544: ! 1545: DEBUG("Pwait3: no children found"); ! 1546: ! 1547: return EFILNF; ! 1548: ! 1549: } ! 1550: ! 1551: } ! 1552: ! 1553: } while (!p); ! 1554: ! 1555: ! 1556: ! 1557: /* OK, we've found our child */ ! 1558: ! 1559: /* calculate the return code from the child's exit code and pid */ ! 1560: ! 1561: r = (((unsigned long)p->pid) << 16) | (p->wait_cond & 0x0000ffff); ! 1562: ! 1563: ! 1564: ! 1565: /* check resource usage */ ! 1566: ! 1567: if (rusage) { ! 1568: ! 1569: *rusage++ = p->usrtime; ! 1570: ! 1571: *rusage++ = p->systime; ! 1572: ! 1573: } ! 1574: ! 1575: ! 1576: ! 1577: /* add child's resource usage to parent's */ ! 1578: ! 1579: if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q) { ! 1580: ! 1581: curproc->chldstime += p->systime; ! 1582: ! 1583: curproc->chldutime += p->usrtime; ! 1584: ! 1585: } ! 1586: ! 1587: ! 1588: ! 1589: /* if it was a TSR, mark it as having been found and return */ ! 1590: ! 1591: if (p->wait_q == TSR_Q) { ! 1592: ! 1593: p->ppid = -1; ! 1594: ! 1595: return r; ! 1596: ! 1597: } ! 1598: ! 1599: ! 1600: ! 1601: /* if it was stopped, mark it as having been found and again return */ ! 1602: ! 1603: if (p->wait_q == STOP_Q) { ! 1604: ! 1605: p->wait_cond = 0; ! 1606: ! 1607: return r; ! 1608: ! 1609: } ! 1610: ! 1611: ! 1612: ! 1613: /* it better have been on the ZOMBIE queue from here on in... */ ! 1614: ! 1615: assert(p->wait_q == ZOMBIE_Q); ! 1616: ! 1617: assert(p != curproc); ! 1618: ! 1619: ! 1620: ! 1621: /* take the child off both the global and ZOMBIE lists */ ! 1622: ! 1623: rm_q(ZOMBIE_Q, p); ! 1624: ! 1625: ! 1626: ! 1627: if (proclist == p) { ! 1628: ! 1629: proclist = p->gl_next; ! 1630: ! 1631: p->gl_next = 0; ! 1632: ! 1633: } ! 1634: ! 1635: else { ! 1636: ! 1637: q = proclist; ! 1638: ! 1639: while(q && q->gl_next != p) ! 1640: ! 1641: q = q->gl_next; ! 1642: ! 1643: assert(q); ! 1644: ! 1645: q->gl_next = p->gl_next; ! 1646: ! 1647: p->gl_next = 0; ! 1648: ! 1649: } ! 1650: ! 1651: ! 1652: ! 1653: dispose_proc(p); /* free the PROC structure */ ! 1654: ! 1655: ! 1656: ! 1657: return r; ! 1658: ! 1659: } ! 1660: ! 1661: ! 1662: ! 1663: /* p_wait: block until a child has exited, and don't worry about ! 1664: ! 1665: resource stats. this is provided as a convenience, and to maintain ! 1666: ! 1667: compatibility with existing binaries (yes, I'm lazy...). we could ! 1668: ! 1669: make do with Pwait3(). ! 1670: ! 1671: */ ! 1672: ! 1673: ! 1674: ! 1675: long ! 1676: ! 1677: p_wait() ! 1678: ! 1679: { ! 1680: ! 1681: return p_wait3(2, (long *)0); ! 1682: ! 1683: } ! 1684: ! 1685: ! 1686: ! 1687: /* ! 1688: ! 1689: * do_vfork(save): create a duplicate of the current process. This is ! 1690: ! 1691: * essentially a vfork() algorithm, except that if (save == 1) the ! 1692: ! 1693: * parent's address space is saved, and then restored when the process ! 1694: ! 1695: * is made runnable again. The parent is suspended until either the child ! 1696: ! 1697: * process (the duplicate) exits or does a Pexec which overlays its ! 1698: ! 1699: * memory space. ! 1700: ! 1701: * ! 1702: ! 1703: * "txtsize" is the size of the process' TEXT area, if it has a valid one; ! 1704: ! 1705: * this is part of the second memory region attached (the basepage one) ! 1706: ! 1707: * and need not be saved (we assume processes don't write on their own ! 1708: ! 1709: * code segment) ! 1710: ! 1711: */ ! 1712: ! 1713: ! 1714: ! 1715: static long ! 1716: ! 1717: do_vfork(save) ! 1718: ! 1719: int save; ! 1720: ! 1721: { ! 1722: ! 1723: PROC *p; ! 1724: ! 1725: long sigmask; ! 1726: ! 1727: MEMREGION *m, *savemem = 0; ! 1728: ! 1729: long savesize, txtsize; ! 1730: ! 1731: int i; ! 1732: ! 1733: char *saveplace; ! 1734: ! 1735: ! 1736: ! 1737: p = fork_proc(); ! 1738: ! 1739: if (!p) { ! 1740: ! 1741: DEBUG("do_vfork: couldn't get new PROC struct"); ! 1742: ! 1743: return mint_errno; ! 1744: ! 1745: } ! 1746: ! 1747: /* set u:\proc time+date */ ! 1748: ! 1749: proctime = timestamp; ! 1750: ! 1751: procdate = datestamp; ! 1752: ! 1753: ! 1754: ! 1755: /* ! 1756: ! 1757: * maybe save the parent's address space ! 1758: ! 1759: */ ! 1760: ! 1761: txtsize = p->txtsize; ! 1762: ! 1763: ! 1764: ! 1765: if (save) { ! 1766: ! 1767: TRACE("do_vfork: saving parent"); ! 1768: ! 1769: savesize = memused(curproc) - txtsize; ! 1770: ! 1771: assert(savesize >= 0); ! 1772: ! 1773: ! 1774: ! 1775: saveplace = (char *)alloc_region(alt, savesize); ! 1776: ! 1777: if (!saveplace) ! 1778: ! 1779: saveplace = (char *)alloc_region(core, savesize); ! 1780: ! 1781: ! 1782: ! 1783: if (!saveplace) { ! 1784: ! 1785: DEBUG("do_vfork: can't save parent's memory"); ! 1786: ! 1787: p->ppid = 0; /* abandon the child */ ! 1788: ! 1789: post_sig(p, SIGKILL); /* then kill it */ ! 1790: ! 1791: p->ctxt[CURRENT].pc = (long)check_sigs; ! 1792: ! 1793: /* just to make sure it dies */ ! 1794: ! 1795: p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE); ! 1796: ! 1797: p->pri = MAX_NICE+1; ! 1798: ! 1799: run_next(p, 1); ! 1800: ! 1801: yield(); ! 1802: ! 1803: return ENSMEM; ! 1804: ! 1805: } ! 1806: ! 1807: savemem = addr2mem((virtaddr)saveplace); ! 1808: ! 1809: assert(savemem); ! 1810: ! 1811: for (i = 0; i < curproc->num_reg; i++) { ! 1812: ! 1813: m = curproc->mem[i]; ! 1814: ! 1815: if (m && m != savemem) { ! 1816: ! 1817: if (i != 1 || txtsize == 0) { ! 1818: ! 1819: quickmove(saveplace, (char *)m->loc, m->len); ! 1820: ! 1821: saveplace += m->len; ! 1822: ! 1823: } ! 1824: ! 1825: else { ! 1826: ! 1827: quickmove(saveplace, (char *)m->loc+txtsize, ! 1828: ! 1829: m->len - txtsize); ! 1830: ! 1831: saveplace += m->len - txtsize; ! 1832: ! 1833: } ! 1834: ! 1835: } ! 1836: ! 1837: } ! 1838: ! 1839: } ! 1840: ! 1841: ! 1842: ! 1843: p->ctxt[CURRENT] = p->ctxt[SYSCALL]; ! 1844: ! 1845: p->ctxt[CURRENT].regs[0] = 0; /* child returns a 0 from call */ ! 1846: ! 1847: p->ctxt[CURRENT].sr &= ~(0x2000); /* child must be in user mode */ ! 1848: ! 1849: #if 0 /* set up in fork_proc() */ ! 1850: ! 1851: p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE); ! 1852: ! 1853: #endif ! 1854: ! 1855: ! 1856: ! 1857: /* watch out for job control signals, since our parent can never wake ! 1858: ! 1859: * up to respond to them. solution: block them; exec_region (in mem.c) ! 1860: ! 1861: * clears the signal mask, so an exec() will unblock them. ! 1862: ! 1863: */ ! 1864: ! 1865: p->sigmask |= (1L << SIGTSTP) | (1L << SIGTTIN) | (1L << SIGTTOU); ! 1866: ! 1867: ! 1868: ! 1869: TRACE("do_vfork: parent going to sleep, wait_cond == %lx", ! 1870: ! 1871: (long)p); ! 1872: ! 1873: ! 1874: ! 1875: /* WARNING: This sleep() must absolutely not wake up until the child ! 1876: ! 1877: * has released the memory space correctly. That's why we mask off ! 1878: ! 1879: * all signals. ! 1880: ! 1881: */ ! 1882: ! 1883: sigmask = curproc->sigmask; ! 1884: ! 1885: curproc->sigmask = ~(1L << SIGKILL); ! 1886: ! 1887: ! 1888: ! 1889: add_q(READY_Q, p); /* put it on the ready queue */ ! 1890: ! 1891: sleep(WAIT_Q, (long)p); /* while we wait for it */ ! 1892: ! 1893: TRACE("do_vfork: parent waking up"); ! 1894: ! 1895: ! 1896: ! 1897: if (save) { ! 1898: ! 1899: TRACE("do_vfork: parent restoring memory"); ! 1900: ! 1901: saveplace = (char *)savemem->loc; ! 1902: ! 1903: for (i = 0; i < curproc->num_reg; i++) { ! 1904: ! 1905: m = curproc->mem[i]; ! 1906: ! 1907: if (m && (m != savemem)) { ! 1908: ! 1909: if (i != 1 || txtsize == 0) { ! 1910: ! 1911: quickmove((char *)m->loc, saveplace, m->len); ! 1912: ! 1913: saveplace += m->len; ! 1914: ! 1915: } ! 1916: ! 1917: else { ! 1918: ! 1919: quickmove((char *)m->loc+txtsize, saveplace, ! 1920: ! 1921: m->len - txtsize); ! 1922: ! 1923: saveplace += m->len - txtsize; ! 1924: ! 1925: } ! 1926: ! 1927: } ! 1928: ! 1929: } ! 1930: ! 1931: detach_region(curproc, savemem); ! 1932: ! 1933: } ! 1934: ! 1935: curproc->sigmask = sigmask; ! 1936: ! 1937: check_sigs(); /* did we get any signals while sleeping? */ ! 1938: ! 1939: return p->pid; ! 1940: ! 1941: } ! 1942: ! 1943: ! 1944: ! 1945: /* ! 1946: ! 1947: * here are the interfaces that the user sees. Pvfork() doesn't save ! 1948: ! 1949: * the child's address space; Pfork() does. Someday Pfork() should ! 1950: ! 1951: * allow asynchronous execution of both child and parent, but this ! 1952: ! 1953: * will do for now. ! 1954: ! 1955: */ ! 1956: ! 1957: ! 1958: ! 1959: long ! 1960: ! 1961: p_vfork() ! 1962: ! 1963: { ! 1964: ! 1965: return do_vfork(0); ! 1966: ! 1967: } ! 1968: ! 1969: ! 1970: ! 1971: long ! 1972: ! 1973: p_fork() ! 1974: ! 1975: { ! 1976: ! 1977: return do_vfork(1); ! 1978: ! 1979: } ! 1980:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.