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

2002/0925/port/proc.c (diff list | history)

port/proc.c on 1990/0227
1990/0227    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1990/0227    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1990/0227    
 
2001/0527    
int	nrdy; 
1992/0428    
Ref	noteidalloc; 
1990/0227    
 
2002/0403    
long	delayedscheds;	/* statistics */ 
 
2001/0527    
static Ref	pidalloc; 
 
static struct Procalloc 
1990/0227    
{ 
	Lock; 
2001/0510    
	Proc*	ht[128]; 
1997/0327    
	Proc*	arena; 
	Proc*	free; 
2001/0527    
} procalloc; 
1990/0227    
 
2001/0527    
static Schedq	runq[Nrq]; 
1994/0728    
 
2002/0704    
extern Edfinterface	nulledf; 
 
Edfinterface *edf = &nulledf; 
 
1992/0309    
char *statename[] = 
2002/0315    
{	/* BUG: generate automatically */ 
1990/0227    
	"Dead", 
	"Moribund", 
	"Ready", 
	"Scheding", 
	"Running", 
	"Queueing", 
1998/0806    
	"QueueingR", 
1998/0325    
	"QueueingW", 
1990/0227    
	"Wakeme", 
	"Broken", 
1991/0705    
	"Stopped", 
1991/0806    
	"Rendez", 
2002/0315    
	"Released", 
1990/0227    
}; 
 
2001/0510    
static void pidhash(Proc*); 
static void pidunhash(Proc*); 
 
1990/0227    
/* 
 * Always splhi()'ed. 
 */ 
void 
schedinit(void)		/* never returns */ 
{ 
	setlabel(&m->sched); 
1993/0501    
	if(up) { 
1990/0227    
		m->proc = 0; 
1993/0501    
		switch(up->state) { 
		case Running: 
			ready(up); 
			break; 
		case Moribund: 
			up->state = Dead; 
2002/0704    
			if (edf->isedf(up)) 
				edf->edfbury(up); 
2002/0315    
 
1998/0512    
			/* 
1991/0717    
			 * Holding locks from pexit: 
1995/0112    
			 * 	procalloc 
1998/0605    
			 *	palloc 
1991/0705    
			 */ 
1993/0501    
			mmurelease(up); 
1991/0705    
 
1993/0501    
			up->qnext = procalloc.free; 
			procalloc.free = up; 
1995/1230    
 
			unlock(&palloc); 
1990/0227    
			unlock(&procalloc); 
1993/0501    
			break; 
1990/0227    
		} 
1993/0501    
		up->mach = 0; 
2002/0315    
		up = nil; 
1990/0227    
	} 
	sched(); 
} 
 
1998/0514    
/* 
 *  If changing this routine, look also at sleep().  It 
 *  contains a copy of the guts of sched(). 
 */ 
1990/0227    
void 
sched(void) 
{ 
2002/0925    
	int x[1]; 
 
2002/0420    
	if(m->ilockdepth) 
2002/0925    
		panic("ilockdepth %d, last lock 0x%p at 0x%lux, sched called from 0x%lux", 
2002/0626    
			m->ilockdepth, up?up->lastilock:nil, 
2002/0925    
			(up && up->lastilock)?up->lastilock->pc:0, getcallerpc(x+3)); 
2002/0420    
 
2002/0403    
	if(up){ 
2002/0420    
		if(up->nlocks && up->state != Moribund){ 
 			delayedscheds++; 
2002/0403    
			return; 
		} 
 
1990/0227    
		splhi(); 
1993/1212    
 
		/* statistics */ 
1991/0425    
		m->cs++; 
1993/1212    
 
1993/0501    
		procsave(up); 
2002/0403    
		if(setlabel(&up->sched)){ 
1993/0501    
			procrestore(up); 
1990/0227    
			spllo(); 
			return; 
		} 
		gotolabel(&m->sched); 
	} 
1993/0501    
	up = runproc(); 
	up->state = Running; 
1995/0811    
	up->mach = MACHP(m->machno); 
1993/0501    
	m->proc = up; 
	mmuswitch(up); 
	gotolabel(&up->sched); 
1994/0311    
} 
 
1994/0321    
int 
anyready(void) 
{ 
2002/0704    
	return nrdy || edf->edfanyready(); 
1990/1227    
} 
 
1994/0809    
int 
1994/0817    
anyhigher(void) 
1994/0809    
{ 
1999/0326    
	Schedq *rq; 
1994/0817    
 
1999/0326    
	if(nrdy == 0) 
		return 0; 
 
	for(rq = &runq[Nrq-1]; rq > &runq[up->priority]; rq--) 
		if(rq->head != nil) 
			return 1; 
2002/0315    
 
1999/0326    
	return 0; 
1994/0809    
} 
 
1995/0110    
enum 
{ 
2002/0228    
	Squantum = 1, 
1995/0110    
}; 
 
1990/0227    
void 
ready(Proc *p) 
{ 
1996/0523    
	int s, pri; 
1995/0110    
	Schedq *rq; 
1990/0227    
 
	s = splhi(); 
1991/0501    
 
2002/0704    
	if(edf->isedf(p)){ 
		edf->edfready(p); 
2002/0404    
		splx(s); 
		return; 
	} 
2001/0315    
	if(p->fixedpri){ 
		pri = p->basepri; 
1995/0110    
	} else { 
2001/0315    
		/* history counts */ 
		if(p->state == Running){ 
			p->rt++; 
2002/0228    
			pri = (p->art + p->rt)/2; 
2001/0315    
		} else { 
2002/0228    
			p->art = (p->art + p->rt + 2)/2; 
			pri = (p->art + p->rt)/2; 
2001/0315    
			p->rt = 0; 
		} 
2002/0228    
		pri = p->basepri - (pri/Squantum); 
2001/0315    
		if(pri < 0) 
			pri = 0; 
2002/0315    
 
2001/0315    
		/* the only intersection between the classes is at PriNormal */ 
		if(pri < PriNormal && p->basepri > PriNormal) 
			pri = PriNormal; 
1995/0110    
 
2001/0315    
		/* stick at low priority any process waiting for a lock */ 
		if(p->lockwait) 
			pri = PriLock; 
	} 
1998/0606    
 
1996/0523    
	p->priority = pri; 
1995/0110    
	rq = &runq[p->priority]; 
 
	lock(runq); 
1990/0227    
	p->rnext = 0; 
1995/0110    
	if(rq->tail) 
		rq->tail->rnext = p; 
1990/0227    
	else 
1995/0110    
		rq->head = p; 
	rq->tail = p; 
	rq->n++; 
	nrdy++; 
	p->readytime = m->ticks; 
1990/0227    
	p->state = Ready; 
1995/0110    
	unlock(runq); 
1990/0227    
	splx(s); 
} 
 
Proc* 
runproc(void) 
{ 
1998/0901    
	Schedq *rq, *xrq; 
1995/0110    
	Proc *p, *l; 
1998/0901    
	ulong rt; 
2002/0822    
	ulong start, now; 
1990/0227    
 
2002/0822    
	start = perfticks(); 
2002/0821    
 
2002/0704    
	if ((p = edf->edfrunproc()) != nil) 
2002/0404    
		return p; 
 
1990/0227    
loop: 
1995/0110    
 
	/* 
	 *  find a process that last ran on this processor (affinity), 
	 *  or one that hasn't moved in a while (load balancing). 
	 */ 
1992/0603    
	spllo(); 
1995/0912    
	for(;;){ 
1999/0811    
		if((++(m->fairness) & 0x3) == 0){ 
1998/0901    
			/* 
			 *  once in a while, run process that's been waiting longest 
			 *  regardless of movetime 
			 */ 
			rt = 0xffffffff; 
			xrq = nil; 
1995/0110    
			for(rq = runq; rq < &runq[Nrq]; rq++){ 
				p = rq->head; 
1996/0315    
				if(p == 0) 
1995/0110    
					continue; 
1998/0901    
				if(p->readytime < rt){ 
					xrq = rq; 
					rt = p->readytime; 
				} 
			} 
			if(xrq != nil){ 
				rq = xrq; 
				p = rq->head; 
1999/0711    
				if(p != nil && p->wired == nil) 
1998/0901    
					p->movetime = 0; 
1998/0923    
				goto found; 
1998/0901    
			} 
		} else { 
			/* 
			 *  get highest priority process that this 
			 *  processor can run given affinity constraints 
			 */ 
			for(rq = &runq[Nrq-1]; rq >= runq; rq--){ 
				p = rq->head; 
				if(p == 0) 
					continue; 
1996/0315    
				for(; p; p = p->rnext){ 
1998/0901    
					if(p->mp == MACHP(m->machno) 
1999/0811    
					|| p->movetime < MACHP(0)->ticks) 
1996/0315    
						goto found; 
				} 
1995/0110    
			} 
		} 
2002/0822    
 
		/* remember how much time we're here */ 
2000/1130    
		idlehands(); 
2002/0822    
		now = perfticks(); 
		m->perf.inidle += now-start; 
		start = now; 
1994/0729    
	} 
1995/0110    
 
found: 
1994/0729    
	splhi(); 
1997/0821    
	if(!canlock(runq)) 
		goto loop; 
1991/0420    
 
1995/0110    
	l = 0; 
	for(p = rq->head; p; p = p->rnext){ 
2002/0415    
		if(p->mp == MACHP(m->machno) || p->movetime <= MACHP(0)->ticks) 
1995/0110    
			break; 
		l = p; 
1994/0728    
	} 
1995/0110    
 
	/* 
	 *  p->mach==0 only when process state is saved 
	 */ 
1998/0512    
	if(p == 0 || p->mach){ 
1995/0110    
		unlock(runq); 
1990/0227    
		goto loop; 
	} 
1995/0110    
	if(p->rnext == 0) 
		rq->tail = l; 
	if(l) 
		l->rnext = p->rnext; 
1994/0728    
	else 
1995/0110    
		rq->head = p->rnext; 
	rq->n--; 
	nrdy--; 
	if(p->state != Ready) 
1998/0825    
		print("runproc %s %lud %s\n", p->text, p->pid, statename[p->state]); 
1995/0110    
	unlock(runq); 
1995/0102    
 
1995/0110    
	p->state = Scheding; 
1995/0811    
	if(p->mp != MACHP(m->machno)) 
1999/0811    
		p->movetime = MACHP(0)->ticks + HZ/10; 
1995/0811    
	p->mp = MACHP(m->machno); 
2002/0315    
 
1995/0110    
	return p; 
1990/0227    
} 
 
1991/0705    
int 
canpage(Proc *p) 
{ 
	int ok = 0; 
 
	splhi(); 
1995/0110    
	lock(runq); 
1991/0906    
	/* Only reliable way to see if we are Running */ 
	if(p->mach == 0) { 
1991/0705    
		p->newtlb = 1; 
		ok = 1; 
	} 
1995/0110    
	unlock(runq); 
1991/0705    
	spllo(); 
 
	return ok; 
} 
 
1990/0227    
Proc* 
newproc(void) 
{ 
	Proc *p; 
 
1993/0501    
	lock(&procalloc); 
1991/1110    
	for(;;) { 
1993/0501    
		if(p = procalloc.free) 
			break; 
 
1990/0227    
		unlock(&procalloc); 
1991/1110    
		resrcwait("no procs"); 
1993/0501    
		lock(&procalloc); 
1990/0227    
	} 
1993/0501    
	procalloc.free = p->qnext; 
	unlock(&procalloc); 
 
	p->state = Scheding; 
	p->psstate = "New"; 
	p->mach = 0; 
	p->qnext = 0; 
	p->nchild = 0; 
	p->nwait = 0; 
	p->waitq = 0; 
2001/0802    
	p->parent = 0; 
1993/0501    
	p->pgrp = 0; 
	p->egrp = 0; 
	p->fgrp = 0; 
1994/0812    
	p->rgrp = 0; 
1993/0501    
	p->pdbg = 0; 
2000/1027    
	p->fpstate = FPinit; 
1993/0501    
	p->kp = 0; 
	p->procctl = 0; 
	p->notepending = 0; 
1995/0110    
	p->mp = 0; 
	p->movetime = 0; 
1995/0102    
	p->wired = 0; 
1995/0115    
	p->ureg = 0; 
2001/1117    
	p->privatemem = 0; 
2002/0502    
	p->noswap = 0; 
2002/0328    
	p->lockwait = nil; 
2001/0924    
	p->errstr = p->errbuf0; 
	p->syserrstr = p->errbuf1; 
	p->errbuf0[0] = '\0'; 
	p->errbuf1[0] = '\0'; 
2002/0404    
	p->nlocks = 0; 
	p->delaysched = 0; 
2002/0415    
	p->movetime = 0; 
2001/0527    
	kstrdup(&p->user, "*nouser"); 
	kstrdup(&p->text, "*notext"); 
	kstrdup(&p->args, ""); 
	p->nargs = 0; 
1993/0501    
	memset(p->seg, 0, sizeof p->seg); 
	p->pid = incref(&pidalloc); 
2001/0510    
	pidhash(p); 
1993/0501    
	p->noteid = incref(¬eidalloc); 
	if(p->pid==0 || p->noteid==0) 
		panic("pidalloc"); 
	if(p->kstack == 0) 
		p->kstack = smalloc(KSTACK); 
 
2002/0315    
	p->task = nil; 
 
1993/0501    
	return p; 
1990/0227    
} 
 
1995/0102    
/* 
 * wire this proc to a machine 
 */ 
1990/0227    
void 
1999/0711    
procwired(Proc *p, int bm) 
1995/0102    
{ 
	Proc *pp; 
1999/0711    
	int i; 
1995/0102    
	char nwired[MAXMACH]; 
1999/0711    
	Mach *wm; 
1995/0102    
 
1999/0711    
	if(bm < 0){ 
		/* pick a machine to wire to */ 
		memset(nwired, 0, sizeof(nwired)); 
		p->wired = 0; 
		pp = proctab(0); 
		for(i=0; i<conf.nproc; i++, pp++){ 
			wm = pp->wired; 
			if(wm && pp->pid) 
				nwired[wm->machno]++; 
		} 
		bm = 0; 
		for(i=0; i<conf.nmach; i++) 
			if(nwired[i] < nwired[bm]) 
				bm = i; 
	} else { 
		/* use the virtual machine requested */ 
		bm = bm % conf.nmach; 
	} 
 
1995/0102    
	p->wired = MACHP(bm); 
1995/0110    
	p->movetime = 0xffffffff; 
	p->mp = p->wired; 
1995/0102    
} 
 
void 
1990/0227    
procinit0(void)		/* bad planning - clashes with devproc.c */ 
{ 
	Proc *p; 
	int i; 
 
1992/0619    
	procalloc.free = xalloc(conf.nproc*sizeof(Proc)); 
1997/0327    
	if(procalloc.free == nil) 
2002/0114    
		panic("cannot allocate %lud procs\n", conf.nproc); 
1990/0227    
	procalloc.arena = procalloc.free; 
 
	p = procalloc.free; 
1994/0612    
	for(i=0; i<conf.nproc-1; i++,p++) 
1990/0227    
		p->qnext = p+1; 
	p->qnext = 0; 
} 
 
1998/0514    
/* 
2000/0919    
 *  sleep if a condition is not true.  Another process will 
 *  awaken us after it sets the condition.  When we awaken 
 *  the condition may no longer be true. 
1998/0514    
 * 
2000/0919    
 *  we lock both the process and the rendezvous to keep r->p 
 *  and p->r synchronized. 
1998/0514    
 */ 
1990/0227    
void 
1998/0513    
sleep(Rendez *r, int (*f)(void*), void *arg) 
1990/0227    
{ 
	int s; 
 
	s = splhi(); 
1998/0513    
 
2002/0404    
	if (up->nlocks) 
		print("process %lud sleeps with %lud locks held, last lock 0x%p locked at pc 0x%lux\n", 
			up->pid, up->nlocks, up->lastlock, up->lastlock->pc); 
2000/0919    
	lock(r); 
1996/1016    
	lock(&up->rlock); 
1996/1017    
	if(r->p){ 
1998/0825    
		print("double sleep %lud %lud\n", r->p->pid, up->pid); 
1996/1017    
		dumpstack(); 
	} 
1990/0227    
 
	/* 
1998/0514    
	 *  Wakeup only knows there may be something to do by testing 
	 *  r->p in order to get something to lock on. 
	 *  Flush that information out to memory in case the sleep is 
	 *  committed. 
1990/0227    
	 */ 
1998/0513    
	r->p = up; 
 
	if((*f)(arg) || up->notepending){ 
		/* 
		 *  if condition happened or a note is pending 
		 *  never mind 
		 */ 
		r->p = nil; 
1996/1016    
		unlock(&up->rlock); 
2000/0919    
		unlock(r); 
1998/0513    
	} else { 
		/* 
		 *  now we are committed to 
		 *  change state and call scheduler 
		 */ 
		up->state = Wakeme; 
		up->r = r; 
 
		/* statistics */ 
		m->cs++; 
2002/0315    
 
1998/0513    
		procsave(up); 
		if(setlabel(&up->sched)) { 
			/* 
			 *  here when the process is awakened 
			 */ 
			procrestore(up); 
			spllo(); 
		} else { 
			/* 
			 *  here to go to sleep (i.e. stop Running) 
			 */ 
			unlock(&up->rlock); 
2000/0919    
			unlock(r); 
2002/0315    
			// Behind unlock, we may call wakeup on ourselves. 
 
2002/0704    
			if (edf->isedf(up)) 
				edf->edfblock(up); 
2002/0404    
 
1998/0513    
			gotolabel(&m->sched); 
		} 
1990/0227    
	} 
 
1993/0501    
	if(up->notepending) { 
		up->notepending = 0; 
1992/0519    
		splx(s); 
2001/1218    
		error(Eintr); 
1990/0227    
	} 
1998/0513    
 
	splx(s); 
1990/0227    
} 
 
1992/0617    
int 
tfn(void *arg) 
{ 
1997/0327    
	return MACHP(0)->ticks >= up->twhen || up->tfn(arg); 
1992/0617    
} 
 
1990/0227    
void 
1992/0602    
tsleep(Rendez *r, int (*fn)(void*), void *arg, int ms) 
1990/0227    
{ 
1994/0812    
	ulong when; 
1993/0501    
	Proc *f, **l; 
1990/0227    
 
2002/0326    
	when = ms2tk(ms) + MACHP(0)->ticks; 
1992/0602    
 
	lock(&talarm); 
1992/0701    
	/* take out of list if checkalarm didn't */ 
1993/0501    
	if(up->trend) { 
1992/0701    
		l = &talarm.list; 
		for(f = *l; f; f = f->tlink) { 
1993/0501    
			if(f == up) { 
				*l = up->tlink; 
1992/0701    
				break; 
			} 
			l = &f->tlink; 
		} 
	} 
	/* insert in increasing time order */ 
1992/0602    
	l = &talarm.list; 
1992/0701    
	for(f = *l; f; f = f->tlink) { 
		if(f->twhen >= when) 
			break; 
1992/0602    
		l = &f->tlink; 
1991/0727    
	} 
1993/0501    
	up->trend = r; 
	up->twhen = when; 
	up->tfn = fn; 
	up->tlink = *l; 
	*l = up; 
1992/0602    
	unlock(&talarm); 
 
2000/0129    
	if(waserror()){ 
		up->twhen = 0; 
		nexterror(); 
	} 
1992/0617    
	sleep(r, tfn, arg); 
1993/0501    
	up->twhen = 0; 
2000/0129    
	poperror(); 
1990/0227    
} 
 
1992/0909    
/* 
2000/0919    
 *  Expects that only one process can call wakeup for any given Rendez. 
 *  We hold both locks to ensure that r->p and p->r remain consistent. 
 *  Richard Miller has a better solution that doesn't require both to 
 *  be held simultaneously, but I'm a paranoid - presotto. 
1992/0909    
 */ 
2001/0207    
Proc* 
1990/0227    
wakeup(Rendez *r) 
{ 
2001/0529    
	Proc *p; 
2001/0207    
	int s; 
1990/0227    
 
1996/1017    
	s = splhi(); 
 
2000/0919    
	lock(r); 
	p = r->p; 
 
	if(p != nil){ 
		lock(&p->rlock); 
		if(p->state != Wakeme || p->r != r) 
1991/0705    
			panic("wakeup: state"); 
2000/0919    
		r->p = nil; 
		p->r = nil; 
1990/0227    
		ready(p); 
2000/0919    
		unlock(&p->rlock); 
1990/0227    
	} 
2000/0919    
	unlock(r); 
 
1990/0227    
	splx(s); 
1997/0220    
 
2001/0529    
	return p; 
1990/03091    
} 
 
2000/0919    
/* 
 *  if waking a sleeping process, this routine must hold both 
 *  p->rlock and r->lock.  However, it can't know them in 
 *  the same order as wakeup causing a possible lock ordering 
 *  deadlock.  We break the deadlock by giving up the p->rlock 
 *  lock if we can't get the r->lock and retrying. 
 */ 
1990/0227    
int 
postnote(Proc *p, int dolock, char *n, int flag) 
{ 
1991/1120    
	int s, ret; 
1990/0227    
	Rendez *r; 
1991/0806    
	Proc *d, **l; 
1990/0227    
 
	if(dolock) 
1991/1216    
		qlock(&p->debug); 
1991/0430    
 
1993/0501    
	if(flag != NUser && (p->notify == 0 || p->notified)) 
		p->nnote = 0; 
1991/0425    
 
1991/1120    
	ret = 0; 
1993/0501    
	if(p->nnote < NNOTE) { 
1996/0626    
		strcpy(p->note[p->nnote].msg, n); 
1993/0501    
		p->note[p->nnote++].flag = flag; 
1991/1120    
		ret = 1; 
1990/0617    
	} 
1991/0727    
	p->notepending = 1; 
1990/0227    
	if(dolock) 
1991/1216    
		qunlock(&p->debug); 
1991/0705    
 
2000/0919    
	/* this loop is to avoid lock ordering problems. */ 
	for(;;){ 
		s = splhi(); 
		lock(&p->rlock); 
		r = p->r; 
 
		/* waiting for a wakeup? */ 
		if(r == nil) 
			break;	/* no */ 
 
		/* try for the second lock */ 
		if(canlock(r)){ 
			if(p->state != Wakeme || r->p != p) 
				panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state); 
			p->r = nil; 
			r->p = nil; 
			ready(p); 
			unlock(r); 
			break; 
		} 
 
		/* give other process time to get out of critical section and try again */ 
		unlock(&p->rlock); 
		splx(s); 
		sched(); 
1990/0227    
	} 
1996/1017    
	unlock(&p->rlock); 
	splx(s); 
1991/0807    
 
1992/1206    
	if(p->state != Rendezvous) 
		return ret; 
 
	/* Try and pull out of a rendezvous */ 
1994/0812    
	lock(p->rgrp); 
1991/0806    
	if(p->state == Rendezvous) { 
1992/1206    
		p->rendval = ~0; 
1994/0812    
		l = &REND(p->rgrp, p->rendtag); 
1992/1206    
		for(d = *l; d; d = d->rendhash) { 
			if(d == p) { 
				*l = p->rendhash; 
				break; 
1991/0806    
			} 
1992/1206    
			l = &d->rendhash; 
1991/0806    
		} 
1993/0501    
		ready(p); 
1991/0806    
	} 
1994/0812    
	unlock(p->rgrp); 
1991/1120    
	return ret; 
1990/0227    
} 
 
1990/1101    
/* 
 * weird thing: keep at most NBROKEN around 
 */ 
#define	NBROKEN 4 
1992/1206    
struct 
{ 
	QLock; 
1990/1101    
	int	n; 
	Proc	*p[NBROKEN]; 
}broken; 
 
1990/0227    
void 
1992/1206    
addbroken(Proc *p) 
1990/1101    
{ 
1992/1206    
	qlock(&broken); 
	if(broken.n == NBROKEN) { 
1990/1101    
		ready(broken.p[0]); 
1991/0318    
		memmove(&broken.p[0], &broken.p[1], sizeof(Proc*)*(NBROKEN-1)); 
1990/1101    
		--broken.n; 
	} 
1992/1206    
	broken.p[broken.n++] = p; 
	qunlock(&broken); 
 
2002/0704    
	if (edf->isedf(up)) 
		edf->edfbury(up); 
1992/1206    
	p->state = Broken; 
	p->psstate = 0; 
	sched(); 
1990/1101    
} 
 
1992/1206    
void 
unbreak(Proc *p) 
{ 
	int b; 
 
	qlock(&broken); 
1992/1208    
	for(b=0; b < broken.n; b++) 
1992/1225    
		if(broken.p[b] == p) { 
1992/1208    
			broken.n--; 
			memmove(&broken.p[b], &broken.p[b+1], 
					sizeof(Proc*)*(NBROKEN-(b+1))); 
			ready(p); 
			break; 
		} 
1992/1206    
	qunlock(&broken); 
} 
 
1990/1101    
int 
freebroken(void) 
{ 
1991/0109    
	int i, n; 
1990/1101    
 
1992/1206    
	qlock(&broken); 
1990/1101    
	n = broken.n; 
1992/1206    
	for(i=0; i<n; i++) { 
1991/0109    
		ready(broken.p[i]); 
1992/1206    
		broken.p[i] = 0; 
	} 
1991/0109    
	broken.n = 0; 
1992/1206    
	qunlock(&broken); 
1990/1101    
	return n; 
} 
 
void 
1991/0717    
pexit(char *exitstr, int freemem) 
1990/0227    
{ 
1993/0501    
	Proc *p; 
1992/1206    
	Segment **s, **es; 
1993/0501    
	long utime, stime; 
1991/0926    
	Waitq *wq, *f, *next; 
1997/1104    
	Fgrp *fgrp; 
2000/0331    
	Egrp *egrp; 
	Rgrp *rgrp; 
	Pgrp *pgrp; 
	Chan *dot; 
1990/0227    
 
1993/0501    
	up->alarm = 0; 
1991/0517    
 
2000/0331    
	/* nil out all the resources under lock (free later) */ 
	qlock(&up->debug); 
	fgrp = up->fgrp; 
	up->fgrp = nil; 
	egrp = up->egrp; 
	up->egrp = nil; 
	rgrp = up->rgrp; 
	up->rgrp = nil; 
	pgrp = up->pgrp; 
	up->pgrp = nil; 
	dot = up->dot; 
2000/0325    
	up->dot = nil; 
2000/0331    
	qunlock(&up->debug); 
 
	if(fgrp) 
		closefgrp(fgrp); 
	if(egrp) 
		closeegrp(egrp); 
	if(rgrp) 
		closergrp(rgrp); 
	if(dot) 
		cclose(dot); 
	if(pgrp) 
		closepgrp(pgrp); 
1993/0501    
 
1992/0115    
	/* 
	 * if not a kernel process and have a parent, 
	 * do some housekeeping. 
	 */ 
1993/0501    
	if(up->kp == 0) { 
		p = up->parent; 
1992/1206    
		if(p == 0) { 
1992/0902    
			if(exitstr == 0) 
				exitstr = "unknown"; 
			panic("boot process died: %s", exitstr); 
		} 
1992/0805    
 
		while(waserror()) 
1993/0501    
			; 
1998/0512    
 
1992/0620    
		wq = smalloc(sizeof(Waitq)); 
1992/0805    
		poperror(); 
 
2001/0819    
		wq->w.pid = up->pid; 
2002/0501    
		utime = up->time[TUser] + up->time[TCUser]; 
		stime = up->time[TSys] + up->time[TCSys]; 
2002/0710    
		wq->w.time[TUser] = tk2ms(utime); 
		wq->w.time[TSys] = tk2ms(stime); 
		wq->w.time[TReal] = tk2ms(MACHP(0)->ticks - up->time[TReal]); 
2001/0819    
		if(exitstr && exitstr[0]) 
			snprint(wq->w.msg, sizeof(wq->w.msg), "%s %lud: %s", up->text, up->pid, exitstr); 
1992/1206    
		else 
1991/1006    
			wq->w.msg[0] = '\0'; 
 
1991/1005    
		lock(&p->exl); 
1996/1016    
		/* 
		 *  If my parent is no longer alive, or if there would be more 
		 *  than 128 zombie child processes for my parent, then don't 
		 *  leave a wait record behind.  This helps prevent badly 
		 *  written daemon processes from accumulating lots of wait 
		 *  records. 
1992/0620    
		 */ 
1998/0512    
		if(p->pid == up->parentpid && p->state != Broken && p->nwait < 128) { 
1991/1005    
			p->nchild--; 
1992/0205    
			p->time[TCUser] += utime; 
			p->time[TCSys] += stime; 
1998/0512    
 
1991/1005    
			wq->next = p->waitq; 
			p->waitq = wq; 
			p->nwait++; 
1998/0512    
 
1991/1005    
			wakeup(&p->waitr); 
1996/1016    
			unlock(&p->exl); 
1991/1005    
		} 
		else { 
			unlock(&p->exl); 
1992/0620    
			free(wq); 
1991/1005    
		} 
1990/0227    
	} 
1990/03081    
 
1991/0926    
	if(!freemem) 
1993/0501    
		addbroken(up); 
1990/03081    
 
1999/0108    
	qlock(&up->seglock); 
1993/0501    
	es = &up->seg[NSEG]; 
1995/0104    
	for(s = up->seg; s < es; s++) { 
		if(*s) { 
1992/1206    
			putseg(*s); 
1995/0104    
			*s = 0; 
		} 
	} 
1999/0108    
	qunlock(&up->seglock); 
1991/0926    
 
1993/0501    
	lock(&up->exl);		/* Prevent my children from leaving waits */ 
2001/0510    
	pidunhash(up); 
1993/0501    
	up->pid = 0; 
1996/0121    
	wakeup(&up->waitr); 
1993/0501    
	unlock(&up->exl); 
1991/0926    
 
1993/0501    
	for(f = up->waitq; f; f = next) { 
1991/0926    
		next = f->next; 
1992/0620    
		free(f); 
1991/0926    
	} 
 
1991/1110    
	/* release debuggers */ 
1995/0104    
	qlock(&up->debug); 
1993/0501    
	if(up->pdbg) { 
		wakeup(&up->pdbg->sleep); 
		up->pdbg = 0; 
1991/1110    
	} 
1995/0104    
	qunlock(&up->debug); 
1991/1110    
 
1998/0605    
	/* Sched must not loop for these locks */ 
1991/1110    
	lock(&procalloc); 
1995/1230    
	lock(&palloc); 
1991/0705    
 
2002/0704    
	if (edf->isedf(up)) 
		edf->edfbury(up); 
1993/0501    
	up->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) 
{ 
	ulong cpid; 
1991/0926    
	Waitq *wq; 
1990/0227    
 
1993/0501    
	if(!canqlock(&up->qwaitr)) 
1993/0309    
		error(Einuse); 
 
	if(waserror()) { 
1993/0501    
		qunlock(&up->qwaitr); 
1993/0309    
		nexterror(); 
	} 
 
1993/0501    
	lock(&up->exl); 
	if(up->nchild == 0 && up->waitq == 0) { 
		unlock(&up->exl); 
1991/0926    
		error(Enochild); 
1990/0227    
	} 
1993/0501    
	unlock(&up->exl); 
1991/0926    
 
1993/0501    
	sleep(&up->waitr, haswaitq, up); 
1991/0926    
 
1993/0501    
	lock(&up->exl); 
	wq = up->waitq; 
	up->waitq = wq->next; 
	up->nwait--; 
	unlock(&up->exl); 
1993/0309    
 
1993/0501    
	qunlock(&up->qwaitr); 
1993/0309    
	poperror(); 
1991/0926    
 
1990/0227    
	if(w) 
1991/0926    
		memmove(w, &wq->w, sizeof(Waitmsg)); 
2001/0819    
	cpid = wq->w.pid; 
1992/0620    
	free(wq); 
1990/0227    
	return cpid; 
} 
 
Proc* 
proctab(int i) 
{ 
	return &procalloc.arena[i]; 
} 
 
1990/1220    
void 
1995/1030    
dumpaproc(Proc *p) 
{ 
	ulong bss; 
	char *s; 
 
	if(p == 0) 
		return; 
 
	bss = 0; 
	if(p->seg[BSEG]) 
		bss = p->seg[BSEG]->top; 
 
	s = p->psstate; 
	if(s == 0) 
2001/0217    
		s = statename[p->state]; 
2002/0404    
	print("%3lud:%10s pc %8lux dbgpc %8lux  %8s (%s) ut %ld st %ld bss %lux qpc %lux nl %lud nd %lud lpc %lux\n", 
1995/1030    
		p->pid, p->text, p->pc, dbgpc(p),  s, statename[p->state], 
2002/0404    
		p->time[0], p->time[1], bss, p->qpc, p->nlocks, p->delaysched, p->lastlock ? p->lastlock->pc : 0); 
1995/1030    
} 
 
void 
1991/0608    
procdump(void) 
1990/0227    
{ 
1990/0330    
	int i; 
1990/0227    
	Proc *p; 
 
1995/1009    
	if(up) 
1998/0825    
		print("up %lud\n", up->pid); 
1995/1009    
	else 
		print("no current process\n"); 
1993/0501    
	for(i=0; i<conf.nproc; i++) { 
		p = &procalloc.arena[i]; 
		if(p->state == Dead) 
			continue; 
1992/0805    
 
1995/1030    
		dumpaproc(p); 
1994/0728    
	} 
1995/1030    
} 
 
1998/0725    
/* 
 *  wait till all processes have flushed their mmu 
 *  state about segement s 
 */ 
void 
procflushseg(Segment *s) 
{ 
	int i, ns, nm, nwait; 
	Proc *p; 
 
	/* 
	 *  tell all processes with this 
	 *  segment to flush their mmu's 
	 */ 
	nwait = 0; 
	for(i=0; i<conf.nproc; i++) { 
		p = &procalloc.arena[i]; 
		if(p->state == Dead) 
			continue; 
		for(ns = 0; ns < NSEG; ns++) 
			if(p->seg[ns] == s){ 
				p->newtlb = 1; 
				for(nm = 0; nm < conf.nmach; nm++){ 
					if(MACHP(nm)->proc == p){ 
						MACHP(nm)->flushmmu = 1; 
						nwait++; 
					} 
				} 
				break; 
			} 
	} 
 
	if(nwait == 0) 
		return; 
 
	/* 
	 *  wait for all processors to take a clock interrupt 
	 *  and flush their mmu's 
	 */ 
	for(nm = 0; nm < conf.nmach; nm++) 
		if(MACHP(nm) != m) 
			while(MACHP(nm)->flushmmu) 
				sched(); 
} 
 
1995/1030    
void 
scheddump(void) 
{ 
	Proc *p; 
	Schedq *rq; 
 
1995/0110    
	for(rq = &runq[Nrq-1]; rq >= runq; rq--){ 
		if(rq->head == 0) 
			continue; 
1998/0825    
		print("rq%ld:", rq-runq); 
1995/0110    
		for(p = rq->head; p; p = p->rnext) 
1998/0825    
			print(" %lud(%lud, %lud)", p->pid, m->ticks - p->readytime, 
1999/0811    
				MACHP(0)->ticks - p->movetime); 
1994/0728    
		print("\n"); 
1995/1030    
		delay(150); 
1990/0227    
	} 
1995/0110    
	print("nrdy %d\n", nrdy); 
1990/0227    
} 
 
void 
kproc(char *name, void (*func)(void *), void *arg) 
{ 
	Proc *p; 
1990/0722    
	static Pgrp *kpgrp; 
1990/0227    
 
	p = newproc(); 
2001/0527    
	p->psstate = 0; 
	p->procmode = 0640; 
1990/1212    
	p->kp = 1; 
2002/0502    
	p->noswap = 1; 
1990/0227    
 
1993/0501    
	p->fpsave = up->fpsave; 
	p->scallnr = up->scallnr; 
	p->s = up->s; 
	p->nerrlab = 0; 
	p->slash = up->slash; 
	p->dot = up->dot; 
	incref(p->dot); 
1990/0227    
 
1993/0501    
	memmove(p->note, up->note, sizeof(p->note)); 
	p->nnote = up->nnote; 
	p->notified = 0; 
	p->lastnote = up->lastnote; 
	p->notify = up->notify; 
	p->ureg = 0; 
	p->dbgreg = 0; 
1994/0920    
 
1995/0110    
	p->basepri = PriKproc; 
	p->priority = p->basepri; 
1990/0227    
 
1993/0501    
	kprocchild(p, func, arg); 
1991/0705    
 
2001/0527    
	kstrdup(&p->user, eve); 
	kstrdup(&p->text, name); 
1993/0501    
	if(kpgrp == 0) 
1990/0722    
		kpgrp = newpgrp(); 
	p->pgrp = kpgrp; 
	incref(kpgrp); 
1991/0705    
 
1990/0227    
	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. 
	 */ 
2000/1018    
	p->newtlb = 1; 
1990/0227    
	flushmmu(); 
1991/0705    
} 
 
1992/0609    
/* 
 *  called splhi() by notify().  See comment in notify for the 
 *  reasoning. 
 */ 
1991/0705    
void 
procctl(Proc *p) 
{ 
1991/1108    
	char *state; 
1995/0112    
	ulong s; 
1991/1108    
 
1991/0705    
	switch(p->procctl) { 
1995/0215    
	case Proc_exitbig: 
		spllo(); 
		pexit("Killed: Insufficient physical memory", 1); 
 
1991/0705    
	case Proc_exitme: 
1993/0501    
		spllo();		/* pexit has locks in it */ 
1991/0705    
		pexit("Killed", 1); 
1992/0620    
 
1991/1110    
	case Proc_traceme: 
1993/0501    
		if(p->nnote == 0) 
1991/1110    
			return; 
		/* No break */ 
1992/0620    
 
1991/0705    
	case Proc_stopme: 
		p->procctl = 0; 
1991/1108    
		state = p->psstate; 
		p->psstate = "Stopped"; 
1991/1110    
		/* free a waiting debugger */ 
1995/0112    
		s = spllo(); 
1991/1216    
		qlock(&p->debug); 
1991/1110    
		if(p->pdbg) { 
			wakeup(&p->pdbg->sleep); 
			p->pdbg = 0; 
		} 
1991/1216    
		qunlock(&p->debug); 
1995/0105    
		splhi(); 
1991/0705    
		p->state = Stopped; 
2002/0704    
		if (edf->isedf(up)) 
			edf->edfblock(up); 
1995/0112    
		sched(); 
1991/1108    
		p->psstate = state; 
1995/0112    
		splx(s); 
1991/0705    
		return; 
	} 
1990/0227    
} 
1991/0710    
 
#include "errstr.h" 
 
void 
1992/0604    
error(char *err) 
1991/0710    
{ 
1995/0110    
	spllo(); 
2001/0924    
	kstrcpy(up->errstr, err, ERRMAX); 
2002/0413    
	setlabel(&up->errlab[NERR-1]); 
1991/0710    
	nexterror(); 
} 
 
void 
1992/0114    
nexterror(void) 
1991/0710    
{ 
1993/0501    
	gotolabel(&up->errlab[--up->nerrlab]); 
1991/0710    
} 
 
void 
1992/0114    
exhausted(char *resource) 
1991/0710    
{ 
2001/0527    
	char buf[ERRMAX]; 
1992/0114    
 
	sprint(buf, "no free %s", resource); 
1997/0327    
	iprint("%s\n", buf); 
1992/0114    
	error(buf); 
1991/0926    
} 
1993/1123    
 
void 
killbig(void) 
{ 
	int i; 
	Segment *s; 
	ulong l, max; 
	Proc *p, *ep, *kp; 
 
	max = 0; 
	kp = 0; 
	ep = procalloc.arena+conf.nproc; 
	for(p = procalloc.arena; p < ep; p++) { 
		if(p->state == Dead || p->kp) 
			continue; 
		l = 0; 
1994/0325    
		for(i=1; i<NSEG; i++) { 
1993/1123    
			s = p->seg[i]; 
1995/0104    
			if(s != 0) 
1993/1123    
				l += s->top - s->base; 
		} 
2002/0506    
		if(l > max && strcmp(p->text, "kfs") != 0){ 
1993/1123    
			kp = p; 
			max = l; 
		} 
	} 
1995/0215    
	kp->procctl = Proc_exitbig; 
1995/0104    
	for(i = 0; i < NSEG; i++) { 
		s = kp->seg[i]; 
		if(s != 0 && canqlock(&s->lk)) { 
			mfreeseg(s, s->base, (s->top - s->base)/BY2PG); 
			qunlock(&s->lk); 
		} 
	} 
1998/0825    
	print("%lud: %s killed because no swap configured\n", kp->pid, kp->text); 
1993/1123    
} 
1994/1027    
 
/* 
 *  change ownership to 'new' of all processes owned by 'old'.  Used when 
 *  eve changes. 
 */ 
void 
renameuser(char *old, char *new) 
{ 
	Proc *p, *ep; 
 
	ep = procalloc.arena+conf.nproc; 
	for(p = procalloc.arena; p < ep; p++) 
2001/0527    
		if(p->user!=nil && strcmp(old, p->user)==0) 
			kstrdup(&p->user, new); 
1995/0104    
} 
 
/* 
 *  time accounting called by clock() splhi'd 
 */ 
void 
accounttime(void) 
{ 
	Proc *p; 
2002/0822    
	ulong n, per; 
2002/0821    
	static ulong nrun; 
1995/0104    
 
	p = m->proc; 
	if(p) { 
		nrun++; 
		p->time[p->insyscall]++; 
	} 
 
2002/0822    
	/* calculate decaying duty cycles */ 
	n = perfticks(); 
	per = n - m->perf.last; 
	m->perf.last = n; 
	if(per == 0) 
		per = 1; 
	m->perf.period = (m->perf.period*(HZ-1)+per)/HZ; 
 
	m->perf.avg_inidle = (m->perf.avg_inidle*(HZ-1)+m->perf.inidle)/HZ; 
	m->perf.inidle = 0; 
 
	m->perf.avg_inintr = (m->perf.avg_inintr*(HZ-1)+m->perf.inintr)/HZ; 
	m->perf.inintr = 0; 
 
1995/0104    
	/* only one processor gets to compute system load averages */ 
	if(m->machno != 0) 
		return; 
 
	/* calculate decaying load average */ 
1995/0110    
	n = nrun; 
1995/0104    
	nrun = 0; 
1995/0110    
	n = (nrdy+n)*1000; 
	m->load = (m->load*19+n)/20; 
2001/0510    
} 
 
static void 
pidhash(Proc *p) 
{ 
	int h; 
 
	h = p->pid % nelem(procalloc.ht); 
	lock(&procalloc); 
	p->pidhash = procalloc.ht[h]; 
	procalloc.ht[h] = p; 
	unlock(&procalloc); 
} 
 
static void 
pidunhash(Proc *p) 
{ 
	int h; 
	Proc **l; 
 
	h = p->pid % nelem(procalloc.ht); 
	lock(&procalloc); 
	for(l = &procalloc.ht[h]; *l != nil; l = &(*l)->pidhash) 
		if(*l == p){ 
			*l = p->pidhash; 
			break; 
		} 
	unlock(&procalloc); 
} 
 
int 
2001/0527    
procindex(ulong pid) 
2001/0510    
{ 
	Proc *p; 
	int h; 
	int s; 
 
	s = -1; 
	h = pid % nelem(procalloc.ht); 
	lock(&procalloc); 
	for(p = procalloc.ht[h]; p != nil; p = p->pidhash) 
		if(p->pid == pid){ 
			s = p - procalloc.arena; 
			break; 
		} 
	unlock(&procalloc); 
	return s; 
1994/1027    
} 


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