|
|
1.1 root 1: /*
2:
1.1.1.3 ! root 3: Copyright 1990,1991,1992 Eric R. Smith.
! 4:
! 5: Copyright 1992 Atari Corporation.
! 6:
! 7: All rights reserved.
1.1 root 8:
9: */
10:
11:
12:
13: /*
14:
15: * GEMDOS emulation routines: these are for the GEMDOS system calls
16:
17: * concerning allocating/freeing memory, including Pexec() (since
18:
19: * this allocates memory) and Pterm() (since this, implicitly, frees
20:
21: * it).
22:
23: */
24:
25:
26:
27: #include "mint.h"
28:
29:
30:
31: int procdate, proctime; /* set when any processes are created/destroyed */
32:
33:
34:
35: static long do_vfork P_((int));
36:
37:
38:
39: /*
40:
41: * new call for TT TOS, for the user to inform DOS of alternate memory
42:
43: * FIXME: we really shouldn't trust the user so completely
44:
1.1.1.3 ! root 45: * FIXME: doesn't work if memory protection is on
! 46:
1.1 root 47: */
48:
49:
50:
1.1.1.2 root 51: long ARGS_ON_STACK
1.1 root 52:
53: m_addalt(start, size)
54:
55: long start, size;
56:
57: {
58:
1.1.1.3 ! root 59: extern int no_mem_prot; /* see main.c and memprot.c */
! 60:
! 61:
! 62:
! 63: if (!no_mem_prot) return 0; /* pretend to succeed */
! 64:
1.1 root 65: if (!add_region(alt, start, size, M_ALT))
66:
67: return EINTRN;
68:
69: else
70:
71: return 0;
72:
73: }
74:
75:
76:
77: /*
78:
79: * internal routine for doing Malloc on a particular memory map
80:
81: */
82:
83:
84:
85: long
86:
87: _do_malloc(map, size, mode)
88:
89: MMAP map;
90:
91: long size;
92:
93: int mode;
94:
95: {
96:
97: virtaddr v;
98:
99: MEMREGION *m;
100:
101: long maxsize, mleft;
102:
103:
104:
105: if (size == -1L) {
106:
107: maxsize = max_rsize(map);
108:
109: if (curproc->maxmem) {
110:
111: mleft = curproc->maxmem - memused(curproc);
112:
113: if (maxsize > mleft)
114:
115: maxsize = mleft;
116:
117: if (maxsize < 0)
118:
119: maxsize = 0;
120:
121: }
122:
123: /* make sure to round down */
124:
125: return maxsize & ~MASKBITS;
126:
127: }
128:
129:
130:
131: /* special case: Malloc(0) should always return 0 */
132:
133: if (size == 0)
134:
135: return 0;
136:
137:
138:
139: if (curproc->maxmem) { /* memory limit? */
140:
141: if (size > curproc->maxmem - memused(curproc)) {
142:
1.1.1.2 root 143: DEBUG(("malloc: memory request would exceed limit"));
1.1 root 144:
145: return 0;
146:
147: }
148:
149: }
150:
151:
152:
1.1.1.3 ! root 153: m = get_region(map, size, mode);
1.1 root 154:
155: if (!m) {
156:
157: return 0;
158:
159: }
160:
161: v = attach_region(curproc, m);
162:
163: if (!v) {
164:
165: m->links = 0;
166:
167: free_region(m);
168:
169: return 0;
170:
171: }
172:
173: /* NOTE: get_region returns a region with link count 1; since attach_region
174:
175: * increments the link count, we have to remember to decrement the count
176:
177: * to correct for this.
178:
179: */
180:
181: m->links--;
182:
183: if ((mode & F_KEEP)) { /* request for permanent memory */
184:
185: m->mflags |= M_KEEP;
186:
187: }
188:
189: return (long)v;
190:
191: }
192:
193:
194:
1.1.1.2 root 195: long ARGS_ON_STACK
1.1 root 196:
197: m_xalloc(size, mode)
198:
199: long size;
200:
201: int mode;
202:
203: {
204:
205: long r, r1;
206:
1.1.1.3 ! root 207: int protmode;
! 208:
! 209: #ifndef NO_DEBUG_INFO
! 210:
! 211: int origmode = mode;
! 212:
! 213: #endif
! 214:
1.1 root 215:
216:
1.1.1.2 root 217: TRACE(("Mxalloc(%ld,%x)",size,mode));
1.1 root 218:
219:
220:
1.1.1.3 ! root 221: /*
! 222:
! 223: * AKP: Hack here: if the calling process' PC is in ROM, then this is a
! 224:
! 225: * Malloc call made by VDI's v_opnvwk routine. So we change mode to
! 226:
! 227: * include "super accessible." This is temporary, until VDI catches up
! 228:
! 229: * with multitasking TOS.
! 230:
! 231: */
! 232:
! 233:
! 234:
! 235: if (((mode & F_PROTMODE) == 0) &&
! 236:
! 237: (curproc->ctxt[SYSCALL].pc > 0x00e00000L) &&
! 238:
! 239: (curproc->ctxt[SYSCALL].pc < 0x00efffffL)) {
! 240:
! 241: mode |= (F_PROT_S + 0x10) | F_KEEP;
! 242:
! 243: TRACE(("m_xalloc: VDI special (call from ROM)"));
1.1 root 244:
245: }
246:
1.1.1.3 ! root 247: /*
! 248:
! 249: * If the mode argument comes in a zero, then set it to the default
! 250:
! 251: * value from prgflags. Otherwise subtract one from it to bring it
! 252:
! 253: * into line with the actual argument to alloc_region.
! 254:
! 255: */
! 256:
! 257: protmode = (mode & F_PROTMODE) >> F_PROTSHIFT;
! 258:
! 259:
! 260:
! 261: if (protmode == 0) {
! 262:
! 263: protmode = (curproc->memflags & F_PROTMODE) >> F_PROTSHIFT;
! 264:
! 265: }
! 266:
! 267: else --protmode;
! 268:
! 269:
! 270:
! 271: #if 0
! 272:
! 273: /* I'm very suspicious of the 0x08 flag; I can't see how it could
! 274:
! 275: * work as the comment below seems to indicate -- ERS
! 276:
! 277: */
! 278:
! 279:
! 280:
! 281: /*
! 282:
! 283: * if the mode argument has the 0x08 bit set then you're trying to change
! 284:
! 285: * the protection mode of a block you already own. "size" is really its
! 286:
! 287: * base address. (new as of 2/6/92)
! 288:
! 289: */
! 290:
! 291: if (mode & 0x08) change_prot_status(curproc,size,protmode);
! 292:
! 293: #endif
1.1 root 294:
295:
296:
1.1.1.3 ! root 297: /*
! 298:
! 299: * Copy the F_KEEP attribute into protmode. We didn't do that
! 300:
! 301: * before now because change_prot_status don't want to see no
! 302:
! 303: * steenking nofree attributes.
! 304:
! 305: */
! 306:
! 307:
! 308:
! 309: protmode |= (mode & F_KEEP);
! 310:
! 311:
! 312:
! 313: /* mask off all but the ST/alternative RAM bits before further use */
! 314:
! 315: mode &= 3;
! 316:
! 317:
! 318:
! 319: if (mode == 0) {
! 320:
! 321: r = _do_malloc(core, size, protmode);
! 322:
! 323: goto ret;
! 324:
! 325: }
! 326:
! 327: else if (mode == 1) {
! 328:
! 329: r = _do_malloc(alt, size, protmode);
! 330:
! 331: goto ret;
! 332:
! 333: }
1.1 root 334:
335: else if (size == -1) {
336:
337: /* modes 2 and 3 are the same for for size -1 */
338:
1.1.1.3 ! root 339: r = _do_malloc(core, -1L, PROT_P);
! 340:
! 341: r1 = _do_malloc(alt, -1L, PROT_P);
! 342:
! 343: if (r1 > r) r = r1;
! 344:
! 345: goto ret;
! 346:
! 347: }
! 348:
! 349: else if (mode == 2) {
1.1 root 350:
1.1.1.3 ! root 351: r = _do_malloc(core, size, protmode);
1.1 root 352:
1.1.1.3 ! root 353: if (r == 0) r = _do_malloc(alt, size, protmode);
1.1 root 354:
1.1.1.3 ! root 355: goto ret;
1.1 root 356:
357: }
358:
1.1.1.3 ! root 359: else /* if (mode == 3) */ {
1.1 root 360:
1.1.1.3 ! root 361: r = _do_malloc(alt, size, protmode);
1.1 root 362:
1.1.1.3 ! root 363: if (r == 0) r = _do_malloc(core, size, protmode);
1.1 root 364:
1.1.1.3 ! root 365: goto ret;
1.1 root 366:
367: }
368:
1.1.1.3 ! root 369: ret:
1.1 root 370:
1.1.1.3 ! root 371: if (r == 0) {
1.1 root 372:
1.1.1.3 ! root 373: DEBUG(("m_xalloc(%lx,%x) returns 0",size,origmode));
1.1 root 374:
1.1.1.3 ! root 375: } else {
! 376:
! 377: TRACE(("m_xalloc(%lx,%x) returns %lx",size,origmode,r));
1.1 root 378:
379: }
380:
1.1.1.3 ! root 381: return r;
! 382:
1.1 root 383: }
384:
385:
386:
1.1.1.2 root 387: long ARGS_ON_STACK
1.1 root 388:
389: m_alloc(size)
390:
391: long size;
392:
393: {
394:
395: long r;
396:
397:
398:
1.1.1.2 root 399: TRACE(("Malloc(%lx)", size));
1.1 root 400:
401: if (curproc->memflags & F_ALTALLOC)
402:
403: r = m_xalloc(size, 3);
404:
405: else
406:
407: r = m_xalloc(size, 0);
408:
1.1.1.2 root 409: TRACE(("Malloc: returning %lx", r));
1.1 root 410:
411: return r;
412:
413: }
414:
415:
416:
1.1.1.2 root 417: long ARGS_ON_STACK
1.1 root 418:
419: m_free(block)
420:
421: virtaddr block;
422:
423: {
424:
425: MEMREGION *m;
426:
427: int i;
428:
429:
430:
1.1.1.2 root 431: TRACE(("Mfree(%lx)", block));
1.1 root 432:
433: if (!block) {
434:
1.1.1.2 root 435: DEBUG(("Mfree: null pointer"));
1.1 root 436:
437: return EIMBA;
438:
439: }
440:
441:
442:
443: /* search backwards so that most recently allocated incarnations of
444:
445: shared memory blocks are freed first (this doesn't matter very often)
446:
447: */
448:
449:
450:
451: for (i = curproc->num_reg - 1; i >= 0; i--) {
452:
453: if (curproc->addr[i] == block) {
454:
455: m = curproc->mem[i];
456:
457: assert(m != NULL);
458:
459: assert(m->loc == (long)block);
460:
461: curproc->mem[i] = 0;
462:
463: curproc->addr[i] = 0;
464:
465: m->links--;
466:
467: if (m->links == 0) {
468:
469: free_region(m);
470:
471: }
472:
473: return 0;
474:
475: }
476:
477: }
478:
479:
480:
481: /* hmmm... if we didn't find the region, perhaps it's a global
482:
483: * one (with the M_KEEP flag set) belonging to a process that
484:
485: * terminated
486:
487: */
488:
489: for (i = rootproc->num_reg - 1; i >= 0; i--) {
490:
491: if (rootproc->addr[i] == block) {
492:
493: m = rootproc->mem[i];
494:
495: assert(m != NULL);
496:
497: assert(m->loc == (long)block);
498:
499: if (!(m->mflags & M_KEEP))
500:
501: continue;
502:
1.1.1.3 ! root 503: TRACE(("Freeing M_KEPT memory"));
! 504:
1.1 root 505: rootproc->mem[i] = 0;
506:
507: rootproc->addr[i] = 0;
508:
509: m->links--;
510:
511: if (m->links == 0) {
512:
513: free_region(m);
514:
515: }
516:
517: return 0;
518:
519: }
520:
521: }
522:
523:
524:
525:
526:
1.1.1.2 root 527: DEBUG(("Mfree: bad address %lx", block));
1.1 root 528:
529: return EIMBA;
530:
531: }
532:
533:
534:
1.1.1.2 root 535: long ARGS_ON_STACK
1.1 root 536:
537: m_shrink(dummy, block, size)
538:
539: int dummy;
540:
541: virtaddr block;
542:
543: long size;
544:
545: {
546:
547: MEMREGION *m;
548:
549: int i;
550:
551:
552:
1.1.1.2 root 553: UNUSED(dummy);
554:
555: TRACE(("Mshrink: %lx to %ld", block, size));
1.1 root 556:
557: if (!block) {
558:
1.1.1.2 root 559: DEBUG(("Mshrink: null pointer"));
1.1 root 560:
561: return EIMBA;
562:
563: }
564:
565:
566:
567: for (i = 0; i < curproc->num_reg; i++) {
568:
569: if (curproc->addr[i] == block) {
570:
571: m = curproc->mem[i];
572:
573: assert(m != NULL);
574:
575: assert(m->loc == (long)block);
576:
577: return shrink_region(m, size);
578:
579: }
580:
581: }
582:
1.1.1.2 root 583: DEBUG(("Mshrink: bad address (%lx)", block));
1.1 root 584:
585: return EIMBA;
586:
587: }
588:
589:
590:
1.1.1.2 root 591: long ARGS_ON_STACK
1.1 root 592:
593: p_exec(mode, ptr1, ptr2, ptr3)
594:
595: int mode;
596:
597: void *ptr1, *ptr2, *ptr3;
598:
599: {
600:
1.1.1.2 root 601: MEMREGION *base,
602:
603: *env = 0; /* assignment suppresses spurious warning */
1.1 root 604:
1.1.1.2 root 605: MEMREGION *text = 0; /* for shared text regions */
606:
607: PROC *p;
1.1 root 608:
609: long r, flags = 0;
610:
611: int i;
612:
613: char mkbase = 0, mkload = 0, mkgo = 0, mkwait = 0, mkfree = 0;
614:
615: char overlay = 0;
616:
617: char thread = 0;
618:
1.1.1.2 root 619: char ptrace;
620:
1.1 root 621: char mkname = 0, *newname, *lastslash;
622:
623: char localname[PNAMSIZ+1];
624:
625: XATTR xattr;
626:
1.1.1.3 ! root 627: int newpid;
! 628:
! 629:
! 630:
! 631: /* tfmt and tail_offs are used for debugging only */
! 632:
! 633: const char *tfmt = "Pexec(%d,%s,\"%s\",%lx)";
! 634:
! 635: int tail_offs = 1;
! 636:
1.1 root 637:
638:
1.1.1.2 root 639: /* the high bit of mode controls process tracing */
640:
641: switch(mode & 0x7fff) {
1.1 root 642:
643: case 0:
644:
645: mkwait = 1; /* fall through */
646:
647: case 100:
648:
649: mkload = mkgo = mkfree = 1;
650:
651: mkname = 1;
652:
653: break;
654:
655: case 200: /* overlay current process */
656:
657: mkload = mkgo = 1;
658:
659: overlay = mkname = 1;
660:
661: break;
662:
663: case 3:
664:
665: mkload = 1;
666:
667: break;
668:
669: case 6:
670:
671: mkfree = 1;
672:
673: /* fall through */
674:
675: case 4:
676:
677: mkwait = mkgo = 1;
678:
1.1.1.3 ! root 679: tfmt = "Pexec(%d,%lx,BP:%lx,%lx)";
! 680:
! 681: tail_offs = 0;
1.1 root 682:
683: break;
684:
685: case 106:
686:
687: mkfree = 1; /* fall through */
688:
689: case 104:
690:
691: thread = (mode == 104);
692:
693: mkgo = 1;
694:
695: mkname = (ptr1 != 0);
696:
1.1.1.3 ! root 697: tfmt = "Pexec(%d,%s,BP:%lx,%lx)";
! 698:
! 699: tail_offs = 0;
1.1.1.2 root 700:
701: break;
702:
703: case 206:
704:
705: #if 0
706:
707: /* mkfree has no effect when overlay is set, since
708:
709: * in this case the "parent" and "child" are the same
710:
711: * process; since the "child" will run in memory that the
712:
713: * "parent" allocated, we don't want that memory freed!
714:
715: */
716:
717: mkfree = 1;
718:
719: #endif
720:
721: /* fall through */
722:
723: case 204:
724:
725: mkgo = overlay = 1;
726:
727: mkname = (ptr1 != 0);
728:
1.1.1.3 ! root 729: tfmt = "Pexec(%d,%s,BP:%lx,%lx)";
! 730:
! 731: tail_offs = 0;
1.1 root 732:
733: break;
734:
735: case 7:
736:
737: flags = (long)ptr1; /* set program flags */
738:
739: /* and fall through */
740:
741: case 5:
742:
743: mkbase = 1;
744:
1.1.1.3 ! root 745: tfmt = "Pexec(%d,%lx,%s,%lx)";
! 746:
! 747: tail_offs = 0;
1.1 root 748:
749: break;
750:
751: default:
752:
1.1.1.3 ! root 753: DEBUG(("Pexec(%d,%lx,%lx,%lx): bad mode",mode,ptr1,ptr2,ptr3));
1.1 root 754:
755: return EINVFN;
756:
757: }
758:
759:
760:
1.1.1.3 ! root 761: TRACE((tfmt,mode,ptr1,(char *)ptr2+tail_offs,ptr3));
! 762:
! 763:
! 764:
! 765: /* Pexec with mode 0x8000 indicates tracing should be active */
! 766:
1.1.1.2 root 767: ptrace = (!mkwait && (mode & 0x8000));
768:
769:
770:
1.1 root 771: /* in most cases, we'll want a process struct to exist,
772:
773: * so make sure one is around. Note that we must be
774:
775: * careful to free it later!
776:
777: */
778:
779:
780:
1.1.1.3 ! root 781: TRACE(("Checking for memory for new PROC structure"));
! 782:
1.1 root 783: p = 0;
784:
785: if (!overlay) {
786:
787: p = new_proc();
788:
789: if (!p) {
790:
1.1.1.2 root 791: DEBUG(("Pexec: couldn't get a PROC struct"));
1.1 root 792:
793: return ENSMEM;
794:
795: }
796:
797: }
798:
799:
800:
1.1.1.3 ! root 801: TRACE(("creating environment"));
! 802:
1.1 root 803:
804:
805: if (mkload || mkbase) {
806:
807: env = create_env((char *)ptr3);
808:
809: if (!env) {
810:
1.1.1.2 root 811: DEBUG(("Pexec: unable to create environment"));
1.1 root 812:
813: if (p) dispose_proc(p);
814:
815: return ENSMEM;
816:
817: }
818:
819: }
820:
821:
822:
1.1.1.3 ! root 823: TRACE(("creating base page"));
! 824:
! 825:
! 826:
1.1 root 827: if (mkbase) {
828:
829: base = create_base((char *)ptr2, env, flags, 0L);
830:
831: if (!base) {
832:
1.1.1.2 root 833: DEBUG(("Pexec: unable to create basepage"));
1.1 root 834:
835: detach_region(curproc, env);
836:
837: if (p) dispose_proc(p);
838:
839: return ENSMEM;
840:
841: }
842:
1.1.1.3 ! root 843: TRACELOW(("Pexec: basepage region(%lx) is %ld bytes at %lx", base, base->len, base->loc));
1.1.1.2 root 844:
1.1 root 845: }
846:
847: else if (mkload) {
848:
1.1.1.2 root 849: base = load_region((char *)ptr1, env, (char *)ptr2,
850:
1.1.1.3 ! root 851: &xattr, &text, &flags);
1.1 root 852:
853: if (!base) {
854:
1.1.1.2 root 855: DEBUG(("Pexec: load_region failed"));
1.1 root 856:
857: detach_region(curproc, env);
858:
859: if (p) dispose_proc(p);
860:
861: return mint_errno;
862:
863: }
864:
1.1.1.2 root 865: TRACE(("Pexec: basepage region(%lx) is %ld bytes at %lx", base, base->len, base->loc));
866:
1.1 root 867: }
868:
1.1.1.2 root 869: else { /* mode == 4,6,104,106,204, or 206 -- just go */
1.1 root 870:
871: base = addr2mem((virtaddr)ptr2);
872:
873: if (base)
874:
875: env = addr2mem(*(void **)(base->loc + 0x2c));
876:
877: else
878:
879: env = 0;
880:
881: if (!env) {
882:
883: if (p) dispose_proc(p);
884:
885: return EIMBA;
886:
887: }
888:
889: }
890:
891:
892:
893: /* make a local copy of the name, in case we are overlaying the current
894:
895: * process
896:
897: */
898:
899: if (mkname) {
900:
901: lastslash = 0;
902:
903: newname = ptr1;
904:
905: while (*newname) {
906:
907: if (*newname == '\\' || *newname == '/')
908:
909: lastslash = newname;
910:
911: ++newname;
912:
913: }
914:
915: if (!lastslash)
916:
917: lastslash = ptr1;
918:
919: else
920:
921: lastslash++;
922:
923:
924:
925: i = 0; newname = localname;
926:
927: while (i++ < PNAMSIZ) {
928:
929: if (*lastslash == '.' || *lastslash == 0) {
930:
931: *newname = 0; break;
932:
933: }
934:
935: else
936:
937: *newname++ = *lastslash++;
938:
939: }
940:
941: *newname = 0;
942:
943: }
944:
945:
946:
1.1.1.3 ! root 947: if (mkload || mkbase) {
! 948:
! 949: /*
! 950:
! 951: * Now that the file's loaded, flags is set to the prgflags
! 952:
! 953: * for the file. In the case of mkbase it's been right all along.
! 954:
! 955: * Here's where we change the protection on the environment to
! 956:
! 957: * match those flags.
! 958:
! 959: */
! 960:
! 961: mark_region(env,(short)((flags & F_PROTMODE) >> F_PROTSHIFT));
! 962:
! 963: }
! 964:
! 965:
! 966:
1.1 root 967: if (p) {
968:
969: /* free the PROC struct so fork_proc will succeed */
970:
1.1.1.3 ! root 971: /* FIXME: it would be much better to pass the PROC as a parameter
! 972:
! 973: * to fork_proc!!
! 974:
! 975: */
! 976:
1.1 root 977: dispose_proc(p);
978:
979: p = 0;
980:
981: }
982:
983:
984:
985: if (mkgo) {
986:
987: BASEPAGE *b;
988:
989:
990:
1.1.1.3 ! root 991: /* tell the child who the parent was */
! 992:
! 993: b = (BASEPAGE *)base->loc;
! 994:
! 995:
! 996:
1.1 root 997: if (overlay) {
998:
1.1.1.3 ! root 999: b->p_parent = curproc->base->p_parent;
! 1000:
1.1 root 1001: p = curproc;
1002:
1003: /* make sure that exec_region doesn't free the base and env */
1004:
1005: base->links++;
1006:
1007: env->links++;
1008:
1.1.1.2 root 1009: if (text) text->links++;
1010:
1.1 root 1011: }
1012:
1013: else {
1014:
1.1.1.3 ! root 1015: b->p_parent = curproc->base;
! 1016:
1.1 root 1017: p = fork_proc();
1018:
1019: }
1020:
1021: if (!p) {
1022:
1023: if (mkbase) {
1024:
1025: detach_region(curproc, base);
1026:
1027: detach_region(curproc, env);
1028:
1.1.1.2 root 1029: if (text) detach_region(curproc, text);
1030:
1.1 root 1031: }
1032:
1033: return mint_errno;
1034:
1035: }
1036:
1.1.1.2 root 1037: if (ptrace)
1038:
1039: p->ptracer = pid2proc(p->ppid);
1040:
1041:
1042:
1043: /* Even though the file system won't allow unauthorized access
1.1 root 1044:
1.1.1.2 root 1045: * to setuid/setgid programs, it's better to err on the side of
1.1 root 1046:
1.1.1.2 root 1047: * caution and forbid them to be traced (since the parent can arrange
1048:
1049: * to share the child's address space, not all accesses need to
1050:
1.1.1.3 ! root 1051: * go through the file system.)
1.1.1.2 root 1052:
1053: */
1054:
1055: if (mkload && mkgo && !p->ptracer) { /* setuid/setgid is OK */
1.1 root 1056:
1057: if (xattr.mode & S_ISUID)
1058:
1059: p->euid = xattr.uid;
1060:
1061: if (xattr.mode & S_ISGID)
1062:
1063: p->egid = xattr.gid;
1064:
1065: }
1066:
1.1.1.3 ! root 1067: /* exec_region frees the memory attached to p; that's always what
1.1 root 1068:
1.1.1.3 ! root 1069: * we want, since fork_proc duplicates the memory, and since
1.1 root 1070:
1.1.1.3 ! root 1071: * if we didn't call fork_proc then we're overlaying.
1.1 root 1072:
1.1.1.3 ! root 1073: * NOTE: after this call, we may not be able to access the
1.1.1.2 root 1074:
1.1.1.3 ! root 1075: * original address space that the Pexec was taking place in
1.1 root 1076:
1.1.1.3 ! root 1077: * (if this is an overlaid Pexec, we just freed that memory).
1.1 root 1078:
1.1.1.3 ! root 1079: */
1.1 root 1080:
1.1.1.3 ! root 1081: (void)exec_region(p, base, thread);
! 1082:
! 1083: attach_region(p, env);
1.1 root 1084:
1.1.1.3 ! root 1085: attach_region(p, base);
1.1 root 1086:
1.1.1.3 ! root 1087: if (text) attach_region(p, text);
1.1 root 1088:
1089:
1090:
1091: if (mkname) {
1092:
1093: /* interesting coincidence -- if a process needs a name, it usually
1094:
1095: * needs to have its domain reset to DOM_TOS. Doing it this way
1096:
1097: * (instead of doing it in exec_region) means that Pexec(4,...)
1098:
1099: * can be used to create new threads of execution which retain
1100:
1101: * the same domain.
1102:
1103: */
1104:
1105: if (!thread)
1106:
1107: p->domain = DOM_TOS;
1108:
1109:
1110:
1111: /* put in the new process name we saved above */
1112:
1113: strcpy(p->name, localname);
1114:
1115: }
1116:
1117:
1118:
1.1.1.2 root 1119: /* turn on tracing for the new process */
1120:
1121: if (p->ptracer)
1122:
1123: p->ctxt[CURRENT].ptrace = 1;
1124:
1125:
1126:
1.1 root 1127: /* set the time/date stamp of u:\proc */
1128:
1129: proctime = timestamp;
1130:
1131: procdate = datestamp;
1132:
1133:
1134:
1135: if (overlay) {
1136:
1137: /* correct for temporary increase in links (see above) */
1138:
1139: base->links--;
1140:
1141: env->links--;
1142:
1.1.1.2 root 1143: if (text) text->links--;
1144:
1.1 root 1145: /* let our parent run, if it Vfork'd() */
1146:
1147: if ( (p = pid2proc(curproc->ppid)) != 0 ) {
1148:
1149: if (p->wait_q == WAIT_Q &&
1150:
1151: p->wait_cond == (long)curproc) {
1152:
1.1.1.3 ! root 1153: short sr = spl7();
! 1154:
1.1 root 1155: rm_q(WAIT_Q, p);
1156:
1157: add_q(READY_Q, p);
1158:
1.1.1.3 ! root 1159: spl(sr);
! 1160:
1.1 root 1161: }
1162:
1163: }
1164:
1165:
1166:
1167: /* OK, let's run our new code */
1168:
1169: /* we guarantee ourselves at least 2 timeslices to do an Mshrink */
1170:
1171: assert(curproc->magic == CTXT_MAGIC);
1172:
1173: fresh_slices(2);
1174:
1175: leave_kernel();
1176:
1.1.1.3 ! root 1177: change_context(&(curproc->ctxt[CURRENT]));
1.1 root 1178:
1179: }
1180:
1181: else {
1182:
1183: /* we want this process to run ASAP */
1184:
1185: /* so we temporarily give it high priority and put it first on the
1186:
1187: * run queue
1188:
1189: */
1190:
1191: run_next(p, 2);
1192:
1193: }
1194:
1195: }
1196:
1197:
1198:
1199: if (mkfree) {
1200:
1201: detach_region(curproc, base);
1202:
1203: detach_region(curproc, env);
1204:
1.1.1.2 root 1205: if (text) detach_region(curproc, text);
1206:
1.1 root 1207: }
1208:
1209:
1210:
1211: if (mkwait) {
1212:
1213: long oldsigint, oldsigquit;
1214:
1215:
1216:
1217: oldsigint = curproc->sighandle[SIGINT];
1218:
1219: oldsigquit = curproc->sighandle[SIGQUIT];
1220:
1221: curproc->sighandle[SIGINT] =
1222:
1223: curproc->sighandle[SIGQUIT] = SIG_IGN;
1224:
1225:
1226:
1.1.1.3 ! root 1227: newpid = p->pid;
1.1 root 1228:
1229: for(;;) {
1230:
1231: r = p_wait3(0, (long *)0);
1232:
1233: if (r < 0) {
1234:
1235: ALERT("p_exec: wait error");
1236:
1237: return EINTRN;
1238:
1239: }
1240:
1.1.1.3 ! root 1241: if ( newpid == ((r&0xffff0000L) >> 16) ) {
1.1 root 1242:
1.1.1.3 ! root 1243: TRACE(("leaving Pexec; child return code %ld", r));
1.1 root 1244:
1.1.1.2 root 1245: r = r & 0x0000ffffL;
1.1 root 1246:
1247: break;
1248:
1249: }
1250:
1251: if (curproc->pid)
1252:
1.1.1.2 root 1253: DEBUG(("Pexec: wrong child found"));
1.1 root 1254:
1255: }
1256:
1257: curproc->sighandle[SIGINT] = oldsigint;
1258:
1259: curproc->sighandle[SIGQUIT] = oldsigquit;
1260:
1261: return r;
1262:
1263: }
1264:
1265: else if (mkgo) {
1266:
1.1.1.3 ! root 1267: /* warning: after the yield() the "p" structure may not exist any more
! 1268:
! 1269: * (if the child exits right away)
! 1270:
! 1271: */
! 1272:
! 1273: newpid = p->pid;
! 1274:
1.1 root 1275: yield(); /* let the new process run */
1276:
1.1.1.3 ! root 1277: return newpid;
1.1 root 1278:
1279: } else {
1280:
1.1.1.2 root 1281: TRACE(("leaving Pexec with basepage address %lx", base->loc));
1.1 root 1282:
1283: return base->loc;
1284:
1285: }
1286:
1287: }
1288:
1289:
1290:
1291: /*
1292:
1293: * terminate a process, with return code "code". If que == ZOMBIE_Q, free
1294:
1295: * all resources attached to the child; if que == TSR_Q, free everything
1296:
1.1.1.2 root 1297: * but memory.
1298:
1299: * NOTE: terminate() should be called only when the process is to be
1300:
1301: * "terminated with extreme prejuidice". Most times, p_term or p_termres
1302:
1303: * are the functions to use, since they allow the user to do some cleaning
1304:
1305: * up, etc.
1.1 root 1306:
1307: */
1308:
1309:
1310:
1311: long
1312:
1313: terminate(code, que)
1314:
1315: int code, que;
1316:
1317: {
1318:
1319: extern PROC *dlockproc[]; /* in dosdir.c */
1320:
1321: PROC *p;
1322:
1323: FILEPTR *fp;
1324:
1325: MEMREGION *m;
1326:
1.1.1.3 ! root 1327: MEMREGION **hold_mem;
! 1328:
! 1329: virtaddr *hold_addr;
! 1330:
1.1 root 1331: int i, wakemint = 0;
1332:
1.1.1.3 ! root 1333: DIR *dirh, *nexth;
! 1334:
1.1 root 1335: extern short bconbsiz; /* in bios.c */
1336:
1337:
1338:
1339: if (bconbsiz)
1340:
1341: (void) bflush();
1342:
1343:
1344:
1345: assert(que == ZOMBIE_Q || que == TSR_Q);
1346:
1347:
1348:
1349: if (curproc->pid == 0) {
1350:
1351: FATAL("attempt to terminate MiNT");
1352:
1353: }
1354:
1355:
1356:
1357: /* cancel all pending timeouts for this process */
1358:
1359: cancelalltimeouts();
1360:
1361: /* cancel alarm clock */
1362:
1363: curproc->alarmtim = 0;
1364:
1365:
1366:
1367: /* release any drives locked by Dlock */
1368:
1369: for(i = 0; i < NUM_DRIVES; i++) {
1370:
1371: if (dlockproc[i] == curproc) {
1372:
1373: dlockproc[i] = 0;
1374:
1375: changedrv(i);
1376:
1377: }
1378:
1379: }
1380:
1381:
1382:
1383: /* release the controlling terminal, if we're a process group leader */
1384:
1385: fp = curproc->handle[-1];
1386:
1387: if (fp && is_terminal(fp) && curproc->pgrp == curproc->pid) {
1388:
1389: struct tty *tty = (struct tty *)fp->devinfo;
1390:
1391: if (curproc->pgrp == tty->pgrp)
1392:
1393: tty->pgrp = 0;
1394:
1395: }
1396:
1397:
1398:
1399: /* close all files */
1400:
1401: for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
1402:
1.1.1.2 root 1403: if ((fp = curproc->handle[i]) != 0)
1.1 root 1404:
1405: do_close(fp);
1406:
1407: curproc->handle[i] = 0;
1408:
1409: }
1410:
1411:
1412:
1413: /* close any unresolved Fsfirst/Fsnext directory searches */
1414:
1415: for (i = 0; i < NUM_SEARCH; i++) {
1416:
1417: if (curproc->srchdta[i]) {
1418:
1419: DIR *dirh = &curproc->srchdir[i];
1420:
1421: (*dirh->fc.fs->closedir)(dirh);
1422:
1.1.1.3 ! root 1423: release_cookie(&dirh->fc);
! 1424:
! 1425: dirh->fc.fs = 0;
! 1426:
1.1 root 1427: }
1428:
1429: }
1430:
1431:
1432:
1.1.1.3 ! root 1433: /* close pending opendir/readdir searches */
! 1434:
! 1435: for (dirh = curproc->searches; dirh; ) {
! 1436:
! 1437: if (!dirh->fc.fs) continue;
! 1438:
! 1439: (*dirh->fc.fs->closedir)(dirh);
! 1440:
! 1441: release_cookie(&dirh->fc);
! 1442:
! 1443: nexth = dirh->next;
! 1444:
! 1445: kfree(dirh);
! 1446:
! 1447: dirh = nexth;
! 1448:
! 1449: }
! 1450:
! 1451:
! 1452:
! 1453: /* release the directory cookies held by the process */
! 1454:
! 1455: for (i = 0; i < NUM_DRIVES; i++) {
! 1456:
! 1457: release_cookie(&curproc->curdir[i]);
! 1458:
! 1459: curproc->curdir[i].fs = 0;
! 1460:
! 1461: release_cookie(&curproc->root[i]);
! 1462:
! 1463: curproc->root[i].fs = 0;
! 1464:
! 1465: }
! 1466:
! 1467:
! 1468:
1.1 root 1469: /* release all semaphores owned by this process */
1470:
1471: free_semaphores(curproc->pid);
1472:
1473:
1474:
1475: /* free all memory */
1476:
1.1.1.3 ! root 1477: /* if mflags & M_KEEP then attach it to process 0 */
! 1478:
1.1 root 1479: if (que == ZOMBIE_Q) {
1480:
1481: for (i = curproc->num_reg - 1; i >=0; i--) {
1482:
1483: m = curproc->mem[i];
1484:
1485: curproc->mem[i] = 0; curproc->addr[i] = 0;
1486:
1487: if (m) {
1488:
1489: /* don't free specially allocated memory */
1490:
1491: if (m->mflags & M_KEEP) {
1492:
1493: if (curproc != rootproc)
1494:
1495: attach_region(rootproc, m);
1496:
1497: }
1498:
1499: m->links--;
1500:
1501: if (m->links == 0) {
1502:
1503: free_region(m);
1504:
1505: }
1506:
1507: }
1508:
1509: }
1510:
1511:
1512:
1.1.1.3 ! root 1513: /*
! 1514:
! 1515: * mark the mem & addr arrays as void so the memory
! 1516:
! 1517: * protection code won't try to walk them. Do this before
! 1518:
! 1519: * freeing them so we don't try to walk them when marking
! 1520:
! 1521: * those pages themselves as free!
! 1522:
! 1523: *
! 1524:
! 1525: * Note: when a process terminates, the MMU root pointer
! 1526:
! 1527: * still points to that process' page table, until the next
! 1528:
! 1529: * process is dispatched. This is OK, since the process'
! 1530:
! 1531: * page table is in system memory, and it isn't going to be
! 1532:
! 1533: * freed. It is going to wind up on the free process list,
! 1534:
! 1535: * though, after dispose_proc. This might be Not A Good
! 1536:
! 1537: * Thing.
! 1538:
! 1539: */
! 1540:
! 1541:
! 1542:
! 1543: hold_addr = curproc->addr;
! 1544:
! 1545: hold_mem = curproc->mem;
! 1546:
! 1547:
! 1548:
! 1549: curproc->mem = NULL;
! 1550:
! 1551: curproc->addr = NULL;
1.1 root 1552:
1553: curproc->num_reg = 0;
1554:
1.1.1.3 ! root 1555:
! 1556:
! 1557: kfree(hold_addr);
! 1558:
! 1559: kfree(hold_mem);
! 1560:
1.1 root 1561: }
1562:
1563: /* else
1564:
1565: make TSR process non-swappable */
1566:
1567:
1568:
1569: /*
1570:
1571: * make sure that any open files that refer to this process are
1572:
1573: * closed
1574:
1575: */
1576:
1577: changedrv(PROC_BASE_DEV | curproc->pid);
1578:
1579:
1580:
1581: /* find our parent (if parent not found, then use process 0 as parent
1582:
1583: * since that process is constantly in a wait loop)
1584:
1585: */
1586:
1587:
1588:
1589: p = pid2proc(curproc->ppid);
1590:
1591: if (!p) {
1592:
1.1.1.2 root 1593: TRACE(("terminate: parent not found"));
1.1 root 1594:
1595: p = pid2proc(0);
1596:
1597: }
1598:
1599:
1600:
1601: /* NOTE: normally just post_sig is sufficient for sending a signal; but
1602:
1603: * in this particular case, we have to worry about processes that are
1604:
1605: * blocking all signals because they Vfork'd and are waiting for us to
1606:
1607: * finish (which is indicated by a wait_cond matching our PROC
1608:
1609: * structure), and also processes that are ignoring SIGCHLD but are
1610:
1611: * waiting for us.
1612:
1613: */
1614:
1615: if (p->wait_q == WAIT_Q &&
1616:
1.1.1.2 root 1617: (p->wait_cond == (long)curproc || p->wait_cond == (long)p_waitpid) ) {
1.1 root 1618:
1.1.1.3 ! root 1619: short sr = spl7();
! 1620:
1.1.1.2 root 1621: TRACE(("terminate: waking up parent"));
1.1 root 1622:
1623: rm_q(WAIT_Q, p);
1624:
1625: add_q(READY_Q, p);
1626:
1.1.1.3 ! root 1627: spl(sr);
! 1628:
1.1 root 1629: }
1630:
1.1.1.2 root 1631: if (curproc->ptracer && curproc->ptracer != p) {
1632:
1633: /* BUG: should we ensure curproc->ptracer is awake ? */
1634:
1635: post_sig(curproc->ptracer, SIGCHLD); /* tell tracing process */
1636:
1637: }
1638:
1.1 root 1639: post_sig(p, SIGCHLD); /* inform of process termination */
1640:
1641:
1642:
1.1.1.2 root 1643: /* find our children, and orphan them
1644:
1645: * also, check for processes we were tracing, and
1646:
1647: * cancel the trace
1648:
1649: */
1.1 root 1650:
1651: i = curproc->pid;
1652:
1653: for (p = proclist; p; p = p->gl_next) {
1654:
1655: if (p->ppid == i) {
1656:
1657: p->ppid = 0; /* have the system adopt it */
1658:
1659: if (p->wait_q == ZOMBIE_Q)
1660:
1661: wakemint = 1; /* we need to wake proc. 0 */
1662:
1663: }
1664:
1.1.1.2 root 1665: if (p->ptracer == curproc) {
1666:
1667: p->ptracer = 0;
1668:
1669: /*
1670:
1671: * `FEATURE': we terminate traced processes when the tracer terminates.
1672:
1673: * It might plausibly be argued that it would be better to let them
1674:
1675: * continue, to let some (new) tracer take them over. On the other hand,
1676:
1677: * if the tracer terminated normally, it should have used Fcntl(PTRACESFLAGS)
1678:
1679: * to reset the trace nicely, so something must be wrong for us to have
1680:
1681: * reached here.
1682:
1683: */
1684:
1685: post_sig(p, SIGTERM); /* arrange for termination */
1686:
1687: }
1688:
1.1 root 1689: }
1690:
1691:
1692:
1693: if (wakemint) {
1694:
1695: p = rootproc; /* pid 0 */
1696:
1697: if (p->wait_q == WAIT_Q) {
1698:
1.1.1.3 ! root 1699: short sr = spl7();
! 1700:
1.1 root 1701: rm_q(WAIT_Q, p);
1702:
1703: add_q(READY_Q, p);
1704:
1.1.1.3 ! root 1705: spl(sr);
! 1706:
1.1 root 1707: }
1708:
1709: }
1710:
1711:
1712:
1713: /* this makes sure that our children are inherited by the system;
1714:
1715: * plus, it may help avoid problems if somehow a signal gets
1716:
1717: * through to us
1718:
1719: */
1720:
1721: for(i = 0; i < NSIG; i++)
1722:
1723: curproc->sighandle[i] = SIG_IGN;
1724:
1725:
1726:
1727: /* finally, reset the time/date stamp for u:\proc */
1728:
1729: proctime = timestamp;
1730:
1731: procdate = datestamp;
1732:
1733:
1734:
1.1.1.2 root 1735: sleep(que, (long)(unsigned)code);
1.1 root 1736:
1737:
1738:
1.1.1.2 root 1739: /* we shouldn't ever get here */
1.1 root 1740:
1.1.1.2 root 1741: FATAL("terminate: sleep woke up when it shouldn't have");
1.1 root 1742:
1.1.1.2 root 1743: return 0;
1.1 root 1744:
1745: }
1746:
1747:
1748:
1749: /*
1750:
1751: * TOS process termination entry points:
1752:
1.1.1.2 root 1753: * p_term terminates the process, freeing its memory
1.1 root 1754:
1755: * p_termres lets the process hang around resident in memory, after
1756:
1757: * shrinking its transient program area to "save" bytes
1758:
1759: */
1760:
1761:
1762:
1.1.1.2 root 1763: long ARGS_ON_STACK
1.1 root 1764:
1765: p_term(code)
1766:
1767: int code;
1768:
1769: {
1770:
1771: CONTEXT *syscall;
1772:
1773:
1774:
1.1.1.2 root 1775: TRACE(("Pterm(%d)", code));
1.1 root 1776:
1777: /* call the process termination vector */
1778:
1779: syscall = &curproc->ctxt[SYSCALL];
1780:
1781:
1782:
1783: if (syscall->term_vec != (long)rts) {
1784:
1.1.1.2 root 1785: TRACE(("term_vec: user has something to do"));
1.1 root 1786:
1787: /*
1788:
1789: * we handle the termination vector just like Supexec(), by
1790:
1791: * sending signal 0 to the process. See supexec() in xbios.c for details.
1792:
1.1.1.2 root 1793: * Note that we _always_ want to unwind the signal stack, and setting
1.1 root 1794:
1.1.1.2 root 1795: * bit 1 of curproc->sigmask tells handle_sig to do that -- see signal.c.
1.1 root 1796:
1797: */
1798:
1799: curproc->sigmask |= 1L;
1800:
1801: (void)supexec((Func)syscall->term_vec, 0L, 0L, 0L, 0L,
1802:
1803: (long)code);
1804:
1805: /*
1806:
1807: * if we arrive here, continue with the termination...
1808:
1809: */
1810:
1811: }
1812:
1813: return terminate(code, ZOMBIE_Q);
1814:
1815: }
1816:
1817:
1818:
1.1.1.2 root 1819: long ARGS_ON_STACK
1.1 root 1820:
1821: p_term0()
1822:
1823: {
1824:
1825: return p_term(0);
1826:
1827: }
1828:
1829:
1830:
1.1.1.2 root 1831: long ARGS_ON_STACK
1.1 root 1832:
1833: p_termres(save, code)
1834:
1835: long save;
1836:
1837: int code;
1838:
1839: {
1840:
1841: MEMREGION *m;
1842:
1.1.1.3 ! root 1843: int i;
! 1844:
1.1 root 1845:
1846:
1.1.1.2 root 1847: TRACE(("Ptermres(%ld, %d)", save, code));
1.1 root 1848:
1849: m = curproc->mem[1]; /* should be the basepage (0 is env.) */
1850:
1851: if (m) {
1852:
1853: (void)shrink_region(m, save);
1854:
1855: }
1856:
1.1.1.3 ! root 1857: /*
! 1858:
! 1859: * make all of the TSR's private memory globally accessible;
! 1860:
! 1861: * this means that more TSR's will "do the right thing"
! 1862:
! 1863: * without having to have prgflags set.
! 1864:
! 1865: */
! 1866:
! 1867: for (i = 0; i < curproc->num_reg; i++) {
! 1868:
! 1869: m = curproc->mem[i];
! 1870:
! 1871: if (m && m->links == 1) { /* only the TSR is owner */
! 1872:
! 1873: if (get_prot_mode(m) == PROT_P) {
! 1874:
! 1875: mark_region(m, PROT_G);
! 1876:
! 1877: }
! 1878:
! 1879: }
! 1880:
! 1881: }
! 1882:
1.1 root 1883: return terminate(code, TSR_Q);
1884:
1885: }
1886:
1887:
1888:
1889: /*
1890:
1891: * routine for waiting for children to die. Return has the pid of the
1892:
1893: * found child in the high word, and the child's exit code in
1894:
1895: * the low word. If no children exist, return "File Not Found".
1896:
1897: * If (nohang & 1) is nonzero, then return a 0 immediately if we have
1898:
1899: * no dead children but some living ones that we still have to wait
1900:
1901: * for. If (nohang & 2) is nonzero, then we return any stopped
1902:
1903: * children; otherwise, only children that have exited or are stopped
1904:
1905: * due to a trace trap are returned.
1906:
1907: * If "rusage" is non-zero and a child is found, put the child's
1908:
1909: * resource usage into it (currently only the user and system time are
1910:
1.1.1.2 root 1911: * sent back).
1912:
1913: * The pid argument specifies a set of child processes for which status
1914:
1915: * is requested:
1916:
1917: * If pid is equal to -1, status is requested for any child process.
1918:
1919: *
1920:
1921: * If pid is greater than zero, it specifies the process ID of a
1922:
1923: * single child process for which status is requested.
1924:
1925: *
1926:
1927: * If pid is equal to zero, status is requested for any child
1928:
1929: * process whose process group ID is equal to that of the calling
1930:
1931: * process.
1932:
1933: *
1934:
1935: * If pid is less than -1, status is requested for any child process
1936:
1937: * whose process group ID is equal to the absolute value of pid.
1938:
1939: *
1940:
1941: * Note this call is a real standard crosser... POSIX.1 doesn't have the
1942:
1943: * rusage stuff, BSD doesn't have the pid stuff; both are useful, so why
1944:
1945: * not have it all!
1.1 root 1946:
1947: */
1948:
1949:
1950:
1.1.1.2 root 1951: long ARGS_ON_STACK
1.1 root 1952:
1.1.1.2 root 1953: p_waitpid(pid, nohang, rusage)
1954:
1955: int pid;
1.1 root 1956:
1957: int nohang;
1958:
1959: long *rusage;
1960:
1961: {
1962:
1963: long r;
1964:
1965: PROC *p, *q;
1966:
1967: int ourpid;
1968:
1969: int found;
1970:
1971:
1972:
1.1.1.2 root 1973: TRACE(("Pwaitpid(%d, %d, %lx)", pid, nohang, rusage));
1.1 root 1974:
1975: ourpid = curproc->pid;
1976:
1977:
1978:
1979: /* if there are terminated children, clean up and return their info;
1980:
1981: * if there are children, but still running, wait for them;
1982:
1983: * if there are no children, return an error
1984:
1985: */
1986:
1987:
1988:
1989: do {
1990:
1991: /* look for any children */
1992:
1993: found = 0;
1994:
1995: for (p = proclist; p; p = p->gl_next) {
1996:
1.1.1.2 root 1997: if ((p->ppid == ourpid || p->ptracer == curproc) &&
1998:
1999: (pid == -1 ||
2000:
2001: (pid > 0 && pid == p->pid) ||
2002:
2003: (pid == 0 && p->pgrp == ourpid) ||
2004:
2005: (pid < -1 && p->pgrp == -pid))) {
1.1 root 2006:
2007: found++;
2008:
2009: if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q)
2010:
2011: break;
2012:
2013:
2014:
2015: /* p->wait_cond == 0 if a stopped process has already been waited for */
2016:
2017: if (p->wait_q == STOP_Q && p->wait_cond) {
2018:
2019: if ((nohang & 2) ||
2020:
1.1.1.2 root 2021: ((p->wait_cond&0x1f00) == (SIGTRAP<<8)))
1.1 root 2022:
2023: break;
2024:
2025: }
2026:
2027: }
2028:
2029: }
2030:
2031: if (!p) {
2032:
2033: if (found) {
2034:
2035: if (nohang & 1)
2036:
2037: return 0;
2038:
2039: if (curproc->pid)
2040:
1.1.1.2 root 2041: TRACE(("Pwaitpid: going to sleep"));
1.1 root 2042:
1.1.1.2 root 2043: sleep(WAIT_Q, (long)p_waitpid);
1.1 root 2044:
2045: }
2046:
2047: else {
2048:
1.1.1.2 root 2049: DEBUG(("Pwaitpid: no children found"));
1.1 root 2050:
2051: return EFILNF;
2052:
2053: }
2054:
2055: }
2056:
2057: } while (!p);
2058:
2059:
2060:
2061: /* OK, we've found our child */
2062:
2063: /* calculate the return code from the child's exit code and pid */
2064:
2065: r = (((unsigned long)p->pid) << 16) | (p->wait_cond & 0x0000ffff);
2066:
2067:
2068:
2069: /* check resource usage */
2070:
2071: if (rusage) {
2072:
2073: *rusage++ = p->usrtime;
2074:
1.1.1.2 root 2075: *rusage = p->systime;
1.1 root 2076:
2077: }
2078:
2079:
2080:
1.1.1.2 root 2081: /* avoid adding adopted trace processes usage to the foster parent */
2082:
2083: if (curproc->pid == p->ppid) {
1.1 root 2084:
1.1.1.2 root 2085: /* add child's resource usage to parent's */
1.1 root 2086:
1.1.1.2 root 2087: if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q) {
1.1 root 2088:
1.1.1.2 root 2089: curproc->chldstime += p->systime;
2090:
2091: curproc->chldutime += p->usrtime;
2092:
2093: }
1.1 root 2094:
2095: }
2096:
2097:
2098:
1.1.1.2 root 2099: /* if it was stopped, mark it as having been found and again return */
1.1 root 2100:
1.1.1.2 root 2101: if (p->wait_q == STOP_Q) {
1.1 root 2102:
1.1.1.2 root 2103: p->wait_cond = 0;
1.1 root 2104:
2105: return r;
2106:
2107: }
2108:
2109:
2110:
1.1.1.2 root 2111: /* We have to worry about processes which attach themselves to running
1.1 root 2112:
1.1.1.2 root 2113: * processes which they want to trace. We fix things up so that the
1.1 root 2114:
1.1.1.2 root 2115: * second time the signal gets delivered we will go all the way to the
2116:
2117: * end of this function.
2118:
2119: */
2120:
2121: if (p->ptracer && p->ptracer->pid != p->ppid) {
2122:
2123: if (curproc == p->ptracer) {
2124:
2125: /* deliver the signal to the tracing process first */
2126:
2127: TRACE(("Pwaitpid(ptracer): returning status to tracing process"));
2128:
2129: p->ptracer = NULL;
2130:
2131: return r;
2132:
2133: }
2134:
2135: else {
2136:
2137: /* Hmmm, the real parent got here first */
2138:
2139: TRACE(("Pwaitpid(ptracer): returning status to parent process"));
2140:
2141: p->ppid = -1;
2142:
2143: return r;
2144:
2145: }
2146:
2147: }
2148:
2149:
2150:
2151: /* if it was a TSR, mark it as having been found and return */
2152:
2153: if (p->wait_q == TSR_Q) {
2154:
2155: p->ppid = -1;
1.1 root 2156:
2157: return r;
2158:
2159: }
2160:
2161:
2162:
2163: /* it better have been on the ZOMBIE queue from here on in... */
2164:
2165: assert(p->wait_q == ZOMBIE_Q);
2166:
2167: assert(p != curproc);
2168:
2169:
2170:
2171: /* take the child off both the global and ZOMBIE lists */
2172:
2173: rm_q(ZOMBIE_Q, p);
2174:
2175:
2176:
2177: if (proclist == p) {
2178:
2179: proclist = p->gl_next;
2180:
2181: p->gl_next = 0;
2182:
2183: }
2184:
2185: else {
2186:
2187: q = proclist;
2188:
2189: while(q && q->gl_next != p)
2190:
2191: q = q->gl_next;
2192:
2193: assert(q);
2194:
2195: q->gl_next = p->gl_next;
2196:
2197: p->gl_next = 0;
2198:
2199: }
2200:
2201:
2202:
2203: dispose_proc(p); /* free the PROC structure */
2204:
2205:
2206:
2207: return r;
2208:
2209: }
2210:
2211:
2212:
1.1.1.2 root 2213: /* p_wait3: BSD process termination primitive, here to maintain
2214:
2215: * compatibility with existing binaries.
2216:
2217: */
2218:
2219: long ARGS_ON_STACK
2220:
2221: p_wait3(nohang, rusage)
2222:
2223: int nohang;
2224:
2225: long *rusage;
2226:
2227: {
2228:
2229: return p_waitpid(-1, nohang, rusage);
2230:
2231: }
2232:
2233:
2234:
1.1 root 2235: /* p_wait: block until a child has exited, and don't worry about
2236:
2237: resource stats. this is provided as a convenience, and to maintain
2238:
2239: compatibility with existing binaries (yes, I'm lazy...). we could
2240:
1.1.1.2 root 2241: make do with Pwaitpid().
1.1 root 2242:
2243: */
2244:
2245:
2246:
1.1.1.2 root 2247: long ARGS_ON_STACK
1.1 root 2248:
2249: p_wait()
2250:
2251: {
2252:
1.1.1.2 root 2253: /*
2254:
2255: * BEWARE:
2256:
2257: * POSIX says that wait() should be implemented as
2258:
2259: * Pwaitpid(-1, 0, (long *)0). Pwait is really not
2260:
2261: * useful for much at all, but we'll keep it around
2262:
2263: * for a while (with it's old, crufty semantics)
2264:
2265: * for backwards compatibility. People implementing
2266:
2267: * POSIX style libraries should use Pwaitpid even
2268:
2269: * to implement wait().
2270:
2271: */
2272:
1.1 root 2273: return p_wait3(2, (long *)0);
2274:
2275: }
2276:
2277:
2278:
2279: /*
2280:
2281: * do_vfork(save): create a duplicate of the current process. This is
2282:
2283: * essentially a vfork() algorithm, except that if (save == 1) the
2284:
2285: * parent's address space is saved, and then restored when the process
2286:
2287: * is made runnable again. The parent is suspended until either the child
2288:
2289: * process (the duplicate) exits or does a Pexec which overlays its
2290:
2291: * memory space.
2292:
2293: *
2294:
2295: * "txtsize" is the size of the process' TEXT area, if it has a valid one;
2296:
2297: * this is part of the second memory region attached (the basepage one)
2298:
2299: * and need not be saved (we assume processes don't write on their own
2300:
2301: * code segment)
2302:
2303: */
2304:
2305:
2306:
2307: static long
2308:
2309: do_vfork(save)
2310:
2311: int save;
2312:
2313: {
2314:
2315: PROC *p;
2316:
2317: long sigmask;
2318:
2319: MEMREGION *m, *savemem = 0;
2320:
2321: long savesize, txtsize;
2322:
2323: int i;
2324:
2325: char *saveplace;
2326:
2327:
2328:
2329: p = fork_proc();
2330:
2331: if (!p) {
2332:
1.1.1.2 root 2333: DEBUG(("do_vfork: couldn't get new PROC struct"));
1.1 root 2334:
2335: return mint_errno;
2336:
2337: }
2338:
2339: /* set u:\proc time+date */
2340:
2341: proctime = timestamp;
2342:
2343: procdate = datestamp;
2344:
2345:
2346:
2347: /*
2348:
2349: * maybe save the parent's address space
2350:
2351: */
2352:
2353: txtsize = p->txtsize;
2354:
2355:
2356:
2357: if (save) {
2358:
1.1.1.2 root 2359: TRACE(("do_vfork: saving parent"));
1.1 root 2360:
2361: savesize = memused(curproc) - txtsize;
2362:
2363: assert(savesize >= 0);
2364:
2365:
2366:
1.1.1.3 ! root 2367: saveplace = (char *)alloc_region(alt, savesize, PROT_P);
1.1 root 2368:
2369: if (!saveplace)
2370:
1.1.1.3 ! root 2371: saveplace = (char *)alloc_region(core, savesize, PROT_P);
1.1 root 2372:
2373:
2374:
2375: if (!saveplace) {
2376:
1.1.1.2 root 2377: DEBUG(("do_vfork: can't save parent's memory"));
1.1 root 2378:
2379: p->ppid = 0; /* abandon the child */
2380:
2381: post_sig(p, SIGKILL); /* then kill it */
2382:
2383: p->ctxt[CURRENT].pc = (long)check_sigs;
2384:
2385: /* just to make sure it dies */
2386:
2387: p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
2388:
2389: p->pri = MAX_NICE+1;
2390:
2391: run_next(p, 1);
2392:
2393: yield();
2394:
2395: return ENSMEM;
2396:
2397: }
2398:
2399: savemem = addr2mem((virtaddr)saveplace);
2400:
2401: assert(savemem);
2402:
2403: for (i = 0; i < curproc->num_reg; i++) {
2404:
2405: m = curproc->mem[i];
2406:
1.1.1.2 root 2407: if (m && m != savemem && !(m->mflags & M_SHTEXT)) {
1.1 root 2408:
2409: if (i != 1 || txtsize == 0) {
2410:
2411: quickmove(saveplace, (char *)m->loc, m->len);
2412:
2413: saveplace += m->len;
2414:
2415: }
2416:
2417: else {
2418:
2419: quickmove(saveplace, (char *)m->loc+txtsize,
2420:
2421: m->len - txtsize);
2422:
2423: saveplace += m->len - txtsize;
2424:
2425: }
2426:
2427: }
2428:
2429: }
2430:
2431: }
2432:
2433:
2434:
2435: p->ctxt[CURRENT] = p->ctxt[SYSCALL];
2436:
2437: p->ctxt[CURRENT].regs[0] = 0; /* child returns a 0 from call */
2438:
2439: p->ctxt[CURRENT].sr &= ~(0x2000); /* child must be in user mode */
2440:
2441: #if 0 /* set up in fork_proc() */
2442:
2443: p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
2444:
2445: #endif
2446:
2447:
2448:
2449: /* watch out for job control signals, since our parent can never wake
2450:
2451: * up to respond to them. solution: block them; exec_region (in mem.c)
2452:
2453: * clears the signal mask, so an exec() will unblock them.
2454:
2455: */
2456:
2457: p->sigmask |= (1L << SIGTSTP) | (1L << SIGTTIN) | (1L << SIGTTOU);
2458:
2459:
2460:
1.1.1.2 root 2461: TRACE(("do_vfork: parent going to sleep, wait_cond == %lx",
1.1 root 2462:
1.1.1.2 root 2463: (long)p));
1.1 root 2464:
2465:
2466:
2467: /* WARNING: This sleep() must absolutely not wake up until the child
2468:
2469: * has released the memory space correctly. That's why we mask off
2470:
2471: * all signals.
2472:
2473: */
2474:
2475: sigmask = curproc->sigmask;
2476:
1.1.1.2 root 2477: curproc->sigmask = ~((unsigned long)1 << SIGKILL);
1.1 root 2478:
2479:
2480:
2481: add_q(READY_Q, p); /* put it on the ready queue */
2482:
2483: sleep(WAIT_Q, (long)p); /* while we wait for it */
2484:
1.1.1.2 root 2485: TRACE(("do_vfork: parent waking up"));
1.1 root 2486:
2487:
2488:
2489: if (save) {
2490:
1.1.1.2 root 2491: TRACE(("do_vfork: parent restoring memory"));
1.1 root 2492:
2493: saveplace = (char *)savemem->loc;
2494:
2495: for (i = 0; i < curproc->num_reg; i++) {
2496:
2497: m = curproc->mem[i];
2498:
1.1.1.2 root 2499: if (m && (m != savemem) && !(m->mflags & M_SHTEXT)) {
1.1 root 2500:
2501: if (i != 1 || txtsize == 0) {
2502:
2503: quickmove((char *)m->loc, saveplace, m->len);
2504:
2505: saveplace += m->len;
2506:
2507: }
2508:
2509: else {
2510:
2511: quickmove((char *)m->loc+txtsize, saveplace,
2512:
2513: m->len - txtsize);
2514:
2515: saveplace += m->len - txtsize;
2516:
2517: }
2518:
2519: }
2520:
2521: }
2522:
2523: detach_region(curproc, savemem);
2524:
2525: }
2526:
2527: curproc->sigmask = sigmask;
2528:
2529: check_sigs(); /* did we get any signals while sleeping? */
2530:
2531: return p->pid;
2532:
2533: }
2534:
2535:
2536:
2537: /*
2538:
2539: * here are the interfaces that the user sees. Pvfork() doesn't save
2540:
2541: * the child's address space; Pfork() does. Someday Pfork() should
2542:
2543: * allow asynchronous execution of both child and parent, but this
2544:
2545: * will do for now.
2546:
2547: */
2548:
2549:
2550:
1.1.1.2 root 2551: long ARGS_ON_STACK
1.1 root 2552:
2553: p_vfork()
2554:
2555: {
2556:
2557: return do_vfork(0);
2558:
2559: }
2560:
2561:
2562:
1.1.1.2 root 2563: long ARGS_ON_STACK
1.1 root 2564:
2565: p_fork()
2566:
2567: {
2568:
2569: return do_vfork(1);
2570:
2571: }
2572:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.