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.
--- /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;
+}
+