ref: cc44473e8c095bb48bfcf68b982239bddfb97e07
dir: /kern/devproc.c/
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
static char *luser;
extern int pflag;
enum
{
Qdir = 1,
Qtrace,
Qargs,
Qctl,
Qfd,
Qnote,
Qnoteid,
Qnotepg,
Qns,
Qppid,
Qproc,
Qsegment,
Qstatus,
Qwait,
Qprofile,
Qsyscall,
};
enum
{
CMclose,
CMclosefiles,
CMfixedpri,
CMhang,
CMkill,
CMnohang,
CMnoswap,
CMpri,
CMprivate,
CMprofile,
CMstart,
CMstartstop,
CMstartsyscall,
CMstop,
CMwaitstop,
CMtrace,
CMinterrupt,
CMnointerrupt,
};
enum{
Nevents = 0x4000,
Emask = Nevents - 1,
};
#define STATSIZE (2*28+12+9*12)
#define QSHIFT 5
#define QID(q) ((((ulong)(q).path)&0x0000001F)>>0)
#define SLOTMAX 0x4000000
#define SLOT(q) (((((ulong)(q).path)>>QSHIFT)&(SLOTMAX-1))-1)
#define PID(q) ((q).vers)
#define NOTEID(q) ((q).vers)
static void procctlreq(Proc*, char*, int);
static long procctlmemio(Chan*, Proc*, uintptr, void*, long, int);
static Chan* proctext(Chan*, Proc*);
static int procstopped(void*);
/*
* Status, fd, and ns are left fully readable (0444) because of their use in debugging,
* particularly on shared servers.
* Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
*/
Dirtab procdir[] =
{
"args", {Qargs}, 0, 0660,
"ctl", {Qctl}, 0, 0660, // So, this is not ideal but it will let us at least spin up our factotum
"fd", {Qfd}, 0, 0444,
"note", {Qnote}, 0, 0000,
"noteid", {Qnoteid}, 0, 0664,
"notepg", {Qnotepg}, 0, 0000,
"ns", {Qns}, 0, 0444,
"ppid", {Qppid}, 0, 0444,
"proc", {Qproc}, 0, 0400,
"segment", {Qsegment}, 0, 0444,
"status", {Qstatus}, STATSIZE, 0444,
"wait", {Qwait}, 0, 0400,
"profile", {Qprofile}, 0, 0400,
"syscall", {Qsyscall}, 0, 0400,
};
static
Cmdtab proccmd[] = {
CMclose, "close", 2,
CMclosefiles, "closefiles", 1,
CMfixedpri, "fixedpri", 2,
CMhang, "hang", 1,
CMnohang, "nohang", 1,
CMnoswap, "noswap", 1,
CMkill, "kill", 1,
CMpri, "pri", 2,
CMprivate, "private", 1,
CMprofile, "profile", 1,
CMstart, "start", 1,
CMstartstop, "startstop", 1,
CMstartsyscall, "startsyscall", 1,
CMstop, "stop", 1,
CMwaitstop, "waitstop", 1,
CMtrace, "trace", 0,
CMinterrupt, "interrupt", 1,
CMnointerrupt, "nointerrupt", 1,
};
/* Segment type from dat.h */
static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", "Fixed", "Sticky" };
static void
nonone(Proc *p)
{
if(p == up)
return;
if(strcmp(up->user, "none") != 0)
return;
if(iseve())
return;
error(Eperm);
}
static void
procstopwait(Proc *p, int ctl)
{
//char *state;
//int pid;
/*
if(p->pdbg != nil)
error(Einuse);
if(procstopped(p) || p->state == Broken)
return;
pid = p->pid;
if(pid == 0)
error(Eprocdied);
if(ctl != 0)
p->procctl = ctl;
if(p == up)
return;
p->pdbg = up;
qunlock(&p->debug);
state = up->psstate;
up->psstate = "Stopwait";
if(waserror()) {
up->psstate = state;
qlock(&p->debug);
if(p->pdbg == up)
p->pdbg = nil;
nexterror();
}
sleep(&up->sleep, procstopped, p);
poperror();
up->psstate = state;
qlock(&p->debug);
if(p->pid != pid)
error(Eprocdied);
*/
}
static void
procctlclosefiles(Proc *p, int all, int fd)
{
Fgrp *f;
Chan *c;
if(fd < 0)
error(Ebadfd);
f = p->fgrp;
if(f == nil)
error(Eprocdied);
incref(&f->ref);
lock(&f->lk);
while(fd <= f->maxfd){
c = f->fd[fd];
if(c != nil){
f->fd[fd] = nil;
unlock(&f->lk);
qunlock(&p->debug);
cclose(c);
qlock(&p->debug);
lock(&f->lk);
}
if(!all)
break;
fd++;
}
unlock(&f->lk);
closefgrp(f);
}
static int
procgen(Chan *c, char *name, Dirtab *tab, int nd, int s, Dir *dp)
{
Qid qid;
Proc *p;
char *ename;
Segment *q;
ulong pid, path, perm, len;
if(s == DEVDOTDOT){
mkqid(&qid, Qdir, 0, QTDIR);
devdir(c, qid, "#p", 0, eve, 0555, dp);
return 1;
}
if(c->qid.path == Qdir){
if(s == 0){
strcpy(up->genbuf, "trace");
mkqid(&qid, Qtrace, -1, QTFILE);
devdir(c, qid, up->genbuf, 0, eve, 0400, dp);
return 1;
}
if(name != nil){
/* ignore s and use name to find pid */
pid = strtol(name, &ename, 10);
if(pid==0 || ename[0]!='\0')
return -1;
s = pid;
if(s < 0)
return -1;
}
else if(--s >= conf.nproc)
return -1;
p = proctab(s);
if(p == nil)
return 0;
pid = p->pid;
if(pid == 0)
return 0;
/*
* String comparison is done in devwalk so name must match its formatted pid
*/
snprint(up->genbuf, sizeof(up->genbuf), "%lud", pid);
if(name != nil && strcmp(name, up->genbuf) != 0)
return -1;
mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
devdir(c, qid, up->genbuf, 0, p->user, 0555, dp);
return 1;
}
if(c->qid.path == Qtrace){
strcpy(up->genbuf, "trace");
mkqid(&qid, Qtrace, -1, QTFILE);
devdir(c, qid, up->genbuf, 0, eve, 0400, dp);
return 1;
}
if(s >= nelem(procdir))
return -1;
if(tab)
panic("procgen");
tab = &procdir[s];
path = c->qid.path&~((1<<QSHIFT)-1); /* slot component */
/* p->procmode determines default mode for files in /proc */
p = proctab(SLOT(c->qid));
perm = tab->perm;
if(perm == 0)
perm = p->procmode;
else /* just copy read bits */
perm |= p->procmode & 0444;
len = tab->length;
switch(QID(c->qid)) {
case Qwait:
// len = p->nwait; /* incorrect size, but >0 means there's something to read */
break;
case Qprofile:
// q = p->seg[TSEG];
// if(q != nil && q->profile != nil) {
// len = (q->size-q->start)>>LRESPROF;
// len *= sizeof(*q->profile);
// }
break;
}
len = 0;
mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
devdir(c, qid, tab->name, len, p->user, perm, dp);
return 1;
}
static void
int2flag(int flag, char *s)
{
if(flag == 0){
*s = '\0';
return;
}
*s++ = '-';
if(flag & MAFTER)
*s++ = 'a';
if(flag & MBEFORE)
*s++ = 'b';
if(flag & MCREATE)
*s++ = 'c';
if(flag & MCACHE)
*s++ = 'C';
*s = '\0';
}
static int
readfd1(Chan *c, Proc *p, char *buf, int nbuf)
{
Fgrp *fg;
int n, i;
fg = p->fgrp;
if(fg == nil || p->dot == nil || p->pid != PID(c->qid))
return 0;
if(c->nrock == 0){
c->nrock = 1;
return snprint(buf, nbuf, "%s\n", p->dot->path->s);
}
lock(fg);
n = 0;
for(;;){
i = c->nrock-1;
if(i < 0 || i > fg->maxfd)
break;
c->nrock++;
if(fg->fd[i] != nil){
n = procfdprint(fg->fd[i], i, buf, nbuf);
break;
}
}
unlock(fg);
return n;
}
static int
readns1(Chan *c, Proc *p, char *buf, int nbuf)
{
Pgrp *pg;
Mount *t, *cm;
Mhead *f, *mh;
ulong minid, bestmid;
char flag[10], *srv;
int i;
pg = p->pgrp;
if(pg == nil || p->dot == nil || p->pid != PID(c->qid))
error(Eprocdied);
bestmid = ~0;
minid = c->nrock;
if(minid == bestmid)
return 0;
rlock(&pg->ns);
mh = nil;
cm = nil;
for(i = 0; i < MNTHASH; i++) {
for(f = pg->mnthash[i]; f != nil; f = f->hash) {
rlock(&f->lock);
for(t = f->mount; t != nil; t = t->next) {
if(t->mountid >= minid && t->mountid < bestmid) {
bestmid = t->mountid;
cm = t;
mh = f;
}
}
runlock(&f->lock);
}
}
if(bestmid == ~0) {
c->nrock = bestmid;
i = snprint(buf, nbuf, "cd %q\n", p->dot->path->s);
} else {
c->nrock = bestmid+1;
int2flag(cm->mflag, flag);
if(strcmp(cm->to->path->s, "#M") == 0){
srv = cm->to->mchan->path->s;
i = snprint(buf, nbuf, *cm->spec?
"mount %s %q %q %q\n": "mount %s %q %q\n", flag,
srv, mh->from->path->s, cm->spec);
}else{
i = snprint(buf, nbuf, "bind %s %q %q\n", flag,
cm->to->path->s, mh->from->path->s);
}
}
runlock(&pg->ns);
return i;
}
static void
procinit(void)
{
return;
}
static Chan*
procattach(char *spec)
{
Chan *c;
c = devattach('p', spec);
c->qid.path = Qdir;
c->qid.vers = 0;
c->qid.type = QTDIR;
return c;
}
static Walkqid*
procwalk(Chan *c, Chan *nc, char **name, int nname)
{
return devwalk(c, nc, name, nname, nil, 0, procgen);
}
static Chan*
procopen(Chan *c, int omode0)
{
Proc *p;
Chan *tc;
int pid;
int omode;
if(c->qid.type & QTDIR)
return devopen(c, omode0, 0, 0, procgen);
if(QID(c->qid) == Qtrace){
if (omode0 != OREAD || !iseve())
error(Eperm);
// lock(&tlock);
// if (waserror()){
// topens--;
// unlock(&tlock);
// nexterror();
// }
// if (topens++ > 0)
// error("already open");
// if (tevents == nil){
// tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
// if(tevents == nil)
// error(Enomem);
// tproduced = tconsumed = 0;
// }
// proctrace = _proctrace;
// unlock(&tlock);
// poperror();
c->mode = openmode(omode0);
c->flag |= COPEN;
c->offset = 0;
return c;
}
p = proctab(SLOT(c->qid));
qlock(&p->debug);
if(waserror()){
qunlock(&p->debug);
nexterror();
}
pid = PID(c->qid);
if(p == nil || p->pid != pid)
error(Eprocdied);
omode = openmode(omode0);
switch(QID(c->qid)){
case Qstatus:
case Qppid:
case Qproc:
case Qsegment:
case Qns:
case Qfd:
if(omode != OREAD)
error(Eperm);
break;
case Qctl:
case Qargs:
case Qwait:
case Qnoteid:
if(omode == OREAD)
break;
case Qnote:
if(p->kp)
error(Eperm);
break;
case Qnotepg:
if(p->kp || omode != OWRITE)
error(Eperm);
pid = p->noteid;
break;
case Qprofile:
case Qsyscall:
break;
default:
print("procopen %#lux\n", QID(c->qid));
error(Egreg);
}
nonone(p);
/* Affix pid to qid */
if(pid == 0)
error(Eprocdied);
c->qid.vers = pid;
tc = devopen(c, omode, 0, 0, procgen);
if(waserror()){
cclose(tc);
nexterror();
}
poperror();
qunlock(&p->debug);
poperror();
return tc;
}
static long
procread(Chan *c, void *va, long n, vlong off)
{
char statbuf[1024], *sps;
ulong offset;
int i, j, rsize;
uchar *rptr;
uintptr addr;
Segment *s;
Waitq *wq;
Proc *p;
offset = off;
if(c->qid.type & QTDIR)
return devdirread(c, va, n, 0, 0, procgen);
if(QID(c->qid) == Qtrace){
// int navail, ne;
// if(!eventsavailable(nil))
// return 0;
// rptr = (uchar*)va;
// navail = tproduced - tconsumed;
// if(navail > n / sizeof(Traceevent))
// navail = n / sizeof(Traceevent);
// while(navail > 0) {
// ne = ((tconsumed & Emask) + navail > Nevents)?
// Nevents - (tconsumed & Emask): navail;
// memmove(rptr, &tevents[tconsumed & Emask],
// ne * sizeof(Traceevent));
// tconsumed += ne;
// rptr += ne * sizeof(Traceevent);
// navail -= ne;
// }
return rptr - (uchar*)va;
}
p = proctab(SLOT(c->qid));
if(p->pid != PID(c->qid))
error(Eprocdied);
switch(QID(c->qid)){
case Qctl:
return readnum(offset, va, n, p->pid, NUMSIZE);
case Qnoteid:
return readnum(offset, va, n, p->noteid, NUMSIZE);
case Qppid:
if(!p->parent)
return readnum(offset, va, n, 0, NUMSIZE);
return readnum(offset, va, n, p->parent->pid, NUMSIZE);
case Qprofile:
// s = p->seg[TSEG];
// if(s == nil || s->profile == nil)
// error("profile is off");
// i = (s->size-s->start)>>LRESPROF;
// i *= sizeof(s->profile[0]);
// if(i < 0 || offset >= i)
// return 0;
// if(offset+n > i)
// n = i - offset;
// memmove(va, ((char*)s->profile)+offset, n);
return n;
case Qproc:
rptr = (uchar*)p;
rsize = sizeof(Proc);
regread:
if(rptr == nil)
error(Enoreg);
if(offset >= rsize)
return 0;
if(offset+n > rsize)
n = rsize - offset;
memmove(va, rptr+offset, n);
return n;
case Qstatus:
// sps = p->psstate;
// if(sps == nil)
// sps = statename[p->state];
/* NOTE: We don't have any p->time tracking
this is handled by the pthreads/windows
j = snprint(statbuf, sizeof(statbuf),
"%-27s %-27s %-11s "
"%11lud %11lud %11lud "
"%11lud %11lud %11lud "
"%11lud %11lud %11lud\n",
p->text, p->user, sps,
tk2ms(p->time[TUser]),
tk2ms(p->time[TSys]),
tk2ms(MACHP(0)->ticks - p->time[TReal]),
tk2ms(p->time[TCUser]),
tk2ms(p->time[TCSys]),
tk2ms(p->time[TCReal]),
(ulong)(procpagecount(p)*BY2PG/1024),
p->basepri, p->priority);
*/
statbufread:
if(offset >= j)
return 0;
if(offset+n > j)
n = j - offset;
memmove(va, statbuf+offset, n);
return n;
case Qsegment:
j = 0;
for(i = 0; i < NSEG; i++) {
s = p->seg[i];
if(s == nil)
continue;
j += snprint(statbuf+j, sizeof(statbuf)-j,
"%-6s %c%c %8p %8p %4ld\n",
sname[s->type&SG_TYPE],
s->type&SG_FAULT ? 'F' : (s->type&SG_RONLY ? 'R' : ' '),
' ', //s->profile ? 'P' : ' ',
s->start, s->size, s->ref);
}
goto statbufread;
case Qwait:
// if(!canqlock(&p->qwaitr))
// error(Einuse);
// if(waserror()) {
// qunlock(&p->qwaitr);
// nexterror();
// }
// lock(&p->exl);
// while(p->waitq == nil && p->pid == PID(c->qid)) {
// if(up == p && p->nchild == 0) {
// unlock(&p->exl);
// error(Enochild);
// }
// unlock(&p->exl);
// sleep(&p->waitr, prochaswaitq, c);
// lock(&p->exl);
// }
// if(p->pid != PID(c->qid)){
// unlock(&p->exl);
// error(Eprocdied);
// }
// wq = p->waitq;
// p->waitq = wq->next;
// p->nwait--;
// unlock(&p->exl);
// qunlock(&p->qwaitr);
// poperror();
// j = snprint(statbuf, sizeof(statbuf), "%d %lud %lud %lud %q",
// wq->w.pid,
// wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
// wq->w.msg);
// free(wq);
// offset = 0;
goto statbufread;
}
qlock(&p->debug);
if(waserror()){
qunlock(&p->debug);
nexterror();
}
if(p->pid != PID(c->qid))
error(Eprocdied);
switch(QID(c->qid)){
case Qns:
case Qfd:
if(offset == 0 || offset != c->mrock)
c->nrock = c->mrock = 0;
do {
if(QID(c->qid) == Qns)
j = readns1(c, p, statbuf, sizeof(statbuf));
else
j = readfd1(c, p, statbuf, sizeof(statbuf));
if(j == 0)
break;
c->mrock += j;
} while(c->mrock <= offset);
i = c->mrock - offset;
qunlock(&p->debug);
poperror();
if(i <= 0 || i > j)
return 0;
if(i < n)
n = i;
offset = j - i;
goto statbufread;
case Qargs:
// j = procargs(p, statbuf, sizeof(statbuf));
qunlock(&p->debug);
poperror();
goto statbufread;
case Qsyscall:
// if(p->syscalltrace != nil)
// n = readstr(offset, va, n, p->syscalltrace);
// else
// n = 0;
break;
case Qnote:
if(n < 1) /* must accept at least the '\0' */
error(Etoosmall);
if(p->nnote == 0)
n = 0;
else {
assert(p->note[0] != nil);
i = strlen(p->note[0]->msg) + 1;
if(i < n)
n = i;
memmove(va, p->note[0]->msg, n-1);
((char*)va)[n-1] = '\0';
freenote(p->note[0]);
if(--p->nnote == 0)
p->notepending = 0;
else
memmove(&p->note[0], &p->note[1], p->nnote*sizeof(Note*));
p->note[p->nnote] = nil;
}
break;
default:
print("unknown qid in procwread\n");
error(Egreg);
}
qunlock(&p->debug);
poperror();
return n;
}
static long
procwrite(Chan *c, void *va, long n, vlong off)
{
char buf[ERRMAX];
ulong offset;
uchar *rptr;
Proc *p;
offset = off;
if(c->qid.type & QTDIR)
error(Eisdir);
/* use the remembered noteid in the channel qid */
if(QID(c->qid) == Qnotepg) {
if(n >= sizeof(buf))
error(Etoobig);
memmove(buf, va, n);
buf[n] = 0;
postnotepg(NOTEID(c->qid), buf, NUser);
return n;
}
p = proctab(SLOT(c->qid));
qlock(&p->debug);
if(waserror()){
qunlock(&p->debug);
nexterror();
}
if(p->pid != PID(c->qid))
error(Eprocdied);
switch(QID(c->qid)){
case Qargs:
if(offset != 0 || n >= sizeof(buf))
error(Etoobig);
memmove(buf, va, n);
buf[n] = 0;
kstrdup(&p->arg, buf);
break;
case Qctl:
procctlreq(p, va, n);
break;
case Qnote:
if(n >= sizeof(buf))
error(Etoobig);
memmove(buf, va, n);
buf[n] = 0;
if(!postnote(p, 0, buf, NUser))
error("note not posted");
break;
case Qnoteid:
if(offset != 0 || n >= sizeof(buf))
error(Etoobig);
memmove(buf, va, n);
buf[n] = 0;
p->noteid = atoi(buf);
break;
default:
print("unknown qid in procwrite\n");
error(Egreg);
}
poperror();
qunlock(&p->debug);
return n;
}
/*
* called with p->debug locked.
*/
void
killproc(Proc *p, int ctl)
{
static Note killnote = {
"sys: killed",
NExit,
1,
};
if(p->state <= New || p->pid == 0 || p->kp)
return;
//if(p->state == Broken){
// unbreak(p);
// return;
//}
if(ctl != 0)
p->procctl = ctl;
incref(&killnote.ref);
pushnote(p, &killnote);
//if(p->state == Stopped)
// ready(p);
}
static void
procclose(Chan *c)
{
//Segio *sio;
if((c->flag & COPEN) == 0)
return;
switch(QID(c->qid)){
case Qtrace:
// lock(&tlock);
// if(topens > 0)
// topens--;
// if(topens == 0)
// proctrace = nil;
// unlock(&tlock);
return;
}
}
static int
procwstat(Chan *c, uchar *db, int n)
{
Dir *d;
Proc *p;
if(c->qid.type&QTDIR)
error(Eperm);
switch(QID(c->qid)){
case Qnotepg:
case Qtrace:
return devwstat(c, db, n);
}
d = smalloc(sizeof(Dir)+n);
if(waserror()){
free(d);
nexterror();
}
n = convM2D(db, n, &d[0], (char*)&d[1]);
if(n == 0)
error(Eshortstat);
p = proctab(SLOT(c->qid));
qlock(&p->debug);
if(waserror()){
qunlock(&p->debug);
nexterror();
}
if(p->pid != PID(c->qid))
error(Eprocdied);
nonone(p);
if(strcmp(up->user, p->user) != 0 && !iseve())
error(Eperm);
if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
if(strcmp(d->uid, "none") != 0 && !iseve())
error(Eperm);
kstrdup(&p->user, d->uid);
}
/* p->procmode determines default mode for files in /proc */
if(d->mode != ~0)
p->procmode = d->mode&0777;
qunlock(&p->debug);
poperror();
poperror();
free(d);
return n;
}
static int
procstat(Chan *c, uchar *db, int n)
{
return devstat(c, db, n, nil, 0, procgen);
}
static void
changenoteid(Proc *p, ulong noteid)
{
Proc *pp;
int i;
if(noteid <= 0)
error(Ebadarg);
if(noteid == p->noteid)
return;
if(noteid == p->pid){
p->noteid = noteid;
return;
}
for(i = 0; (pp = proctab(i)) != nil; i++){
if(pp->noteid != noteid || pp->kp)
continue;
if(strcmp(pp->user, p->user) == 0){
nonone(pp);
p->noteid = noteid;
return;
}
}
error(Eperm);
}
static void
procctlreq(Proc *p, char *va, int n)
{
Segment *s;
uintptr npc;
int pri;
Cmdbuf *cb;
Cmdtab *ct;
vlong time;
char *e;
void (*pt)(Proc*, int, vlong);
cb = parsecmd(va, n);
if(waserror()){
free(cb);
nexterror();
}
ct = lookupcmd(cb, proccmd, nelem(proccmd));
switch(ct->index){
case CMclose:
procctlclosefiles(p, 0, atoi(cb->f[1]));
break;
case CMclosefiles:
procctlclosefiles(p, 1, 0);
break;
case CMhang:
p->hang = 1;
break;
case CMkill:
killproc(p, Proc_exitme);
break;
case CMnohang:
p->hang = 0;
break;
case CMnoswap:
error(Enoswap);
break;
case CMpri:
// pri = atoi(cb->f[1]);
// if(pri > PriNormal && !iseve())
// error(Eperm);
// procpriority(p, pri, 0);
break;
case CMfixedpri:
// pri = atoi(cb->f[1]);
// if(pri > PriNormal && !iseve())
// error(Eperm);
// procpriority(p, pri, 1);
break;
case CMprivate:
// p->privatemem = 1;
/*
* pages will now get marked private
* when faulted in for writing
* so force a tlb flush.
*/
// p->newtlb = 1;
// if(p == up)
// flushmmu();
break;
case CMprofile:
// s = p->seg[TSEG];
// if(s == nil || (s->type&SG_TYPE) != SG_TEXT) /* won't expand */
// error(Egreg);
// qlock(s);
// npc = (s->size-s->start)>>LRESPROF;
// if(s->profile == nil){
// s->profile = malloc(npc*sizeof(*s->profile));
// if(s->profile == nil){
// qunlock(s);
// error(Enomem);
// }
// } else {
// memset(s->profile, 0, npc*sizeof(*s->profile));
// }
// qunlock(s);
break;
case CMstart:
//if(p->state != Stopped)
// error(Ebadctl);
//ready(p);
break;
case CMstartstop:
//if(p->state != Stopped)
// error(Ebadctl);
//p->procctl = Proc_traceme;
//ready(p);
//procstopwait(p, Proc_traceme);
break;
case CMstartsyscall:
if(p->state != Stopped)
error(Ebadctl);
p->procctl = Proc_tracesyscall;
//ready(p);
procstopwait(p, Proc_tracesyscall);
break;
case CMstop:
procstopwait(p, Proc_stopme);
break;
case CMwaitstop:
procstopwait(p, 0);
break;
case CMtrace:
// switch(cb->nf){
// case 1:
// p->trace ^= 1;
// break;
// case 2:
// p->trace = (atoi(cb->f[1]) != 0);
// break;
// default:
// error("args");
// }
break;
case CMinterrupt:
procinterrupt(p);
break;
case CMnointerrupt:
if(p->nnote == 0)
p->notepending = 0;
else
error("notes pending");
break;
}
poperror();
free(cb);
}
static int
procstopped(void *a)
{
return ((Proc*)a)->state == Stopped;
}
static long
procctlmemio(Chan *c, Proc *p, uintptr offset, void *a, long n, int read)
{
Segment *s;
int i;
/*
qlock(&p->seglock);
if(waserror()) {
qunlock(&p->rw);
nexterror();
}
if(p->pid != PID(c->qid))
error(Eprocdied);
s = seg(p, offset, 1);
if(s == nil)
error(Ebadarg);
if(waserror()){
qunlock(&s->rw);
nexterror();
}
if(!read && (s->type&SG_TYPE) == SG_TEXT) {
p->seg[i] = txt2data(s);
qunlock(&s->qlock);
putseg(s);
s = p->seg[i];
} else {
qunlock(s);
}
poperror();
incref(&s->ref); // for us while we copy
qunlock(&p->seglock);
poperror();
if(waserror()) {
putseg(s);
nexterror();
}
offset -= s->start;
putseg(s);
poperror();
*/
return n;
}
Dev procdevtab = {
'p',
"proc",
devreset,
procinit,
devshutdown,
procattach,
procwalk,
procstat,
procopen,
devcreate,
procclose,
procread,
devbread,
procwrite,
devbwrite,
devremove,
procwstat,
};