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