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);
}