xref: /inferno-os/emu/port/dis.c (revision 6cde411a8ffd477459336cedf48034e46f56f913)
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 	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
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*
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
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
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
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
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
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
652 cdone(void *vp)
653 {
654 	Prog *p = vp;
655 
656 	return p->addrun == nil || p->kill != nil;
657 }
658 
659 void
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
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*
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
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*
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*
750 currun(void)
751 {
752 	return isched.runhd;
753 }
754 
755 Prog*
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
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
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
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
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
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
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
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
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
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