shithub: riscv

Download patch

ref: a54782d69b31f3eaeb77a8087016065790c200bb
parent: 9c3de0c87a00e09e8a51d7f6de461a0221c6409b
author: Matthew Veety <mveety@mveety.com>
date: Tue Feb 9 11:24:41 EST 2016

Imported ngfs libgio. This is a library to create virtual file descriptors, similar to common lisp grey-streams or golang's io.Reader/io.Writer. Now 95% bug-free.

diff: cannot open b/sys/src/libgio//null: file does not exist: 'b/sys/src/libgio//null'
--- /dev/null
+++ b/sys/include/gio.h
@@ -1,0 +1,24 @@
+#pragma lib "libgio.a"
+#pragma src "/sys/src/libgio"
+
+typedef struct ReadWriter ReadWriter;
+
+struct ReadWriter {
+	RWLock;
+	int (*open)(ReadWriter*);
+	int (*close)(ReadWriter*);
+	long (*pread)(ReadWriter*, void*, long, vlong);
+	long (*pwrite)(ReadWriter*, void*, long, vlong);
+	void *aux;
+	u64int offset;
+	u64int length;
+};
+
+ReadWriter* getrdstruct(int);
+int gopen(ReadWriter*, void*);
+int gclose(int);
+long gread(int, void*, long, vlong);
+long gwrite(int, void*, long, vlong);
+vlong gseek(int, vlong, int);
+int fd2gio(int);
+
--- /dev/null
+++ b/sys/man/2/gio
@@ -1,0 +1,94 @@
+.TH GIO 2
+.SH NAME
+gopen, gclose, gseek, gread, gwrite, fd2gio \- Programmable streams
+.SH SYNOPSIS
+.B #include <u.h>
+.br
+.B #include <libc.h>
+.br
+.B #include <gio.h>
+.PP
+.ft L
+.nf
+typedef struct ReadWriter {
+	RWLock;
+	int (*open)(ReadWriter*);
+	int (*close)(ReadWriter*);
+	long (*pread)(ReadWriter*, void*, long, vlong);
+	long (*pwrite)(ReadWriter*, void*, long, vlong);
+	void *aux;
+	u64int offset;
+	u64int length;
+} ReadWriter;
+.fi
+.PP
+.B
+int gopen(ReadWriter *r, void *aux)
+.PP
+.B
+int gclose(int gfd)
+.PP
+.B
+vlong gseek(int gfd, vlong offset, int whence)
+.PP
+.B
+long gread(int gfd, void *buf, long nbytes, vlong offset)
+.PP
+.B
+long gwrite(int gfd, void *buf, long nbytes, vlong offset)
+.PP
+.B
+int fd2gio(int fd)
+.SH DESCRIPTION
+.I gopen
+takes a ReadWriter struct and creates a new instance of a gio fd.
+.I aux
+is an auxillary argument that may or may not be optional depending on how the gio stream is implemented.
+.I gclose
+closes a gio fd and frees any resources allocated to it.
+.I gseek
+changes the fd in a similar way to
+.IR seek (2).
+.I gread
+and
+.I gwrite
+are the gio equivalents to
+.IR pread (2)
+and
+.IR pwrite (2).
+They are functionally equivalent and have nearly the same usage.
+.I fd2gio
+takes a Plan 9 file descriptor and returns a gio descriptor made from that fd.
+.SH SOURCE
+.B /sys/src/libgio
+.SH NOTES
+The gio functions automatically lock the ReadWriter struct in use hopefully making things work better with
+.IR thread (2).
+.SH BUGS
+Things get interesting with
+.IR rfork (2)
+when you disable shared memory.
+.br
+The file descriptor table is poorly implemented.
+.br
+You cannot easily mix gio file descriptors with functions that want Plan 9 ones.
+.br
+
+.SH SEE ALSO
+.IR read (2),
+.IR seek (2),
+.IR open (2)
+.SH DIAGNOSTICS
+By default, no. Users can have their methods set 
+.I errstr,
+and
+.I gopen,
+.I gclose,
+.I gread,
+and
+.I gwrite
+will return -2 if a function pointer is nil.
+.SH HISTORY
+First appeared as part of
+.IR ngfs (8)
+in September 2015; imported into 9front February 2016.
--- /dev/null
+++ b/sys/src/libgio/fd.c
@@ -1,0 +1,59 @@
+#include <u.h>
+#include <libc.h>
+#include <gio.h>
+
+int fdopen(ReadWriter*);
+int fdclose(ReadWriter*);
+long fdread(ReadWriter*, void*, long, vlong);
+long fdwrite(ReadWriter*, void*, long, vlong);
+
+ReadWriter fdrdwr = {
+	.open = fdopen,
+	.close = fdclose,
+	.pread = fdread,
+	.pwrite = fdwrite,
+};
+
+int
+fdopen(ReadWriter *rd)
+{
+	int *afd = (int*)rd->aux;
+
+	rd->offset = 0;
+	rd->length = (u64int) seek(*afd, 0, 2);
+	seek(*afd, 0, 0);
+	return 0;
+}
+
+int
+fdclose(ReadWriter *rd)
+{
+	void *x = rd->aux;
+	free(x);
+	return 0;
+}
+
+long
+fdread(ReadWriter *rd, void *bf, long len, vlong offset)
+{
+	int *afd = (int*)rd->aux;
+
+	return pread(*afd, bf, len, offset);
+}
+
+long
+fdwrite(ReadWriter *rd, void *bf, long len, vlong offset)
+{
+	int *afd = (int*)rd->aux;
+
+	return pwrite(*afd, bf, len, offset);
+}
+
+int
+fd2gio(int fd)
+{
+	void *x = malloc(sizeof(int));
+	memcpy(x, &fd, sizeof(int));
+	return gopen(&fdrdwr, x);
+}
+
--- /dev/null
+++ b/sys/src/libgio/mkfile
@@ -1,0 +1,19 @@
+</$objtype/mkfile
+
+LIB=/$objtype/lib/libgio.a
+OFILES=\
+	fd.$O \
+	openclose.$O \
+	readp.$O \
+	writep.$O \
+
+HFILES=\
+	/sys/include/gio.h\
+
+UPDATE=\
+	mkfile\
+	$HFILES\
+	${OFILES:%.$O=%.c}\
+	${LIB:/$objtype/%=/386/%}\
+
+</sys/src/cmd/mksyslib
--- /dev/null
+++ b/sys/src/libgio/openclose.c
@@ -1,0 +1,82 @@
+#include <u.h>
+#include <libc.h>
+#include <gio.h>
+
+RWLock giolock;
+ReadWriter *gio_filedes[256];
+uchar gio_filedes_st[256];
+
+int
+getnext(void)
+{
+	int i;
+	for(i = 0; i < 256; i++)
+		if(gio_filedes_st[i] == 0)
+			break;
+	if(i == 256)
+		return -1;
+	return i;
+}
+
+ReadWriter*
+getrdstruct(int fd)
+{
+	rlock(&giolock);
+	ReadWriter *rval;
+	if(gio_filedes_st[fd] != 1)
+		rval = nil;
+	rval = gio_filedes[fd];
+	runlock(&giolock);
+	return rval;
+}
+
+int
+gopen(ReadWriter* rd, void *aux)
+{
+	int pfd;
+	ReadWriter *buf;
+
+	wlock(&giolock);
+	if(pfd == -1){
+		wunlock(&giolock);
+		return -1;
+	}
+	buf = malloc(sizeof(ReadWriter));
+	if(buf == nil)
+		exits("bad malloc");
+	memcpy(buf, rd, sizeof(ReadWriter));
+	buf->aux = aux;
+	buf->offset = 0;
+	if(buf->open != nil){
+		if((buf->open(buf)) != 0){
+			buf->close(buf);
+			free(buf);
+			wunlock(&giolock);
+			return -1;
+		}
+	}
+	gio_filedes[pfd] = buf;
+	gio_filedes_st[pfd] = 1;
+	wunlock(&giolock);
+	return pfd;
+}
+
+int
+gclose(int fd)
+{
+	ReadWriter *bf;
+	int rval = 0;
+
+	if(gio_filedes_st[fd] == 0)
+		return -1;
+	wlock(&giolock);
+	bf = gio_filedes[fd];
+	if(bf->close != nil)
+		rval = bf->close(bf);
+	free(bf);
+	gio_filedes_st[fd] = 0;
+	gio_filedes[fd] = nil;
+	wunlock(&giolock);
+	return rval;
+}
+
--- /dev/null
+++ b/sys/src/libgio/readp.c
@@ -1,0 +1,45 @@
+#include <u.h>
+#include <libc.h>
+#include <gio.h>
+
+long
+gread(int fd, void *bf, long len, vlong offset)
+{
+	ReadWriter *rd;
+	long rval = 0;
+	
+	rd = getrdstruct(fd);
+	if(rd == nil)
+		return -1;
+	if(rd->pread == nil)
+		return -2;
+	rlock(rd);
+	rval = rd->pread(rd, bf, offset, len);
+	runlock(rd);
+	return rval;
+}
+
+vlong
+gseek(int fd, vlong offset, int type)
+{
+	ReadWriter *rd;
+
+	rd = getrdstruct(fd);
+	if(rd == nil)
+		return -1;
+	wlock(rd);
+	switch(type){
+	case 0:
+		rd->offset = (u64int)offset;
+		break;
+	case 1:
+		rd->offset = rd->offset + (u64int)offset;
+		break;
+	case 2:
+		rd->offset = rd->length + (u64int)offset;
+		break;
+	}
+	wunlock(rd);
+	return rd->offset;
+}
+
--- /dev/null
+++ b/sys/src/libgio/test.c
@@ -1,0 +1,65 @@
+#include <u.h>
+#include <libc.h>
+#include <gio.h>
+
+int topen(ReadWriter*);
+int tclose(ReadWriter*);
+long tread(ReadWriter*, void*, long, vlong);
+long twrite(ReadWriter*, void*, long, vlong);
+
+ReadWriter tester = {
+	.open = topen,
+	.close = tclose,
+	.pread = tread,
+	.pwrite = twrite,
+};
+
+void
+main(int argc, char *argv[])
+{
+	int gfd = gopen(&tester, nil);
+	if(gfd < 0){
+		print("gio_test: failed to open gio fd\n");
+		exits("failure");
+	}
+	char *test1 = "Hello World!\n";
+	char test2[256];
+
+	gread(gfd, &test2, 256, 23);
+	gwrite(gfd, test1, sizeof(test1), 8);
+	print("gio_test: %s\n", test2);
+	gclose(gfd);
+	print("gio_test: passed\n");
+	exits(nil);
+}
+
+int
+topen(ReadWriter *rd)
+{
+	print("gio_test: topen: file opened!\n");
+	return 0;
+}
+
+int
+tclose(ReadWriter *rd)
+{
+	print("gio_test: tclose: file closed!\n");
+	return 0;
+}
+
+long
+tread(ReadWriter *rd, void *bf, long len, vlong offset)
+{
+	char *test = "this is a read string!";
+	memcpy(bf, test, strlen(test)+1);
+	print("gio_test: tread: len = %ud, offset = %ud\n", len, offset);
+	return len;
+}
+
+long
+twrite(ReadWriter *rd, void *bf, long len, vlong offset)
+{
+	print("gio_test: twrite: written string: %s\n", bf);
+	print("gio_test: twrite: len = %ud, offset = %ud\n", len, offset);
+	return len;
+}
--- /dev/null
+++ b/sys/src/libgio/writep.c
@@ -1,0 +1,21 @@
+#include <u.h>
+#include <libc.h>
+#include <gio.h>
+
+long
+gwrite(int fd, void *buf, long len, vlong offset)
+{
+	ReadWriter *rd;
+	long rval;
+
+	rd = getrdstruct(fd);
+	if(rd == nil)
+		return -1;
+	if(rd->pwrite == nil)
+		return -2;
+	wlock(rd);
+	rval = rd->pwrite(rd, buf, len, offset);
+	wunlock(rd);
+	return rval;
+}
+