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