aboutsummaryrefslogtreecommitdiff
path: root/src/libthread/ioproc.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-12-25 21:57:50 +0000
committerrsc <devnull@localhost>2004-12-25 21:57:50 +0000
commit619085f0b4a85104ef6c7496f9ce1f46e9b17c82 (patch)
tree9959c15a14c44e8c8fe38f78bbcbbb576d23b2aa /src/libthread/ioproc.c
parent1544f90960275dc9211bde30329c3258e0e1bf38 (diff)
downloadplan9port-619085f0b4a85104ef6c7496f9ce1f46e9b17c82.tar.gz
plan9port-619085f0b4a85104ef6c7496f9ce1f46e9b17c82.tar.bz2
plan9port-619085f0b4a85104ef6c7496f9ce1f46e9b17c82.zip
more new libthread
Diffstat (limited to 'src/libthread/ioproc.c')
-rw-r--r--src/libthread/ioproc.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/libthread/ioproc.c b/src/libthread/ioproc.c
new file mode 100644
index 00000000..2296690f
--- /dev/null
+++ b/src/libthread/ioproc.c
@@ -0,0 +1,130 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "ioproc.h"
+
+enum
+{
+ STACK = 32768,
+};
+
+void
+iointerrupt(Ioproc *io)
+{
+ if(!io->inuse)
+ return;
+ fprint(2, "bug: cannot iointerrupt yet\n");
+}
+
+static void
+xioproc(void *a)
+{
+ Ioproc *io, *x;
+ io = a;
+ /*
+ * first recvp acquires the ioproc.
+ * second tells us that the data is ready.
+ */
+ for(;;){
+ while(recv(io->c, &x) == -1)
+ ;
+ if(x == 0) /* our cue to leave */
+ break;
+ assert(x == io);
+
+ /* caller is now committed -- even if interrupted he'll return */
+ while(recv(io->creply, &x) == -1)
+ ;
+ if(x == 0) /* caller backed out */
+ continue;
+ assert(x == io);
+
+ io->ret = io->op(&io->arg);
+ if(io->ret < 0)
+ rerrstr(io->err, sizeof io->err);
+ while(send(io->creply, &io) == -1)
+ ;
+ while(recv(io->creply, &x) == -1)
+ ;
+ }
+}
+
+Ioproc*
+ioproc(void)
+{
+ Ioproc *io;
+
+ io = mallocz(sizeof(*io), 1);
+ if(io == nil)
+ sysfatal("ioproc malloc: %r");
+ io->c = chancreate(sizeof(void*), 0);
+ chansetname(io->c, "ioc%p", io->c);
+ io->creply = chancreate(sizeof(void*), 0);
+ chansetname(io->creply, "ior%p", io->c);
+ io->tid = proccreate(xioproc, io, STACK);
+ return io;
+}
+
+void
+closeioproc(Ioproc *io)
+{
+ if(io == nil)
+ return;
+ iointerrupt(io);
+ while(send(io->c, 0) == -1)
+ ;
+ chanfree(io->c);
+ chanfree(io->creply);
+ free(io);
+}
+
+long
+iocall(Ioproc *io, long (*op)(va_list*), ...)
+{
+ char e[ERRMAX];
+ int ret, inted;
+ Ioproc *msg;
+
+ if(send(io->c, &io) == -1){
+ werrstr("interrupted");
+ return -1;
+ }
+ assert(!io->inuse);
+ io->inuse = 1;
+ io->op = op;
+ va_start(io->arg, op);
+ msg = io;
+ inted = 0;
+ while(send(io->creply, &msg) == -1){
+ msg = nil;
+ inted = 1;
+ }
+ if(inted){
+ werrstr("interrupted");
+ return -1;
+ }
+
+ /*
+ * If we get interrupted, we have stick around so that
+ * the IO proc has someone to talk to. Send it an interrupt
+ * and try again.
+ */
+ inted = 0;
+ while(recv(io->creply, nil) == -1){
+ inted = 1;
+ iointerrupt(io);
+ }
+ USED(inted);
+ va_end(io->arg);
+ ret = io->ret;
+ if(ret < 0)
+ strecpy(e, e+sizeof e, io->err);
+ io->inuse = 0;
+
+ /* release resources */
+ while(send(io->creply, &io) == -1)
+ ;
+ if(ret < 0)
+ errstr(e, sizeof e);
+ return ret;
+}