|
|
1.1 root 1: /*
2:
3: Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
4:
5: */
6:
7:
8:
9: /* routines for handling processes */
10:
11:
12:
13: #include "mint.h"
14:
15: #include "xbra.h"
16:
17:
18:
19: static void do_wakeup_things P_((void));
20:
21:
22:
23: extern short proc_clock;
24:
25:
26:
27: /* global process variables */
28:
29: PROC *proclist; /* list of all active processes */
30:
31: PROC *curproc; /* current process */
32:
33: PROC *rootproc; /* pid 0 -- MiNT itself */
34:
35: PROC *sys_q[NUM_QUEUES];
36:
37:
38:
39: #define TIME_SLICE 1 /* number of 20ms ticks before process is
40:
41: pre-empted */
42:
43:
44:
45:
46:
47: /* macro for calculating number of missed time slices, based on a
48:
49: * process' priority
50:
51: */
52:
53: #define SLICES(pri) (((pri) >= 0) ? 0 : -(pri))
54:
55:
56:
57: extern FILESYS bios_filesys;
58:
59:
60:
61: /*
62:
63: * get a new process struct
64:
65: */
66:
67:
68:
69: PROC *
70:
71: new_proc()
72:
73: {
74:
75: PROC *p;
76:
77:
78:
79: p = (PROC *)kmalloc(SIZEOF(PROC));
80:
81: return p;
82:
83: }
84:
85:
86:
87: /*
88:
89: * dispose of an old proc
90:
91: */
92:
93:
94:
95: void
96:
97: dispose_proc(p)
98:
99: PROC *p;
100:
101: {
102:
103: kfree(p);
104:
105: }
106:
107:
108:
109: /*
110:
111: * create a new process that is (practically) a duplicate of the
112:
113: * current one
114:
115: */
116:
117:
118:
119: PROC *
120:
121: fork_proc()
122:
123: {
124:
125: PROC *p;
126:
127: int i;
128:
129: FILEPTR *f;
130:
131:
132:
1.1.1.2 ! root 133: if ((p = new_proc()) == 0) {
1.1 root 134:
135: nomem:
136:
1.1.1.2 ! root 137: DEBUG(("fork_proc: insufficient memory"));
1.1 root 138:
139: mint_errno = ENSMEM; return 0;
140:
141: }
142:
143:
144:
145: *p = *curproc; /* child shares most things with parent... */
146:
147:
148:
149: /* ... except for these: */
150:
151: p->ppid = curproc->pid;
152:
153: p->pid = newpid();
154:
155: p->sigpending = 0;
156:
157: p->sysstack = (long)(p->stack + STKSIZE - 12);
158:
159: p->ctxt[CURRENT].ssp = p->sysstack;
160:
161: p->ctxt[SYSCALL].ssp = (long)(p->stack + ISTKSIZE);
162:
163: p->alarmtim = 0;
164:
165: p->curpri = p->pri;
166:
167: p->slices = SLICES(p->pri);
168:
169: p->starttime = timestamp;
170:
171: p->startdate = datestamp;
172:
173:
174:
175: ((long *)p->sysstack)[1] = FRAME_MAGIC;
176:
177: ((long *)p->sysstack)[2] = 0;
178:
179: ((long *)p->sysstack)[3] = 0;
180:
181:
182:
183: p->usrtime = p->systime = p->chldstime = p->chldutime = 0;
184:
185:
186:
187: /* copy open handles */
188:
189: for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
190:
191: if ((f = p->handle[i]) != 0) {
192:
193: if (f->flags & O_NOINHERIT)
194:
195: /* oops, we didn't really want to copy this handle */
196:
197: p->handle[i] = 0;
198:
199: else
200:
201: f->links++;
202:
203: }
204:
205: }
206:
207:
208:
209: /* clear directory search info */
210:
211: zero((char *)p->srchdta, NUM_SEARCH * SIZEOF(DTABUF *));
212:
213:
214:
215: /* copy memory */
216:
217: p->mem = (MEMREGION **) kmalloc(p->num_reg * SIZEOF(MEMREGION *));
218:
219: if (!p->mem) {
220:
221: dispose_proc(p);
222:
223: goto nomem;
224:
225: }
226:
227: p->addr = (virtaddr *)kmalloc(p->num_reg * SIZEOF(virtaddr));
228:
229: if (!p->addr) {
230:
231: kfree(p->mem);
232:
233: dispose_proc(p);
234:
235: goto nomem;
236:
237: }
238:
239:
240:
241: for (i = 0; i < curproc->num_reg; i++) {
242:
1.1.1.2 ! root 243: p->mem[i] = curproc->mem[i];
! 244:
! 245: if (p->mem[i] != 0)
1.1 root 246:
247: p->mem[i]->links++;
248:
249: p->addr[i] = curproc->addr[i];
250:
251: }
252:
253:
254:
1.1.1.2 ! root 255: /* child isn't traced */
! 256:
! 257: p->ptracer = 0;
! 258:
! 259: p->ptraceflags = 0;
! 260:
! 261:
! 262:
1.1 root 263: p->starttime = Tgettime();
264:
265: p->startdate = Tgetdate();
266:
267:
268:
269: p->q_next = 0;
270:
271: p->wait_q = 0;
272:
273: p->gl_next = proclist;
274:
275: proclist = p; /* hook into the process list */
276:
277: return p;
278:
279: }
280:
281:
282:
283: /*
284:
285: * initialize the process table
286:
287: */
288:
289:
290:
291: void
292:
293: init_proc()
294:
295: {
296:
297: int i;
298:
299: FILESYS *fs;
300:
301: fcookie dir;
302:
303:
304:
305: rootproc = curproc = new_proc();
306:
307: assert(curproc);
308:
309:
310:
311: zero((char *)curproc, (long)sizeof(PROC));
312:
313:
314:
315: curproc->ppid = -1; /* no parent */
316:
317: curproc->domain = DOM_TOS; /* TOS domain */
318:
319: curproc->sysstack = (long) (curproc->stack+STKSIZE-12);
320:
321: curproc->magic = CTXT_MAGIC;
322:
323: ((long *)curproc->sysstack)[1] = FRAME_MAGIC;
324:
325: ((long *)curproc->sysstack)[2] = 0;
326:
327: ((long *)curproc->sysstack)[3] = 0;
328:
329:
330:
1.1.1.2 ! root 331: /* NOTE: in main.c this could be changed, later */
! 332:
! 333: curproc->base = _base;
1.1 root 334:
335:
336:
337: strcpy(curproc->name, "MiNT");
338:
339:
340:
341: /* get some memory */
342:
343: curproc->mem = (MEMREGION **)kmalloc(NUM_REGIONS*SIZEOF(MEMREGION *));
344:
345: curproc->addr = (virtaddr *)kmalloc(NUM_REGIONS*SIZEOF(virtaddr));
346:
347: assert(curproc->mem && curproc->addr);
348:
349:
350:
351: /* make sure it's filled with zeros */
352:
353: zero((char *)curproc->addr, NUM_REGIONS * SIZEOF(virtaddr));
354:
355: zero((char *)curproc->mem, NUM_REGIONS * SIZEOF(MEMREGION *));
356:
357: curproc->num_reg = NUM_REGIONS;
358:
359:
360:
361: /* get root and current directories for all drives */
362:
363: for (i = 0; i < NUM_DRIVES; i++) {
364:
365: if ((fs = drives[i]) != 0 && (*fs->root)(i, &dir) == E_OK) {
366:
367: curproc->root[i] = curproc->curdir[i] = dir;
368:
369: } else {
370:
371: curproc->root[i].fs = curproc->curdir[i].fs = 0;
372:
373: curproc->root[i].dev = curproc->curdir[i].dev = i;
374:
375: }
376:
377: }
378:
379:
380:
381: /* Set the correct drive. The current directory we
382:
383: * set later, after all file systems have been loaded.
384:
385: */
386:
387:
388:
389: curproc->curdrv = Dgetdrv();
390:
391: proclist = curproc;
392:
393:
394:
395: curproc->umask = 0;
396:
397:
398:
399: /*
400:
401: * some more protection against job control; unless these signals are
402:
403: * re-activated by a shell that knows about job control, they'll have
404:
405: * no effect
406:
407: */
408:
409: curproc->sighandle[SIGTTIN] = curproc->sighandle[SIGTTOU] =
410:
411: curproc->sighandle[SIGTSTP] = SIG_IGN;
412:
413:
414:
415: /* set up some more per-process variables */
416:
417: curproc->starttime = Tgettime();
418:
419: curproc->startdate = Tgetdate();
420:
421: if (has_bconmap)
422:
423: curproc->bconmap = curbconmap;
424:
425: else
426:
427: curproc->bconmap = 1;
428:
429:
430:
431: curproc->logbase = (void *)Logbase();
432:
1.1.1.2 ! root 433: curproc->criticerr = *((long ARGS_ON_STACK (**) P_((long)))0x404L);
1.1 root 434:
435: }
436:
437:
438:
439: /*
440:
441: * reset all process priorities to their base level
442:
443: * called once per second, so that cpu hogs can get _some_ time
444:
445: * slices :-).
446:
447: */
448:
449:
450:
451: void
452:
453: reset_priorities()
454:
455: {
456:
457: PROC *p;
458:
459:
460:
461: for (p = proclist; p; p = p->gl_next) {
462:
463: p->curpri = p->pri;
464:
465: p->slices = SLICES(p->curpri);
466:
467: }
468:
469: }
470:
471:
472:
473: /*
474:
475: * more priority code stuff:
476:
477: * run_next(p, slices): schedule process "p" to run next, with "slices"
478:
479: * initial time slices; "p" does not actually start running until
480:
481: * the next context switch
482:
483: * fresh_slices(slices): give the current process "slices" more slices in
484:
485: * which to run
486:
487: */
488:
489:
490:
491: void
492:
493: run_next(p, slices)
494:
495: PROC *p;
496:
497: int slices; /* BUG: currently ignored */
498:
499: {
500:
1.1.1.2 ! root 501: UNUSED(slices);
! 502:
! 503:
! 504:
1.1 root 505: p->slices = 0;
506:
507: p->curpri = MAX_NICE;
508:
509: p->wait_q = READY_Q;
510:
511: p->q_next = sys_q[READY_Q];
512:
513: sys_q[READY_Q] = p;
514:
515: }
516:
517:
518:
519: void
520:
521: fresh_slices(slices)
522:
523: int slices;
524:
525: {
526:
527: curproc->slices = 0;
528:
529: curproc->curpri = MAX_NICE+1;
530:
531: proc_clock = slices;
532:
533: }
534:
535:
536:
537: /*
538:
539: * add a process to a wait (or ready) queue.
540:
541: *
542:
543: * processes go onto a queue in first in-first out order
544:
545: */
546:
547:
548:
549: void
550:
551: add_q(que, proc)
552:
553: int que;
554:
555: PROC *proc;
556:
557: {
558:
559: PROC *q, **lastq;
560:
561:
562:
563: /* "proc" should not already be on a list */
564:
565: assert(proc->wait_q == 0);
566:
567: assert(proc->q_next == 0);
568:
569:
570:
571: lastq = &sys_q[que];
572:
573: q = *lastq;
574:
575: while(q) {
576:
577: lastq = &q->q_next;
578:
579: q = *lastq;
580:
581: }
582:
583: *lastq = proc;
584:
585: proc->wait_q = que;
586:
587: if (que != READY_Q) {
588:
589: proc->curpri = proc->pri; /* reward the process */
590:
591: proc->slices = SLICES(proc->curpri);
592:
593: }
594:
595: }
596:
597:
598:
599: /*
600:
601: * remove a process from a queue
602:
603: */
604:
605:
606:
607: void
608:
609: rm_q(que, proc)
610:
611: int que;
612:
613: PROC *proc;
614:
615: {
616:
617: PROC *q;
618:
619: PROC *old = 0;
620:
621:
622:
623: assert(proc->wait_q == que);
624:
625:
626:
627: q = sys_q[que];
628:
629: while (q && q != proc) {
630:
631: old = q;
632:
633: q = q->q_next;
634:
635: }
636:
637: if (q == 0)
638:
639: FATAL("rm_q: unable to remove process from queue");
640:
641:
642:
643: if (old)
644:
645: old->q_next = proc->q_next;
646:
647: else
648:
649: sys_q[que] = proc->q_next;
650:
651:
652:
653: proc->wait_q = 0;
654:
655: proc->q_next = 0;
656:
657: }
658:
659:
660:
661: /*
662:
663: * preempt(): called by the vbl routine and/or the trap handlers when
664:
665: * they detect that a process has exceeded its time slice and hasn't
666:
667: * yielded gracefully. For now, it just does sleep(READY_Q); later,
668:
669: * we might want to keep track of statistics or something.
670:
671: */
672:
673:
674:
1.1.1.2 ! root 675: void ARGS_ON_STACK
1.1 root 676:
677: preempt()
678:
679: {
680:
681: extern short bconbsiz; /* in bios.c */
682:
683:
684:
685: if (bconbsiz)
686:
687: (void)bflush();
688:
689: else {
690:
691: /* punish the pre-empted process */
692:
693: if (curproc->curpri >= MIN_NICE)
694:
695: curproc->curpri -= 1;
696:
697: }
698:
699: sleep(READY_Q, curproc->wait_cond);
700:
701: }
702:
703:
704:
705: /*
706:
707: * sleep(que, cond): put the current process on the given queue, then switch
708:
709: * contexts. Before a new process runs, give it a fresh time slice. "cond"
710:
711: * is the condition for which the process is waiting, and is placed in
712:
713: * curproc->wait_cond
714:
715: */
716:
717:
718:
719: static void
720:
721: do_wakeup_things()
722:
723: {
724:
725: /*
726:
727: * check for stack underflow, just in case
728:
729: */
730:
731: auto int foo;
732:
1.1.1.2 ! root 733: PROC *p;
1.1 root 734:
735:
736:
1.1.1.2 ! root 737: p = curproc;
1.1 root 738:
1.1.1.2 ! root 739:
! 740:
! 741: if ( p->pid != 0 &&
! 742:
! 743: ((long)&foo) < (long)p->stack + ISTKSIZE + 512 ) {
! 744:
! 745: ALERT("stack underflow");
1.1 root 746:
747: handle_sig(SIGBUS);
748:
749: }
750:
1.1.1.2 ! root 751:
! 752:
! 753: /* see if process' time limit has been exceeded */
! 754:
! 755:
! 756:
! 757: if (p->maxcpu) {
! 758:
! 759: if (p->maxcpu <= p->systime + p->usrtime) {
! 760:
! 761: DEBUG(("cpu limit exceeded"));
! 762:
! 763: raise(SIGXCPU);
! 764:
! 765: }
! 766:
! 767: }
! 768:
! 769:
! 770:
1.1 root 771: /*
772:
1.1.1.2 ! root 773: * check for alarms and similar time out stuff (see timeout.c)
1.1 root 774:
775: */
776:
777:
778:
779: checkalarms();
780:
1.1.1.2 ! root 781: if (p->sigpending)
1.1 root 782:
1.1.1.2 ! root 783: check_sigs(); /* check for signals */
1.1 root 784:
785:
786:
787: proc_clock = TIME_SLICE; /* get a fresh time slice */
788:
1.1.1.2 ! root 789: p->slices = SLICES(p->curpri);
1.1 root 790:
791: }
792:
793:
794:
1.1.1.2 ! root 795: void ARGS_ON_STACK
1.1 root 796:
797: sleep(que, cond)
798:
799: int que;
800:
801: long cond;
802:
803: {
804:
805: PROC *p;
806:
807: short sr;
808:
809: extern short kintr; /* in bios.c */
810:
811: #ifdef FASTTEXT
812:
813: extern int hardscroll; /* in fasttext.c */
814:
815: #endif
816:
817:
818:
819: /*
820:
821: * if there have been keyboard interrupts since our last sleep, check for
822:
823: * special keys like CTRL-ALT-Fx
824:
825: */
826:
827:
828:
829: if (kintr) {
830:
831: (void)checkkeys();
832:
833: kintr = 0;
834:
835: }
836:
837:
838:
839: if (que == READY_Q && !sys_q[READY_Q]) {
840:
841: /* we're just going to wake up again right away! */
842:
843: do_wakeup_things();
844:
845: return;
846:
847: }
848:
849:
850:
851: sr = spl7();
852:
853:
854:
855: add_q(que, curproc);
856:
857: curproc->wait_cond = cond;
858:
859:
860:
861: if (!sys_q[READY_Q]) {
862:
863: /* hmm, no-one is ready to run. might be a deadlock, might not.
864:
865: * first, try waking up any napping processes; if that doesn't work,
866:
867: * run the root process, just so we have someone to charge time
868:
869: * to.
870:
871: */
872:
1.1.1.2 ! root 873: wake(SELECT_Q, (long)nap);
1.1 root 874:
875: if (!sys_q[READY_Q]) {
876:
877: p = rootproc; /* pid 0 */
878:
879: rm_q(p->wait_q, p);
880:
881: add_q(READY_Q, p);
882:
883: }
884:
885: }
886:
887:
888:
889: /*
890:
891: * Walk through the ready list, to find what process should run next.
892:
893: * Lower priority processes don't get to run every time through this
894:
895: * loop; if "p->slices" is positive, it's the number of times that they
896:
897: * will have to miss a turn before getting to run again
898:
899: */
900:
901: p = 0;
902:
903:
904:
905: while (!p) {
906:
907: for (p = sys_q[READY_Q]; p; p = p->q_next) {
908:
909: if (p->slices > 0)
910:
911: p->slices--;
912:
913: else
914:
915: break;
916:
917: }
918:
919: }
920:
921: rm_q(READY_Q, p);
922:
923:
924:
925: spl(sr);
926:
927:
928:
929: if (save_context(&(curproc->ctxt[CURRENT]))) {
930:
931: /*
932:
933: * restore per-process variables here
934:
935: */
936:
937: #ifdef FASTTEXT
938:
939: if (!hardscroll)
940:
941: #endif
942:
943: *((void **)0x44eL) = curproc->logbase;
944:
945: do_wakeup_things();
946:
947: return;
948:
949: }
950:
951: /*
952:
953: * save per-process variables here
954:
955: */
956:
957: #ifdef FASTTEXT
958:
959: if (!hardscroll)
960:
961: #endif
962:
963: curproc->logbase = *((void **)0x44eL);
964:
965: curproc->ctxt[CURRENT].regs[0] = 1;
966:
967: curproc = p;
968:
969: proc_clock = TIME_SLICE; /* fresh time */
970:
971: if ((p->ctxt[CURRENT].sr & 0x2000) == 0) { /* user mode? */
972:
973: leave_kernel();
974:
975: }
976:
977: assert(p->magic == CTXT_MAGIC);
978:
979: restore_context(&(p->ctxt[CURRENT]));
980:
981: }
982:
983:
984:
985: /*
986:
987: * wake(que, cond): wake up all processes on the given queue that are waiting
988:
989: * for the indicated condition
990:
991: */
992:
993:
994:
1.1.1.2 ! root 995: void ARGS_ON_STACK
1.1 root 996:
997: wake(que, cond)
998:
999: int que;
1000:
1001: long cond;
1002:
1003: {
1004:
1005: PROC *p;
1006:
1007:
1008:
1009: if (que == READY_Q) {
1010:
1011: ALERT("wake: why wake up ready processes??");
1012:
1013: return;
1014:
1015: }
1016:
1017: top:
1018:
1019: for(p = sys_q[que]; p; p = p->q_next) {
1020:
1021: if (p->wait_cond == cond) {
1022:
1023: rm_q(que, p);
1024:
1025: add_q(READY_Q, p);
1026:
1027: goto top;
1028:
1029: }
1030:
1031: }
1032:
1033: }
1034:
1035:
1036:
1037: /*
1038:
1039: * wakeselect(p): wake process p from a select() system call
1040:
1041: * may be called by an interrupt handler or whatever
1042:
1043: */
1044:
1045:
1046:
1.1.1.2 ! root 1047: void ARGS_ON_STACK
1.1 root 1048:
1049: wakeselect(param)
1050:
1051: long param;
1052:
1053: {
1054:
1055: PROC *p = (PROC *)param;
1056:
1057: short s;
1058:
1059:
1060:
1061: s = spl7(); /* block interrupts */
1062:
1.1.1.2 ! root 1063: if(p->wait_cond == (long)wakeselect) {
1.1 root 1064:
1065: p->wait_cond = 0;
1066:
1067: }
1068:
1069: if (p->wait_q == SELECT_Q) {
1070:
1071: rm_q(SELECT_Q, p);
1072:
1073: add_q(READY_Q, p);
1074:
1075: }
1076:
1077: spl(s);
1078:
1079: }
1080:
1081:
1082:
1083: /*
1084:
1085: * dump out information about processes
1086:
1087: */
1088:
1089:
1090:
1091: /*
1092:
1093: * kludge alert! In order to get the right pid printed by ALERT, we use
1094:
1095: * curproc as the loop variable.
1096:
1097: */
1098:
1099:
1100:
1101: void
1102:
1103: DUMPPROC()
1104:
1105: {
1106:
1.1.1.2 ! root 1107: #ifndef NO_DEBUG_INFO
! 1108:
1.1 root 1109: PROC *p = curproc;
1110:
1111:
1112:
1113: for (curproc = proclist; curproc; curproc = curproc->gl_next) {
1114:
1.1.1.2 ! root 1115: ALERT("queue %d cond %lx PC: %lx USP: %lx SSP: %lx SYSSP: %lx",
1.1 root 1116:
1117: curproc->wait_q, curproc->wait_cond,
1118:
1119: curproc->ctxt[SYSCALL].pc,
1120:
1121: curproc->ctxt[SYSCALL].usp,
1122:
1123: curproc->ctxt[SYSCALL].ssp,
1124:
1.1.1.2 ! root 1125: curproc->sysstack
1.1 root 1126:
1127: );
1128:
1129: }
1130:
1131: curproc = p; /* restore the real curproc */
1132:
1.1.1.2 ! root 1133: #endif
! 1134:
1.1 root 1135: }
1136:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.