xref: /inferno-os/os/port/proc.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	<interp.h>
8 
9 Ref	pidalloc;
10 
11 struct
12 {
13 	Lock;
14 	Proc*	arena;
15 	Proc*	free;
16 }procalloc;
17 
18 typedef struct
19 {
20 	Lock;
21 	Proc*	head;
22 	Proc*	tail;
23 }Schedq;
24 
25 static Schedq	runq[Nrq];
26 static ulong	occupied;
27 int	nrdy;
28 
29 char *statename[] =
30 {			/* BUG: generate automatically */
31 	"Dead",
32 	"Moribund",
33 	"Ready",
34 	"Scheding",
35 	"Running",
36 	"Queueing",
37 	"Wakeme",
38 	"Broken",
39 	"Stopped",
40 	"Rendez",
41 };
42 
43 /*
44  * Always splhi()'ed.
45  */
46 void
47 schedinit(void)		/* never returns */
48 {
49 	setlabel(&m->sched);
50 	if(up) {
51 /*
52 		if((e = up->edf) && (e->flags & Admitted))
53 			edfrecord(up);
54 */
55 		m->proc = nil;
56 		switch(up->state) {
57 		case Running:
58 			ready(up);
59 			break;
60 		case Moribund:
61 			up->state = Dead;
62 /*
63 			edfstop(up);
64 			if(up->edf){
65 				free(up->edf);
66 				up->edf = nil;
67 			}
68 */
69 			/*
70 			 * Holding locks from pexit:
71 			 * 	procalloc
72 			 */
73 			up->qnext = procalloc.free;
74 			procalloc.free = up;
75 			unlock(&procalloc);
76 			break;
77 		}
78 		up->mach = nil;
79 		up = nil;
80 	}
81 	sched();
82 }
83 
84 void
85 sched(void)
86 {
87 	if(up) {
88 		splhi();
89 		procsave(up);
90 		if(setlabel(&up->sched)) {
91 			/* procrestore(up); */
92 			spllo();
93 			return;
94 		}
95 		gotolabel(&m->sched);
96 	}
97 	up = runproc();
98 	up->state = Running;
99 	up->mach = MACHP(m->machno);	/* m might be a fixed address; use MACHP */
100 	m->proc = up;
101 	gotolabel(&up->sched);
102 }
103 
104 void
105 ready(Proc *p)
106 {
107 	int s;
108 	Schedq *rq;
109 
110 	s = splhi();
111 /*
112 	if(edfready(p)){
113 		splx(s);
114 		return;
115 	}
116 */
117 	rq = &runq[p->pri];
118 	lock(runq);
119 	p->rnext = 0;
120 	if(rq->tail)
121 		rq->tail->rnext = p;
122 	else
123 		rq->head = p;
124 	rq->tail = p;
125 
126 	nrdy++;
127 	occupied |= 1<<p->pri;
128 	p->state = Ready;
129 	unlock(runq);
130 	splx(s);
131 }
132 
133 int
134 anyready(void)
135 {
136 	/* same priority only */
137 	return occupied & (1<<up->pri);
138 }
139 
140 int
141 anyhigher(void)
142 {
143 	return occupied & ((1<<up->pri)-1);
144 }
145 
146 int
147 preemption(int tick)
148 {
149 	if(up != nil && up->state == Running && !up->preempted &&
150 	   (anyhigher() || tick && anyready())){
151 		up->preempted = 1;
152 		sched();
153 		splhi();
154 		up->preempted = 0;
155 		return 1;
156 	}
157 	return 0;
158 }
159 
160 Proc*
161 runproc(void)
162 {
163 	Proc *p, *l;
164 	Schedq *rq, *erq;
165 
166 	erq = runq + Nrq - 1;
167 loop:
168 	splhi();
169 	for(rq = runq; rq->head == 0; rq++)
170 		if(rq >= erq) {
171 			idlehands();
172 			spllo();
173 			goto loop;
174 		}
175 
176 	if(!canlock(runq))
177 		goto loop;
178 	/* choose first one we last ran on this processor at this level or hasn't moved recently */
179 	l = nil;
180 	for(p = rq->head; p != nil; p = p->rnext)
181 		if(p->mp == nil || p->mp == MACHP(m->machno) || p->movetime < MACHP(0)->ticks)
182 			break;
183 	if(p == nil)
184 		p = rq->head;
185 	/* p->mach==0 only when process state is saved */
186 	if(p == 0 || p->mach) {
187 		unlock(runq);
188 		goto loop;
189 	}
190 	if(p->rnext == nil)
191 		rq->tail = l;
192 	if(l)
193 		l->rnext = p->rnext;
194 	else
195 		rq->head = p->rnext;
196 	if(rq->head == nil){
197 		rq->tail = nil;
198 		occupied &= ~(1<<p->pri);
199 	}
200 	nrdy--;
201 	if(p->dbgstop){
202 		p->state = Stopped;
203 		unlock(runq);
204 		goto loop;
205 	}
206 	if(p->state != Ready)
207 		print("runproc %s %lud %s\n", p->text, p->pid, statename[p->state]);
208 	unlock(runq);
209 	p->state = Scheding;
210 	if(p->mp != MACHP(m->machno))
211 		p->movetime = MACHP(0)->ticks + HZ/10;
212 	p->mp = MACHP(m->machno);
213 
214 /*
215 	if(edflock(p)){
216 		edfrun(p, rq == &runq[PriEdf]);	// start deadline timer and do admin
217 		edfunlock();
218 	}
219 */
220 	return p;
221 }
222 
223 int
224 setpri(int pri)
225 {
226 	int p;
227 
228 	/* called by up so not on run queue */
229 	p = up->pri;
230 	up->pri = pri;
231 	if(up->state == Running && anyhigher())
232 		sched();
233 	return p;
234 }
235 
236 Proc*
237 newproc(void)
238 {
239 	Proc *p;
240 
241 	lock(&procalloc);
242 	for(;;) {
243 		if(p = procalloc.free)
244 			break;
245 
246 		unlock(&procalloc);
247 		resrcwait("no procs");
248 		lock(&procalloc);
249 	}
250 	procalloc.free = p->qnext;
251 	unlock(&procalloc);
252 
253 	p->type = Unknown;
254 	p->state = Scheding;
255 	p->pri = PriNormal;
256 	p->psstate = "New";
257 	p->mach = 0;
258 	p->qnext = 0;
259 	p->fpstate = FPINIT;
260 	p->kp = 0;
261 	p->killed = 0;
262 	p->swipend = 0;
263 	p->mp = 0;
264 	p->movetime = 0;
265 	p->delaysched = 0;
266 	p->edf = nil;
267 	memset(&p->defenv, 0, sizeof(p->defenv));
268 	p->env = &p->defenv;
269 	p->dbgreg = 0;
270 	kstrdup(&p->env->user, "*nouser");
271 	p->env->errstr = p->env->errbuf0;
272 	p->env->syserrstr = p->env->errbuf1;
273 
274 	p->pid = incref(&pidalloc);
275 	if(p->pid == 0)
276 		panic("pidalloc");
277 	if(p->kstack == 0)
278 		p->kstack = smalloc(KSTACK);
279 	addprog(p);
280 
281 	return p;
282 }
283 
284 void
285 procinit(void)
286 {
287 	Proc *p;
288 	int i;
289 
290 	procalloc.free = xalloc(conf.nproc*sizeof(Proc));
291 	procalloc.arena = procalloc.free;
292 
293 	p = procalloc.free;
294 	for(i=0; i<conf.nproc-1; i++,p++)
295 		p->qnext = p+1;
296 	p->qnext = 0;
297 
298 	debugkey('p', "processes", procdump, 0);
299 }
300 
301 void
302 sleep(Rendez *r, int (*f)(void*), void *arg)
303 {
304 	int s;
305 
306 	if(up == nil)
307 		panic("sleep() not in process (%lux)", getcallerpc(&r));
308 	/*
309 	 * spl is to allow lock to be called
310 	 * at interrupt time. lock is mutual exclusion
311 	 */
312 	s = splhi();
313 
314 	lock(&up->rlock);
315 	lock(r);
316 
317 	/*
318 	 * if killed or condition happened, never mind
319 	 */
320 	if(up->killed || f(arg)){
321 		unlock(r);
322 	}else{
323 
324 		/*
325 		 * now we are committed to
326 		 * change state and call scheduler
327 		 */
328 		if(r->p != nil) {
329 			print("double sleep pc=0x%lux %lud %lud r=0x%lux\n", getcallerpc(&r), r->p->pid, up->pid, r);
330 			dumpstack();
331 			panic("sleep");
332 		}
333 		up->state = Wakeme;
334 		r->p = up;
335 		unlock(r);
336 		up->swipend = 0;
337 		up->r = r;	/* for swiproc */
338 		unlock(&up->rlock);
339 
340 		sched();
341 		splhi();	/* sched does spllo */
342 
343 		lock(&up->rlock);
344 		up->r = nil;
345 	}
346 
347 	if(up->killed || up->swipend) {
348 		up->killed = 0;
349 		up->swipend = 0;
350 		unlock(&up->rlock);
351 		splx(s);
352 		error(Eintr);
353 	}
354 	unlock(&up->rlock);
355 	splx(s);
356 }
357 
358 int
359 tfn(void *arg)
360 {
361 	return MACHP(0)->ticks >= up->twhen || (*up->tfn)(arg);
362 }
363 
364 void
365 tsleep(Rendez *r, int (*fn)(void*), void *arg, int ms)
366 {
367 	ulong when;
368 	Proc *f, **l;
369 
370 	if(up == nil)
371 		panic("tsleep() not in process (0x%lux)", getcallerpc(&r));
372 
373 	when = MS2TK(ms)+MACHP(0)->ticks;
374 	lock(&talarm);
375 	/* take out of list if checkalarm didn't */
376 	if(up->trend) {
377 		l = &talarm.list;
378 		for(f = *l; f; f = f->tlink) {
379 			if(f == up) {
380 				*l = up->tlink;
381 				break;
382 			}
383 			l = &f->tlink;
384 		}
385 	}
386 	/* insert in increasing time order */
387 	l = &talarm.list;
388 	for(f = *l; f; f = f->tlink) {
389 		if(f->twhen >= when)
390 			break;
391 		l = &f->tlink;
392 	}
393 	up->trend = r;
394 	up->twhen = when;
395 	up->tfn = fn;
396 	up->tlink = *l;
397 	*l = up;
398 	unlock(&talarm);
399 
400 	if(waserror()){
401 		up->twhen = 0;
402 		nexterror();
403 	}
404 	sleep(r, tfn, arg);
405 	up->twhen = 0;
406 	poperror();
407 }
408 
409 int
410 wakeup(Rendez *r)
411 {
412 	Proc *p;
413 	int s;
414 
415 	s = splhi();
416 	lock(r);
417 	p = r->p;
418 	if(p){
419 		r->p = nil;
420 		if(p->state != Wakeme)
421 			panic("wakeup: state");
422 		ready(p);
423 	}
424 	unlock(r);
425 	splx(s);
426 	return p != nil;
427 }
428 
429 void
430 swiproc(Proc *p, int interp)
431 {
432 	ulong s;
433 	Rendez *r;
434 
435 	if(p == nil)
436 		return;
437 
438 	s = splhi();
439 	lock(&p->rlock);
440 	if(!interp)
441 		p->killed = 1;
442 	r = p->r;
443 	if(r != nil) {
444 		lock(r);
445 		if(r->p == p){
446 			p->swipend = 1;
447 			r->p = nil;
448 			ready(p);
449 		}
450 		unlock(r);
451 	}
452 	unlock(&p->rlock);
453 	splx(s);
454 }
455 
456 void
457 notkilled(void)
458 {
459 	lock(&up->rlock);
460 	up->killed = 0;
461 	unlock(&up->rlock);
462 }
463 
464 void
465 pexit(char*, int)
466 {
467 	Osenv *o;
468 
469 	up->alarm = 0;
470 
471 	o = up->env;
472 	if(o != nil){
473 		closefgrp(o->fgrp);
474 		closepgrp(o->pgrp);
475 		closeegrp(o->egrp);
476 		closesigs(o->sigs);
477 	}
478 
479 	/* Sched must not loop for this lock */
480 	lock(&procalloc);
481 
482 /*
483 	edfstop(up);
484 */
485 	up->state = Moribund;
486 	sched();
487 	panic("pexit");
488 }
489 
490 Proc*
491 proctab(int i)
492 {
493 	return &procalloc.arena[i];
494 }
495 
496 void
497 procdump(void)
498 {
499 	int i;
500 	char *s;
501 	Proc *p;
502 	char tmp[14];
503 
504 	for(i=0; i<conf.nproc; i++) {
505 		p = &procalloc.arena[i];
506 		if(p->state == Dead)
507 			continue;
508 
509 		s = p->psstate;
510 		if(s == nil)
511 			s = "kproc";
512 		if(p->state == Wakeme)
513 			snprint(tmp, sizeof(tmp), " /%.8lux", p->r);
514 		else
515 			*tmp = '\0';
516 		print("%lux:%3lud:%14s pc %.8lux %s/%s qpc %.8lux pri %d%s\n",
517 			p, p->pid, p->text, p->pc, s, statename[p->state], p->qpc, p->pri, tmp);
518 	}
519 }
520 
521 void
522 kproc(char *name, void (*func)(void *), void *arg, int flags)
523 {
524 	Proc *p;
525 	Pgrp *pg;
526 	Fgrp *fg;
527 	Egrp *eg;
528 
529 	p = newproc();
530 	p->psstate = 0;
531 	p->kp = 1;
532 
533 	p->fpsave = up->fpsave;
534 	p->scallnr = up->scallnr;
535 	p->nerrlab = 0;
536 
537 	kstrdup(&p->env->user, up->env->user);
538 	if(flags & KPDUPPG) {
539 		pg = up->env->pgrp;
540 		incref(pg);
541 		p->env->pgrp = pg;
542 	}
543 	if(flags & KPDUPFDG) {
544 		fg = up->env->fgrp;
545 		incref(fg);
546 		p->env->fgrp = fg;
547 	}
548 	if(flags & KPDUPENVG) {
549 		eg = up->env->egrp;
550 		if(eg != nil)
551 			incref(eg);
552 		p->env->egrp = eg;
553 	}
554 
555 	kprocchild(p, func, arg);
556 
557 	strcpy(p->text, name);
558 
559 	ready(p);
560 }
561 
562 void
563 errorf(char *fmt, ...)
564 {
565 	va_list arg;
566 	char buf[PRINTSIZE];
567 
568 	va_start(arg, fmt);
569 	vseprint(buf, buf+sizeof(buf), fmt, arg);
570 	va_end(arg);
571 	error(buf);
572 }
573 
574 void
575 error(char *err)
576 {
577 	if(up == nil)
578 		panic("error(%s) not in a process", err);
579 	spllo();
580 	if(up->nerrlab > NERR)
581 		panic("error stack too deep");
582 	if(err != up->env->errstr)
583 		kstrcpy(up->env->errstr, err, ERRMAX);
584 	setlabel(&up->errlab[NERR-1]);
585 	nexterror();
586 }
587 
588 #include "errstr.h"
589 
590 /* Set kernel error string */
591 void
592 kerrstr(char *err, uint size)
593 {
594 
595 	char tmp[ERRMAX];
596 
597 	kstrcpy(tmp, up->env->errstr, sizeof(tmp));
598 	kstrcpy(up->env->errstr, err, ERRMAX);
599 	kstrcpy(err, tmp, size);
600 }
601 
602 /* Get kernel error string */
603 void
604 kgerrstr(char *err, uint size)
605 {
606 	char tmp[ERRMAX];
607 
608 	kstrcpy(tmp, up->env->errstr, sizeof(tmp));
609 	kstrcpy(up->env->errstr, err, ERRMAX);
610 	kstrcpy(err, tmp, size);
611 }
612 
613 /* Set kernel error string, using formatted print */
614 void
615 kwerrstr(char *fmt, ...)
616 {
617 	va_list arg;
618 	char buf[ERRMAX];
619 
620 	va_start(arg, fmt);
621 	vseprint(buf, buf+sizeof(buf), fmt, arg);
622 	va_end(arg);
623 	kstrcpy(up->env->errstr, buf, ERRMAX);
624 }
625 
626 void
627 werrstr(char *fmt, ...)
628 {
629 	va_list arg;
630 	char buf[ERRMAX];
631 
632 	va_start(arg, fmt);
633 	vseprint(buf, buf+sizeof(buf), fmt, arg);
634 	va_end(arg);
635 	kstrcpy(up->env->errstr, buf, ERRMAX);
636 }
637 
638 void
639 nexterror(void)
640 {
641 	gotolabel(&up->errlab[--up->nerrlab]);
642 }
643 
644 /* for dynamic modules - functions not macros */
645 
646 void*
647 waserr(void)
648 {
649 	up->nerrlab++;
650 	return &up->errlab[up->nerrlab-1];
651 }
652 
653 void
654 poperr(void)
655 {
656 	up->nerrlab--;
657 }
658 
659 char*
660 enverror(void)
661 {
662 	return up->env->errstr;
663 }
664 
665 void
666 exhausted(char *resource)
667 {
668 	char buf[64];
669 
670 	snprint(buf, sizeof(buf), "no free %s", resource);
671 	iprint("%s\n", buf);
672 	error(buf);
673 }
674 
675 /*
676  *  change ownership to 'new' of all processes owned by 'old'.  Used when
677  *  eve changes.
678  */
679 void
680 renameuser(char *old, char *new)
681 {
682 	Proc *p, *ep;
683 	Osenv *o;
684 
685 	ep = procalloc.arena+conf.nproc;
686 	for(p = procalloc.arena; p < ep; p++) {
687 		o = &p->defenv;
688 		if(o->user != nil && strcmp(o->user, old) == 0)
689 			kstrdup(&o->user, new);
690 	}
691 }
692 
693 int
694 return0(void*)
695 {
696 	return 0;
697 }
698 
699 void
700 setid(char *name, int owner)
701 {
702 	if(!owner || iseve())
703 		kstrdup(&up->env->user, name);
704 }
705 
706 void
707 rptwakeup(void *o, void *ar)
708 {
709 	Rept *r;
710 
711 	r = ar;
712 	if(r == nil)
713 		return;
714 	lock(&r->l);
715 	r->o = o;
716 	unlock(&r->l);
717 	wakeup(&r->r);
718 }
719 
720 static int
721 rptactive(void *a)
722 {
723 	Rept *r = a;
724 	int i;
725 	lock(&r->l);
726 	i = r->active(r->o);
727 	unlock(&r->l);
728 	return i;
729 }
730 
731 static void
732 rproc(void *a)
733 {
734 	long now, then;
735 	ulong t;
736 	int i;
737 	void *o;
738 	Rept *r;
739 
740 	r = a;
741 	t = r->t;
742 
743 Wait:
744 	sleep(&r->r, rptactive, r);
745 	lock(&r->l);
746 	o = r->o;
747 	unlock(&r->l);
748 	then = TK2MS(MACHP(0)->ticks);
749 	for(;;){
750 		tsleep(&up->sleep, return0, nil, t);
751 		now = TK2MS(MACHP(0)->ticks);
752 		if(waserror())
753 			break;
754 		i = r->ck(o, now-then);
755 		poperror();
756 		if(i == -1)
757 			goto Wait;
758 		if(i == 0)
759 			continue;
760 		then = now;
761 		acquire();
762 		if(waserror()) {
763 			release();
764 			break;
765 		}
766 		r->f(o);
767 		poperror();
768 		release();
769 	}
770 	pexit("", 0);
771 }
772 
773 void*
774 rptproc(char *s, int t, void *o, int (*active)(void*), int (*ck)(void*, int), void (*f)(void*))
775 {
776 	Rept *r;
777 
778 	r = mallocz(sizeof(Rept), 1);
779 	if(r == nil)
780 		return nil;
781 	r->t = t;
782 	r->active = active;
783 	r->ck = ck;
784 	r->f = f;
785 	r->o = o;
786 	kproc(s, rproc, r, KPDUP);
787 	return r;
788 }
789