xref: /inferno-os/emu/port/dis.c (revision cd17ce433410c01516d7ba8f052a6c5b67b0e2d5)
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 		if(((ulong)gcidlepass&0xFF) == 0)
108 			osyield();
109 	}
110 	up->type = Interp;
111 	delrunq(up->prog);
112 }
113 
114 Prog*
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
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
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
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
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*
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
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
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
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
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 	g->child = nil;
463 	pg = delgrp(p);
464 	g->head = g->tail = p;
465 	p->group = g;
466 	if(pg != nil){
467 		g->sib = pg->child;
468 		pg->child = g;
469 	}
470 	g->parent = pg;
471 }
472 
473 static void
474 addgrp(Prog *n, Prog *p)
475 {
476 	Progs *g;
477 
478 	n->group = p->group;
479 	if((g = n->group) != nil){
480 		n->grpnext = nil;
481 		if(g->head != nil){
482 			n->grpprev = g->tail;
483 			g->tail->grpnext = n;
484 		}else{
485 			n->grpprev = nil;
486 			g->head = n;
487 		}
488 		g->tail = n;
489 	}
490 }
491 
492 static Progs*
493 delgrp(Prog *p)
494 {
495 	Progs *g, *pg, *cg, **l;
496 
497 	g = p->group;
498 	if(g == nil)
499 		return nil;
500 	if(p->grpprev)
501 		p->grpprev->grpnext = p->grpnext;
502 	else
503 		g->head = p->grpnext;
504 	if(p->grpnext)
505 		p->grpnext->grpprev = p->grpprev;
506 	else
507 		g->tail = p->grpprev;
508 	p->grpprev = p->grpnext = nil;
509 	p->group = nil;
510 
511 	if(g->head == nil){
512 		/* move up, giving subgroups of groups with no Progs to their parents */
513 		do{
514 			if((pg = g->parent) != nil){
515 				pg = g->parent;
516 				for(l = &pg->child; *l != nil && *l != g; l = &(*l)->sib)
517 					;
518 				*l = g->sib;
519 			}
520 			/* put subgroups in new parent group */
521 			while((cg = g->child) != nil){
522 				g->child = cg->sib;
523 				cg->parent = pg;
524 				if(pg != nil){
525 					cg->sib = pg->child;
526 					pg->child = cg;
527 				}
528 			}
529 			free(g);
530 		}while((g = pg) != nil && g->head == nil);
531 	}
532 	return g;
533 }
534 
535 void
536 printgrp(Prog *p, char *v)
537 {
538 	Progs *g;
539 	Prog *q;
540 
541 	g = p->group;
542 	print("%s pid %d grp %d pgrp %d: [pid", v, p->pid, g->id, g->parent!=nil?g->parent->id:0);
543 	for(q = g->head; q != nil; q = q->grpnext)
544 		print(" %d", q->pid);
545 	print(" subgrp");
546 	for(g = g->child; g != nil; g = g->sib)
547 		print(" %d", g->id);
548 	print("]\n");
549 }
550 
551 int
552 killgrp(Prog *p, char *msg)
553 {
554 	int i, npid, *pids;
555 	Prog *f;
556 	Progs *g;
557 
558 	/* interpreter has been acquired */
559 	g = p->group;
560 	if(g == nil || g->head == nil)
561 		return 0;
562 	while(g->flags & Pkilled){
563 		release();
564 		acquire();
565 	}
566 	npid = 0;
567 	for(f = g->head; f != nil; f = f->grpnext)
568 		if(f->group != g)
569 			panic("killgrp");
570 		else
571 			npid++;
572 	/* use pids not Prog* because state can change during killprog (eg, in delprog) */
573 	pids = malloc(npid*sizeof(int));
574 	if(pids == nil)
575 		error(Enomem);
576 	npid = 0;
577 	for(f = g->head; f != nil; f = f->grpnext)
578 		pids[npid++] = f->pid;
579 	g->flags |= Pkilled;
580 	if(waserror()) {
581 		g->flags &= ~Pkilled;
582 		free(pids);
583 		nexterror();
584 	}
585 	for(i = 0; i < npid; i++) {
586 		f = progpid(pids[i]);
587 		if(f != nil && f != currun())
588 			killprog(f, msg);
589 	}
590 	poperror();
591 	g->flags &= ~Pkilled;
592 	free(pids);
593 	return 1;
594 }
595 
596 char	changup[] = "channel hangup";
597 
598 void
599 killcomm(Progq **q)
600 {
601 	Prog *p;
602 	Progq *f;
603 
604 	for (f = *q; f != nil; f = *q) {
605 		*q = f->next;
606 		p = f->prog;
607 		free(f);
608 		if(p == nil)
609 			return;
610 		p->ptr = nil;
611 		switch(p->state) {
612 		case Prelease:
613 			swiprog(p);
614 			break;
615 		case Psend:
616 		case Precv:
617 			p->kill = changup;
618 			addrun(p);
619 			break;
620 		case Palt:
621 			altgone(p);
622 			break;
623 		}
624 	}
625 }
626 
627 void
628 addprog(Proc *p)
629 {
630 	Prog *n;
631 
632 	n = malloc(sizeof(Prog));
633 	if(n == nil)
634 		panic("no memory");
635 	p->prog = n;
636 	n->osenv = p->env;
637 }
638 
639 static void
640 cwakeme(Prog *p)
641 {
642 	Osenv *o;
643 
644 	p->addrun = nil;
645 	o = p->osenv;
646 	Wakeup(o->rend);
647 }
648 
649 static int
650 cdone(void *vp)
651 {
652 	Prog *p = vp;
653 
654 	return p->addrun == nil || p->kill != nil;
655 }
656 
657 void
658 cblock(Prog *p)
659 {
660 	Osenv *o;
661 
662 	p->addrun = cwakeme;
663 	o = p->osenv;
664 	o->rend = &up->sleep;
665 	release();
666 
667 	/*
668 	 * To allow cdone(p) safely after release,
669 	 * p must be currun before the release.
670 	 * Exits in the error case with the vm acquired.
671 	 */
672 	if(waserror()) {
673 		acquire();
674 		p->addrun = nil;
675 		nexterror();
676 	}
677 	Sleep(o->rend, cdone, p);
678 	if (p->kill != nil)
679 		error(Eintr);
680 	poperror();
681 	acquire();
682 }
683 
684 void
685 addrun(Prog *p)
686 {
687 	if(p->addrun != 0) {
688 		p->addrun(p);
689 		return;
690 	}
691 	p->state = Pready;
692 	p->link = nil;
693 	if(isched.runhd == nil)
694 		isched.runhd = p;
695 	else
696 		isched.runtl->link = p;
697 
698 	isched.runtl = p;
699 }
700 
701 Prog*
702 delrun(int state)
703 {
704 	Prog *p;
705 
706 	p = isched.runhd;
707 	p->state = state;
708 	isched.runhd = p->link;
709 	if(p->link == nil)
710 		isched.runtl = nil;
711 
712 	return p;
713 }
714 
715 void
716 delrunq(Prog *p)
717 {
718 	Prog *prev, *f;
719 
720 	prev = nil;
721 	for(f = isched.runhd; f; f = f->link) {
722 		if(f == p)
723 			break;
724 		prev = f;
725 	}
726 	if(f == nil)
727 		return;
728 	if(prev == nil)
729 		isched.runhd = p->link;
730 	else
731 		prev->link = p->link;
732 	if(p == isched.runtl)
733 		isched.runtl = prev;
734 }
735 
736 Prog*
737 delruntail(int state)
738 {
739 	Prog *p;
740 
741 	p = isched.runtl;
742 	delrunq(p);
743 	p->state = state;
744 	return p;
745 }
746 
747 Prog*
748 currun(void)
749 {
750 	return isched.runhd;
751 }
752 
753 Prog*
754 schedmod(Module *m)
755 {
756 	Heap *h;
757 	Type *t;
758 	Prog *p;
759 	Modlink *ml;
760 	Frame f, *fp;
761 
762 	ml = mklinkmod(m, 0);
763 
764 	if(m->origmp != H && m->ntype > 0) {
765 		t = m->type[0];
766 		h = nheap(t->size);
767 		h->t = t;
768 		t->ref++;
769 		ml->MP = H2D(uchar*, h);
770 		newmp(ml->MP, m->origmp, t);
771 	}
772 
773 	p = newprog(nil, ml);
774 	h = D2H(ml);
775 	h->ref--;
776 	p->R.PC = m->entry;
777 	fp = &f;
778 	R.s = &fp;
779 	f.t = m->entryt;
780 	newstack(p);
781 	initmem(m->entryt, p->R.FP);
782 
783 	return p;
784 }
785 
786 /*
787 static char*
788 m(Prog *p)
789 {
790 	if(p)
791 		if(p->R.M)
792 			if(p->R.M->m)
793 				return p->R.M->m->name;
794 	return "nil";
795 }
796 */
797 
798 void
799 acquire(void)
800 {
801 	int empty;
802 	Prog *p;
803 
804 	lock(&isched.l);
805 	if(isched.idle) {
806 		isched.idle = 0;
807 		unlock(&isched.l);
808 	}
809 	else {
810 		up->qnext = nil;
811 		if(isched.vmq != nil){
812 			empty = 0;
813 			isched.vmqt->qnext = up;
814 		}else{
815 			isched.vmq = up;
816 			empty = 1;
817 		}
818 		isched.vmqt = up;
819 
820 		unlock(&isched.l);
821 		strcpy(up->text, "acquire");
822 		if(empty)
823 			Wakeup(&isched.irend);
824 		osblock();
825 	}
826 
827 	if(up->type == Interp) {
828 		p = up->iprog;
829 		up->iprog = nil;
830 		irestore(p);
831 	}
832 	else
833 		p = up->prog;
834 
835 	p->state = Pready;
836 	p->link = isched.runhd;
837 	isched.runhd = p;
838 	if(p->link == nil)
839 		isched.runtl = p;
840 
841 	strcpy(up->text, "dis");
842 }
843 
844 void
845 release(void)
846 {
847 	Proc *p, **pq;
848 	int f;
849 
850 	if(up->type == Interp)
851 		up->iprog = isave();
852 	else
853 		delrun(Prelease);
854 
855 	lock(&isched.l);
856 	if(*(pq = &isched.vmq) == nil && *(pq = &isched.idlevmq) == nil) {
857 		isched.idle = 1;
858 		f = isched.creating;
859 		isched.creating = 1;
860 		unlock(&isched.l);
861 		if(f == 0)
862 			kproc("dis", vmachine, nil, 0);
863 		return;
864 	}
865 	p = *pq;
866 	*pq = p->qnext;
867 	unlock(&isched.l);
868 
869 	osready(p);		/* wake up thread to run VM */
870 	strcpy(up->text, "released");
871 }
872 
873 void
874 iyield(void)
875 {
876 	Proc *p;
877 
878 	lock(&isched.l);
879 	p = isched.vmq;
880 	if(p == nil) {
881 		unlock(&isched.l);
882 		return;
883 	}
884 	isched.nyield++;
885 	isched.vmq = p->qnext;
886 
887 	if(up->iprog != nil)
888 		panic("iyield but iprog, type %d", up->type);
889 	if(up->type != Interp){
890 		static int once;
891 		if(!once++)
892 			print("tell charles: #%p->type==%d\n", up, up->type);
893 	}
894 	up->qnext = isched.idlevmq;
895 	isched.idlevmq = up;
896 
897 	unlock(&isched.l);
898 	osready(p);		/* wake up acquiring kproc */
899 	strcpy(up->text, "yield");
900 	osblock();		/* sleep */
901 	strcpy(up->text, "dis");
902 }
903 
904 void
905 startup(void)
906 {
907 
908 	up->type = Interp;
909 	up->iprog = nil;
910 
911 	lock(&isched.l);
912 	isched.creating = 0;
913 	if(isched.idle) {
914 		isched.idle = 0;
915 		unlock(&isched.l);
916 		return;
917 	}
918 	up->qnext = isched.idlevmq;
919 	isched.idlevmq = up;
920 	unlock(&isched.l);
921 
922 	osblock();
923 }
924 
925 void
926 progexit(void)
927 {
928 	Prog *r;
929 	Module *m;
930 	int broken;
931 	char *estr, msg[ERRMAX+2*KNAMELEN];
932 
933 	estr = up->env->errstr;
934 	broken = 0;
935 	if(estr[0] != '\0' && strcmp(estr, Eintr) != 0 && strncmp(estr, "fail:", 5) != 0)
936 		broken = 1;
937 
938 	r = up->iprog;
939 	if(r != nil)
940 		acquire();
941 	else
942 		r = currun();
943 
944 	if(*estr == '\0' && r->flags & Pkilled)
945 		estr = "killed";
946 
947 	m = R.M->m;
948 	if(broken){
949 		if(cflag){	/* only works on Plan9 for now */
950 			char *pc = strstr(estr, "pc=");
951 
952 			if(pc != nil)
953 				R.PC = r->R.PC = (Inst*)strtol(pc+3, nil, 0);	/* for debugging */
954 		}
955 		print("[%s] Broken: \"%s\"\n", m->name, estr);
956 	}
957 
958 	snprint(msg, sizeof(msg), "%d \"%s\":%s", r->pid, m->name, estr);
959 
960 	if(up->env->debug != nil) {
961 		dbgexit(r, broken, estr);
962 		broken = 1;
963 		/* must force it to break if in debug */
964 	}else if(broken && (!keepbroken || strncmp(estr, "out of memory", 13)==0 || memusehigh()))
965 		broken = 0;	/* don't want them or short of memory */
966 
967 	if(broken){
968 		tellsomeone(r, msg);
969 		r = isave();
970 		r->state = Pbroken;
971 		return;
972 	}
973 
974 	gclock();
975 	destroystack(&R);
976 	delprog(r, msg);
977 	gcunlock();
978 
979 	if(isched.head == nil)
980 		cleanexit(0);
981 }
982 
983 void
984 disfault(void *reg, char *msg)
985 {
986 	Prog *p;
987 
988 	USED(reg);
989 
990 	if(strncmp(msg, Eintr, 6) == 0)
991 		exits(0);
992 
993 	if(up == nil) {
994 		print("EMU: faults: %s\n", msg);
995 		cleanexit(0);
996 	}
997 	if(up->type != Interp) {
998 		print("SYS: process %s faults: %s\n", up->text, msg);
999 		cleanexit(0);
1000 	}
1001 
1002 	if(up->iprog != nil)
1003 		acquire();
1004 
1005 	p = currun();
1006 	if(p == nil)
1007 		panic("Interp faults with no dis prog");
1008 
1009 	/* cause an exception in the dis prog.  As for error(), but Plan 9 needs reg*/
1010 	kstrcpy(up->env->errstr, msg, ERRMAX);
1011 	oslongjmp(reg, up->estack[--up->nerr], 1);
1012 }
1013 
1014 void
1015 vmachine(void *a)
1016 {
1017 	Prog *r;
1018 	Osenv *o;
1019 	int cycles;
1020 	static int gccounter;
1021 
1022 	USED(a);
1023 
1024 	startup();
1025 
1026 	while(waserror()) {
1027 		if(up->iprog != nil)
1028 			acquire();
1029 		if(handler(up->env->errstr) == 0) {
1030 			propex(currun(), up->env->errstr);
1031 			progexit();
1032 		}
1033 		up->env = &up->defenv;
1034 	}
1035 
1036 	cycles = 0;
1037 	for(;;) {
1038 		if(tready(nil) == 0) {
1039 			execatidle();
1040 			strcpy(up->text, "idle");
1041 			Sleep(&isched.irend, tready, 0);
1042 			strcpy(up->text, "dis");
1043 		}
1044 
1045 		if(isched.vmq != nil && (isched.runhd == nil || ++cycles > 2)){
1046 			iyield();
1047 			cycles = 0;
1048 		}
1049 
1050 		r = isched.runhd;
1051 		if(r != nil) {
1052 			o = r->osenv;
1053 			up->env = o;
1054 
1055 			FPrestore(&o->fpu);
1056 			r->xec(r);
1057 			FPsave(&o->fpu);
1058 
1059 			if(isched.runhd != nil)
1060 			if(r == isched.runhd)
1061 			if(isched.runhd != isched.runtl) {
1062 				isched.runhd = r->link;
1063 				r->link = nil;
1064 				isched.runtl->link = r;
1065 				isched.runtl = r;
1066 			}
1067 			up->env = &up->defenv;
1068 		}
1069 		if(isched.runhd != nil)
1070 		if((++gccounter&0xFF) == 0 || memlow()) {
1071 			gcbusy++;
1072 			up->type = BusyGC;
1073 			pushrun(up->prog);
1074 			rungc(isched.head);
1075 			up->type = Interp;
1076 			delrunq(up->prog);
1077 		}
1078 	}
1079 }
1080 
1081 void
1082 disinit(void *a)
1083 {
1084 	Prog *p;
1085 	Osenv *o;
1086 	Module *root;
1087 	char *initmod = a;
1088 
1089 	if(waserror())
1090 		panic("disinit error: %r");
1091 
1092 	if(vflag)
1093 		print("Initial Dis: \"%s\"\n", initmod);
1094 
1095 	fmtinstall('D', Dconv);
1096 
1097 	FPinit();
1098 	FPsave(&up->env->fpu);
1099 
1100 	opinit();
1101 	modinit();
1102 	excinit();
1103 
1104 	root = load(initmod);
1105 	if(root == 0) {
1106 		kgerrstr(up->genbuf, sizeof up->genbuf);
1107 		panic("loading \"%s\": %s", initmod, up->genbuf);
1108 	}
1109 
1110 	p = schedmod(root);
1111 
1112 	memmove(p->osenv, up->env, sizeof(Osenv));
1113 	o = p->osenv;
1114 	incref(&o->pgrp->r);
1115 	incref(&o->fgrp->r);
1116 	incref(&o->egrp->r);
1117 	if(o->sigs != nil)
1118 		incref(&o->sigs->r);
1119 	o->user = nil;
1120 	kstrdup(&o->user, up->env->user);
1121 	o->errstr = o->errbuf0;
1122 	o->syserrstr = o->errbuf1;
1123 
1124 	isched.idle = 1;
1125 	poperror();
1126 	vmachine(nil);
1127 }
1128 
1129 void
1130 pushrun(Prog *p)
1131 {
1132 	if(p->addrun != nil)
1133 		panic("pushrun addrun");
1134 	p->state = Pready;
1135 	p->link = isched.runhd;
1136 	isched.runhd = p;
1137 	if(p->link == nil)
1138 		isched.runtl = p;
1139 }
1140