]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/port/devproc.c
kernel: use tk2ms() instead of TK2MS macro for process time conversion
[plan9front.git] / sys / src / 9 / port / devproc.c
old mode 100755 (executable)
new mode 100644 (file)
index d1ee87d..b6218a6
@@ -9,6 +9,8 @@
 #include       "ureg.h"
 #include       "edf.h"
 
+#include       <pool.h>
+
 enum
 {
        Qdir,
@@ -23,6 +25,7 @@ enum
        Qnoteid,
        Qnotepg,
        Qns,
+       Qppid,
        Qproc,
        Qregs,
        Qsegment,
@@ -52,6 +55,8 @@ enum
        CMwaitstop,
        CMwired,
        CMtrace,
+       CMinterrupt,
+       CMnointerrupt,
        /* real time */
        CMperiod,
        CMdeadline,
@@ -87,6 +92,7 @@ Dirtab procdir[] =
        "noteid",       {Qnoteid},      0,                      0664,
        "notepg",       {Qnotepg},      0,                      0000,
        "ns",           {Qns},          0,                      0444,
+       "ppid",         {Qppid},        0,                      0444,
        "proc",         {Qproc},        0,                      0400,
        "regs",         {Qregs},        sizeof(Ureg),           0000,
        "segment",      {Qsegment},     0,                      0444,
@@ -116,6 +122,8 @@ Cmdtab proccmd[] = {
        CMwaitstop,             "waitstop",             1,
        CMwired,                "wired",                2,
        CMtrace,                "trace",                0,
+       CMinterrupt,            "interrupt",            1,
+       CMnointerrupt,          "nointerrupt",          1,
        CMperiod,               "period",               2,
        CMdeadline,             "deadline",             2,
        CMcost,                 "cost",                 2,
@@ -128,7 +136,7 @@ Cmdtab proccmd[] = {
 };
 
 /* Segment type from portdat.h */
-static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
+static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", "Fixed", };
 
 /*
  * Qids are, in path:
@@ -146,11 +154,10 @@ static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
 #define        NOTEID(q)       ((q).vers)
 
 void   procctlreq(Proc*, char*, int);
-int    procctlmemio(Proc*, ulong, int, void*, int);
+long   procctlmemio(Chan*, Proc*, uintptr, void*, long, int);
 Chan*  proctext(Chan*, Proc*);
-Segment* txt2data(Proc*, Segment*);
 int    procstopped(void*);
-void   mntscan(Mntwalk*, Proc*);
+ulong  procpagecount(Proc *);
 
 static Traceevent *tevents;
 static Lock tlock;
@@ -158,14 +165,12 @@ static int topens;
 static int tproduced, tconsumed;
 void (*proctrace)(Proc*, int, vlong);
 
-extern int unfair;
-
 static void
 profclock(Ureg *ur, Timer *)
 {
        Tos *tos;
 
-       if(up == 0 || up->state != Running)
+       if(up == nil || up->state != Running)
                return;
 
        /* user profiling clock */
@@ -254,7 +259,7 @@ procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
                break;
        case Qprofile:
                q = p->seg[TSEG];
-               if(q && q->profile) {
+               if(q != nil && q->profile != nil) {
                        len = (q->top-q->base)>>LRESPROF;
                        len *= sizeof(*q->profile);
                }
@@ -345,12 +350,12 @@ procopen(Chan *c, int omode)
                        error(Eperm);
                lock(&tlock);
                if (waserror()){
+                       topens--;
                        unlock(&tlock);
                        nexterror();
                }
-               if (topens > 0)
+               if (topens++ > 0)
                        error("already open");
-               topens++;
                if (tevents == nil){
                        tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
                        if(tevents == nil)
@@ -368,7 +373,7 @@ procopen(Chan *c, int omode)
        }
                
        p = proctab(SLOT(c->qid));
-       qlock(&p->debug);
+       eqlock(&p->debug);
        if(waserror()){
                qunlock(&p->debug);
                nexterror();
@@ -387,12 +392,14 @@ procopen(Chan *c, int omode)
                tc->offset = 0;
                qunlock(&p->debug);
                poperror();
+               cclose(c);
                return tc;
 
        case Qproc:
        case Qkregs:
        case Qsegment:
        case Qprofile:
+       case Qns:
        case Qfd:
                if(omode != OREAD)
                        error(Eperm);
@@ -417,28 +424,23 @@ procopen(Chan *c, int omode)
        case Qregs:
        case Qfpregs:
        case Qsyscall:  
+       case Qppid:
                nonone(p);
                break;
 
-       case Qns:
-               if(omode != OREAD)
-                       error(Eperm);
-               c->aux = malloc(sizeof(Mntwalk));
-               break;
-
        case Qnotepg:
                nonone(p);
                pg = p->pgrp;
                if(pg == nil)
                        error(Eprocdied);
-               if(omode!=OWRITE || pg->pgrpid == 1)
+               if(omode!=OWRITE)
                        error(Eperm);
                c->pgrpid.path = pg->pgrpid+1;
                c->pgrpid.vers = p->noteid;
                break;
 
        default:
-               pprint("procopen %#lux\n", QID(c->qid));
+               print("procopen %#lux\n", QID(c->qid));
                error(Egreg);
        }
 
@@ -473,17 +475,18 @@ procwstat(Chan *c, uchar *db, int n)
        p = proctab(SLOT(c->qid));
        nonone(p);
        d = nil;
+
+       eqlock(&p->debug);
        if(waserror()){
-               free(d);
                qunlock(&p->debug);
+               free(d);
                nexterror();
        }
-       qlock(&p->debug);
 
        if(p->pid != PID(c->qid))
                error(Eprocdied);
 
-       if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
+       if(strcmp(up->user, p->user) != 0 && !iseve())
                error(Eperm);
 
        d = smalloc(sizeof(Dir)+n);
@@ -491,131 +494,89 @@ procwstat(Chan *c, uchar *db, int n)
        if(n == 0)
                error(Eshortstat);
        if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
-               if(strcmp(up->user, eve) != 0)
+               if(!iseve())
                        error(Eperm);
-               else
-                       kstrdup(&p->user, d->uid);
+               kstrdup(&p->user, d->uid);
        }
        /* p->procmode determines default mode for files in /proc */
        if(d->mode != ~0UL)
                p->procmode = d->mode&0777;
 
+       qunlock(&p->debug);
        poperror();
        free(d);
-       qunlock(&p->debug);
        return n;
 }
 
-
-static long
-procoffset(long offset, char *va, int *np)
+static void
+procclose(Chan *c)
 {
-       if(offset > 0) {
-               offset -= *np;
-               if(offset < 0) {
-                       memmove(va, va+*np+offset, -offset);
-                       *np = -offset;
+       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;
+       case Qmem:
+               sio = c->aux;
+               if(sio != nil){
+                       c->aux = nil;
+                       segio(sio, nil, nil, 0, 0, 0);
+                       free(sio);
                }
-               else
-                       *np = 0;
+               return;
        }
-       return offset;
 }
 
 static int
-procqidwidth(Chan *c)
+procargs(Proc *p, char *buf, int nbuf)
 {
-       char buf[32];
+       int j, k, m;
+       char *a;
+       int n;
 
-       return sprint(buf, "%lud", c->qid.vers);
+       a = p->args;
+       if(p->setargs){
+               snprint(buf, nbuf, "%s [%s]", p->text, p->args);
+               return strlen(buf);
+       }
+       n = p->nargs;
+       for(j = 0; j < nbuf - 1; j += m){
+               if(n <= 0)
+                       break;
+               if(j != 0)
+                       buf[j++] = ' ';
+               m = snprint(buf+j, nbuf-j, "%q",  a);
+               k = strlen(a) + 1;
+               a += k;
+               n -= k;
+       }
+       return j;
 }
 
-int
-procfdprint(Chan *c, int fd, int w, char *s, int ns)
+static int
+eventsavailable(void *)
 {
-       int n;
-
-       if(w == 0)
-               w = procqidwidth(c);
-       n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
-               fd,
-               &"r w rw"[(c->mode&3)<<1],
-               devtab[c->type]->dc, c->dev,
-               c->qid.path, w, c->qid.vers, c->qid.type,
-               c->iounit, c->offset, c->path->s);
-       return n;
+       return tproduced > tconsumed;
 }
 
 static int
-procfds(Proc *p, char *va, int count, long offset)
+prochaswaitq(void *x)
 {
-       Fgrp *f;
        Chan *c;
-       char buf[256];
-       int n, i, w, ww;
-       char *a;
-
-       /* print to buf to avoid holding fgrp lock while writing to user space */
-       if(count > sizeof buf)
-               count = sizeof buf;
-       a = buf;
-
-       qlock(&p->debug);
-       f = p->fgrp;
-       if(f == nil){
-               qunlock(&p->debug);
-               return 0;
-       }
-       lock(f);
-       if(waserror()){
-               unlock(f);
-               qunlock(&p->debug);
-               nexterror();
-       }
-
-       n = readstr(0, a, count, p->dot->path->s);
-       n += snprint(a+n, count-n, "\n");
-       offset = procoffset(offset, a, &n);
-       /* compute width of qid.path */
-       w = 0;
-       for(i = 0; i <= f->maxfd; i++) {
-               c = f->fd[i];
-               if(c == nil)
-                       continue;
-               ww = procqidwidth(c);
-               if(ww > w)
-                       w = ww;
-       }
-       for(i = 0; i <= f->maxfd; i++) {
-               c = f->fd[i];
-               if(c == nil)
-                       continue;
-               n += procfdprint(c, i, w, a+n, count-n);
-               offset = procoffset(offset, a, &n);
-       }
-       unlock(f);
-       qunlock(&p->debug);
-       poperror();
-
-       /* copy result to user space, now that locks are released */
-       memmove(va, buf, n);
-
-       return n;
-}
+       Proc *p;
 
-static void
-procclose(Chan * c)
-{
-       if(QID(c->qid) == Qtrace){
-               lock(&tlock);
-               if(topens > 0)
-                       topens--;
-               if(topens == 0)
-                       proctrace = nil;
-               unlock(&tlock);
-       }
-       if(QID(c->qid) == Qns && c->aux != 0)
-               free(c->aux);
+       c = (Chan *)x;
+       p = proctab(SLOT(c->qid));
+       return p->pid != PID(c->qid) || p->waitq != nil;
 }
 
 static void
@@ -638,48 +599,130 @@ int2flag(int flag, char *s)
 }
 
 static int
-procargs(Proc *p, char *buf, int nbuf)
+readns1(Chan *c, Proc *p, char *buf, int nbuf)
 {
-       int j, k, m;
-       char *a;
-       int n;
+       Pgrp *pg;
+       Mount *t, *cm;
+       Mhead *f, *mh;
+       ulong minid, bestmid;
+       char flag[10], *srv;
+       int i;
 
-       a = p->args;
-       if(p->setargs){
-               snprint(buf, nbuf, "%s [%s]", p->text, p->args);
-               return strlen(buf);
+       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) {
+                       for(t = f->mount; t != nil; t = t->next) {
+                               if(t->mountid >= minid && t->mountid < bestmid) {
+                                       bestmid = t->mountid;
+                                       cm = t;
+                                       mh = f;
+                               }
+                       }
+               }
        }
-       n = p->nargs;
-       for(j = 0; j < nbuf - 1; j += m){
-               if(n <= 0)
-                       break;
-               if(j != 0)
-                       buf[j++] = ' ';
-               m = snprint(buf+j, nbuf-j, "%q",  a);
-               k = strlen(a) + 1;
-               a += k;
-               n -= k;
+
+       if(bestmid == ~0) {
+               c->nrock = bestmid;
+               i = snprint(buf, nbuf, "cd %s\n", p->dot->path->s);
+       } else {
+               c->nrock = bestmid+1;
+
+               int2flag(cm->mflag, flag);
+               if(strcmp(cm->to->path->s, "#M") == 0){
+                       srv = srvname(cm->to->mchan);
+                       i = snprint(buf, nbuf, "mount %s %s %s %s\n", flag,
+                               srv==nil? cm->to->mchan->path->s : srv,
+                               mh->from->path->s, cm->spec? cm->spec : "");
+                       free(srv);
+               }else{
+                       i = snprint(buf, nbuf, "bind %s %s %s\n", flag,
+                               cm->to->path->s, mh->from->path->s);
+               }
        }
-       return j;
+
+       runlock(&pg->ns);
+
+       return i;
+}
+
+int
+procfdprint(Chan *c, int fd, char *s, int ns)
+{
+       return snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %lud %.2ux) %5ld %8lld %s\n",
+               fd,
+               &"r w rw"[(c->mode&3)<<1],
+               devtab[c->type]->dc, c->dev,
+               c->qid.path, c->qid.vers, c->qid.type,
+               c->iounit, c->offset, c->path->s);
 }
 
 static int
-eventsavailable(void *)
+readfd1(Chan *c, Proc *p, char *buf, int nbuf)
 {
-       return tproduced > tconsumed;
+       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;
+}
+
+/*
+ * userspace can't pass negative file offset for a
+ * 64 bit kernel address, so we use 63 bit and sign
+ * extend to 64 bit.
+ */
+static uintptr
+off2addr(vlong off)
+{
+       off <<= 1;
+       off >>= 1;
+       return off;
 }
 
 static long
 procread(Chan *c, void *va, long n, vlong off)
 {
-       /* NSEG*32 was too small for worst cases */
-       char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
-       int i, j, m, navail, ne, pid, rsize;
-       long l;
+       char *a, *sps, statbuf[1024];
+       int i, j, navail, ne, rsize;
+       ulong l;
        uchar *rptr;
+       uintptr addr;
        ulong offset;
        Confmem *cm;
-       Mntwalk *mw;
        Proc *p;
        Segment *sg, *s;
        Ureg kur;
@@ -687,7 +730,6 @@ procread(Chan *c, void *va, long n, vlong off)
        
        a = va;
        offset = off;
-
        if(c->qid.type & QTDIR)
                return devdirread(c, a, n, 0, 0, procgen);
 
@@ -718,42 +760,54 @@ procread(Chan *c, void *va, long n, vlong off)
 
        switch(QID(c->qid)){
        case Qargs:
-               qlock(&p->debug);
-               j = procargs(p, up->genbuf, sizeof up->genbuf);
+               eqlock(&p->debug);
+               j = procargs(p, statbuf, sizeof(statbuf));
                qunlock(&p->debug);
                if(offset >= j)
                        return 0;
                if(offset+n > j)
                        n = j-offset;
-               memmove(a, &up->genbuf[offset], n);
+       statbufread:
+               memmove(a, statbuf+offset, n);
                return n;
+
        case Qsyscall:
-               if(!p->syscalltrace)
-                       return 0;
-               n = readstr(offset, a, n, p->syscalltrace);
-               return n;
+               eqlock(&p->debug);
+               if(waserror()){
+                       qunlock(&p->debug);
+                       nexterror();
+               }
+               if(p->pid != PID(c->qid))
+                       error(Eprocdied);
+               j = 0;
+               if(p->syscalltrace != nil)
+                       j = readstr(offset, a, n, p->syscalltrace);
+               qunlock(&p->debug);
+               poperror();
+               return j;
 
        case Qmem:
-               if(offset < KZERO)
-                       return procctlmemio(p, offset, n, va, 1);
+               addr = off2addr(off);
+               if(addr < KZERO)
+                       return procctlmemio(c, p, addr, va, n, 1);
 
-               if(!iseve())
+               if(!iseve() || poolisoverlap(secrmem, (uchar*)addr, n))
                        error(Eperm);
 
                /* validate kernel addresses */
-               if(offset < (ulong)end) {
-                       if(offset+n > (ulong)end)
-                               n = (ulong)end - offset;
-                       memmove(a, (char*)offset, n);
+               if(addr < (uintptr)end) {
+                       if(addr+n > (uintptr)end)
+                               n = (uintptr)end - addr;
+                       memmove(a, (char*)addr, n);
                        return n;
                }
                for(i=0; i<nelem(conf.mem); i++){
                        cm = &conf.mem[i];
                        /* klimit-1 because klimit might be zero! */
-                       if(cm->kbase <= offset && offset <= cm->klimit-1){
-                               if(offset+n >= cm->klimit-1)
-                                       n = cm->klimit - offset;
-                               memmove(a, (char*)offset, n);
+                       if(cm->kbase <= addr && addr <= cm->klimit-1){
+                               if(addr+n >= cm->klimit-1)
+                                       n = cm->klimit - addr;
+                               memmove(a, (char*)addr, n);
                                return n;
                        }
                }
@@ -761,11 +815,11 @@ procread(Chan *c, void *va, long n, vlong off)
 
        case Qprofile:
                s = p->seg[TSEG];
-               if(s == 0 || s->profile == 0)
+               if(s == nil || s->profile == nil)
                        error("profile is off");
                i = (s->top-s->base)>>LRESPROF;
-               i *= sizeof(*s->profile);
-               if(offset >= i)
+               i *= sizeof(s->profile[0]);
+               if(i < 0 || offset >= i)
                        return 0;
                if(offset+n > i)
                        n = i - offset;
@@ -773,7 +827,7 @@ procread(Chan *c, void *va, long n, vlong off)
                return n;
 
        case Qnote:
-               qlock(&p->debug);
+               eqlock(&p->debug);
                if(waserror()){
                        qunlock(&p->debug);
                        nexterror();
@@ -785,17 +839,15 @@ procread(Chan *c, void *va, long n, vlong off)
                if(p->nnote == 0)
                        n = 0;
                else {
-                       m = strlen(p->note[0].msg) + 1;
-                       if(m > n)
-                               m = n;
-                       memmove(va, p->note[0].msg, m);
-                       ((char*)va)[m-1] = '\0';
-                       p->nnote--;
+                       i = strlen(p->note[0].msg) + 1;
+                       if(i < n)
+                               n = i;
+                       memmove(a, p->note[0].msg, n-1);
+                       a[n-1] = '\0';
+                       if(--p->nnote == 0)
+                               p->notepending = 0;
                        memmove(p->note, p->note+1, p->nnote*sizeof(Note));
-                       n = m;
                }
-               if(p->nnote == 0)
-                       p->notepending = 0;
                poperror();
                qunlock(&p->debug);
                return n;
@@ -824,7 +876,7 @@ procread(Chan *c, void *va, long n, vlong off)
                rptr = (uchar*)&p->fpsave;
                rsize = sizeof(FPsave);
        regread:
-               if(rptr == 0)
+               if(rptr == nil)
                        error(Enoreg);
                if(offset >= rsize)
                        return 0;
@@ -840,41 +892,34 @@ procread(Chan *c, void *va, long n, vlong off)
                        n = STATSIZE - offset;
 
                sps = p->psstate;
-               if(sps == 0)
+               if(sps == nil)
                        sps = statename[p->state];
+
                memset(statbuf, ' ', sizeof statbuf);
-               memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text));
-               memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user));
-               memmove(statbuf+2*KNAMELEN, sps, strlen(sps));
-               j = 2*KNAMELEN + 12;
+               readstr(0, statbuf+0*KNAMELEN, KNAMELEN-1, p->text);
+               readstr(0, statbuf+1*KNAMELEN, KNAMELEN-1, p->user);
+               readstr(0, statbuf+2*KNAMELEN, 11, sps);
 
+               j = 2*KNAMELEN + 12;
                for(i = 0; i < 6; i++) {
                        l = p->time[i];
                        if(i == TReal)
                                l = MACHP(0)->ticks - l;
-                       l = TK2MS(l);
-                       readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
+                       readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, tk2ms(l), NUMSIZE);
                }
-               /* ignore stack, which is mostly non-existent */
-               l = 0;
-               for(i=1; i<NSEG; i++){
-                       s = p->seg[i];
-                       if(s)
-                               l += s->top - s->base;
-               }
-               readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
+
+               readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, procpagecount(p)*BY2PG/1024, NUMSIZE);
                readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
                readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
-               memmove(a, statbuf+offset, n);
-               return n;
+               goto statbufread;
 
        case Qsegment:
                j = 0;
                for(i = 0; i < NSEG; i++) {
                        sg = p->seg[i];
-                       if(sg == 0)
+                       if(sg == nil)
                                continue;
-                       j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n",
+                       j += sprint(statbuf+j, "%-6s %c%c %8p %8p %4ld\n",
                                sname[sg->type&SG_TYPE],
                                sg->type&SG_RONLY ? 'R' : ' ',
                                sg->profile ? 'P' : ' ',
@@ -884,10 +929,7 @@ procread(Chan *c, void *va, long n, vlong off)
                        return 0;
                if(offset+n > j)
                        n = j-offset;
-               if(n == 0 && offset == 0)
-                       exhausted("segments");
-               memmove(a, &statbuf[offset], n);
-               return n;
+               goto statbufread;
 
        case Qwait:
                if(!canqlock(&p->qwaitr))
@@ -899,17 +941,18 @@ procread(Chan *c, void *va, long n, vlong off)
                }
 
                lock(&p->exl);
-               if(up == p && p->nchild == 0 && p->waitq == 0) {
+               while(p->waitq == nil && p->pid == PID(c->qid)) {
+                       if(up == p && p->nchild == 0) {
+                               unlock(&p->exl);
+                               error(Enochild);
+                       }
                        unlock(&p->exl);
-                       error(Enochild);
+                       sleep(&p->waitr, prochaswaitq, c);
+                       lock(&p->exl);
                }
-               pid = p->pid;
-               while(p->waitq == 0) {
+               if(p->pid != PID(c->qid)){
                        unlock(&p->exl);
-                       sleep(&p->waitr, haswaitq, p);
-                       if(p->pid != pid)
-                               error(Eprocdied);
-                       lock(&p->exl);
+                       error(Eprocdied);
                }
                wq = p->waitq;
                p->waitq = wq->next;
@@ -918,94 +961,55 @@ procread(Chan *c, void *va, long n, vlong off)
 
                qunlock(&p->qwaitr);
                poperror();
-               n = snprint(a, n, "%d %lud %lud %lud %q",
+
+               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);
-               return n;
+               if(j < n)
+                       n = j;
+               offset = 0;
+               goto statbufread;
 
        case Qns:
-               qlock(&p->debug);
+       case Qfd:
+               eqlock(&p->debug);
                if(waserror()){
                        qunlock(&p->debug);
                        nexterror();
                }
-               if(p->pgrp == nil || p->pid != PID(c->qid))
-                       error(Eprocdied);
-               mw = c->aux;
-               if(mw->cddone){
-                       qunlock(&p->debug);
-                       poperror();
-                       return 0;
-               }
-               mntscan(mw, p);
-               if(mw->mh == 0){
-                       mw->cddone = 1;
-                       i = snprint(a, n, "cd %s\n", p->dot->path->s);
-                       qunlock(&p->debug);
-                       poperror();
-                       return i;
-               }
-               int2flag(mw->cm->mflag, flag);
-               if(strcmp(mw->cm->to->path->s, "#M") == 0){
-                       srv = srvname(mw->cm->to->mchan);
-                       i = snprint(a, n, "mount %s %s %s %s\n", flag,
-                               srv==nil? mw->cm->to->mchan->path->s : srv,
-                               mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
-                       free(srv);
-               }else
-                       i = snprint(a, n, "bind %s %s %s\n", flag,
-                               mw->cm->to->path->s, mw->mh->from->path->s);
+               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();
-               return i;
+
+               if(i <= 0 || i > j)
+                       return 0;
+               if(i < n)
+                       n = i;
+               offset = j - i;
+               goto statbufread;
 
        case Qnoteid:
                return readnum(offset, va, n, p->noteid, NUMSIZE);
-       case Qfd:
-               return procfds(p, va, n, offset);
-       }
-       error(Egreg);
-       return 0;               /* not reached */
-}
-
-void
-mntscan(Mntwalk *mw, Proc *p)
-{
-       Pgrp *pg;
-       Mount *t;
-       Mhead *f;
-       int nxt, i;
-       ulong last, bestmid;
-
-       pg = p->pgrp;
-       rlock(&pg->ns);
-
-       nxt = 0;
-       bestmid = ~0;
 
-       last = 0;
-       if(mw->mh)
-               last = mw->cm->mountid;
+       case Qppid:
+               return readnum(offset, va, n, p->parentpid, NUMSIZE);
 
-       for(i = 0; i < MNTHASH; i++) {
-               for(f = pg->mnthash[i]; f; f = f->hash) {
-                       for(t = f->mount; t; t = t->next) {
-                               if(mw->mh == 0 ||
-                                 (t->mountid > last && t->mountid < bestmid)) {
-                                       mw->cm = t;
-                                       mw->mh = f;
-                                       bestmid = mw->cm->mountid;
-                                       nxt = 1;
-                               }
-                       }
-               }
        }
-       if(nxt == 0)
-               mw->mh = 0;
-
-       runlock(&pg->ns);
+       error(Egreg);
+       return 0;               /* not reached */
 }
 
 static long
@@ -1014,9 +1018,10 @@ procwrite(Chan *c, void *va, long n, vlong off)
        int id, m;
        Proc *p, *t, *et;
        char *a, *arg, buf[ERRMAX];
-       ulong offset = off;
+       ulong offset;
 
        a = va;
+       offset = off;
        if(c->qid.type & QTDIR)
                error(Eisdir);
 
@@ -1030,7 +1035,7 @@ procwrite(Chan *c, void *va, long n, vlong off)
                return n;
        }
 
-       qlock(&p->debug);
+       eqlock(&p->debug);
        if(waserror()){
                qunlock(&p->debug);
                nexterror();
@@ -1060,8 +1065,7 @@ procwrite(Chan *c, void *va, long n, vlong off)
        case Qmem:
                if(p->state != Stopped)
                        error(Ebadctl);
-
-               n = procctlmemio(p, offset, n, va, 0);
+               n = procctlmemio(c, p, off2addr(off), va, n, 0);
                break;
 
        case Qregs:
@@ -1069,7 +1073,7 @@ procwrite(Chan *c, void *va, long n, vlong off)
                        n = 0;
                else if(offset+n > sizeof(Ureg))
                        n = sizeof(Ureg) - offset;
-               if(p->dbgreg == 0)
+               if(p->dbgreg == nil)
                        error(Enoreg);
                setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
                break;
@@ -1097,16 +1101,21 @@ procwrite(Chan *c, void *va, long n, vlong off)
                        error("note not posted");
                break;
        case Qnoteid:
+               if(p->kp)
+                       error(Eperm);
                id = atoi(a);
+               if(id <= 0)
+                       error(Ebadarg);
                if(id == p->pid) {
                        p->noteid = id;
                        break;
                }
                t = proctab(0);
                for(et = t+conf.nproc; t < et; t++) {
-                       if(t->state == Dead)
+                       if(t->state == Dead || t->kp)
                                continue;
                        if(id == t->noteid) {
+                               nonone(t);
                                if(strcmp(p->user, t->user) != 0)
                                        error(Eperm);
                                p->noteid = id;
@@ -1117,7 +1126,7 @@ procwrite(Chan *c, void *va, long n, vlong off)
                        error(Ebadarg);
                break;
        default:
-               pprint("unknown qid in procwrite\n");
+               print("unknown qid in procwrite\n");
                error(Egreg);
        }
        poperror();
@@ -1154,36 +1163,34 @@ proctext(Chan *c, Proc *p)
        Segment *s;
 
        s = p->seg[TSEG];
-       if(s == 0)
+       if(s == nil)
                error(Enonexist);
        if(p->state==Dead)
                error(Eprocdied);
 
-       lock(s);
        i = s->image;
-       if(i == 0) {
-               unlock(s);
+       if(i == nil)
                error(Eprocdied);
-       }
-       unlock(s);
 
        lock(i);
        if(waserror()) {
                unlock(i);
                nexterror();
        }
-
+               
        tc = i->c;
-       if(tc == 0)
+       if(tc == nil)
                error(Eprocdied);
 
-       if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
+       if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode != OREAD) {
                cclose(tc);
                error(Eprocdied);
        }
 
-       if(p->pid != PID(c->qid))
+       if(p->pid != PID(c->qid)) {
+               cclose(tc);
                error(Eprocdied);
+       }
 
        unlock(i);
        poperror();
@@ -1196,20 +1203,21 @@ procstopwait(Proc *p, int ctl)
 {
        int pid;
 
-       if(p->pdbg)
+       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;
        p->pdbg = up;
-       pid = p->pid;
        qunlock(&p->debug);
        up->psstate = "Stopwait";
        if(waserror()) {
-               p->pdbg = 0;
                qlock(&p->debug);
+               p->pdbg = nil;
                nexterror();
        }
        sleep(&up->sleep, procstopped, p);
@@ -1219,39 +1227,34 @@ procstopwait(Proc *p, int ctl)
                error(Eprocdied);
 }
 
-static void
-procctlcloseone(Proc *p, Fgrp *f, int fd)
-{
-       Chan *c;
-
-       c = f->fd[fd];
-       if(c == nil)
-               return;
-       f->fd[fd] = nil;
-       unlock(f);
-       qunlock(&p->debug);
-       cclose(c);
-       qlock(&p->debug);
-       lock(f);
-}
-
 void
 procctlclosefiles(Proc *p, int all, int fd)
 {
-       int i;
        Fgrp *f;
+       Chan *c;
 
+       if(fd < 0)
+               error(Ebadfd);
        f = p->fgrp;
        if(f == nil)
                error(Eprocdied);
 
+       incref(f);
        lock(f);
-       f->ref++;
-       if(all)
-               for(i = 0; i < f->maxfd; i++)
-                       procctlcloseone(p, f, i);
-       else
-               procctlcloseone(p, f, fd);
+       while(fd <= f->maxfd){
+               c = f->fd[fd];
+               if(c != nil){
+                       f->fd[fd] = nil;
+                       unlock(f);
+                       qunlock(&p->debug);
+                       cclose(c);
+                       qlock(&p->debug);
+                       lock(f);
+               }
+               if(!all)
+                       break;
+               fd++;
+       }
        unlock(f);
        closefgrp(f);
 }
@@ -1359,13 +1362,13 @@ procctlreq(Proc *p, char *va, int n)
                break;
        case CMprofile:
                s = p->seg[TSEG];
-               if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
+               if(s == nil || (s->type&SG_TYPE) != SG_TEXT)
                        error(Ebadctl);
-               if(s->profile != 0)
+               if(s->profile != nil)
                        free(s->profile);
                npc = (s->top-s->base)>>LRESPROF;
                s->profile = malloc(npc*sizeof(*s->profile));
-               if(s->profile == 0)
+               if(s->profile == nil)
                        error(Enomem);
                break;
        case CMstart:
@@ -1408,6 +1411,15 @@ procctlreq(Proc *p, char *va, int n)
                        error("args");
                }
                break;
+       case CMinterrupt:
+               postnote(p, 0, nil, NUser);
+               break;
+       case CMnointerrupt:
+               if(p->nnote == 0)
+                       p->notepending = 0;
+               else
+                       error("notes pending");
+               break;
        /* real time */
        case CMperiod:
                if(p->edf == nil)
@@ -1444,7 +1456,7 @@ procctlreq(Proc *p, char *va, int n)
                p->edf->flags |= Sendnotes;
                break;
        case CMadmit:
-               if(p->edf == 0)
+               if(p->edf == nil)
                        error("edf params");
                if(e = edfadmit(p))
                        error(e);
@@ -1455,12 +1467,12 @@ procctlreq(Proc *p, char *va, int n)
                p->edf->flags |= Extratime;
                break;
        case CMexpel:
-               if(p->edf)
+               if(p->edf != nil)
                        edfstop(p);
                break;
        case CMevent:
                pt = proctrace;
-               if(up->trace && pt)
+               if(up->trace && pt != nil)
                        pt(up, SUser, 0);
                break;
        }
@@ -1472,121 +1484,61 @@ procctlreq(Proc *p, char *va, int n)
 int
 procstopped(void *a)
 {
-       Proc *p = a;
-       return p->state == Stopped;
+       return ((Proc*)a)->state == Stopped;
 }
 
-int
-procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
+long
+procctlmemio(Chan *c, Proc *p, uintptr offset, void *a, long n, int read)
 {
-       KMap *k;
-       Pte *pte;
-       Page *pg;
+       Segio *sio;
        Segment *s;
-       ulong soff, l;
-       char *a = va, *b;
-
-       for(;;) {
-               s = seg(p, offset, 1);
-               if(s == 0)
-                       error(Ebadarg);
-
-               if(offset+n >= s->top)
-                       n = s->top-offset;
-
-               if(!read && (s->type&SG_TYPE) == SG_TEXT)
-                       s = txt2data(p, s);
+       int i;
 
-               s->steal++;
-               soff = offset-s->base;
-               if(waserror()) {
-                       s->steal--;
-                       nexterror();
-               }
-               if(fixfault(s, offset, read, 0) == 0)
+       s = seg(p, offset, 0);
+       if(s == nil)
+               error(Ebadarg);
+       eqlock(&p->seglock);
+       if(waserror()) {
+               qunlock(&p->seglock);
+               nexterror();
+       }
+       sio = c->aux;
+       if(sio == nil){
+               sio = smalloc(sizeof(Segio));
+               c->aux = sio;
+       }
+       for(i = 0; i < NSEG; i++) {
+               if(p->seg[i] == s)
                        break;
-               poperror();
-               s->steal--;
        }
+       if(i == NSEG)
+               error(Egreg);   /* segment gone */
+       eqlock(s);
+       if(waserror()){
+               qunlock(s);
+               nexterror();
+       }
+       if(!read && (s->type&SG_TYPE) == SG_TEXT) {
+               s = txt2data(s);
+               p->seg[i] = s;
+       }
+       offset -= s->base;
+       incref(s);              /* for us while we copy */
+       qunlock(s);
        poperror();
-       pte = s->map[soff/PTEMAPMEM];
-       if(pte == 0)
-               panic("procctlmemio");
-       pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
-       if(pagedout(pg))
-               panic("procctlmemio1");
-
-       l = BY2PG - (offset&(BY2PG-1));
-       if(n > l)
-               n = l;
-
-       k = kmap(pg);
+       qunlock(&p->seglock);
+       poperror();
+
        if(waserror()) {
-               s->steal--;
-               kunmap(k);
+               putseg(s);
                nexterror();
        }
-       b = (char*)VA(k);
-       b += offset&(BY2PG-1);
-       if(read == 1)
-               memmove(a, b, n);       /* This can fault */
-       else
-               memmove(b, a, n);
-       kunmap(k);
+       n = segio(sio, s, a, n, offset, read);
+       putseg(s);
        poperror();
 
-       /* Ensure the process sees text page changes */
-       if(s->flushme)
-               memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
-
-       s->steal--;
-
-       if(read == 0)
+       if(!read)
                p->newtlb = 1;
 
        return n;
 }
-
-Segment*
-txt2data(Proc *p, Segment *s)
-{
-       int i;
-       Segment *ps;
-
-       ps = newseg(SG_DATA, s->base, s->size);
-       ps->image = s->image;
-       incref(ps->image);
-       ps->fstart = s->fstart;
-       ps->flen = s->flen;
-       ps->flushme = 1;
-
-       qlock(&p->seglock);
-       for(i = 0; i < NSEG; i++)
-               if(p->seg[i] == s)
-                       break;
-       if(i == NSEG)
-               panic("segment gone");
-
-       qunlock(&s->lk);
-       putseg(s);
-       qlock(&ps->lk);
-       p->seg[i] = ps;
-       qunlock(&p->seglock);
-
-       return ps;
-}
-
-Segment*
-data2txt(Segment *s)
-{
-       Segment *ps;
-
-       ps = newseg(SG_TEXT, s->base, s->size);
-       ps->image = s->image;
-       incref(ps->image);
-       ps->fstart = s->fstart;
-       ps->flen = s->flen;
-       ps->flushme = 1;
-
-       return ps;
-}