shithub: gpufs

ref: 8b6238bf263ac5d1f357c0f4a4d0e113b83f1570
dir: /gpufs.c/

View raw version
#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);
}