ref: 8b6238bf263ac5d1f357c0f4a4d0e113b83f1570
dir: /gpufs.c/
#include <u.h> #include <libc.h> #include <fcall.h> #include <thread.h> #include <9p.h> #include <String.h> #include "vm.h" void usage(void) { fprint(2, "usage: %s [-d]\n", argv0); exits("usage"); } void* emalloc(int n) { void *v; v = emalloc9p(n); setmalloctag(v, getcallerpc(&n)); memset(v, 0, n); return v; } char* estrdup(char *s) { s = estrdup9p(s); setmalloctag(s, getcallerpc(&s)); return s; } enum { Qroot, Qrctl, Qdesc, Qobject, Qctl, Qbuffer, Qshader, }; static char *nametab[] = { "/", "ctl", "desc", nil, "ctl", "buffer", "shader", }; typedef struct Gpufid Gpufid; struct Gpufid { int level; int id; }; #define OBJECTID(c) (((Gpufid*)(c))->id) char fserr[512]; static void responderr(Req *r) { snprint(fserr, 512, "%r"); respond(r, fserr); } String *fsqueue = nil; static void fsqprint(char *fmt, ...) { char sbuf[512]; va_list arg; va_start(arg, fmt); vseprint(sbuf, sbuf + sizeof(sbuf), fmt, arg); va_end(arg); fsqueue = s_append(fsqueue, sbuf); } int debug = 0; static char *user; static long time0; static void* wfaux(Gpufid *f) { if (f->level < Qobject) return nil; return f; } static void fsmkqid(Qid *q, int level, void *aux) { q->type = 0; q->vers = 0; switch (level) { case Qroot: case Qobject: q->type = QTDIR; default: q->path = (level<<24) | (((uintptr)aux ^ time0) & 0x00ffffff); } } static void fsmkdir(Dir *d, int level, void *aux) { char buf[1024]; memset(d, 0, sizeof(*d)); fsmkqid(&d->qid, level, aux); d->mode = 0666; d->atime = d->mtime = time0; d->uid = estrdup(user); d->gid = estrdup(user); d->muid = estrdup(user); if (d->qid.type & QTDIR) d->mode |= DMDIR | 0111; switch (level) { case Qobject: snprint(buf, sizeof(buf), "%lld", (vlong)aux); d->name = estrdup(buf); return; case Qrctl: case Qctl: break; case Qdesc: d->length = getnumdescpools(); break; case Qbuffer: d->length = getbufferlength(OBJECTID(aux)); break; case Qshader: d->length = getshaderlength(OBJECTID(aux)); break; } d->mode = 0666; d->name = strdup(nametab[level]); } static int rootgen(int i, Dir *d, void*) { vlong id; i += Qroot + 1; if (i < Qobject) { fsmkdir(d, i, 0); return 0; } i -= Qobject; if (i < getnumobjects()) { id = getobjectid(i); if (id < 0) { fprint(2, "error: %r\n"); return -1; } fsmkdir(d, Qobject, (void*)id); return 0; } return -1; } static int objectgen(int i, Dir *d, void *aux) { Gpufid *f; i += Qobject + 1; f = aux; switch (i) { case Qctl: fsmkdir(d, Qctl, aux); return 0; case Qbuffer: fsmkdir(d, getobjecttype(f->id) == BUFFER ? Qbuffer : Qshader, aux); return 0; } return -1; } static void readrctl(Req *r) { readstr(r, s_to_c(fsqueue)); s_reset(fsqueue); } static void fsread(Req *r) { //char buf[1024]; //int n; Gpufid *f; char *s; f = r->fid->aux; switch (f->level) { case Qroot: dirread9p(r, rootgen, nil); respond(r, nil); return; case Qobject: dirread9p(r, objectgen, f); respond(r, nil); return; case Qrctl: readrctl(r); respond(r, nil); return; case Qdesc: s = getpoolinfo(); if (s) readstr(r, s); respond(r, nil); return; case Qshader: r->ofcall.count = readshader(OBJECTID(f), r->ofcall.data, r->ifcall.count, r->ifcall.offset); respond(r, nil); return; case Qbuffer: r->ofcall.count = readbuffer(OBJECTID(f), r->ofcall.data, r->ifcall.count, r->ifcall.offset); respond(r, nil); return; case Qctl: s = getobjectinfo(OBJECTID(f)); if (!s) { respond(r, nil); return; } readstr(r, s); respond(r, nil); return; } respond(r, "not implemented"); } static void fsstart(Srv*) { fsqueue = s_new(); } static void fsend(Srv*) { postnote(PNGROUP, getpid(), "shutdown"); exits(nil); } static void fsattach(Req *r) { Gpufid *f; if (r->ifcall.aname && r->ifcall.aname[0]) { respond(r, "invalid attach specifier"); return; } f = emalloc(sizeof(*f)); f->level = Qroot; fsmkqid(&r->fid->qid, f->level, wfaux(f)); r->ofcall.qid = r->fid->qid; r->fid->aux = f; respond(r, nil); } static void fsstat(Req *r) { Gpufid *f; f = r->fid->aux; fsmkdir(&r->d, f->level, wfaux(f)); respond(r, nil); } static char* fswalk1(Fid *fid, char *name, Qid *qid) { Gpufid *f; int i, j; if (!(fid->qid.type & QTDIR)) return "walk in non-directory"; f = fid->aux; if (strcmp(name, "..") == 0) { switch (f->level) { case Qroot: break; case Qobject: //freeobject(f->object); break; default: f->level = Qobject; } } else { for (i = f->level+1; i < nelem(nametab); i++) { if (nametab[i]) { if (strcmp(name, nametab[i]) == 0) break; } if (i == Qobject) { j = atoi(name); if (j >= 0 && j < getnumobjects()) { //f->object = &objects[j]; f->id = j; //incref(f->object); break; } } } if (i >= nelem(nametab)) return "directory entry not found"; f->level = i; } fsmkqid(qid, f->level, wfaux(f)); fid->qid = *qid; return nil; } static void fsopen(Req *r) { respond(r, nil); } static vlong newshader(void) { vlong id = genshader(); if (id < 0) { return -1; } fsqprint("s %lld\n", id); return id; } static vlong newbuffer(long len) { vlong id = genbuffer(len); if (id < 0) { return -1; } fsqprint("b %lld\n", id); return id; } static void rootcommand(Req *r, int argc, char **argv) { // n(ew) s(hader) // n(ew) b(uffer) <len> // n(ew) p(ool) <numsets> // b(ind) <buffer> <pool> <set> <binding> // s(et) <pool> <set> <numbindings> if (argc <= 0) return; if (strcmp(argv[0], "n") == 0) { switch (argc) { case 2: if (strcmp(argv[1], "s") == 0) { if (newshader() < 0) respond(r, "error creating shader!"); else respond(r, nil); return; } break; case 3: if (strcmp(argv[1], "b") == 0) { long len = atol(argv[2]); if (newbuffer(len) < 0) respond(r, "error creating buffer!"); else respond(r, nil); return; } if (strcmp(argv[1], "p") == 0) { int len = atol(argv[2]); int pool = gendescpool(len); if (pool < 0) responderr(r); else { fsqprint("p %d\n", pool); respond(r, nil); } return; } } } if (strcmp(argv[0], "b") == 0) { if (argc != 5) { respond(r, "bad arguments!"); return; } vlong buffer; int pool, set, binding; buffer = atoll(argv[1]); pool = atoi(argv[2]); set = atoi(argv[3]); binding = atoi(argv[4]); if (!binduniform(buffer, pool, set, binding)) { responderr(r); return; } respond(r, nil); return; } if (strcmp(argv[0], "s") == 0) { if (argc != 4) { respond(r, "bad arguments!"); return; } int pool, set, num; pool = atoi(argv[1]); set = atoi(argv[2]); num = atoi(argv[3]); if (!allocdescset(pool, set, num)) { responderr(r); return; } respond(r, nil); return; } respond(r, "error: bad command!"); } static void objectcommand(Req *r, int argc, char **argv) { // c(ompile) // r(un) <entrypoint> // b(ind) <pool> Gpufid* f; int i; f = r->fid->aux; if (argc <= 0) return; switch (getobjecttype(f->id)) { case SHADER: if (strcmp(argv[0], "c") == 0) { if (!compileshader(f->id)) { responderr(r); return; } } if (strcmp(argv[0], "r") == 0) { if (argc != 2) { respond(r, "bad command"); return; } if (!runshader(f->id, argv[1])) { responderr(r); return; } return; } if (strcmp(argv[0], "b") == 0) { if (argc != 2) { respond(r, "bad command"); return; } i = atoi(argv[1]); if (!bindshader(f->id, i)) { responderr(r); return; } respond(r, nil); return; } break; case BUFFER: break; } respond(r, nil); } static void parsecommand(Req *r, char *cmd, void (*f)(Req*,int,char**)) { char *lines[10]; int linec; linec = getfields(cmd, lines, 10, 1, "\n"); for (int i = 0; i < linec; i++) { char *c[10]; int num = getfields(lines[i], c, 10, 1, " \t"); f(r, num, c); } } static void fswrite(Req *r) { Gpufid *f; int n; char *s; char err[256]; f = r->fid->aux; switch (f->level) { case Qrctl: n = r->ofcall.count = r->ifcall.count; s = emalloc(n+1); memmove(s, r->ifcall.data, n); parsecommand(r, s, rootcommand); return; case Qdesc: respond(r, "not supported"); return; case Qshader: r->ofcall.count = writeshader(OBJECTID(f), r->ifcall.data, r->ifcall.count, r->ifcall.offset); if (r->ofcall.count > 0) { respond(r, nil); return; } snprint(err, 256, "%r"); respond(r, err); return; case Qbuffer: r->ofcall.count = writebuffer(OBJECTID(f), r->ifcall.data, r->ifcall.count, r->ifcall.offset); if (r->ofcall.count > 0) { respond(r, nil); return; } snprint(err, 256, "%r"); respond(r, err); return; case Qctl: n = r->ofcall.count = r->ifcall.count; s = emalloc(n+1); memmove(s, r->ifcall.data, n); parsecommand(r, s, objectcommand); return; } respond(r, "not implemented"); } static void fsdestroyfid(Fid *fid) { Gpufid *f; if (f = fid->aux) { fid->aux = nil; //freeobject(f->object); free(f); } } static char* fsclone(Fid *oldfid, Fid *newfid) { Gpufid *f, *o; o = oldfid->aux; if (o == nil) return "bad fid"; f = emalloc(sizeof(*f)); memmove(f, o, sizeof(*f)); //if (f->object) // incref(f->object); newfid->aux = f; return nil; } Srv fs = { .start = fsstart, .attach = fsattach, .stat = fsstat, .walk1 = fswalk1, .clone = fsclone, .open = fsopen, .read = fsread, .write = fswrite, .destroyfid = fsdestroyfid, .end = fsend, }; void main(int argc, char **argv) { char *mtpt = "/mnt/gpu"; char *service = nil; time0 = time(0); user = getuser(); ARGBEGIN { case 'd': debug++; break; } ARGEND; rfork(RFNOTEG); postmountsrv(&fs, service, mtpt, MREPL); exits(nil); }