diff --git a/sys/include/gio.h b/sys/include/gio.h new file mode 100644 index 000000000..825b57d80 --- /dev/null +++ b/sys/include/gio.h @@ -0,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); + diff --git a/sys/man/2/gio b/sys/man/2/gio new file mode 100644 index 000000000..77e29329f --- /dev/null +++ b/sys/man/2/gio @@ -0,0 +1,94 @@ +.TH GIO 2 +.SH NAME +gopen, gclose, gseek, gread, gwrite, fd2gio \- Programmable streams +.SH SYNOPSIS +.B #include +.br +.B #include +.br +.B #include +.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. diff --git a/sys/src/libgio/fd.c b/sys/src/libgio/fd.c new file mode 100644 index 000000000..b83db6ce0 --- /dev/null +++ b/sys/src/libgio/fd.c @@ -0,0 +1,59 @@ +#include +#include +#include + +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); +} + diff --git a/sys/src/libgio/mkfile b/sys/src/libgio/mkfile new file mode 100644 index 000000000..91d0daf67 --- /dev/null +++ b/sys/src/libgio/mkfile @@ -0,0 +1,19 @@ + +#include +#include + +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; +} + diff --git a/sys/src/libgio/readp.c b/sys/src/libgio/readp.c new file mode 100644 index 000000000..13ee405ba --- /dev/null +++ b/sys/src/libgio/readp.c @@ -0,0 +1,45 @@ +#include +#include +#include + +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; +} + diff --git a/sys/src/libgio/test.c b/sys/src/libgio/test.c new file mode 100644 index 000000000..8e3cb008f --- /dev/null +++ b/sys/src/libgio/test.c @@ -0,0 +1,65 @@ +#include +#include +#include + +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; +} diff --git a/sys/src/libgio/writep.c b/sys/src/libgio/writep.c new file mode 100644 index 000000000..0cfeb9530 --- /dev/null +++ b/sys/src/libgio/writep.c @@ -0,0 +1,21 @@ +#include +#include +#include + +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; +} +