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

1991/1109/port/devproc.c (diff list | history)

port/devproc.c on 1990/0227
1990/0227    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"errno.h" 
1991/1109    
#include	"fcall.h" 
1990/0227    
 
#include	"devtab.h" 
 
enum{ 
	Qdir, 
	Qctl, 
	Qmem, 
	Qnote, 
1990/1110    
	Qnotepg, 
1990/0227    
	Qproc, 
1991/0705    
	Qsegment, 
1990/0227    
	Qstatus, 
	Qtext, 
}; 
 
1991/0712    
#define	STATSIZE	(2*NAMELEN+12+6*12) 
1990/0227    
Dirtab procdir[]={ 
1991/1109    
	"ctl",		{Qctl},		0,			0000, 
	"mem",		{Qmem},		0,			0000, 
	"note",		{Qnote},	0,			0000, 
1990/11211    
	"notepg",	{Qnotepg},	0,			0200, 
1991/1109    
	"proc",		{Qproc},	sizeof(Proc),		0000, 
1991/0705    
	"segment",	{Qsegment},	0,			0400, 
1991/0807    
	"status",	{Qstatus},	STATSIZE,		0400, 
1991/1109    
	"text",		{Qtext},	0,			0000, 
1990/0227    
}; 
 
1991/1109    
/* Segment type from portdat.h */ 
char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys" }; 
1991/0705    
 
1990/0227    
/* 
1990/11211    
 * Qids are, in path: 
1990/0227    
 *	 4 bits of file type (qids above) 
1990/1128    
 *	23 bits of process slot number + 1 
1990/11211    
 *	     in vers, 
 *	32 bits of pid, for consistency checking 
 * If notepg, c->pgrpid.path is pgrp slot, .vers is pgrpid. 
1990/0227    
 */ 
#define	NPROC	(sizeof procdir/sizeof(Dirtab)) 
#define	QSHIFT	4	/* location in qid of proc slot # */ 
1990/11211    
#define	QID(q)	(((q).path&0x0000000F)>>0) 
1990/1128    
#define	SLOT(q)	((((q).path&0x07FFFFFF0)>>QSHIFT)-1) 
1990/11211    
#define	PID(q)	((q).vers) 
1990/0227    
 
1991/1109    
void	procctlreq(Proc*, char*, int); 
int	procctlmemio(Proc*, ulong, int, void*, int); 
Chan   *procctlnotepg(Chan*, void *va, int n); 
 
1990/0227    
int 
procgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) 
{ 
	Proc *p; 
	char buf[NAMELEN]; 
1991/1109    
	ulong pid, path, perm; 
1990/0227    
 
1990/11211    
	if(c->qid.path == CHDIR){ 
1990/0227    
		if(s >= conf.nproc) 
			return -1; 
		p = proctab(s); 
		pid = p->pid; 
		if(pid == 0) 
			return 0; 
		sprint(buf, "%d", pid); 
1991/1109    
		devdir(c, (Qid){CHDIR|((s+1)<<QSHIFT), pid}, buf, 0, p->user, CHDIR|0500, dp); 
1990/0227    
		return 1; 
	} 
	if(s >= NPROC) 
		return -1; 
	if(tab) 
		panic("procgen"); 
	tab = &procdir[s]; 
1991/0705    
	path = c->qid.path&~(CHDIR|((1<<QSHIFT)-1));	/* slot component */ 
1991/1109    
 
	p = proctab(SLOT(c->qid)); 
	perm = tab->perm; 
	if(perm == 0) 
		perm = p->procmode; 
 
	devdir(c, (Qid){path|tab->qid.path, c->qid.vers}, tab->name, tab->length, p->user, perm, dp); 
1990/0227    
	return 1; 
} 
 
void 
procinit(void) 
{ 
	if(conf.nproc >= (1<<(16-QSHIFT))-1) 
		print("warning: too many procs for devproc\n"); 
} 
 
void 
procreset(void) 
{ 
} 
 
Chan* 
procattach(char *spec) 
{ 
1990/03081    
	Chan *c; 
1990/0227    
	return devattach('p', spec); 
} 
 
Chan* 
procclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
 
int 
procwalk(Chan *c, char *name) 
{ 
1991/1106    
	if(strcmp(name, "..") == 0) { 
1991/1011    
		c->qid.path = Qdir|CHDIR; 
		return 1; 
	} 
 
1990/0227    
	return devwalk(c, name, 0, 0, procgen); 
} 
 
void 
procstat(Chan *c, char *db) 
{ 
	devstat(c, db, 0, 0, procgen); 
} 
 
Chan * 
procopen(Chan *c, int omode) 
{ 
	Proc *p; 
1990/1110    
	Pgrp *pg; 
1991/0705    
	Segment *s; 
1990/0227    
	Chan *tc; 
 
1990/11211    
	if(c->qid.path == CHDIR){ 
1990/03081    
		if(omode != OREAD) 
1990/11211    
			error(Eperm); 
1990/03081    
		goto done; 
	} 
1990/0227    
	p = proctab(SLOT(c->qid)); 
1990/1110    
	pg = p->pgrp; 
1990/11211    
	if(p->pid != PID(c->qid)) 
1990/0227    
    Died: 
1990/11211    
		error(Eprocdied); 
1990/0227    
	omode = openmode(omode); 
 
	switch(QID(c->qid)){ 
	case Qtext: 
1991/0705    
		s = p->seg[TSEG]; 
		if(s==0 || p->state==Dead || s->image==0)  
1990/0227    
			goto Died; 
1991/0605    
 
1991/0705    
		tc = s->image->c; 
1990/0227    
		if(tc == 0) 
			goto Died; 
1991/0605    
 
1990/0227    
		if(incref(tc) == 0){ 
    Close: 
			close(tc); 
			goto Died; 
		} 
		if(!(tc->flag&COPEN) || tc->mode!=OREAD) 
			goto Close; 
1991/0605    
 
1990/11211    
		if(p->pid != PID(c->qid)) 
1990/0227    
			goto Close; 
1991/0605    
 
1990/0227    
		tc->offset = 0; 
		return tc; 
	case Qctl: 
	case Qnote: 
1991/0705    
	case Qsegment: 
1990/0227    
		break; 
1990/1110    
 
	case Qnotepg: 
1990/1115    
		if(omode!=OWRITE || pg->pgrpid==1)	/* easy to do by mistake */ 
1990/11211    
			error(Eperm); 
		c->pgrpid.path = pg->index+1; 
		c->pgrpid.vers = pg->pgrpid; 
1990/1110    
		break; 
 
1990/0227    
	case Qdir: 
1990/0614    
	case Qmem: 
1990/0227    
	case Qproc: 
	case Qstatus: 
1990/1110    
		if(omode != OREAD) 
1990/11211    
			error(Eperm); 
1990/0424    
		break; 
1990/0227    
	default: 
		pprint("unknown qid in devopen\n"); 
1990/11211    
		error(Egreg); 
1990/0227    
	} 
	/* 
	 * Affix pid to qid 
	 */ 
	if(p->state != Dead) 
1990/11211    
		c->qid.vers = p->pid; 
1990/03081    
   done: 
1990/0227    
	c->mode = omode; 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
} 
 
void 
proccreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1990/11211    
	error(Eperm); 
1990/0227    
} 
 
void 
procremove(Chan *c) 
{ 
1990/11211    
	error(Eperm); 
1990/0227    
} 
 
void 
procwstat(Chan *c, char *db) 
{ 
1991/1109    
	Proc *p; 
	Dir d; 
 
	convM2D(db, &d); 
	p = proctab(SLOT(c->qid)); 
	if(p->pid != PID(c->qid)) 
		error(Eprocdied); 
 
	if(strcmp(u->p->user, p->user) != 0 && strcmp(u->p->user, eve) != 0) 
		error(Eperm); 
 
	p->procmode = d.mode&0777; 
1990/0227    
} 
 
void 
procclose(Chan * c) 
{ 
} 
 
long 
1991/0411    
procread(Chan *c, void *va, long n, ulong offset) 
1990/0227    
{ 
	char *a = va, *b; 
1991/0705    
	char statbuf[NSEG*32]; 
1990/0227    
	Proc *p; 
	Page *pg; 
1990/0614    
	KMap *k; 
1991/0705    
	int i, j; 
1990/0227    
	long l; 
	long pid; 
	User *up; 
1991/0705    
	Segment *sg; 
1990/0227    
 
1990/11211    
	if(c->qid.path & CHDIR) 
1990/0227    
		return devdirread(c, a, n, 0, 0, procgen); 
 
	p = proctab(SLOT(c->qid)); 
1990/11211    
	if(p->pid != PID(c->qid)) 
		error(Eprocdied); 
1990/0227    
 
	switch(QID(c->qid)){ 
	case Qmem: 
		/* 
		 * One page at a time 
		 */ 
1991/0411    
		if(((offset+n)&~(BY2PG-1)) != (offset&~(BY2PG-1))) 
			n = BY2PG - (offset&(BY2PG-1)); 
1991/0705    
 
1991/1109    
		if(offset >= USERADDR && offset < USERADDR+BY2PG) { 
1991/0411    
			if(offset+n > USERADDR+BY2PG) 
				n = USERADDR+BY2PG - offset; 
1990/0227    
			pg = p->upage; 
1990/11211    
			if(pg==0 || p->pid!=PID(c->qid)) 
				error(Eprocdied); 
1990/0614    
			k = kmap(pg); 
			b = (char*)VA(k); 
1991/0411    
			memmove(a, b+(offset-USERADDR), n); 
1990/0614    
			kunmap(k); 
1990/0227    
			return n; 
		} 
 
1991/1109    
		if(offset >= KZERO && offset < KZERO+conf.npage0*BY2PG){ 
1991/0411    
			if(offset+n > KZERO+conf.npage0*BY2PG) 
				n = KZERO+conf.npage0*BY2PG - offset; 
			memmove(a, (char*)offset, n); 
1990/0914    
			return n; 
1990/0227    
		} 
1991/1109    
 
		if(offset >= KZERO && offset < KZERO+conf.base1+conf.npage1*BY2PG){ 
1991/1025    
			if(offset+n > KZERO+conf.base1+conf.npage1*BY2PG) 
				n = KZERO+conf.base1+conf.npage1*BY2PG - offset; 
			memmove(a, (char*)offset, n); 
			return n; 
		} 
1990/0227    
 
1991/1109    
		return procctlmemio(p, offset, n, va, 1); 
 
1990/0227    
	case Qnote: 
		lock(&p->debug); 
		if(waserror()){ 
			unlock(&p->debug); 
			nexterror(); 
		} 
1990/11211    
		if(p->pid != PID(c->qid)) 
			error(Eprocdied); 
1990/0614    
		k = kmap(p->upage); 
		up = (User*)VA(k); 
1990/0227    
		if(up->p != p){ 
1990/0614    
			kunmap(k); 
1990/0227    
			pprint("note read u/p mismatch"); 
1990/11211    
			error(Egreg); 
1990/0227    
		} 
		if(n < ERRLEN) 
1990/11211    
			error(Etoosmall); 
1990/0227    
		if(up->nnote == 0) 
			n = 0; 
		else{ 
1991/0318    
			memmove(va, up->note[0].msg, ERRLEN); 
1990/0227    
			up->nnote--; 
1991/0318    
			memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); 
1990/0227    
			n = ERRLEN; 
		} 
1990/0614    
		kunmap(k); 
1991/0614    
		poperror(); 
1990/0227    
		unlock(&p->debug); 
		return n; 
 
	case Qproc: 
1991/0411    
		if(offset >= sizeof(Proc)) 
1990/0227    
			return 0; 
1991/0411    
		if(offset+n > sizeof(Proc)) 
			n = sizeof(Proc) - offset; 
		memmove(a, ((char*)p)+offset, n); 
1990/0227    
		return n; 
 
	case Qstatus: 
1991/0712    
		if(offset >= STATSIZE) 
1990/0227    
			return 0; 
1991/0712    
		if(offset+n > STATSIZE) 
			n = STATSIZE - offset; 
		j = sprint(statbuf, "%-27s %-27s %-11s ", 
1991/1105    
			p->text, p->user, p->psstate ? p->psstate : statename[p->state]); 
1990/0227    
		for(i=0; i<6; i++){ 
			l = p->time[i]; 
			if(i == TReal) 
				l = MACHP(0)->ticks - l; 
1990/0614    
			l = TK2MS(l); 
1991/0712    
			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE); 
1990/0227    
		} 
1991/0411    
		memmove(a, statbuf+offset, n); 
1990/0227    
		return n; 
1991/0705    
	case Qsegment: 
		j = 0; 
		for(i = 0; i < NSEG; i++) 
			if(sg = p->seg[i]) 
				j += sprint(&statbuf[j], "%-6s %c %.8lux %.8lux %4d\n", 
				sname[sg->type&SG_TYPE], sg->type&SG_RONLY ? 'R' : ' ', 
				sg->base, sg->top, sg->ref); 
		if(offset >= j) 
			return 0; 
		if(offset+n > j) 
			n = j-offset; 
		memmove(a, &statbuf[offset], n); 
		return n; 
1990/0227    
	} 
1990/11211    
	error(Egreg); 
1990/0227    
} 
 
 
long 
1991/0411    
procwrite(Chan *c, void *va, long n, ulong offset) 
1990/0227    
{ 
	Proc *p; 
	User *up; 
1990/0614    
	KMap *k; 
1990/0227    
	char buf[ERRLEN]; 
 
1990/11211    
	if(c->qid.path & CHDIR) 
		error(Eisdir); 
1990/1110    
 
1990/1126    
	p = proctab(SLOT(c->qid)); 
1991/1109    
 
	/* Use the remembered pgrp id in the channel rather than the process pgrpid */ 
1990/1110    
	if(QID(c->qid) == Qnotepg){ 
1991/1109    
		procctlnotepg(c, va, n); 
1990/1110    
		return n; 
	} 
 
1990/0227    
	lock(&p->debug); 
	if(waserror()){ 
		unlock(&p->debug); 
		nexterror(); 
	} 
1990/11211    
	if(p->pid != PID(c->qid)) 
		error(Eprocdied); 
1990/0227    
 
	switch(QID(c->qid)){ 
1991/1109    
	case Qmem: 
		return procctlmemio(p, offset, n, va, 0); 
1990/0227    
	case Qctl: 
1991/1109    
		procctlreq(p, va, n); 
		return n; 
1990/0227    
	case Qnote: 
1990/0614    
		k = kmap(p->upage); 
		up = (User*)VA(k); 
1990/0227    
		if(up->p != p){ 
1990/0614    
			kunmap(k); 
1990/0227    
			pprint("note write u/p mismatch"); 
1990/11211    
			error(Egreg); 
1990/0227    
		} 
1990/0614    
		kunmap(k); 
1990/0227    
		if(n >= ERRLEN-1) 
1990/11211    
			error(Etoobig); 
1990/0227    
		if(n>=4 && strncmp(va, "sys:", 4)==0) 
1990/11211    
			error(Ebadarg); 
1991/0318    
		memmove(buf, va, n); 
1990/0227    
		buf[n] = 0; 
		if(!postnote(p, 0, buf, NUser)) 
1990/11211    
			error(Enonote); 
1990/0227    
		break; 
	default: 
		pprint("unknown qid in procwrite\n"); 
1990/11211    
		error(Egreg); 
1990/0227    
	} 
1991/0614    
	poperror(); 
1990/0227    
	unlock(&p->debug); 
1991/1109    
	return n; 
} 
 
Chan * 
procctlnotepg(Chan *c, void *va, int n) 
{ 
	Pgrp *pg; 
 
	pg = pgrptab(c->pgrpid.path-1); 
	qlock(&pg->debug); 
	if(waserror()){ 
		qunlock(&pg->debug); 
		nexterror(); 
	} 
	if(pg->pgrpid != c->pgrpid.vers){ 
		qunlock(&pg->debug); 
		error(Eprocdied); 
	} 
	pgrpnote(pg, va, n, NUser); 
	poperror(); 
	qunlock(&pg->debug); 
} 
 
void 
procctlreq(Proc *p, char *va, int n) 
{ 
	if(n >= 4) { 
		if(strncmp(va, "exit", 4) == 0) { 
			if(p->state == Broken) 
				ready(p); 
			return; 
		} 
		if(strncmp(va, "stop", 4) == 0) { 
			p->procctl = Proc_stopme; 
			return; 
		} 
		if(strncmp(va, "kill", 4) == 0) { 
			postnote(p, 0, "sys: killed", NExit); 
			p->procctl = Proc_exitme; 
			return; 
		} 
	} 
 
	if(n >= 5 && strncmp(va, "start", 5) == 0) { 
		if(p->state != Stopped) 
			errors("not stopped"); 
		ready(p); 
		return; 
	} 
	error(Ebadctl); 
} 
 
int 
procctlmemio(Proc *p, ulong offset, int n, void *va, int read) 
{ 
	Pte **pte; 
	Page *pg; 
	KMap *k; 
	Segment *ps, *s; 
	ulong soff; 
	int i; 
	char *a = va, *b; 
 
	s = seg(p, offset, 1); 
	if(s == 0) 
		errors("not in address space"); 
 
	/* Revert a text segment to data */ 
	if(read == 0 && (s->type&SG_TYPE) == SG_TEXT) { 
		ps = newseg(SG_DATA, s->base, s->size); 
		ps->image = s->image; 
		incref(ps->image); 
		ps->fstart = s->fstart; 
		ps->flen = s->flen; 
 
		for(i = 0; i < NSEG; i++) 
			if(p->seg[i] == s) 
				break; 
		if(p->seg[i] != s) 
			panic("segment gone"); 
 
		qunlock(&s->lk); 
		putseg(s); 
		p->seg[i] = ps; 
	} 
	else 
		qunlock(&s->lk); 
 
Again: 
	s = seg(p, offset, 1); 
	if(s == 0) 
		errors("not in address space"); 
 
	s->steal++; 
	soff = offset-s->base; 
	pte = &s->map[soff/PTEMAPMEM]; 
	if(*pte == 0) { 
		if(waserror()) { 
			s->steal--; 
			nexterror(); 
		} 
		if(fixfault(s, offset, read, 0) != 0) { 
			s->steal--; 
			poperror(); 
			goto Again; 
		} 
		poperror(); 
		if(*pte == 0) 
			panic("procctlmemio");  
	} 
	pg = (*pte)->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 
	if(pagedout(pg)) { 
		if(waserror()) { 
			s->steal--; 
			nexterror(); 
		} 
		if(fixfault(s, offset, read, 0) != 0) { 
			s->steal--; 
			poperror(); 
			goto Again; 
		} 
		poperror(); 
		pg = (*pte)->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 
		if(pg == 0) 
			panic("procctlmemio1"); 
	} 
 
	k = kmap(pg); 
	b = (char*)VA(k); 
	memmove(a, b+(offset&(BY2PG-1)), n); 
	kunmap(k); 
 
	s->steal--; 
	qunlock(&s->lk); 
1990/0227    
	return n; 
} 


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