plan 9 kernel history: overview | file list | diff list

1991/0926/port/proc.c (diff list | history)

port/proc.c on 1990/0227
1990/0227    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"errno.h" 
 
struct 
{ 
	Lock; 
	ulong	pid; 
}pidalloc; 
 
struct 
{ 
	Lock; 
	Proc	*arena; 
	Proc	*free; 
}procalloc; 
 
1991/0926    
struct 
{ 
	Lock; 
	Waitq	*free; 
}waitqalloc; 
 
1991/0420    
typedef struct 
1990/0227    
{ 
	Lock; 
	Proc	*head; 
	Proc	*tail; 
1991/0420    
}Schedq; 
1990/0227    
 
1991/0420    
Schedq runhiq, runloq; 
 
1990/0227    
char *statename[]={	/* BUG: generate automatically */ 
	"Dead", 
	"Moribund", 
	"Ready", 
	"Scheding", 
	"Running", 
	"Queueing", 
	"Wakeme", 
	"Broken", 
1991/0705    
	"Stopped", 
1991/0806    
	"Rendez", 
1990/0227    
}; 
 
/* 
 * Always splhi()'ed. 
 */ 
void 
schedinit(void)		/* never returns */ 
{ 
	Proc *p; 
1991/0705    
	Page *pg; 
1990/0227    
 
	setlabel(&m->sched); 
	if(u){ 
		m->proc = 0; 
		p = u->p; 
1990/1211    
		invalidateu();	/* safety first */ 
1990/0227    
		u = 0; 
		if(p->state == Running) 
			ready(p); 
1991/0705    
		else if(p->state == Moribund) { 
			/* 
			 * The Grim Reaper lays waste the bodies of the dead 
			 */ 
1990/0227    
			p->pid = 0; 
1991/0507    
			mmurelease(p); 
1991/0705    
			/*  
1991/0717    
			 * Holding locks from pexit: 
1991/0705    
			 * 	procalloc, debug, palloc 
			 */ 
			pg = p->upage; 
			pg->ref = 0; 
			p->upage = 0; 
			palloc.freecount++; 
			if(palloc.head) { 
				pg->next = palloc.head; 
				palloc.head->prev = pg; 
				pg->prev = 0; 
				palloc.head = pg; 
			} 
			else { 
				palloc.head = palloc.tail = pg; 
				pg->prev = pg->next = 0; 
			} 
 
1990/0227    
			p->qnext = procalloc.free; 
			procalloc.free = p; 
1991/0705    
		 
			unlock(&palloc); 
1991/0430    
			unlock(&p->debug); 
1990/0227    
			unlock(&procalloc); 
1991/0705    
 
1990/0227    
			p->state = Dead; 
		} 
		p->mach = 0; 
	} 
	sched(); 
} 
 
void 
sched(void) 
{ 
1991/0705    
	uchar procstate[64]; 
1990/0227    
	Proc *p; 
	ulong tlbvirt, tlbphys; 
1990/0731    
	void (*f)(ulong, ulong); 
1990/0227    
 
	if(u){ 
		splhi(); 
1991/0425    
		m->cs++; 
1990/1212    
		procsave(procstate, sizeof(procstate)); 
1990/0227    
		if(setlabel(&u->p->sched)){	/* woke up */ 
			p = u->p; 
			p->state = Running; 
			p->mach = m; 
			m->proc = p; 
1990/1212    
			procrestore(p, procstate); 
1990/0227    
			spllo(); 
			return; 
		} 
		gotolabel(&m->sched); 
	} 
	spllo(); 
	p = runproc(); 
	splhi(); 
	mapstack(p); 
	gotolabel(&p->sched); 
} 
 
1990/1227    
int 
anyready(void) 
{ 
1991/0420    
	return runloq.head != 0 || runhiq.head != 0; 
1990/1227    
} 
 
1990/0227    
void 
ready(Proc *p) 
{ 
1991/0420    
	Schedq *rq; 
1990/0227    
	int s; 
 
	s = splhi(); 
1991/0501    
 
1991/0420    
	if(p->state == Running) 
		rq = &runloq; 
	else 
		rq = &runhiq; 
 
	lock(&runhiq); 
1990/0227    
	p->rnext = 0; 
1991/0420    
	if(rq->tail) 
		rq->tail->rnext = p; 
1990/0227    
	else 
1991/0420    
		rq->head = p; 
	rq->tail = p; 
 
1990/0227    
	p->state = Ready; 
1991/0420    
	unlock(&runhiq); 
1990/0227    
	splx(s); 
} 
 
/* 
 * Always called spllo 
 */ 
Proc* 
runproc(void) 
{ 
1991/0420    
	Schedq *rq; 
1990/0227    
	Proc *p; 
	int i; 
 
loop: 
1991/0420    
	while(runhiq.head==0 && runloq.head==0) 
1990/1211    
		for(i=0; i<10; i++)	/* keep out of shared memory for a while */ 
1990/0227    
			; 
	splhi(); 
1991/0420    
	lock(&runhiq); 
	if(runhiq.head) 
		rq = &runhiq; 
	else 
		rq = &runloq; 
 
	p = rq->head; 
1990/0227    
	if(p==0 || p->mach){	/* p->mach==0 only when process state is saved */ 
1991/0420    
		unlock(&runhiq); 
1990/0227    
		spllo(); 
		goto loop; 
	} 
	if(p->rnext == 0) 
1991/0420    
		rq->tail = 0; 
	rq->head = p->rnext; 
1990/0227    
	if(p->state != Ready) 
		print("runproc %s %d %s\n", p->text, p->pid, statename[p->state]); 
1991/0420    
	unlock(&runhiq); 
1990/0227    
	p->state = Scheding; 
	spllo(); 
	return p; 
} 
 
1991/0705    
int 
canpage(Proc *p) 
{ 
	int ok = 0; 
 
	splhi(); 
	lock(&runhiq); 
1991/0906    
	/* Only reliable way to see if we are Running */ 
	if(p->mach == 0) { 
1991/0705    
		p->newtlb = 1; 
		ok = 1; 
	} 
	unlock(&runhiq); 
	spllo(); 
 
	return ok; 
} 
 
1990/0227    
Proc* 
newproc(void) 
{ 
	Proc *p; 
 
loop: 
	lock(&procalloc); 
	if(p = procalloc.free){		/* assign = */ 
		procalloc.free = p->qnext; 
1991/0926    
		p->state = Scheding; 
		p->psstate = "New"; 
1990/0227    
		unlock(&procalloc); 
		p->mach = 0; 
		p->qnext = 0; 
		p->nchild = 0; 
1991/0926    
		p->nwait = 0; 
		p->waitq = 0; 
1991/0317    
		p->pgrp = 0; 
1991/0705    
		p->egrp = 0; 
		p->fgrp = 0; 
1990/0722    
		p->fpstate = FPinit; 
1991/0425    
		p->kp = 0; 
1991/0705    
		p->procctl = 0; 
1991/0727    
		p->notepending = 0; 
1990/0227    
		memset(p->seg, 0, sizeof p->seg); 
		lock(&pidalloc); 
		p->pid = ++pidalloc.pid; 
		unlock(&pidalloc); 
		if(p->pid == 0) 
			panic("pidalloc"); 
		return p; 
	} 
	unlock(&procalloc); 
	print("no procs\n"); 
	if(u == 0) 
		panic("newproc"); 
1990/0619    
	u->p->state = Wakeme; 
1990/0227    
	alarm(1000, wakeme, u->p); 
	sched(); 
	goto loop; 
} 
 
void 
procinit0(void)		/* bad planning - clashes with devproc.c */ 
{ 
	Proc *p; 
	int i; 
 
	procalloc.free = ialloc(conf.nproc*sizeof(Proc), 0); 
	procalloc.arena = procalloc.free; 
 
	p = procalloc.free; 
1990/0310    
	for(i=0; i<conf.nproc-1; i++,p++) 
1990/0227    
		p->qnext = p+1; 
	p->qnext = 0; 
} 
 
void 
sleep1(Rendez *r, int (*f)(void*), void *arg) 
{ 
	Proc *p; 
	int s; 
 
	/* 
	 * spl is to allow lock to be called 
	 * at interrupt time. lock is mutual exclusion 
	 */ 
	s = splhi(); 
1991/0727    
	p = u->p; 
	p->r = r;	/* early so postnote knows */ 
1990/0227    
	lock(r); 
 
	/* 
	 * if condition happened, never mind 
	 */ 
1991/0727    
	if((*f)(arg)){ 
		p->r = 0; 
1990/0227    
		unlock(r); 
		splx(s); 
		return; 
	} 
 
	/* 
	 * now we are committed to 
	 * change state and call scheduler 
	 */ 
1991/0807    
	if(r->p){ 
1990/03013    
		print("double sleep %d %d\n", r->p->pid, p->pid); 
1991/0807    
		dumpstack(); 
	} 
1990/0227    
	p->state = Wakeme; 
	r->p = p; 
	unlock(r); 
} 
 
void 
sleep(Rendez *r, int (*f)(void*), void *arg) 
{ 
1991/0727    
	Proc *p; 
 
	p = u->p; 
1990/0227    
	sleep1(r, f, arg); 
1991/0727    
	if(p->notepending == 0) 
		sched();	/* notepending may go true while asleep */ 
	if(p->notepending){ 
		p->notepending = 0; 
1991/0805    
		lock(r); 
		if(r->p == p) 
			r->p = 0; 
		unlock(r); 
1990/11211    
		error(Eintr); 
1990/0227    
	} 
} 
 
void 
tsleep(Rendez *r, int (*f)(void*), void *arg, int ms) 
{ 
	Alarm *a; 
1991/0727    
	Proc *p; 
1990/0227    
 
1991/0727    
	p = u->p; 
1990/0227    
	sleep1(r, f, arg); 
1991/0727    
	if(p->notepending == 0){ 
		a = alarm(ms, twakeme, r); 
		sched();	/* notepending may go true while asleep */ 
		cancel(a); 
	} 
	if(p->notepending){ 
		p->notepending = 0; 
1991/0805    
		lock(r); 
		if(r->p == p) 
			r->p = 0; 
		unlock(r); 
1990/11211    
		error(Eintr); 
1990/0227    
	} 
} 
 
void 
wakeup(Rendez *r) 
{ 
	Proc *p; 
	int s; 
 
	s = splhi(); 
	lock(r); 
	p = r->p; 
	if(p){ 
		r->p = 0; 
1991/0705    
		if(p->state != Wakeme)  
			panic("wakeup: state"); 
1990/0227    
		p->r = 0; 
		ready(p); 
	} 
	unlock(r); 
	splx(s); 
} 
 
1990/03091    
void 
wakeme(Alarm *a) 
{ 
	ready((Proc*)(a->arg)); 
	cancel(a); 
} 
 
void 
twakeme(Alarm *a) 
{ 
	wakeup((Rendez*)(a->arg)); 
} 
 
1990/0227    
int 
postnote(Proc *p, int dolock, char *n, int flag) 
{ 
	User *up; 
1990/0617    
	KMap *k; 
1990/0227    
	int s; 
	Rendez *r; 
1991/0806    
	Proc *d, **l; 
1990/0227    
 
1991/0425    
	SET(k); 
	USED(k); 
 
1990/0227    
	if(dolock) 
		lock(&p->debug); 
1991/0430    
 
1991/0810    
	if(p->upage == 0){ 
		if(dolock) 
			unlock(&p->debug); 
1991/0430    
		errors("noted process disappeared"); 
1991/0810    
	} 
1991/0425    
 
1991/0523    
	if(u == 0 || p != u->p){ 
1991/0109    
		k = kmap(p->upage); 
		up = (User*)VA(k); 
1991/0425    
	}else  
1991/0109    
		up = u; 
1991/0523    
 
1991/0425    
 
1990/0227    
	if(flag!=NUser && (up->notify==0 || up->notified)) 
		up->nnote = 0;	/* force user's hand */ 
1990/0617    
	else if(up->nnote == NNOTE-1){ 
1991/0109    
		if(up != u) 
			kunmap(k); 
1991/0810    
		if(dolock) 
			unlock(&p->debug); 
1990/0227    
		return 0; 
1990/0617    
	} 
1991/0727    
	p->notepending = 1; 
1990/0227    
	strcpy(up->note[up->nnote].msg, n); 
	up->note[up->nnote++].flag = flag; 
1991/0109    
	if(up != u) 
		kunmap(k); 
1990/0227    
	if(dolock) 
		unlock(&p->debug); 
1991/0705    
 
1991/0727    
	if(r = p->r){		/* assign = */ 
		/* wake up; can't call wakeup itself because we're racing with it */ 
1990/0227    
		s = splhi(); 
		lock(r); 
1991/0727    
		if(p->r==r && r->p==p){	/* check we won the race */ 
1991/0805    
			if(p->state == Wakeme){ 
				r->p = 0; 
				p->r = 0; 
				ready(p); 
			} 
1990/0227    
		} 
		unlock(r); 
		splx(s); 
	} 
1991/0807    
 
1991/0806    
	if(p->state == Rendezvous) { 
		lock(p->pgrp); 
		if(p->state == Rendezvous) { 
1991/0807    
			p->rendval = ~0; 
1991/0806    
			l = &REND(p->pgrp, p->rendtag); 
			for(d = *l; d; d = d->rendhash) { 
				if(d == p) { 
					*l = p->rendhash; 
					break; 
				} 
				l = &d->rendhash; 
			} 
			ready(p); 
		} 
		unlock(p->pgrp); 
	} 
 
1990/0227    
	return 1; 
} 
 
1990/1101    
 
/* 
 * weird thing: keep at most NBROKEN around 
 */ 
#define	NBROKEN 4 
struct{ 
	Lock; 
	int	n; 
	Proc	*p[NBROKEN]; 
}broken; 
 
1990/0227    
void 
1990/1101    
addbroken(Proc *c) 
{ 
	int b; 
 
	lock(&broken); 
	if(broken.n == NBROKEN){ 
		ready(broken.p[0]); 
1991/0318    
		memmove(&broken.p[0], &broken.p[1], sizeof(Proc*)*(NBROKEN-1)); 
1990/1101    
		--broken.n; 
	} 
	broken.p[broken.n++] = c; 
	unlock(&broken); 
	c->state = Broken; 
1991/0926    
	c->psstate = 0; 
1990/1101    
	sched();		/* until someone lets us go */ 
	lock(&broken); 
	for(b=0; b<NBROKEN; b++) 
		if(broken.p[b] == c){ 
			broken.n--; 
1991/0318    
			memmove(&broken.p[b], &broken.p[b+1], sizeof(Proc*)*(NBROKEN-(b+1))); 
1990/1101    
			break; 
		} 
	unlock(&broken); 
} 
 
int 
freebroken(void) 
{ 
1991/0109    
	int i, n; 
1990/1101    
 
	lock(&broken); 
	n = broken.n; 
1991/0109    
	for(i=0; i<n; i++) 
		ready(broken.p[i]); 
	broken.n = 0; 
1990/1101    
	unlock(&broken); 
	return n; 
} 
 
void 
1991/0717    
pexit(char *exitstr, int freemem) 
1990/0227    
{ 
1991/0926    
	Proc *p, *c; 
1991/0717    
	Segment **s, **es, *os; 
1991/0926    
	Waitq *wq, *f, *next; 
1990/0227    
 
1990/03081    
	c = u->p; 
1991/0513    
	c->alarm = 0; 
1991/0517    
 
1991/0712    
	if(c->fgrp) 
		closefgrp(c->fgrp); 
1991/0517    
 
1991/0926    
	wq = newwaitq(); 
	wq->w.pid = c->pid; 
	wq->w.time[TUser] = TK2MS(c->time[TUser]); 
	wq->w.time[TCUser] = TK2MS(c->time[TCUser]); 
	wq->w.time[TSys] = TK2MS(c->time[TSys]); 
	wq->w.time[TCSys] = TK2MS(c->time[TCSys]); 
	wq->w.time[TReal] = TK2MS(MACHP(0)->ticks - c->time[TReal]); 
	if(exitstr) 
		strncpy(wq->w.msg, exitstr, ERRLEN); 
	else 
		wq->w.msg[0] = '\0'; 
1990/0227    
 
1991/0926    
	/* Find my parent */ 
1990/03081    
	p = c->parent; 
1991/0926    
 
	lock(&p->exl); 
	/* My parent still alive */ 
	if(p->pid == c->parentpid && p->state != Broken && p->nwait < 128) {	 
		p->nchild--; 
		p->time[TCUser] += c->time[TUser] + c->time[TCUser]; 
		p->time[TCSys] += c->time[TSys] + c->time[TCSys]; 
 
		wq->next = p->waitq; 
		p->waitq = wq; 
		p->nwait++; 
		unlock(&p->exl); 
 
		wakeup(&p->waitr); 
1990/0227    
	} 
1991/0926    
	else { 
		unlock(&p->exl); 
		freewaitq(wq); 
1990/0227    
	} 
1990/03081    
 
1991/0926    
	if(!freemem) 
		addbroken(c); 
1990/03081    
 
1991/0926    
	flushvirt(); 
	es = &c->seg[NSEG]; 
	for(s = c->seg; s < es; s++) 
		if(os = *s) { 
			*s = 0; 
			putseg(os); 
		} 
	closepgrp(c->pgrp); 
	closeegrp(c->egrp); 
	close(u->dot); 
 
	lock(&c->exl);		/* Prevent my children from leaving waits */ 
	c->pid = 0; 
	unlock(&c->exl); 
 
	for(f = c->waitq; f; f = next) { 
		next = f->next; 
		freewaitq(f); 
	} 
 
1991/0705    
	/* 
	 * sched() cannot wait on these locks 
	 */ 
	lock(&procalloc); 
	lock(&c->debug); 
	lock(&palloc); 
 
1990/03081    
	c->state = Moribund; 
1991/0705    
	sched(); 
	panic("pexit"); 
1990/0227    
} 
 
1991/0926    
int 
haswaitq(void *x) 
{ 
	Proc *p; 
 
	p = (Proc *)x; 
	return p->waitq != 0; 
} 
 
1990/0227    
ulong 
pwait(Waitmsg *w) 
{ 
1991/0926    
	Proc *p; 
1990/0227    
	ulong cpid; 
1991/0926    
	Waitq *wq; 
1990/0227    
 
	p = u->p; 
1991/0926    
 
	lock(&p->exl); 
	if(p->nchild == 0 && p->waitq == 0) { 
		unlock(&p->exl); 
		error(Enochild); 
1990/0227    
	} 
1991/0926    
	unlock(&p->exl); 
 
	sleep(&p->waitr, haswaitq, u->p); 
 
	lock(&p->exl); 
	wq = p->waitq; 
	p->waitq = wq->next; 
	p->nwait--; 
	unlock(&p->exl); 
 
1990/0227    
	if(w) 
1991/0926    
		memmove(w, &wq->w, sizeof(Waitmsg)); 
	cpid = wq->w.pid; 
	freewaitq(wq); 
1990/0227    
	return cpid; 
} 
 
Proc* 
proctab(int i) 
{ 
	return &procalloc.arena[i]; 
} 
 
#include <ureg.h> 
1990/1220    
void 
1991/0608    
procdump(void) 
1990/0227    
{ 
1990/0330    
	int i; 
1990/0227    
	Proc *p; 
 
	for(i=0; i<conf.nproc; i++){ 
		p = procalloc.arena+i; 
1990/0312    
		if(p->state != Dead){ 
1991/0830    
			print("%d:%s %s upc %lux %s ut %ld st %ld r %lux qpc %lux\n", 
1991/0807    
				p->pid, p->text,  
				p->pgrp ? p->pgrp->user : "pgrp=0", p->pc,  
1991/0830    
				statename[p->state], p->time[0], p->time[1], p->r, p->qlockpc); 
1990/0312    
		} 
1990/0227    
	} 
} 
 
void 
kproc(char *name, void (*func)(void *), void *arg) 
{ 
	Proc *p; 
	int n; 
	ulong upa; 
1990/0424    
	int lastvar;	/* used to compute stack address */ 
1990/0617    
	User *up; 
	KMap *k; 
1990/0722    
	static Pgrp *kpgrp; 
1991/0705    
	char *user; 
1990/0227    
 
	/* 
	 * Kernel stack 
	 */ 
	p = newproc(); 
1991/0926    
	p->psstate = 0; 
1990/1212    
	p->kp = 1; 
1990/0227    
	p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF)); 
1990/0617    
	k = kmap(p->upage); 
	upa = VA(k); 
	up = (User*)upa; 
1990/0227    
 
	/* 
	 * Save time: only copy u-> data and useful stack 
	 */ 
1991/0529    
	clearmmucache();	/* so child doesn't inherit any of your mappings */ 
1991/0318    
	memmove(up, u, sizeof(User)); 
1990/0227    
	n = USERADDR+BY2PG - (ulong)&lastvar; 
	n = (n+32) & ~(BY2WD-1);	/* be safe & word align */ 
1991/0318    
	memmove((void*)(upa+BY2PG-n), (void*)(USERADDR+BY2PG-n), n); 
1991/0820    
	up->p = p; 
1990/0227    
 
	/* 
	 * Refs 
	 */ 
	incref(up->dot); 
1990/0617    
	kunmap(k); 
1990/0227    
 
	/* 
	 * Sched 
	 */ 
	if(setlabel(&p->sched)){ 
		p->state = Running; 
		p->mach = m; 
		m->proc = p; 
		spllo(); 
		(*func)(arg); 
		pexit(0, 1); 
	} 
1991/0705    
 
	user = "bootes"; 
1990/0722    
	if(kpgrp == 0){ 
		kpgrp = newpgrp(); 
1991/0705    
		strcpy(kpgrp->user, user); 
1990/0722    
	} 
	p->pgrp = kpgrp; 
	incref(kpgrp); 
1991/0705    
 
	if(u->p->pgrp->user[0] != '\0') 
		user = u->p->pgrp->user; 
	sprint(p->text, "%s.%.6s", name, user); 
 
1990/0227    
	p->nchild = 0; 
	p->parent = 0; 
	memset(p->time, 0, sizeof(p->time)); 
	p->time[TReal] = MACHP(0)->ticks; 
1991/0926    
	ready(p); 
1991/0529    
	/* 
	 *  since the bss/data segments are now shareable, 
	 *  any mmu info about this process is now stale 
	 *  and has to be discarded. 
	 */ 
1990/0227    
	flushmmu(); 
1991/0705    
} 
 
void 
procctl(Proc *p) 
{ 
	switch(p->procctl) { 
	case Proc_exitme: 
		pexit("Killed", 1); 
	case Proc_stopme: 
		p->procctl = 0; 
		p->state = Stopped; 
		sched(); 
		return; 
	} 
1990/0227    
} 
1991/0710    
 
#include "errstr.h" 
 
void 
error(int code) 
{ 
	strncpy(u->error, errstrtab[code], ERRLEN); 
	nexterror(); 
} 
 
void 
errors(char *err) 
{ 
	strncpy(u->error, err, ERRLEN); 
	nexterror(); 
} 
 
void 
nexterror(void) 
{ 
	gotolabel(&u->errlab[--u->nerrlab]); 
} 
 
1991/0926    
Waitq * 
newwaitq(void) 
{ 
	Waitq *wq, *e, *f; 
 
	for(;;) { 
		lock(&waitqalloc); 
		if(wq = waitqalloc.free) { 
			waitqalloc.free = wq->next; 
			unlock(&waitqalloc); 
			return wq; 
		} 
		unlock(&waitqalloc); 
 
		wq = (Waitq*)VA(kmap(newpage(0, 0, 0))); 
		e = &wq[(BY2PG/sizeof(Waitq))-1]; 
		for(f = wq; f < e; f++) 
			f->next = f+1; 
 
		lock(&waitqalloc); 
		e->next = waitqalloc.free; 
		waitqalloc.free = wq; 
		unlock(&waitqalloc); 
	} 
} 
 
void 
freewaitq(Waitq *wq) 
{ 
	lock(&waitqalloc); 
	wq->next = waitqalloc.free; 
	waitqalloc.free = wq; 
	unlock(&waitqalloc); 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)