for recv(queue, 0) start the next guy on the queue as well, as recv(queue, 0) dequeues nothing. also remove splhi() within ilock, and use Mpl to store the return value of spl*(). Reference: /n/atom/patch/applied2013/fsqueuerev0 Date: Tue Aug 27 23:29:15 CES 2013 Signed-off-by: quanstro@quanstro.net --- /usr/quanstro/src/fs/port/sub.c Thu Jan 1 00:00:00 1970 +++ /usr/quanstro/src/fs/port/sub.c Tue Aug 27 23:27:30 2013 @@ -0,0 +1,1206 @@ +#include "all.h" +#include "io.h" +#include "../ip/ip.h" + +Filsys* +fsstr(char *p) +{ + Filsys *fs; + + for(fs=filsys; fs->name; fs++) + if(strcmp(fs->name, p) == 0) + return fs; + return 0; +} + +Filsys* +dev2fs(Device *dev) +{ + Filsys *fs; + + for(fs=filsys; fs->name; fs++) + if(fs->dev == dev) + return fs; + return 0; +} + +/* + * allocate 'count' contiguous channels + * of type 'type' and return pointer to base + */ +Chan* +chaninit(int type, int count, int data) +{ + uchar *p; + Chan *cp, *icp; + int i; + static Lock lk; + + p = ialloc(count * (sizeof(Chan)+data), 0); + icp = (Chan*)p; + for(i=0; inext = chans; + chans = cp; + cp->type = type; + cp->chan = cons.chano; + lock(&lk); + cons.chano++; + unlock(&lk); + strncpy(cp->whoname, "", sizeof(cp->whoname)); + dofilter(&cp->work); + dofilter(&cp->rate); + snprint(cp->rname, sizeof cp->rname, "rch%d/%d", type, cp->chan); + snprint(cp->wname, sizeof cp->wname, "wch%d/%d", type, cp->chan); + cp->reflock.rd.name = cp->rname; + cp->reflock.wr.name = cp->wname; + wlock(&cp->reflock); + wunlock(&cp->reflock); + rlock(&cp->reflock); + runlock(&cp->reflock); + + p += sizeof(Chan); + if(data){ + cp->pdata = p; + p += data; + } + } + return icp; +} + +void +fileinit(Chan *cp) +{ + File *f, *prev; + Tlock *t; + int h; + +loop: + lock(&flock); + for (h=0; hnext) { + if(f->cp != cp) + continue; + if(prev) { + prev->next = f->next; + f->next = flist[h]; + flist[h] = f; + } + flist[h] = f->next; + unlock(&flock); + + qlock(f); + if(t = f->tlock) { + if(t->file == f) + t->time = 0; /* free the lock */ + f->tlock = 0; + } + if(f->open & FREMOV) + doremove(f); + freewp(f->wpath); + f->open = 0; + authfree(f->auth); + f->auth = 0; + f->cp = 0; + qunlock(f); + goto loop; + } + unlock(&flock); +} + +#define NOFID (ulong)~0 + +/* + * returns a locked file structure + */ +File* +filep(Chan *cp, ulong fid, int flag) +{ + File *f; + int h; + + if(fid == NOFID) + return 0; + + h = (long)(uintptr)cp + fid; + if(h < 0) + h = ~h; + h %= nelem(flist); + +loop: + lock(&flock); + for(f=flist[h]; f; f=f->next) + if(f->fid == fid && f->cp == cp){ + /* + * Already in use is an error + * when called from attach or clone (walk + * in 9P2000). The console uses FID[12] and + * never clunks them so catch that case. + */ + if(flag == 0 || cp == cons.chan) + goto out; + unlock(&flock); + return 0; + } + + if(flag) { + f = newfp(); + if(f) { + f->fid = fid; + f->cp = cp; + f->wpath = 0; + f->tlock = 0; + f->doffset = 0; + f->dslot = 0; + f->auth = 0; + f->next = flist[h]; + flist[h] = f; + goto out; + } + } + unlock(&flock); + return 0; + +out: + unlock(&flock); + qlock(f); + if(f->fid == fid && f->cp == cp) + return f; + qunlock(f); + goto loop; +} + +/* + * always called with flock locked + */ +File* +newfp(void) +{ + static int first; + File *f; + int start, i; + + i = first; + start = i; + do { + f = &files[i]; + i++; + if(i >= conf.nfile) + i = 0; + if(f->cp) + continue; + first = i; + return f; + } while(i != start); + + print("out of files\n"); + return 0; +} + +void +freefp(File *fp) +{ + Chan *cp; + File *f, *prev; + int h; + + if(!fp || !(cp = fp->cp)) + return; + + h = (long)(uintptr)cp + fp->fid; + if(h < 0) + h = ~h; + h %= nelem(flist); + + lock(&flock); + for(prev=0,f=flist[h]; f; prev=f,f=f->next) + if(f == fp) { + if(prev) + prev->next = f->next; + else + flist[h] = f->next; + break; + } + fp->cp = 0; + unlock(&flock); +} + +int +iaccess(File *f, Dentry *d, int m) +{ + + /* uid none gets only other permissions */ + if(f->uid != 0) { + /* + * owner + */ + if(f->uid == d->uid) + if((m<<6) & d->mode) + return 0; + /* + * group membership + */ + if((m<<3) & d->mode) + if(ingroup(f->uid, d->gid)) + return 0; + } + + /* + * other + */ + if(m & d->mode) { + if((d->mode & DDIR) && (m == DEXEC)) + return 0; + if(!ingroup(f->uid, 9999)) + return 0; + } + + /* + * various forms of superuser + */ + if(f->cp == cons.chan) + return 0; + if(ALLOW(f->cp)) + return 0; + if(duallow != 0 && duallow == f->uid) + if((d->mode & DDIR) && (m == DREAD || m == DEXEC)) + return 0; + + return 1; +} + +Tlock* +tlocked(Iobuf *p, Dentry *d) +{ + Tlock *t, *t1; + Off qpath; + Timet tim; + Device *dev; + + tim = toytime(); + qpath = d->qid.path; + dev = p->dev; + +again: + t1 = 0; + for(t=tlocks+NTLOCK-1; t>=tlocks; t--) { + if(t->qpath == qpath) + if(t->time >= tim) + if(t->dev == dev) + return nil; /* its locked */ + if(t1 != nil && t->time == 0) + t1 = t; /* remember free lock */ + } + if(t1 == 0) { + // reclaim old locks + lock(&tlocklock); + for(t=tlocks+NTLOCK-1; t>=tlocks; t--) + if(t->time < tim) { + t->time = 0; + t1 = t; + } + unlock(&tlocklock); + } + if(t1) { + lock(&tlocklock); + if(t1->time != 0) { + unlock(&tlocklock); + goto again; + } + t1->dev = dev; + t1->qpath = qpath; + t1->time = tim + TLOCK; + unlock(&tlocklock); + } + /* botch + * out of tlock nodes simulates + * a locked file + */ + return t1; +} + +Wpath* +newwp(void) +{ + static int si = 0; + int i; + Wpath *w, *sw, *ew; + + i = si + 1; + if(i < 0 || i >= conf.nwpath) + i = 0; + si = i; + sw = &wpaths[i]; + ew = &wpaths[conf.nwpath]; + for(w=sw;;) { + w++; + if(w >= ew) + w = &wpaths[0]; + if(w == sw) { + print("out of wpaths\n"); + return 0; + } + if(w->refs) + continue; + lock(&wpathlock); + if(w->refs) { + unlock(&wpathlock); + continue; + } + w->refs = 1; + w->up = 0; + unlock(&wpathlock); + return w; + } + +} + +void +freewp(Wpath *w) +{ + lock(&wpathlock); + for(; w; w=w->up) + w->refs--; + unlock(&wpathlock); +} + +Off +qidpathgen(Device *dev) +{ + Iobuf *p; + Superb *sb; + Off path; + + p = getbuf(dev, superaddr(dev), Bread|Bmod); + if(!p || checktag(p, Tsuper, QPSUPER)) + panic("newqid: super block"); + sb = (Superb*)p->iobuf; + sb->qidgen++; + path = sb->qidgen; + putbuf(p); + return path; +} + +/* truncating to length > 0 */ +static void +truncfree(Truncstate *ts, Device *dev, int d, Iobuf *p, int i) +{ + int pastlast; + Off a; + + pastlast = ts->pastlast; + a = ((Off *)p->iobuf)[i]; + if (d > 0 || pastlast) + buffree(dev, a, d, ts); + if (pastlast) { + ((Off *)p->iobuf)[i] = 0; + p->flags |= Bmod|Bimm; + } else if (d == 0 && ts->relblk == ts->lastblk) + ts->pastlast = 1; + if (d == 0) + ts->relblk++; +} + +/* + * free the block at `addr' on dev. + * if it's an indirect block (d [depth] > 0), + * first recursively free all the blocks it names. + * + * ts->relblk is the block number within the file of this + * block (or the first data block eventually pointed to via + * this indirect block). + */ +void +buffree(Device *dev, Off addr, int d, Truncstate *ts) +{ + Iobuf *p; + Off a; + int i, pastlast; + + if(!addr) + return; + pastlast = (ts == nil? 1: ts->pastlast); + /* + * if this is an indirect block, recurse and free any + * suitable blocks within it (possibly via further indirect blocks). + */ + if(d > 0) { + d--; + p = getbuf(dev, addr, Bread); + if(p) { + if (ts == nil) /* common case: create */ + for(i=INDPERBUF-1; i>=0; i--) { + a = ((Off *)p->iobuf)[i]; + buffree(dev, a, d, nil); + } + else /* wstat truncation */ + for (i = 0; i < INDPERBUF; i++) + truncfree(ts, dev, d, p, i); + putbuf(p); + } + } + if (!pastlast) + return; + /* + * having zeroed the pointer to this block, add it to the free list. + * stop outstanding i/o + */ + p = getbuf(dev, addr, Bprobe); + if(p) { + p->flags &= ~(Bmod|Bimm); + putbuf(p); + } + /* + * dont put written worm + * blocks into free list + */ + if(dev->type == Devcw) { + i = cwfree(dev, addr); + if(i) + return; + } + p = getbuf(dev, superaddr(dev), Bread|Bmod); + if(!p || checktag(p, Tsuper, QPSUPER)) + panic("buffree: super block"); + addfree(dev, addr, (Superb*)p->iobuf); + putbuf(p); +} + +Off +bufalloc(Device *dev, int tag, long qid, int uid) +{ + Iobuf *bp, *p; + Superb *sb; + Off a, n; + + p = getbuf(dev, superaddr(dev), Bread|Bmod); + if(!p || checktag(p, Tsuper, QPSUPER)) { + print("bufalloc: super block\n"); + if(p) + putbuf(p); + return 0; + } + sb = (Superb*)p->iobuf; + +loop: + n = --sb->fbuf.nfree; + sb->tfree--; + if(n < 0 || n >= FEPERBUF) { + print("bufalloc: %Z: bad freelist\n", dev); + n = 0; + sb->fbuf.free[0] = 0; + } + a = sb->fbuf.free[n]; + if(n <= 0) { + if(a == 0) { + sb->tfree = 0; + sb->fbuf.nfree = 1; + if(dev->type == Devcw) { + n = uid; + if(n < 0 || n >= nelem(growacct)) + n = 0; + growacct[n]++; + if(cwgrow(dev, sb, uid)) + goto loop; + } + putbuf(p); + print("fs %Z full uid=%d\n", dev, uid); + return 0; + } + bp = getbuf(dev, a, Bread); + if(!bp || checktag(bp, Tfree, QPNONE)) { + if(bp) + putbuf(bp); + putbuf(p); + return 0; + } + sb->fbuf = *(Fbuf*)bp->iobuf; + putbuf(bp); + } + + bp = getbuf(dev, a, Bmod); + memset(bp->iobuf, 0, RBUFSIZE); + settag(bp, tag, qid); + if(tag == Tdir || (tag >= Tind1 && tag <= Tmaxind)) + bp->flags |= Bimm; + putbuf(bp); + putbuf(p); + return a; +} + +/* + * what are legal characters in a name? + * only disallow control characters. + * a) utf avoids control characters. + * b) '/' may not be the separator + */ +int +checkname(char *n) +{ + int i, c; + + for(i=0; ifbuf.nfree; + if(n < 0 || n > FEPERBUF) + panic("addfree: bad freelist"); + if(n >= FEPERBUF) { + p = getbuf(dev, addr, Bmod|Bimm); + if(p == 0) + panic("addfree: getbuf"); + *(Fbuf*)p->iobuf = sb->fbuf; + settag(p, Tfree, QPNONE); + putbuf(p); + n = 0; + } + sb->fbuf.free[n++] = addr; + sb->fbuf.nfree = n; + sb->tfree++; + if(addr >= sb->fsize) + sb->fsize = addr+1; +} + +static int +Yfmt(Fmt* fmt) +{ + Chan *cp; + char s[20]; + + cp = va_arg(fmt->args, Chan*); + sprint(s, "C%d.%.3d", cp->type, cp->chan); + + return fmtstrcpy(fmt, s); +} + +static int +Zfmt(Fmt* fmt) +{ + Device *d; + int c, c1; + char s[100]; + + d = va_arg(fmt->args, Device*); + if(d == 0) { + sprint(s, "Z***"); + goto out; + } + switch(d->type) { + default: + sprint(s, "D%d", d->type); + break; + case Devwren: + case Devide: + case Devmv: + case Devia: + case Devworm: + case Devlworm: + c = devtab[d->type].c; + if(d->wren.ctrl == 0 && d->wren.lun == 0) + sprint(s, "%c%d", c, d->wren.targ); + else + sprint(s, "%c%d.%d.%d", c, d->wren.ctrl, d->wren.targ, d->wren.lun); + break; + case Devaoe: + if(d->wren.ctrl != 0) + panic("nonzero aoe controller"); + sprint(s, "e%d.%d", d->wren.targ, d->wren.lun); + break; + case Devmcat: + case Devmlev: + case Devmirr: + c = devtab[d->type].c; + c1 =devtab[d->type].c1; + if(d->cat.first == d->cat.last) + sprint(s, "%c%Z%c", c, d->cat.first, c1); + else if(d->cat.first->link == d->cat.last) + sprint(s, "%c%Z%Z%c", c, d->cat.first, d->cat.last, c1); + else + sprint(s, "%c%Z-%Z%c", c, d->cat.first, d->cat.last, c1); + break; + case Devro: + sprint(s, "o%Z%Z", d->ro.parent->cw.c, d->ro.parent->cw.w); + break; + case Devcw: + sprint(s, "c%Z%Z", d->cw.c, d->cw.w); + break; + case Devjuke: + sprint(s, "j%Z%Z", d->j.j, d->j.m); + break; + case Devfworm: + sprint(s, "f%Z", d->fw.fw); + break; + case Devpart: + if(d->part.name) + sprint(s, "p%Z\"%s\"", d->part.d, d->part.name); + else if(d->part.base < 101) + sprint(s, "p(%Z)%ulld.%ulld", d->part.d, d->part.base, d->part.size); + else + sprint(s, "p(%Z)%ulld.%ulld", d->part.d, d->part.base, d->part.base+d->part.size); + break; + case Devswab: + sprint(s, "x%Z", d->swab.d); + break; + case Devnone: + sprint(s, "n"); + break; + } +out: + return fmtstrcpy(fmt, s); +} + +static int +Wfmt(Fmt* fmt) +{ + Filter* a; + char s[60]; + + a = va_arg(fmt->args, Filter*); + snprint(s, sizeof s, "%9lud %9lud %9lud", + fdf(a->filter[0], 60), + fdf(a->filter[1], 600), + fdf(a->filter[2], 6000)); + return fmtstrcpy(fmt, s); +} + +static int +wfmt(Fmt *fmt) +{ + Filter *a; + char s[12]; + int n; + + n = 60; + if(fmt->flags&FmtPrec) + n = fmt->prec; + a = va_arg(fmt->args, Filter*); + snprint(s, sizeof s, "%9lud", fdf(a->filter[0], n)); + return fmtstrcpy(fmt, s); +} + +static int +Gfmt(Fmt* fmt) +{ + int t; + char *s; + + t = va_arg(fmt->args, int); + s = ""; + if(t >= 0 && t < MAXTAG) + s = tagnames[t]; + return fmtstrcpy(fmt, s); +} + +static int +Efmt(Fmt* fmt) +{ + char s[64]; + uchar *p; + + p = va_arg(fmt->args, uchar*); + sprint(s, "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux", + p[0], p[1], p[2], p[3], p[4], p[5]); + + return fmtstrcpy(fmt, s); +} + +static int +Ifmt(Fmt* fmt) +{ + char s[64]; + uchar *p; + + p = va_arg(fmt->args, uchar*); + sprint(s, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + + return fmtstrcpy(fmt, s); +} + +static char *ipflagtab[] = { +[0] "cec", +[1] "aoe", +[2] "aoejumbo", +}; + +int +φfmt(Fmt *f) +{ + int flag, i; + char buf[32], *p, *e; + + flag = va_arg(f->args, int); + + p = buf; + e = p+sizeof buf; + for(i = 0; i < nelem(ipflagtab); i++) + if(flag&1<args, uintmem); + + if(sizeof(uintmem) <= 4 /* || (pa & ~(uintmem)0xffffffff) == 0 */){ + if(f->flags & FmtSharp) + return fmtprint(f, "%#.8ux", (u32int)pa); + return fmtprint(f, "%ud", (u32int)pa); + } + + if(f->flags & FmtSharp) + return fmtprint(f, "%#.16llux", (u64int)pa); + return fmtprint(f, "%llud", (u64int)pa); +} + +void +formatinit(void) +{ + quotefmtinstall(); + fmtinstall('Y', Yfmt); /* print channels */ + fmtinstall('Z', Zfmt); /* print devices */ + fmtinstall('W', Wfmt); /* print filters */ + fmtinstall('w', wfmt); /* " */ + fmtinstall('G', Gfmt); /* print tags */ + fmtinstall('T', Tfmt); /* print times */ + fmtinstall('E', Efmt); /* print ether addresses */ + fmtinstall('I', Ifmt); /* print ip addresses */ + fmtinstall(L'φ', φfmt); /* print ip flags */ + fmtinstall(L'P', Pfmt); /* print uintmem */ +} + +void +rootream(Device *dev, Off addr) +{ + Iobuf *p; + Dentry *d; + + p = getbuf(dev, addr, Bmod|Bimm); + memset(p->iobuf, 0, RBUFSIZE); + settag(p, Tdir, QPROOT); + d = getdir(p, 0); + strcpy(d->name, "/"); + d->uid = -1; + d->gid = -1; + d->mode = DALLOC | DDIR | + ((DREAD|DEXEC) << 6) | + ((DREAD|DEXEC) << 3) | + ((DREAD|DEXEC) << 0); + d->qid = QID9P1(QPROOT|QPDIR,0); + d->atime = time(); + d->mtime = d->atime; + d->muid = 0; + putbuf(p); +} + +void +superream(Device *dev, Off addr) +{ + Iobuf *p; + Superb *s; + Off i; + + p = getbuf(dev, addr, Bmod|Bimm); + memset(p->iobuf, 0, RBUFSIZE); + settag(p, Tsuper, QPSUPER); + + s = (Superb*)p->iobuf; + s->fstart = 2; + s->fsize = devsize(dev); + s->fbuf.nfree = 1; + s->qidgen = 10; +#ifdef AUTOSWAB + s->magic = 0x123456789abcdef0; +#endif + print("superream %lld bufs\n", s->fsize-1); + for(i=s->fsize-1; i>=addr+2; i--){ + if((i&(512*1024-1)) == 0) + print("%llud ", i); + addfree(dev, i, s); + } + print("done\n"); + putbuf(p); +} + +struct +{ + Lock; + Msgbuf *smsgbuf; + Msgbuf *lmsgbuf; +} msgalloc; + +/* + * pre-allocate some message buffers at boot time. + * if this supply is exhausted, more will be allocated as needed. + */ +void +mbinit(void) +{ + Msgbuf *mb; + Rabuf *rb; + int i; + + lock(&msgalloc); + unlock(&msgalloc); + msgalloc.lmsgbuf = 0; + msgalloc.smsgbuf = 0; + for(i=0; ixdata = ialloc(LARGEBUF+256, 256); + mb->flags = LARGE; + mb->free = 0; + mbfree(mb); + cons.nlarge++; + } + for(i=0; ixdata = ialloc(SMALLBUF+256, 256); + mb->flags = 0; + mb->free = 0; + mbfree(mb); + cons.nsmall++; + } + memset(mballocs, 0, sizeof(mballocs)); + + lock(&rabuflock); + unlock(&rabuflock); + rabuffree = 0; + for(i=0; i<1000; i++) { + rb = ialloc(sizeof(*rb), 0); + rb->link = rabuffree; + rabuffree = rb; + } +} + +Msgbuf* +mballoc(int count, Chan *cp, int category) +{ + Msgbuf *mb; + + ilock(&msgalloc); + if(count > SMALLBUF) { + if(count > LARGEBUF) + panic("msgbuf count"); + mb = msgalloc.lmsgbuf; + if(mb == 0) { + mb = ialloc(sizeof(Msgbuf), 0); + mb->xdata = ialloc(LARGEBUF+256, 256); + cons.nlarge++; + } else + msgalloc.lmsgbuf = mb->next; + mb->flags = LARGE; + } else { + mb = msgalloc.smsgbuf; + if(mb == 0) { + mb = ialloc(sizeof(Msgbuf), 0); + mb->xdata = ialloc(SMALLBUF+256, 256); + cons.nsmall++; + } else + msgalloc.smsgbuf = mb->next; + mb->flags = 0; + } + mballocs[category]++; + iunlock(&msgalloc); + mb->count = count; + mb->chan = cp; + mb->next = 0; + mb->param = 0; + mb->category = category; + mb->data = mb->xdata+256; + mb->free = 0; + return mb; +} + +#define Round(s, n) (((s)+(n-1))&~(n-1)) +void +mballocpool(int n, int sz, int align, int category, void (*f)(Msgbuf*)) +{ + int i; + Msgbuf *a, *mb; + + /* + * put the Msgbuf in the tail of the allocation if it fits. otherwise + * don't waste a whole align + */ + if(align != 0 && Round(sz, align)-sz >= sizeof *a && sizeof *a < align) + a = 0; + else + a = ialloc(n*sizeof *a, 0); + ilock(&msgalloc); + for(i = 0; i < n; i++){ + if(a) + mb = a+i; + else + mb = ialloc(sizeof(Msgbuf), 0); + mb->xdata = ialloc(sz, align); + mb->free = f; + mb->flags = 0; + mballocs[category]++; + mb->count = sz; + mb->chan = 0; + mb->next = 0; + mb->param = 0; + mb->category = category; + mb->data = (uchar*)Round((uintptr)mb->xdata, align); + mb->free(mb); + } + iunlock(&msgalloc); +} + + +void +mbfree(Msgbuf *mb) +{ + if(mb == nil) + return; + if(mb->flags & BTRACE) + print("mbfree: BTRACE cat=%d flags=%ux, caller %#p\n", + mb->category, mb->flags, getcallerpc(&mb)); + if(mb->flags & FREE) + panic("mbfree already free"); + + /* + * drivers which perform non cache coherent DMA manage their own buffer + * pool of uncached buffers and provide their own free routine. + * this is provided mainly for ethernet drivers ported from cpu kernel. + */ + if(mb->free){ + mb->free(mb); + return; + } + + ilock(&msgalloc); + mballocs[mb->category]--; + mb->flags |= FREE; + if(mb->flags & LARGE) { + mb->next = msgalloc.lmsgbuf; + msgalloc.lmsgbuf = mb; + } else { + mb->next = msgalloc.smsgbuf; + msgalloc.smsgbuf = mb; + } + mb->data = 0; + mb->free = 0; + iunlock(&msgalloc); +} + +/* + * returns 1 if n is prime + * used for adjusting lengths + * of hashing things. + * there is no need to be clever + */ +int +prime(vlong n) +{ + long i; + + if((n%2) == 0) + return 0; + for(i=3;; i+=2) { + if((n%i) == 0) + return 0; + if((vlong)i*i >= n) + return 1; + } +} + +char* +getwd(char *word, char *line) +{ + int c, n; + + while(*line == ' ') + line++; + for(n=0; ncount; + if(c > 0) { + if(ret == 0){ + /* since we consume nothing, wake up next guy */ + p = q->rhead; + if(p != nil) { + q->rhead = p->qnext; + if(q->rhead == nil) + q->rtail = nil; + iunlock(q); + ready(p); + }else + iunlock(q); + return 0; + } + i = q->loc; + a = q->args[i]; + i++; + if(i >= q->size) + i = 0; + q->loc = i; + q->count = c-1; + p = q->whead; + if(p) { + q->whead = p->qnext; + if(q->whead == 0) + q->wtail = 0; + iunlock(q); + ready(p); + }else + iunlock(q); + return a; + } + p = q->rtail; + if(p == 0) + q->rhead = u; + else + p->qnext = u; + q->rtail = u; + u->qnext = 0; + u->state = Recving; + iunlock(q); + sched(); + } +} + +void +send(Queue *q, void *a) +{ + User *p; + int i, c; + + if(q == 0) + panic("send null q %#p", getcallerpc(q)); + if(a == 0) + panic("send null a %#p", getcallerpc(q)); + if(u == nil) + panic("send with no u %#p", getcallerpc(q)); + if(u->nlock){ + print("send with locks %#p", getcallerpc(q)); + printlocks(u); + } + for(;;) { + ilock(q); + c = q->count; + if(c < q->size) { + i = q->loc + c; + if(i >= q->size) + i -= q->size; + q->args[i] = a; + q->count = c+1; + p = q->rhead; + if(p != nil) { + q->rhead = p->qnext; + if(q->rhead == nil) + q->rtail = nil; + iunlock(q); + ready(p); + }else + iunlock(q); + return; + } + if(u->nlock) + print("%d: q blocking nlock %ld\n", u->pid, u->nlock); + p = q->wtail; + if(p == 0) + q->whead = u; + else + p->qnext = u; + q->wtail = u; + u->qnext = 0; + u->state = Sending; + iunlock(q); + sched(); + } +} + +Queue* +newqueue(int size) +{ + Queue *q; + + q = ialloc(sizeof(Queue) + (size-1)*sizeof(void*), 0); + q->size = size; + lock(q); + unlock(q); + return q; +} + +no(void*) +{ + return 0; +} --- /usr/quanstro/src/fs/port/proc.c Thu Jan 1 00:00:00 1970 +++ /usr/quanstro/src/fs/port/proc.c Tue Aug 27 23:27:30 2013 @@ -0,0 +1,379 @@ +#include "all.h" + +struct +{ + Lock; + ulong pid; +} pidalloc; + +struct +{ + Lock; + User *arena; + User *free; +} procalloc; + +volatile struct +{ + Lock; + User *head; + User *tail; +} runq; + +char *statename[] = /* BUG: generate automatically */ +{ + [Dead] "Dead", + [Moribund] "Moribund", + [Zombie] "Zombie", + [Ready] "Ready", + [Scheding] "Scheding", + [Running] "Running", + [Queueing] "Queueing", + [Sending] "Sending", + [Recving] "Recving", + [MMUing] "MMUing", + [Exiting] "Exiting", + [Inwait] "Inwait", + [Wakeme] "Wakeme", + [Broken] "Broken", +}; + +static void +cmd_trace(int argc, char *argv[]) +{ + int n; + + n = 0; + if(argc > 1) + n = number(argv[1], n, 10); + dotrace(n); +} + +static void +cmd_cpu(int argc, char *argv[]) +{ + int i, j; + User *p; + char *text; + + /* HACK */ + if(argc == 1) + for(i=0; iidle); + prflush(); + } + + p = procalloc.arena; + for(i=0; itext; + if(text == nil) + continue; + for(j=1; j 1) + continue; + found: + print("%2d %.8s %9s%W\n", + p->pid, text, + statename[p->state], + &p->time); + prflush(); + } +} + +/* + * Always splhi()'ed. + */ +void +schedinit(void) /* never returns */ +{ + User *p; + + setlabel(&m->sched); + if(u != nil) { + m->proc = nil; + p = u; + u = nil; + if(p->state == Running) + ready(p); + p->mach = nil; + } + sched(); +} + +void +sched(void) +{ + User *p; + + if(u != nil) { + splhi(); + if(setlabel(&u->sched)) { /* woke up */ + if(u->mach != nil) + panic("mach non nil"); + u->state = Running; + u->mach = m; + m->proc = u; + spllo(); + return; + } + gotolabel(&m->sched); + } + spllo(); + p = runproc(); + splhi(); + u = p; + gotolabel(&p->sched); +} + +void +ready(User *p) +{ + Mpl s; + + if(p->state == Ready){ + print("ready Ready\n"); + return; + } + s = splhi(); + lock(&runq); + p->rnext = 0; + if(runq.tail) + runq.tail->rnext = p; + else + runq.head = p; + runq.tail = p; + p->state = Ready; + unlock(&runq); + splx(s); +} + +/* + * Always called spllo + */ +User* +runproc(void) +{ + User *p; + + for (;;) { + while(runq.head == nil) /* if nobody to run, */ + idle(); /* idle with intrs enabled */ + splhi(); + lock(&runq); + p = runq.head; + if (p != nil && p->mach == nil) + break; + unlock(&runq); + spllo(); + } + if(p->rnext == nil) + runq.tail = nil; + runq.head = p->rnext; + if(p->state != Ready) + print("runproc %d %s\n", p->pid, statename[p->state]); + unlock(&runq); + p->state = Scheding; + spllo(); + return p; +} + +User* +newproc(void) +{ + User *p; + +loop: + lock(&procalloc); + if(p = procalloc.free) { /* assign = */ + procalloc.free = p->qnext; + p->state = Zombie; + unlock(&procalloc); + p->mach = 0; + p->qnext = 0; + p->exiting = 0; + p->nlock = 0; + p->delaysched = 0; + lock(&pidalloc); + p->pid = ++pidalloc.pid; + unlock(&pidalloc); + return p; + } + unlock(&procalloc); + panic("no procs"); + goto loop; +} + +void +procinit(void) +{ + User *p; + int i; + + procalloc.free = ialloc(conf.nproc*sizeof(User), 0); + procalloc.arena = procalloc.free; + + p = procalloc.free; + for(i=0; iqnext = p+1; + wakeup(&p->tsleep); + } + p->qnext = 0; + wakeup(&p->tsleep); + + cmd_install("cpu", "[proc] -- process cpu time", cmd_cpu); + cmd_install("trace", "[number] -- stack trace/qlocks", cmd_trace); +} + +void +sleep(Rendez *r, int (*f)(void*), void *arg) +{ + User *p; + int s; + + if(u->nlock){ + print("user %d sleeps with %lud at %#p\n", u->pid, u->nlock, getcallerpc(&r)); + printlocks(u); + } + + /* + * spl is to allow lock to be called + * at interrupt time. lock is mutual exclusion + */ + s = splhi(); + lock(r); + + /* + * if condition happened, never mind + */ + if(f(arg)) { + unlock(r); + splx(s); + return; + } + + /* + * now we are committed to + * change state and call scheduler + */ + p = r->p; + if(p) + print("double sleep pid %d/%#p %d\n", u->pid, getcallerpc(&r), p->pid); + u->state = Wakeme; + r->p = u; + + /* + * sched does the unlock(u) when it is safe + * it also allows to be called splhi. + */ + unlock(r); + sched(); +} + +int +tfn(void *arg) +{ + return Ticks - u->twhen >= 0 || (*u->tfn)(arg); +} + +void +tsleep(Rendez *r, int (*fn)(void*), void *arg, int ms) +{ + Timet when; + User *f, **l; + + when = MS2TK(ms)+Ticks; + + lock(&talarm); + /* take out of list if checkalarm didn't */ + if (u == nil) + panic("cpu%d: tsleep: nil u from %#p", m->machno, getcallerpc(&r)); + if(u->trend) { + l = &talarm.list; + for(f = *l; f; f = f->tlink) { + if(f == u) { + *l = u->tlink; + break; + } + l = &f->tlink; + } + } + /* insert in increasing time order */ + l = &talarm.list; + for(f = *l; f; f = f->tlink) { + if(f->twhen - when >= 0) + break; + l = &f->tlink; + } + u->trend = r; + u->twhen = when; + u->tfn = fn; + u->tlink = *l; + *l = u; + unlock(&talarm); + + sleep(r, tfn, arg); + u->twhen = 0; +} + +void +wakeup(Rendez *r) +{ + User *p; + Mpl s; + + s = splhi(); + lock(r); + p = r->p; + if(p != nil) { + r->p = nil; + if(p->state != Wakeme) + panic("wakeup: not Wakeme"); + ready(p); + } + unlock(r); + splx(s); +} + +void +dotrace(int n) +{ + User *p; + QLock *q; + int i, j, f; + + p = procalloc.arena; + for(i=0; ipid == n) + dumpstack(p); + continue; + } + if(q = p->has.want) { + if(q->name) + print("pid %d wants %.10s\n", + p->pid, q->name); + else + print("pid %d wants %p\n", + p->pid, q); + } + f = 0; + for(j=0; jhas.q[j]) { + if(f == 0) { + if(p->has.want == 0) + print("pid %d wants nothing\n", p->pid); + print(" has"); + f = 1; + } + if(q->name) + print(" %.10s", q->name); + else + print(" %p", q); + } + } + if(f) + print("\n"); + } +}