1 #include "dat.h"
2 #include "fns.h"
3 #include <isa.h>
4 #include <interp.h>
5 #include <kernel.h>
6 #include "error.h"
7 #include "raise.h"
8
9 struct
10 {
11 Lock l;
12 Prog* runhd;
13 Prog* runtl;
14 Prog* head;
15 Prog* tail;
16 Rendez irend;
17 int idle;
18 int nyield;
19 int creating;
20 Proc* vmq; /* queue of procs wanting vm */
21 Proc* vmqt;
22 Proc* idlevmq; /* queue of procs wanting work */
23 Atidle* idletasks;
24 } isched;
25
26 int bflag;
27 int cflag;
28 uvlong gcbusy;
29 uvlong gcidle;
30 uvlong gcidlepass;
31 uvlong gcpartial;
32 int keepbroken = 1;
33 extern int vflag;
34 static Prog* proghash[64];
35
36 static Progs* delgrp(Prog*);
37 static void addgrp(Prog*, Prog*);
38 void printgrp(Prog*, char*);
39
40 static Prog**
pidlook(int pid)41 pidlook(int pid)
42 {
43 ulong h;
44 Prog **l;
45
46 h = (ulong)pid % nelem(proghash);
47 for(l = &proghash[h]; *l != nil && (*l)->pid != pid; l = &(*l)->pidlink)
48 ;
49 return l;
50 }
51
52 int
tready(void * a)53 tready(void *a)
54 {
55 USED(a);
56 return isched.runhd != nil || isched.vmq != nil;
57 }
58
59 Prog*
progpid(int pid)60 progpid(int pid)
61 {
62 return *pidlook(pid);
63 }
64
65 Prog*
progn(int n)66 progn(int n)
67 {
68 Prog *p;
69
70 for(p = isched.head; p && n--; p = p->next)
71 ;
72 return p;
73 }
74
75 int
nprog(void)76 nprog(void)
77 {
78 int n;
79 Prog *p;
80
81 n = 0;
82 for(p = isched.head; p; p = p->next)
83 n++;
84 return n;
85 }
86
87 static void
execatidle(void)88 execatidle(void)
89 {
90 int done;
91
92 if(tready(nil))
93 return;
94
95 gcidle++;
96 up->type = IdleGC;
97 up->iprog = nil;
98 addrun(up->prog);
99 done = gccolor+3;
100 while(gccolor < done && gcruns()) {
101 if(isched.vmq != nil || isched.runhd != isched.runtl) {
102 gcpartial++;
103 break;
104 }
105 rungc(isched.head);
106 gcidlepass++;
107 if(((ulong)gcidlepass&0xFF) == 0)
108 osyield();
109 }
110 up->type = Interp;
111 delrunq(up->prog);
112 }
113
114 Prog*
newprog(Prog * p,Modlink * m)115 newprog(Prog *p, Modlink *m)
116 {
117 Heap *h;
118 Prog *n, **ph;
119 Osenv *on, *op;
120 static int pidnum;
121
122 if(p != nil){
123 if(p->group != nil)
124 p->flags |= p->group->flags & Pkilled;
125 if(p->kill != nil)
126 error(p->kill);
127 if(p->flags & Pkilled)
128 error("");
129 }
130 n = malloc(sizeof(Prog)+sizeof(Osenv));
131 if(n == 0){
132 if(p == nil)
133 panic("no memory");
134 else
135 error(exNomem);
136 }
137
138 n->pid = ++pidnum;
139 if(n->pid <= 0)
140 panic("no pids");
141 n->group = nil;
142
143 if(isched.tail != nil) {
144 n->prev = isched.tail;
145 isched.tail->next = n;
146 }
147 else {
148 isched.head = n;
149 n->prev = nil;
150 }
151 isched.tail = n;
152
153 ph = pidlook(n->pid);
154 if(*ph != nil)
155 panic("dup pid");
156 n->pidlink = nil;
157 *ph = n;
158
159 n->osenv = (Osenv*)((uchar*)n + sizeof(Prog));
160 n->xec = xec;
161 n->quanta = PQUANTA;
162 n->flags = 0;
163 n->exval = H;
164
165 h = D2H(m);
166 h->ref++;
167 Setmark(h);
168 n->R.M = m;
169 n->R.MP = m->MP;
170 if(m->MP != H)
171 Setmark(D2H(m->MP));
172 addrun(n);
173
174 if(p == nil){
175 newgrp(n);
176 return n;
177 }
178
179 addgrp(n, p);
180 n->flags = p->flags;
181 if(p->flags & Prestrict)
182 n->flags |= Prestricted;
183 memmove(n->osenv, p->osenv, sizeof(Osenv));
184 op = p->osenv;
185 on = n->osenv;
186 on->waitq = op->childq;
187 on->childq = nil;
188 on->debug = nil;
189 incref(&on->pgrp->r);
190 incref(&on->fgrp->r);
191 incref(&on->egrp->r);
192 if(on->sigs != nil)
193 incref(&on->sigs->r);
194 on->user = nil;
195 kstrdup(&on->user, op->user);
196 on->errstr = on->errbuf0;
197 on->syserrstr = on->errbuf1;
198
199 return n;
200 }
201
202 void
delprog(Prog * p,char * msg)203 delprog(Prog *p, char *msg)
204 {
205 Osenv *o;
206 Prog **ph;
207
208 tellsomeone(p, msg); /* call before being removed from prog list */
209
210 o = p->osenv;
211 release();
212 closepgrp(o->pgrp);
213 closefgrp(o->fgrp);
214 closeegrp(o->egrp);
215 closesigs(o->sigs);
216 acquire();
217
218 delgrp(p);
219
220 if(p->prev)
221 p->prev->next = p->next;
222 else
223 isched.head = p->next;
224
225 if(p->next)
226 p->next->prev = p->prev;
227 else
228 isched.tail = p->prev;
229
230 ph = pidlook(p->pid);
231 if(*ph == nil)
232 panic("lost pid");
233 *ph = p->pidlink;
234
235 if(p == isched.runhd) {
236 isched.runhd = p->link;
237 if(p->link == nil)
238 isched.runtl = nil;
239 }
240 p->state = 0xdeadbeef;
241 free(o->user);
242 free(p->killstr);
243 free(p->exstr);
244 free(p);
245 }
246
247 void
renameproguser(char * old,char * new)248 renameproguser(char *old, char *new)
249 {
250 Prog *p;
251 Osenv *o;
252
253 acquire();
254 for(p = isched.head; p; p = p->next){
255 o = p->osenv;
256 if(o->user != nil && strcmp(o->user, old) == 0)
257 kstrdup(&o->user, new);
258 }
259 release();
260 }
261
262 void
tellsomeone(Prog * p,char * buf)263 tellsomeone(Prog *p, char *buf)
264 {
265 Osenv *o;
266
267 if(waserror())
268 return;
269 o = p->osenv;
270 if(o->childq != nil)
271 qproduce(o->childq, buf, strlen(buf));
272 if(o->waitq != nil)
273 qproduce(o->waitq, buf, strlen(buf));
274 poperror();
275 }
276
277 static void
swiprog(Prog * p)278 swiprog(Prog *p)
279 {
280 Proc *q;
281
282 lock(&procs.l);
283 for(q = procs.head; q; q = q->next) {
284 if(q->iprog == p) {
285 unlock(&procs.l);
286 swiproc(q, 1);
287 return;
288 }
289 }
290 unlock(&procs.l);
291 /*print("didn't find\n");*/
292 }
293
294 static Prog*
grpleader(Prog * p)295 grpleader(Prog *p)
296 {
297 Progs *g;
298 Prog *l;
299
300 g = p->group;
301 if(g != nil && (l = g->head) != nil && l->pid == g->id)
302 return l;
303 return nil;
304 }
305
306 int
exprog(Prog * p,char * exc)307 exprog(Prog *p, char *exc)
308 {
309 /* similar code to killprog but not quite */
310 switch(p->state) {
311 case Palt:
312 altdone(p->R.s, p, nil, -1);
313 break;
314 case Psend:
315 cqdelp(&p->chan->send, p);
316 break;
317 case Precv:
318 cqdelp(&p->chan->recv, p);
319 break;
320 case Pready:
321 break;
322 case Prelease:
323 swiprog(p);
324 break;
325 case Pexiting:
326 case Pbroken:
327 case Pdebug:
328 return 0;
329 default:
330 panic("exprog - bad state 0x%x\n", p->state);
331 }
332 if(p->state != Pready && p->state != Prelease)
333 addrun(p);
334 if(p->kill == nil){
335 if(p->killstr == nil){
336 p->killstr = malloc(ERRMAX);
337 if(p->killstr == nil){
338 p->kill = Enomem;
339 return 1;
340 }
341 }
342 kstrcpy(p->killstr, exc, ERRMAX);
343 p->kill = p->killstr;
344 }
345 return 1;
346 }
347
348 static void
propex(Prog * p,char * estr)349 propex(Prog *p, char *estr)
350 {
351 Prog *f, *nf, *pgl;
352
353 if(!(p->flags & (Ppropagate|Pnotifyleader)) || p->group == nil)
354 return;
355 if(*estr == 0){
356 if((p->flags & Pkilled) == 0)
357 return;
358 estr = "killed";
359 }
360 pgl = grpleader(p);
361 if(pgl == nil)
362 pgl = p;
363 if(!(pgl->flags & (Ppropagate|Pnotifyleader)))
364 return; /* exceptions are local; don't propagate */
365 for(f = p->group->head; f != nil; f = nf){
366 nf = f->grpnext;
367 if(f != p && f != pgl){
368 if(pgl->flags & Ppropagate)
369 exprog(f, estr);
370 else{
371 f->flags &= ~(Ppropagate|Pnotifyleader); /* prevent recursion */
372 killprog(f, "killed");
373 }
374 }
375 }
376 if(p != pgl)
377 exprog(pgl, estr);
378 }
379
380 int
killprog(Prog * p,char * cause)381 killprog(Prog *p, char *cause)
382 {
383 Osenv *env;
384 char msg[ERRMAX+2*KNAMELEN];
385
386 if(p == isched.runhd) {
387 p->kill = "";
388 p->flags |= Pkilled;
389 p->state = Pexiting;
390 return 0;
391 }
392
393 switch(p->state) {
394 case Palt:
395 altdone(p->R.s, p, nil, -1);
396 break;
397 case Psend:
398 cqdelp(&p->chan->send, p);
399 break;
400 case Precv:
401 cqdelp(&p->chan->recv, p);
402 break;
403 case Pready:
404 delrunq(p);
405 break;
406 case Prelease:
407 p->kill = "";
408 p->flags |= Pkilled;
409 p->state = Pexiting;
410 swiprog(p);
411 /* No break */
412 case Pexiting:
413 return 0;
414 case Pbroken:
415 case Pdebug:
416 break;
417 default:
418 panic("killprog - bad state 0x%x\n", p->state);
419 }
420
421 if(p->addrun != nil) {
422 p->kill = "";
423 p->flags |= Pkilled;
424 p->addrun(p);
425 p->addrun = nil;
426 return 0;
427 }
428
429 env = p->osenv;
430 if(env->debug != nil) {
431 p->state = Pbroken;
432 dbgexit(p, 0, cause);
433 return 0;
434 }
435
436 propex(p, "killed");
437
438 snprint(msg, sizeof(msg), "%d \"%s\":%s", p->pid, p->R.M->m->name, cause);
439
440 p->state = Pexiting;
441 gclock();
442 destroystack(&p->R);
443 delprog(p, msg);
444 gcunlock();
445
446 return 1;
447 }
448
449 void
newgrp(Prog * p)450 newgrp(Prog *p)
451 {
452 Progs *pg, *g;
453
454 if(p->group != nil && p->group->id == p->pid)
455 return;
456 g = malloc(sizeof(*g));
457 if(g == nil)
458 error(Enomem);
459 p->flags &= ~(Ppropagate|Pnotifyleader);
460 g->id = p->pid;
461 g->flags = 0;
462 if(p->group != nil)
463 g->flags |= p->group->flags&Pprivatemem;
464 g->child = nil;
465 pg = delgrp(p);
466 g->head = g->tail = p;
467 p->group = g;
468 if(pg != nil){
469 g->sib = pg->child;
470 pg->child = g;
471 }
472 g->parent = pg;
473 }
474
475 static void
addgrp(Prog * n,Prog * p)476 addgrp(Prog *n, Prog *p)
477 {
478 Progs *g;
479
480 n->group = p->group;
481 if((g = n->group) != nil){
482 n->grpnext = nil;
483 if(g->head != nil){
484 n->grpprev = g->tail;
485 g->tail->grpnext = n;
486 }else{
487 n->grpprev = nil;
488 g->head = n;
489 }
490 g->tail = n;
491 }
492 }
493
494 static Progs*
delgrp(Prog * p)495 delgrp(Prog *p)
496 {
497 Progs *g, *pg, *cg, **l;
498
499 g = p->group;
500 if(g == nil)
501 return nil;
502 if(p->grpprev)
503 p->grpprev->grpnext = p->grpnext;
504 else
505 g->head = p->grpnext;
506 if(p->grpnext)
507 p->grpnext->grpprev = p->grpprev;
508 else
509 g->tail = p->grpprev;
510 p->grpprev = p->grpnext = nil;
511 p->group = nil;
512
513 if(g->head == nil){
514 /* move up, giving subgroups of groups with no Progs to their parents */
515 do{
516 if((pg = g->parent) != nil){
517 pg = g->parent;
518 for(l = &pg->child; *l != nil && *l != g; l = &(*l)->sib)
519 ;
520 *l = g->sib;
521 }
522 /* put subgroups in new parent group */
523 while((cg = g->child) != nil){
524 g->child = cg->sib;
525 cg->parent = pg;
526 if(pg != nil){
527 cg->sib = pg->child;
528 pg->child = cg;
529 }
530 }
531 free(g);
532 }while((g = pg) != nil && g->head == nil);
533 }
534 return g;
535 }
536
537 void
printgrp(Prog * p,char * v)538 printgrp(Prog *p, char *v)
539 {
540 Progs *g;
541 Prog *q;
542
543 g = p->group;
544 print("%s pid %d grp %d pgrp %d: [pid", v, p->pid, g->id, g->parent!=nil?g->parent->id:0);
545 for(q = g->head; q != nil; q = q->grpnext)
546 print(" %d", q->pid);
547 print(" subgrp");
548 for(g = g->child; g != nil; g = g->sib)
549 print(" %d", g->id);
550 print("]\n");
551 }
552
553 int
killgrp(Prog * p,char * msg)554 killgrp(Prog *p, char *msg)
555 {
556 int i, npid, *pids;
557 Prog *f;
558 Progs *g;
559
560 /* interpreter has been acquired */
561 g = p->group;
562 if(g == nil || g->head == nil)
563 return 0;
564 while(g->flags & Pkilled){
565 release();
566 acquire();
567 }
568 npid = 0;
569 for(f = g->head; f != nil; f = f->grpnext)
570 if(f->group != g)
571 panic("killgrp");
572 else
573 npid++;
574 /* use pids not Prog* because state can change during killprog (eg, in delprog) */
575 pids = malloc(npid*sizeof(int));
576 if(pids == nil)
577 error(Enomem);
578 npid = 0;
579 for(f = g->head; f != nil; f = f->grpnext)
580 pids[npid++] = f->pid;
581 g->flags |= Pkilled;
582 if(waserror()) {
583 g->flags &= ~Pkilled;
584 free(pids);
585 nexterror();
586 }
587 for(i = 0; i < npid; i++) {
588 f = progpid(pids[i]);
589 if(f != nil && f != currun())
590 killprog(f, msg);
591 }
592 poperror();
593 g->flags &= ~Pkilled;
594 free(pids);
595 return 1;
596 }
597
598 char changup[] = "channel hangup";
599
600 void
killcomm(Progq ** q)601 killcomm(Progq **q)
602 {
603 Prog *p;
604 Progq *f;
605
606 for (f = *q; f != nil; f = *q) {
607 *q = f->next;
608 p = f->prog;
609 free(f);
610 if(p == nil)
611 return;
612 p->ptr = nil;
613 switch(p->state) {
614 case Prelease:
615 swiprog(p);
616 break;
617 case Psend:
618 case Precv:
619 p->kill = changup;
620 addrun(p);
621 break;
622 case Palt:
623 altgone(p);
624 break;
625 }
626 }
627 }
628
629 void
addprog(Proc * p)630 addprog(Proc *p)
631 {
632 Prog *n;
633
634 n = malloc(sizeof(Prog));
635 if(n == nil)
636 panic("no memory");
637 p->prog = n;
638 n->osenv = p->env;
639 }
640
641 static void
cwakeme(Prog * p)642 cwakeme(Prog *p)
643 {
644 Osenv *o;
645
646 p->addrun = nil;
647 o = p->osenv;
648 Wakeup(o->rend);
649 }
650
651 static int
cdone(void * vp)652 cdone(void *vp)
653 {
654 Prog *p = vp;
655
656 return p->addrun == nil || p->kill != nil;
657 }
658
659 void
cblock(Prog * p)660 cblock(Prog *p)
661 {
662 Osenv *o;
663
664 p->addrun = cwakeme;
665 o = p->osenv;
666 o->rend = &up->sleep;
667 release();
668
669 /*
670 * To allow cdone(p) safely after release,
671 * p must be currun before the release.
672 * Exits in the error case with the vm acquired.
673 */
674 if(waserror()) {
675 acquire();
676 p->addrun = nil;
677 nexterror();
678 }
679 Sleep(o->rend, cdone, p);
680 if (p->kill != nil)
681 error(Eintr);
682 poperror();
683 acquire();
684 }
685
686 void
addrun(Prog * p)687 addrun(Prog *p)
688 {
689 if(p->addrun != 0) {
690 p->addrun(p);
691 return;
692 }
693 p->state = Pready;
694 p->link = nil;
695 if(isched.runhd == nil)
696 isched.runhd = p;
697 else
698 isched.runtl->link = p;
699
700 isched.runtl = p;
701 }
702
703 Prog*
delrun(int state)704 delrun(int state)
705 {
706 Prog *p;
707
708 p = isched.runhd;
709 p->state = state;
710 isched.runhd = p->link;
711 if(p->link == nil)
712 isched.runtl = nil;
713
714 return p;
715 }
716
717 void
delrunq(Prog * p)718 delrunq(Prog *p)
719 {
720 Prog *prev, *f;
721
722 prev = nil;
723 for(f = isched.runhd; f; f = f->link) {
724 if(f == p)
725 break;
726 prev = f;
727 }
728 if(f == nil)
729 return;
730 if(prev == nil)
731 isched.runhd = p->link;
732 else
733 prev->link = p->link;
734 if(p == isched.runtl)
735 isched.runtl = prev;
736 }
737
738 Prog*
delruntail(int state)739 delruntail(int state)
740 {
741 Prog *p;
742
743 p = isched.runtl;
744 delrunq(p);
745 p->state = state;
746 return p;
747 }
748
749 Prog*
currun(void)750 currun(void)
751 {
752 return isched.runhd;
753 }
754
755 Prog*
schedmod(Module * m)756 schedmod(Module *m)
757 {
758 Heap *h;
759 Type *t;
760 Prog *p;
761 Modlink *ml;
762 Frame f, *fp;
763
764 ml = mklinkmod(m, 0);
765
766 if(m->origmp != H && m->ntype > 0) {
767 t = m->type[0];
768 h = nheap(t->size);
769 h->t = t;
770 t->ref++;
771 ml->MP = H2D(uchar*, h);
772 newmp(ml->MP, m->origmp, t);
773 }
774
775 p = newprog(nil, ml);
776 h = D2H(ml);
777 h->ref--;
778 p->R.PC = m->entry;
779 fp = &f;
780 R.s = &fp;
781 f.t = m->entryt;
782 newstack(p);
783 initmem(m->entryt, p->R.FP);
784
785 return p;
786 }
787
788 /*
789 static char*
790 m(Prog *p)
791 {
792 if(p)
793 if(p->R.M)
794 if(p->R.M->m)
795 return p->R.M->m->name;
796 return "nil";
797 }
798 */
799
800 void
acquire(void)801 acquire(void)
802 {
803 int empty;
804 Prog *p;
805
806 lock(&isched.l);
807 if(isched.idle) {
808 isched.idle = 0;
809 unlock(&isched.l);
810 }
811 else {
812 up->qnext = nil;
813 if(isched.vmq != nil){
814 empty = 0;
815 isched.vmqt->qnext = up;
816 }else{
817 isched.vmq = up;
818 empty = 1;
819 }
820 isched.vmqt = up;
821
822 unlock(&isched.l);
823 strcpy(up->text, "acquire");
824 if(empty)
825 Wakeup(&isched.irend);
826 osblock();
827 }
828
829 if(up->type == Interp) {
830 p = up->iprog;
831 up->iprog = nil;
832 irestore(p);
833 }
834 else
835 p = up->prog;
836
837 p->state = Pready;
838 p->link = isched.runhd;
839 isched.runhd = p;
840 if(p->link == nil)
841 isched.runtl = p;
842
843 strcpy(up->text, "dis");
844 }
845
846 void
release(void)847 release(void)
848 {
849 Proc *p, **pq;
850 int f;
851
852 if(up->type == Interp)
853 up->iprog = isave();
854 else
855 delrun(Prelease);
856
857 lock(&isched.l);
858 if(*(pq = &isched.vmq) == nil && *(pq = &isched.idlevmq) == nil) {
859 isched.idle = 1;
860 f = isched.creating;
861 isched.creating = 1;
862 unlock(&isched.l);
863 if(f == 0)
864 kproc("dis", vmachine, nil, 0);
865 return;
866 }
867 p = *pq;
868 *pq = p->qnext;
869 unlock(&isched.l);
870
871 osready(p); /* wake up thread to run VM */
872 strcpy(up->text, "released");
873 }
874
875 void
iyield(void)876 iyield(void)
877 {
878 Proc *p;
879
880 lock(&isched.l);
881 p = isched.vmq;
882 if(p == nil) {
883 unlock(&isched.l);
884 return;
885 }
886 isched.nyield++;
887 isched.vmq = p->qnext;
888
889 if(up->iprog != nil)
890 panic("iyield but iprog, type %d", up->type);
891 if(up->type != Interp){
892 static int once;
893 if(!once++)
894 print("tell charles: #%p->type==%d\n", up, up->type);
895 }
896 up->qnext = isched.idlevmq;
897 isched.idlevmq = up;
898
899 unlock(&isched.l);
900 osready(p); /* wake up acquiring kproc */
901 strcpy(up->text, "yield");
902 osblock(); /* sleep */
903 strcpy(up->text, "dis");
904 }
905
906 void
startup(void)907 startup(void)
908 {
909
910 up->type = Interp;
911 up->iprog = nil;
912
913 lock(&isched.l);
914 isched.creating = 0;
915 if(isched.idle) {
916 isched.idle = 0;
917 unlock(&isched.l);
918 return;
919 }
920 up->qnext = isched.idlevmq;
921 isched.idlevmq = up;
922 unlock(&isched.l);
923
924 osblock();
925 }
926
927 void
progexit(void)928 progexit(void)
929 {
930 Prog *r;
931 Module *m;
932 int broken;
933 char *estr, msg[ERRMAX+2*KNAMELEN];
934
935 estr = up->env->errstr;
936 broken = 0;
937 if(estr[0] != '\0' && strcmp(estr, Eintr) != 0 && strncmp(estr, "fail:", 5) != 0)
938 broken = 1;
939
940 r = up->iprog;
941 if(r != nil)
942 acquire();
943 else
944 r = currun();
945
946 if(*estr == '\0' && r->flags & Pkilled)
947 estr = "killed";
948
949 m = R.M->m;
950 if(broken){
951 if(cflag){ /* only works on Plan9 for now */
952 char *pc = strstr(estr, "pc=");
953
954 if(pc != nil)
955 R.PC = r->R.PC = (Inst*)strtol(pc+3, nil, 0); /* for debugging */
956 }
957 print("[%s] Broken: \"%s\"\n", m->name, estr);
958 }
959
960 snprint(msg, sizeof(msg), "%d \"%s\":%s", r->pid, m->name, estr);
961
962 if(up->env->debug != nil) {
963 dbgexit(r, broken, estr);
964 broken = 1;
965 /* must force it to break if in debug */
966 }else if(broken && (!keepbroken || strncmp(estr, "out of memory", 13)==0 || memusehigh()))
967 broken = 0; /* don't want them or short of memory */
968
969 if(broken){
970 tellsomeone(r, msg);
971 r = isave();
972 r->state = Pbroken;
973 return;
974 }
975
976 gclock();
977 destroystack(&R);
978 delprog(r, msg);
979 gcunlock();
980
981 if(isched.head == nil)
982 cleanexit(0);
983 }
984
985 void
disfault(void * reg,char * msg)986 disfault(void *reg, char *msg)
987 {
988 Prog *p;
989
990 USED(reg);
991
992 if(strncmp(msg, Eintr, 6) == 0)
993 exits(0);
994
995 if(up == nil) {
996 print("EMU: faults: %s\n", msg);
997 cleanexit(0);
998 }
999 if(up->type != Interp) {
1000 print("SYS: process %s faults: %s\n", up->text, msg);
1001 cleanexit(0);
1002 }
1003
1004 if(up->iprog != nil)
1005 acquire();
1006
1007 p = currun();
1008 if(p == nil)
1009 panic("Interp faults with no dis prog");
1010
1011 /* cause an exception in the dis prog. As for error(), but Plan 9 needs reg*/
1012 kstrcpy(up->env->errstr, msg, ERRMAX);
1013 oslongjmp(reg, up->estack[--up->nerr], 1);
1014 }
1015
1016 void
vmachine(void * a)1017 vmachine(void *a)
1018 {
1019 Prog *r;
1020 Osenv *o;
1021 int cycles;
1022 static int gccounter;
1023
1024 USED(a);
1025
1026 startup();
1027
1028 while(waserror()) {
1029 if(up->iprog != nil)
1030 acquire();
1031 if(handler(up->env->errstr) == 0) {
1032 propex(currun(), up->env->errstr);
1033 progexit();
1034 }
1035 up->env = &up->defenv;
1036 }
1037
1038 cycles = 0;
1039 for(;;) {
1040 if(tready(nil) == 0) {
1041 execatidle();
1042 strcpy(up->text, "idle");
1043 Sleep(&isched.irend, tready, 0);
1044 strcpy(up->text, "dis");
1045 }
1046
1047 if(isched.vmq != nil && (isched.runhd == nil || ++cycles > 2)){
1048 iyield();
1049 cycles = 0;
1050 }
1051
1052 r = isched.runhd;
1053 if(r != nil) {
1054 o = r->osenv;
1055 up->env = o;
1056
1057 FPrestore(&o->fpu);
1058 r->xec(r);
1059 FPsave(&o->fpu);
1060
1061 if(isched.runhd != nil)
1062 if(r == isched.runhd)
1063 if(isched.runhd != isched.runtl) {
1064 isched.runhd = r->link;
1065 r->link = nil;
1066 isched.runtl->link = r;
1067 isched.runtl = r;
1068 }
1069 up->env = &up->defenv;
1070 }
1071 if(isched.runhd != nil)
1072 if((++gccounter&0xFF) == 0 || memlow()) {
1073 gcbusy++;
1074 up->type = BusyGC;
1075 pushrun(up->prog);
1076 rungc(isched.head);
1077 up->type = Interp;
1078 delrunq(up->prog);
1079 }
1080 }
1081 }
1082
1083 void
disinit(void * a)1084 disinit(void *a)
1085 {
1086 Prog *p;
1087 Osenv *o;
1088 Module *root;
1089 char *initmod = a;
1090
1091 if(waserror())
1092 panic("disinit error: %r");
1093
1094 if(vflag)
1095 print("Initial Dis: \"%s\"\n", initmod);
1096
1097 fmtinstall('D', Dconv);
1098
1099 FPinit();
1100 FPsave(&up->env->fpu);
1101
1102 opinit();
1103 modinit();
1104 excinit();
1105
1106 root = load(initmod);
1107 if(root == 0) {
1108 kgerrstr(up->genbuf, sizeof up->genbuf);
1109 panic("loading \"%s\": %s", initmod, up->genbuf);
1110 }
1111
1112 p = schedmod(root);
1113
1114 memmove(p->osenv, up->env, sizeof(Osenv));
1115 o = p->osenv;
1116 incref(&o->pgrp->r);
1117 incref(&o->fgrp->r);
1118 incref(&o->egrp->r);
1119 if(o->sigs != nil)
1120 incref(&o->sigs->r);
1121 o->user = nil;
1122 kstrdup(&o->user, up->env->user);
1123 o->errstr = o->errbuf0;
1124 o->syserrstr = o->errbuf1;
1125
1126 isched.idle = 1;
1127 poperror();
1128 vmachine(nil);
1129 }
1130
1131 void
pushrun(Prog * p)1132 pushrun(Prog *p)
1133 {
1134 if(p->addrun != nil)
1135 panic("pushrun addrun");
1136 p->state = Pready;
1137 p->link = isched.runhd;
1138 isched.runhd = p;
1139 if(p->link == nil)
1140 isched.runtl = p;
1141 }
1142