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