| 1 | #include <u.h> |
| 2 | #include <libc.h> |
| 3 | #include <ureg.h> |
| 4 | #include "dat.h" |
| 5 | #include "fns.h" |
| 6 | #include "linux.h" |
| 7 | |
| 8 | typedef struct Bufproc Bufproc; |
| 9 | typedef struct Bufq Bufq; |
| 10 | |
| 11 | struct Bufq |
| 12 | { |
| 13 | Bufq *next; |
| 14 | |
| 15 | uchar *start; |
| 16 | uchar *end; |
| 17 | |
| 18 | uchar data[8*1024]; |
| 19 | }; |
| 20 | |
| 21 | struct Bufproc |
| 22 | { |
| 23 | Ref; |
| 24 | QLock; |
| 25 | |
| 26 | int fd; |
| 27 | int error; |
| 28 | int notefd; |
| 29 | |
| 30 | Bufq *qf; |
| 31 | Bufq *qh; |
| 32 | Bufq **qt; |
| 33 | |
| 34 | int wr; |
| 35 | Uwaitq wq; |
| 36 | }; |
| 37 | |
| 38 | static int |
| 39 | queuesize(Bufq *q) |
| 40 | { |
| 41 | int n; |
| 42 | |
| 43 | n = 0; |
| 44 | while(q){ |
| 45 | n += (q->end - q->start); |
| 46 | q = q->next; |
| 47 | } |
| 48 | return n; |
| 49 | } |
| 50 | |
| 51 | void |
| 52 | freebufproc(void *bp) |
| 53 | { |
| 54 | Bufproc *b = bp; |
| 55 | Bufq *q; |
| 56 | |
| 57 | if(b == nil) |
| 58 | return; |
| 59 | qlock(b); |
| 60 | b->fd = -1; |
| 61 | if(decref(b)){ |
| 62 | if(b->wr){ |
| 63 | b->wr = 0; |
| 64 | while(rendezvous(&b->wr, 0) == (void*)~0) |
| 65 | ; |
| 66 | } else { |
| 67 | write(b->notefd, "interrupt", 9); |
| 68 | } |
| 69 | qunlock(b); |
| 70 | return; |
| 71 | } |
| 72 | qunlock(b); |
| 73 | |
| 74 | *b->qt = b->qf; |
| 75 | while(q = b->qh){ |
| 76 | b->qh = q->next; |
| 77 | free(q); |
| 78 | } |
| 79 | close(b->notefd); |
| 80 | free(b); |
| 81 | } |
| 82 | |
| 83 | static void |
| 84 | bufproc(void *aux) |
| 85 | { |
| 86 | Bufproc *b = aux; |
| 87 | Bufq *q; |
| 88 | int ret; |
| 89 | int fd; |
| 90 | |
| 91 | setprocname("bufproc()"); |
| 92 | |
| 93 | q = nil; |
| 94 | qlock(b); |
| 95 | for(;;){ |
| 96 | while((b->fd >= 0) && (queuesize(b->qh) >= 64*1024)){ |
| 97 | b->wr = 1; |
| 98 | qunlock(b); |
| 99 | while(rendezvous(&b->wr, 0) == (void*)~0) |
| 100 | ; |
| 101 | qlock(b); |
| 102 | } |
| 103 | if((fd = b->fd) < 0) |
| 104 | break; |
| 105 | if((q == nil) && (q = b->qf)) |
| 106 | b->qf = q->next; |
| 107 | qunlock(b); |
| 108 | |
| 109 | if(q == nil) |
| 110 | q = kmalloc(sizeof(*q)); |
| 111 | q->next = nil; |
| 112 | q->end = q->start = &q->data[0]; |
| 113 | ret = read(fd, q->start, sizeof(q->data)); |
| 114 | |
| 115 | qlock(b); |
| 116 | if(ret < 0){ |
| 117 | ret = mkerror(); |
| 118 | if(ret == -EINTR || ret == -ERESTART) |
| 119 | continue; |
| 120 | b->error = ret; |
| 121 | b->fd = -1; |
| 122 | break; |
| 123 | } |
| 124 | q->end = q->start + ret; |
| 125 | *b->qt = q; |
| 126 | b->qt = &q->next; |
| 127 | q = nil; |
| 128 | wakeq(&b->wq, MAXPROC); |
| 129 | } |
| 130 | if(q){ |
| 131 | q->next = b->qf; |
| 132 | b->qf = q; |
| 133 | } |
| 134 | wakeq(&b->wq, MAXPROC); |
| 135 | qunlock(b); |
| 136 | freebufproc(b); |
| 137 | } |
| 138 | |
| 139 | void* |
| 140 | newbufproc(int fd) |
| 141 | { |
| 142 | char buf[80]; |
| 143 | Bufproc *b; |
| 144 | int pid; |
| 145 | |
| 146 | b = kmallocz(sizeof(*b), 1); |
| 147 | b->ref = 2; |
| 148 | b->fd = fd; |
| 149 | b->qt = &b->qh; |
| 150 | if((pid = procfork(bufproc, b, 0)) < 0) |
| 151 | panic("unable to fork bufproc: %r"); |
| 152 | snprint(buf, sizeof(buf), "/proc/%d/note", pid); |
| 153 | b->notefd = open(buf, OWRITE); |
| 154 | |
| 155 | return b; |
| 156 | } |
| 157 | |
| 158 | int readbufproc(void *bp, void *data, int len, int peek, int noblock) |
| 159 | { |
| 160 | Bufproc *b = bp; |
| 161 | uchar *p; |
| 162 | Bufq *q; |
| 163 | int ret; |
| 164 | |
| 165 | qlock(b); |
| 166 | while((q = b->qh) == nil){ |
| 167 | if(noblock){ |
| 168 | ret = -EAGAIN; |
| 169 | goto out; |
| 170 | } |
| 171 | if(peek){ |
| 172 | ret = 0; |
| 173 | goto out; |
| 174 | } |
| 175 | if(b->fd < 0){ |
| 176 | if((ret = b->error) == 0) |
| 177 | ret = -EIO; |
| 178 | goto out; |
| 179 | } |
| 180 | if((ret = sleepq(&b->wq, b, 1)) < 0){ |
| 181 | qunlock(b); |
| 182 | return ret; |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | p = data; |
| 187 | ret = 0; |
| 188 | while(q != nil){ |
| 189 | int n; |
| 190 | |
| 191 | n = q->end - q->start; |
| 192 | if(n == 0) |
| 193 | break; |
| 194 | if(n > len - ret) |
| 195 | n = len - ret; |
| 196 | memmove(p, q->start, n); |
| 197 | p += n; |
| 198 | ret += n; |
| 199 | if(q->start+n >= q->end){ |
| 200 | if(!peek){ |
| 201 | Bufq *t; |
| 202 | |
| 203 | t = q->next; |
| 204 | if((b->qh = q->next) == nil) |
| 205 | b->qt = &b->qh; |
| 206 | q->next = b->qf; |
| 207 | b->qf = q; |
| 208 | q = t; |
| 209 | } else { |
| 210 | q = q->next; |
| 211 | } |
| 212 | } else { |
| 213 | if(!peek) |
| 214 | q->start += n; |
| 215 | break; |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | if(b->wr && !peek){ |
| 220 | b->wr = 0; |
| 221 | while(rendezvous(&b->wr, 0) == (void*)~0) |
| 222 | ; |
| 223 | qunlock(b); |
| 224 | |
| 225 | return ret; |
| 226 | } |
| 227 | out: |
| 228 | qunlock(b); |
| 229 | |
| 230 | return ret; |
| 231 | } |
| 232 | |
| 233 | int pollbufproc(void *bp, Ufile *file, void *tab) |
| 234 | { |
| 235 | Bufproc *b = bp; |
| 236 | int ret; |
| 237 | |
| 238 | ret = 0; |
| 239 | |
| 240 | qlock(b); |
| 241 | pollwait(file, &b->wq, tab); |
| 242 | if(b->fd >= 0){ |
| 243 | ret |= POLLOUT; |
| 244 | } else if(b->error < 0) |
| 245 | ret |= POLLERR; |
| 246 | if(b->qh) |
| 247 | ret |= POLLIN; |
| 248 | qunlock(b); |
| 249 | |
| 250 | return ret; |
| 251 | } |
| 252 | |
| 253 | int nreadablebufproc(void *bp) |
| 254 | { |
| 255 | Bufproc *b = bp; |
| 256 | int ret; |
| 257 | |
| 258 | qlock(b); |
| 259 | ret = queuesize(b->qh); |
| 260 | qunlock(b); |
| 261 | |
| 262 | return ret; |
| 263 | } |