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