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 yet\n");
17 }
19 static void
20 xioproc(void *a)
21 {
22 Ioproc *io, *x;
23 io = a;
24 /*
25 * first recvp acquires the ioproc.
26 * second tells us that the data is ready.
27 */
28 for(;;){
29 while(recv(io->c, &x) == -1)
30 ;
31 if(x == 0) /* our cue to leave */
32 break;
33 assert(x == io);
35 /* caller is now committed -- even if interrupted he'll return */
36 while(recv(io->creply, &x) == -1)
37 ;
38 if(x == 0) /* caller backed out */
39 continue;
40 assert(x == io);
42 io->ret = io->op(&io->arg);
43 if(io->ret < 0)
44 rerrstr(io->err, sizeof io->err);
45 while(send(io->creply, &io) == -1)
46 ;
47 while(recv(io->creply, &x) == -1)
48 ;
49 }
50 }
52 Ioproc*
53 ioproc(void)
54 {
55 Ioproc *io;
57 io = mallocz(sizeof(*io), 1);
58 if(io == nil)
59 sysfatal("ioproc malloc: %r");
60 io->c = chancreate(sizeof(void*), 0);
61 chansetname(io->c, "ioc%p", io->c);
62 io->creply = chancreate(sizeof(void*), 0);
63 chansetname(io->creply, "ior%p", io->c);
64 io->tid = proccreate(xioproc, io, STACK);
65 return io;
66 }
68 void
69 closeioproc(Ioproc *io)
70 {
71 if(io == nil)
72 return;
73 iointerrupt(io);
74 while(send(io->c, 0) == -1)
75 ;
76 chanfree(io->c);
77 chanfree(io->creply);
78 free(io);
79 }
81 long
82 iocall(Ioproc *io, long (*op)(va_list*), ...)
83 {
84 char e[ERRMAX];
85 int ret, inted;
86 Ioproc *msg;
88 if(send(io->c, &io) == -1){
89 werrstr("interrupted");
90 return -1;
91 }
92 assert(!io->inuse);
93 io->inuse = 1;
94 io->op = op;
95 va_start(io->arg, op);
96 msg = io;
97 inted = 0;
98 while(send(io->creply, &msg) == -1){
99 msg = nil;
100 inted = 1;
102 if(inted){
103 werrstr("interrupted");
104 return -1;
107 /*
108 * If we get interrupted, we have stick around so that
109 * the IO proc has someone to talk to. Send it an interrupt
110 * and try again.
111 */
112 inted = 0;
113 while(recv(io->creply, nil) == -1){
114 inted = 1;
115 iointerrupt(io);
117 USED(inted);
118 va_end(io->arg);
119 ret = io->ret;
120 if(ret < 0)
121 strecpy(e, e+sizeof e, io->err);
122 io->inuse = 0;
124 /* release resources */
125 while(send(io->creply, &io) == -1)
127 if(ret < 0)
128 errstr(e, sizeof e);
129 return ret;