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