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