Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "ioproc.h"
6 enum
7 {
8 STACK = 32768
9 };
11 void
12 iointerrupt(Ioproc *io)
13 {
14 if(!io->inuse)
15 return;
16 fprint(2, "bug: cannot iointerrupt %p yet\n", io);
17 }
19 static void
20 xioproc(void *a)
21 {
22 Ioproc *io, *x;
24 threadsetname("ioproc");
25 io = a;
26 /*
27 * first recvp acquires the ioproc.
28 * second tells us that the data is ready.
29 */
30 for(;;){
31 while(recv(io->c, &x) == -1)
32 ;
33 if(x == 0) /* our cue to leave */
34 break;
35 assert(x == io);
37 /* caller is now committed -- even if interrupted he'll return */
38 while(recv(io->creply, &x) == -1)
39 ;
40 if(x == 0) /* caller backed out */
41 continue;
42 assert(x == io);
44 io->ret = io->op(&io->arg);
45 if(io->ret < 0)
46 rerrstr(io->err, sizeof io->err);
47 while(send(io->creply, &io) == -1)
48 ;
49 while(recv(io->creply, &x) == -1)
50 ;
51 }
52 }
54 Ioproc*
55 ioproc(void)
56 {
57 Ioproc *io;
59 io = mallocz(sizeof(*io), 1);
60 if(io == nil)
61 sysfatal("ioproc malloc: %r");
62 io->c = chancreate(sizeof(void*), 0);
63 chansetname(io->c, "ioc%p", io->c);
64 io->creply = chancreate(sizeof(void*), 0);
65 chansetname(io->creply, "ior%p", io->c);
66 io->tid = proccreate(xioproc, io, STACK);
67 return io;
68 }
70 void
71 closeioproc(Ioproc *io)
72 {
73 if(io == nil)
74 return;
75 iointerrupt(io);
76 while(send(io->c, 0) == -1)
77 ;
78 chanfree(io->c);
79 chanfree(io->creply);
80 free(io);
81 }
83 long
84 iocall(Ioproc *io, long (*op)(va_list*), ...)
85 {
86 char e[ERRMAX];
87 int ret, inted;
88 Ioproc *msg;
90 if(send(io->c, &io) == -1){
91 werrstr("interrupted");
92 return -1;
93 }
94 assert(!io->inuse);
95 io->inuse = 1;
96 io->op = op;
97 va_start(io->arg, op);
98 msg = io;
99 inted = 0;
100 while(send(io->creply, &msg) == -1){
101 msg = nil;
102 inted = 1;
104 if(inted){
105 werrstr("interrupted");
106 return -1;
109 /*
110 * If we get interrupted, we have stick around so that
111 * the IO proc has someone to talk to. Send it an interrupt
112 * and try again.
113 */
114 inted = 0;
115 while(recv(io->creply, nil) == -1){
116 inted = 1;
117 iointerrupt(io);
119 USED(inted);
120 va_end(io->arg);
121 ret = io->ret;
122 if(ret < 0)
123 strecpy(e, e+sizeof e, io->err);
124 io->inuse = 0;
126 /* release resources */
127 while(send(io->creply, &io) == -1)
129 if(ret < 0)
130 errstr(e, sizeof e);
131 return ret;