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

2000/0129/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    
 
1992/0309    
Ref	pidalloc; 
1992/0428    
Ref	noteidalloc; 
1990/0227    
 
struct 
{ 
	Lock; 
1997/0327    
	Proc*	arena; 
	Proc*	free; 
1990/0227    
}procalloc; 
 
1991/0926    
struct 
{ 
	Lock; 
1997/0327    
	Waitq*	free; 
1991/0926    
}waitqalloc; 
 
1994/0914    
typedef struct 
{ 
	Lock; 
1997/0327    
	Proc*	head; 
	Proc*	tail; 
1994/0914    
	int	n; 
} Schedq; 
1994/0728    
 
1995/0110    
int	nrdy; 
Schedq	runq[Nrq]; 
1991/0420    
 
1992/0309    
char *statename[] = 
{			/* 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", 
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; 
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; 
		up = 0; 
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) 
{ 
1993/0501    
	if(up) { 
1990/0227    
		splhi(); 
1993/1212    
 
		/* statistics */ 
1991/0425    
		m->cs++; 
1993/1212    
 
1993/0501    
		procsave(up); 
		if(setlabel(&up->sched)) { 
			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) 
{ 
1995/0110    
	return nrdy; 
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; 
	 
	return 0; 
1994/0809    
} 
 
1995/0110    
enum 
{ 
	Squantum = (HZ+Nrq-1)/Nrq, 
}; 
 
1990/0227    
void 
ready(Proc *p) 
{ 
1996/0523    
	int s, pri; 
1995/0110    
	Schedq *rq; 
1990/0227    
 
	s = splhi(); 
1991/0501    
 
1995/0110    
	/* history counts */ 
	if(p->state == Running){ 
1996/0516    
		p->rt++; 
		pri = ((p->art + (p->rt<<1))>>2)/Squantum; 
1995/0110    
	} else { 
		p->art = (p->art + (p->rt<<1))>>2; 
		p->rt = 0; 
		pri = p->art/Squantum; 
	} 
1996/0523    
	pri = p->basepri - pri; 
1995/0110    
	if(pri < 0) 
		pri = 0; 
 
	/* the only intersection between the classes is at PriNormal */ 
1996/0523    
	if(pri < PriNormal && p->basepri > PriNormal) 
1995/0110    
		pri = PriNormal; 
1996/0516    
 
1998/0606    
	/* stick at low priority any process waiting for a lock */ 
	if(p->lockwait) 
		pri = PriLock; 
 
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; 
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/0327    
		idlehands(); 
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    
			} 
		} 
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){ 
1999/0811    
		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); 
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; 
	p->pgrp = 0; 
	p->egrp = 0; 
	p->fgrp = 0; 
1994/0812    
	p->rgrp = 0; 
1993/0501    
	p->pdbg = 0; 
	p->fpstate = FPinit; 
	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; 
1996/0426    
	p->error[0] = '\0'; 
1993/0501    
	memset(p->seg, 0, sizeof p->seg); 
	p->pid = incref(&pidalloc); 
	p->noteid = incref(¬eidalloc); 
	if(p->pid==0 || p->noteid==0) 
		panic("pidalloc"); 
	if(p->kstack == 0) 
		p->kstack = smalloc(KSTACK); 
 
	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) 
		panic("cannot allocate %d 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    
 
/* 
 *  Sleep, postnote, and wakeup are complicated by the 
1998/0724    
 *  fact that at least one of them must indirect 
1998/0514    
 *  through an unlocked structure to find the synchronizing 
 *  lock structure.  This is because sleep() 
 *  and wakeup() share direct knowledge only of r while 
 *  sleep() and postnote() share knowledge only of p.  We've 
 *  chosen to put the synchronization lock in p, i.e., 
 *  p->rlock.  Therefore the interaction between sleep() 
 *  and postnote() is completely synchronized by keeping 
 *  p->rlock locked in sleep until the process has 
 *  saved all the information it needs to become dormant. 
 * 
 *  However, wakeup() can only find what process is sleeping 
 *  by looking at r->p.  A wakeup looks like: 
 * 
 *	1) set condition that sleep checks with (*f)() 
 *	2) is p = r->p non zero 
 *	3) lock(p->rlock) 
 *	4) check r->p == p 
 *	5) ... 
 * 
 *  A sleep looks like 
 * 
 *	a) lock(p->rlock) 
 *	b) r->p = up 
 *	c) check condition 
 *	d) ... 
 * 
 *  On a multiprocessor, two processors 
 *  may not see writes occur in the same order.  The coherence() 
 *  instruction ensures that a processor has flushed all its 
 *  writes to memory so that those writes will be seen by other 
 *  processors and that the processor will see all writes flushed 
 *  by other processors. 
 * 
 *  To make the above sequence work on a multiprocessor, we need 
 *  to put a coherence() call between (1) and (2) and between 
 *  (b) and (c).  That way we're guaranteed that if (1) and 
 *  (2) occur after (c), the wakeup process will know 
 *  which process is about to sleep and will enter its 
 *  critical section.  If it doesn't, the sleep could proceed 
 *  while the waker returns without doing anything. 
 *  Similarly, if (b) and (c) occur after (2), 
 *  the sleeper needs coherence to see that the condition was 
 *  set.  Otherwise it could sleep even though the wakeup 
 *  had already decided there was nothing to do. 
 * 
 *	jmk & presotto 
 */ 
1990/0227    
void 
1998/0513    
sleep(Rendez *r, int (*f)(void*), void *arg) 
1990/0227    
{ 
	int s; 
 
	s = splhi(); 
1998/0513    
 
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; 
	coherence(); 
 
	if((*f)(arg) || up->notepending){ 
		/* 
		 *  if condition happened or a note is pending 
		 *  never mind 
		 */ 
		r->p = nil; 
1996/1016    
		unlock(&up->rlock); 
1998/0513    
	} else { 
		/* 
		 *  now we are committed to 
		 *  change state and call scheduler 
		 */ 
		up->state = Wakeme; 
		up->r = r; 
 
		/* statistics */ 
		m->cs++; 
	 
		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); 
			gotolabel(&m->sched); 
		} 
1990/0227    
	} 
 
1993/0501    
	if(up->notepending) { 
		up->notepending = 0; 
1992/0519    
		splx(s); 
1990/11211    
		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    
 
2000/0116    
	/* avoid overflows at the cost of precision */ 
2000/0115    
	if(ms >= 1000000) 
		when = ms/(1000/HZ); 
	else 
		when = MS2TK(ms); 
	when += 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    
/* 
 * Expects that only one process can call wakeup for any given Rendez 
 */ 
1997/0220    
int 
1990/0227    
wakeup(Rendez *r) 
{ 
	Proc *p; 
1997/0220    
	int s, rv; 
1990/0227    
 
1998/0514    
	/* 
	 *  this makes sure that the condition sleep checks 
	 *  with its (*f)(void) is visible to it 
	 */ 
	coherence(); 
1997/0220    
 
	rv = 0; 
1990/0227    
	p = r->p; 
1996/1017    
	if(p == 0) 
1997/0220    
		return rv; 
1996/1017    
 
	s = splhi(); 
	lock(&p->rlock); 
 
	if(r->p == p && p->r == r){ 
1990/0227    
		r->p = 0; 
1998/0512    
		if(p->state != Wakeme) 
1991/0705    
			panic("wakeup: state"); 
1990/0227    
		p->r = 0; 
		ready(p); 
1997/0220    
		rv = 1; 
1990/0227    
	} 
1996/1017    
 
	unlock(&p->rlock); 
1990/0227    
	splx(s); 
1997/0220    
 
	return rv; 
1990/03091    
} 
 
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/0112    
	if(p->kp) 
1998/0825    
		print("sending %s to kproc %lud %s\n", n, p->pid, p->text); 
1993/0112    
 
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    
 
1996/1017    
	s = splhi(); 
	lock(&p->rlock); 
	r = p->r; 
	if(r){ 
		if(r->p != p || p->r != r || p->state != Wakeme) 
1998/0512    
			panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state); 
1996/1017    
		r->p = 0; 
		p->r = 0; 
		ready(p); 
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); 
 
	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    
{ 
1991/1218    
	int n; 
1993/0501    
	Proc *p; 
1992/1206    
	Segment **s, **es; 
1993/0501    
	long utime, stime; 
1991/0926    
	Waitq *wq, *f, *next; 
1997/1104    
	Fgrp *fgrp; 
1990/0227    
 
1993/0501    
	up->alarm = 0; 
1991/0517    
 
1997/1104    
	if(up->fgrp){ 
1998/0425    
		qlock(&up->debug); 
1997/1104    
		fgrp = up->fgrp; 
		up->fgrp = nil; 
		closefgrp(fgrp); 
1998/0425    
		qunlock(&up->debug); 
1997/1104    
	} 
1993/0501    
	if(up->egrp) 
		closeegrp(up->egrp); 
1994/0812    
	if(up->rgrp) 
		closergrp(up->rgrp); 
1991/0517    
 
1997/0327    
	cclose(up->dot); 
1993/0501    
	closepgrp(up->pgrp); 
 
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(); 
 
1993/0501    
		readnum(0, wq->w.pid, NUMSIZE, up->pid, NUMSIZE); 
		utime = up->time[TUser] + up->time[TCUser]; 
		stime = up->time[TSys] + up->time[TCSys]; 
1992/0309    
		readnum(0, &wq->w.time[TUser*12], NUMSIZE, 
			TK2MS(utime), NUMSIZE); 
		readnum(0, &wq->w.time[TSys*12], NUMSIZE, 
			TK2MS(stime), NUMSIZE); 
		readnum(0, &wq->w.time[TReal*12], NUMSIZE, 
1993/0501    
			TK2MS(MACHP(0)->ticks - up->time[TReal]), NUMSIZE); 
1991/1218    
		if(exitstr && exitstr[0]){ 
1998/0825    
			n = sprint(wq->w.msg, "%s %lud:", up->text, up->pid); 
1991/1218    
			strncpy(wq->w.msg+n, exitstr, ERRLEN-n); 
1995/0329    
			wq->w.msg[ERRLEN-1] = 0; 
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 */ 
	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    
 
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)); 
1992/0309    
	cpid = atoi(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) 
		s = "kproc"; 
1999/0110    
	print("%3lud:%10s pc %8lux dbgpc %8lux  %8s (%s) ut %ld st %ld bss %lux qpc %lux\n", 
1995/1030    
		p->pid, p->text, p->pc, dbgpc(p),  s, statename[p->state], 
1999/0110    
		p->time[0], p->time[1], bss, p->qpc); 
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); 
		delay(150); 
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(); 
1991/0926    
	p->psstate = 0; 
1991/1112    
	p->procmode = 0644; 
1990/1212    
	p->kp = 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    
 
1993/0501    
	strcpy(p->user, eve); 
	if(kpgrp == 0) 
1990/0722    
		kpgrp = newpgrp(); 
	p->pgrp = kpgrp; 
	incref(kpgrp); 
1991/0705    
 
1992/0703    
	strcpy(p->text, name); 
1991/0705    
 
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    
} 
 
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; 
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(); 
1993/0501    
	strncpy(up->error, err, ERRLEN); 
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    
{ 
1992/0114    
	char buf[ERRLEN]; 
 
	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; 
		} 
		if(l > max) { 
			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++) 
		if(strcmp(old, p->user) == 0) 
			memmove(p->user, new, NAMELEN); 
1995/0104    
} 
 
/* 
 *  time accounting called by clock() splhi'd 
 */ 
void 
accounttime(void) 
{ 
	Proc *p; 
1995/0110    
	int n; 
	static int nrun; 
1995/0104    
 
	p = m->proc; 
	if(p) { 
		nrun++; 
		p->time[p->insyscall]++; 
	} 
 
	/* 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; 
1994/1027    
} 


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