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