framebuf.c revision 1.17 1 /* $NetBSD: framebuf.c,v 1.17 2007/07/20 13:14:55 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Finnish Cultural Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /*
32 * The event portion of this code is a twisty maze of pointers,
33 * flags, yields and continues. Sincere aplogies.
34 */
35
36 #include <sys/cdefs.h>
37 #if !defined(lint)
38 __RCSID("$NetBSD: framebuf.c,v 1.17 2007/07/20 13:14:55 pooka Exp $");
39 #endif /* !lint */
40
41 #include <sys/types.h>
42 #include <sys/queue.h>
43
44 #include <assert.h>
45 #include <errno.h>
46 #include <poll.h>
47 #include <puffs.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50
51 #include "puffs_priv.h"
52
53 struct puffs_framebuf {
54 struct puffs_cc *pcc; /* pcc to continue with */
55 /* OR */
56 puffs_framev_cb fcb; /* non-blocking callback */
57 void *fcb_arg; /* argument for previous */
58
59 uint8_t *buf; /* buffer base */
60 size_t len; /* total length */
61
62 size_t offset; /* cursor, telloff() */
63 size_t maxoff; /* maximum offset for data, tellsize() */
64
65 volatile int rv; /* errno value */
66
67 int istat;
68
69 TAILQ_ENTRY(puffs_framebuf) pfb_entries;
70 };
71 #define ISTAT_NODESTROY 0x01 /* indestructible by framebuf_destroy() */
72 #define ISTAT_INTERNAL 0x02 /* never leaves library */
73 #define ISTAT_NOREPLY 0x04 /* nuke after sending */
74 #define ISTAT_DIRECT 0x08 /* receive directly, no moveinfo */
75
76 #define ISTAT_ONQUEUE ISTAT_NODESTROY /* alias */
77
78 #define PUFBUF_INCRALLOC 4096
79 #define PUFBUF_REMAIN(p) (p->len - p->offset)
80
81 /* for poll/kqueue */
82 struct puffs_fbevent {
83 struct puffs_cc *pcc;
84 int what;
85 volatile int rv;
86
87 LIST_ENTRY(puffs_fbevent) pfe_entries;
88 };
89
90 static struct puffs_fctrl_io *
91 getfiobyfd(struct puffs_usermount *pu, int fd)
92 {
93 struct puffs_framectrl *pfctrl = &pu->pu_framectrl;
94 struct puffs_fctrl_io *fio;
95
96 LIST_FOREACH(fio, &pfctrl->fb_ios, fio_entries)
97 if (fio->io_fd == fd)
98 return fio;
99 return NULL;
100 }
101
102 struct puffs_framebuf *
103 puffs_framebuf_make()
104 {
105 struct puffs_framebuf *pufbuf;
106
107 pufbuf = malloc(sizeof(struct puffs_framebuf));
108 if (pufbuf == NULL)
109 return NULL;
110 memset(pufbuf, 0, sizeof(struct puffs_framebuf));
111
112 pufbuf->buf = malloc(PUFBUF_INCRALLOC);
113 if (pufbuf->buf == NULL) {
114 free(pufbuf);
115 return NULL;
116 }
117 pufbuf->len = PUFBUF_INCRALLOC;
118
119 puffs_framebuf_recycle(pufbuf);
120 return pufbuf;
121 }
122
123 void
124 puffs_framebuf_destroy(struct puffs_framebuf *pufbuf)
125 {
126
127 assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
128
129 free(pufbuf->buf);
130 free(pufbuf);
131 }
132
133 void
134 puffs_framebuf_recycle(struct puffs_framebuf *pufbuf)
135 {
136
137 assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
138
139 pufbuf->offset = 0;
140 pufbuf->maxoff = 0;
141 pufbuf->istat = 0;
142 }
143
144 static int
145 reservespace(struct puffs_framebuf *pufbuf, size_t off, size_t wantsize)
146 {
147 size_t incr;
148 void *nd;
149
150 if (off <= pufbuf->len && pufbuf->len - off >= wantsize)
151 return 0;
152
153 for (incr = PUFBUF_INCRALLOC;
154 pufbuf->len + incr < off + wantsize;
155 incr += PUFBUF_INCRALLOC)
156 continue;
157
158 nd = realloc(pufbuf->buf, pufbuf->offset + incr);
159 if (nd == NULL)
160 return -1;
161
162 pufbuf->buf = nd;
163 pufbuf->len += incr;
164
165 return 0;
166 }
167
168 int
169 puffs_framebuf_reserve_space(struct puffs_framebuf *pufbuf, size_t wantsize)
170 {
171
172 return reservespace(pufbuf, pufbuf->offset, wantsize);
173 }
174
175 int
176 puffs_framebuf_putdata(struct puffs_framebuf *pufbuf,
177 const void *data, size_t dlen)
178 {
179
180 if (PUFBUF_REMAIN(pufbuf) < dlen)
181 if (puffs_framebuf_reserve_space(pufbuf, dlen) == -1)
182 return -1;
183
184 memcpy(pufbuf->buf + pufbuf->offset, data, dlen);
185 pufbuf->offset += dlen;
186
187 if (pufbuf->offset > pufbuf->maxoff)
188 pufbuf->maxoff = pufbuf->offset;
189
190 return 0;
191 }
192
193 int
194 puffs_framebuf_putdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
195 const void *data, size_t dlen)
196 {
197
198 if (reservespace(pufbuf, offset, dlen) == -1)
199 return -1;
200
201 memcpy(pufbuf->buf + offset, data, dlen);
202
203 if (offset + dlen > pufbuf->maxoff)
204 pufbuf->maxoff = offset + dlen;
205
206 return 0;
207 }
208
209 int
210 puffs_framebuf_getdata(struct puffs_framebuf *pufbuf, void *data, size_t dlen)
211 {
212
213 if (pufbuf->maxoff < pufbuf->offset + dlen) {
214 errno = ENOBUFS;
215 return -1;
216 }
217
218 memcpy(data, pufbuf->buf + pufbuf->offset, dlen);
219 pufbuf->offset += dlen;
220
221 return 0;
222 }
223
224 int
225 puffs_framebuf_getdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
226 void *data, size_t dlen)
227 {
228
229 if (pufbuf->maxoff < offset + dlen) {
230 errno = ENOBUFS;
231 return -1;
232 }
233
234 memcpy(data, pufbuf->buf + offset, dlen);
235 return 0;
236 }
237
238 size_t
239 puffs_framebuf_telloff(struct puffs_framebuf *pufbuf)
240 {
241
242 return pufbuf->offset;
243 }
244
245 size_t
246 puffs_framebuf_tellsize(struct puffs_framebuf *pufbuf)
247 {
248
249 return pufbuf->maxoff;
250 }
251
252 size_t
253 puffs_framebuf_remaining(struct puffs_framebuf *pufbuf)
254 {
255
256 return puffs_framebuf_tellsize(pufbuf) - puffs_framebuf_telloff(pufbuf);
257 }
258
259 int
260 puffs_framebuf_seekset(struct puffs_framebuf *pufbuf, size_t newoff)
261 {
262
263 if (reservespace(pufbuf, newoff, 0) == -1)
264 return -1;
265
266 pufbuf->offset = newoff;
267 return 0;
268 }
269
270 int
271 puffs_framebuf_getwindow(struct puffs_framebuf *pufbuf, size_t winoff,
272 void **data, size_t *dlen)
273 {
274 size_t winlen;
275
276 #ifdef WINTESTING
277 winlen = MIN(*dlen, 32);
278 #else
279 winlen = *dlen;
280 #endif
281
282 if (reservespace(pufbuf, winoff, winlen) == -1)
283 return -1;
284
285 *data = pufbuf->buf + winoff;
286 if (pufbuf->maxoff < winoff + winlen)
287 pufbuf->maxoff = winoff + winlen;
288
289 return 0;
290 }
291
292 static void
293 errnotify(struct puffs_framebuf *pufbuf, int error)
294 {
295
296 pufbuf->rv = error;
297 if (pufbuf->pcc) {
298 puffs_goto(pufbuf->pcc);
299 } else if (pufbuf->fcb) {
300 pufbuf->istat &= ~ISTAT_NODESTROY;
301 pufbuf->fcb(puffs_cc_getusermount(pufbuf->pcc),
302 pufbuf, pufbuf->fcb_arg, error);
303 } else {
304 pufbuf->istat &= ~ISTAT_NODESTROY;
305 puffs_framebuf_destroy(pufbuf);
306 }
307 }
308
309 #define GETFIO(fd) \
310 do { \
311 fio = getfiobyfd(pu, fd); \
312 if (fio == NULL) { \
313 errno = EINVAL; \
314 return -1; \
315 } \
316 if (fio->stat & FIO_WRGONE) { \
317 errno = ESHUTDOWN; \
318 return -1; \
319 } \
320 } while (/*CONSTCOND*/0)
321
322 int
323 puffs_framev_enqueue_cc(struct puffs_cc *pcc, int fd,
324 struct puffs_framebuf *pufbuf, int flags)
325 {
326 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
327 struct puffs_fctrl_io *fio;
328
329 /*
330 * Technically we shouldn't allow this is RDGONE, but it's
331 * difficult to trap write close without allowing writes.
332 * And besides, there's probably a disconnect sequence in
333 * the protocol, so unexpectedly getting a closed fd is
334 * most likely an error condition.
335 */
336 GETFIO(fd);
337
338 pufbuf->pcc = pcc;
339 pufbuf->fcb = NULL;
340 pufbuf->fcb_arg = NULL;
341
342 pufbuf->offset = 0;
343 pufbuf->istat |= ISTAT_NODESTROY;
344
345 if (flags & PUFFS_FBQUEUE_URGENT)
346 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
347 else
348 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
349
350 puffs_cc_yield(pcc);
351 if (pufbuf->rv) {
352 pufbuf->istat &= ~ISTAT_NODESTROY;
353 errno = pufbuf->rv;
354 return -1;
355 }
356
357 return 0;
358 }
359
360 int
361 puffs_framev_enqueue_cb(struct puffs_usermount *pu, int fd,
362 struct puffs_framebuf *pufbuf, puffs_framev_cb fcb, void *arg,
363 int flags)
364 {
365 struct puffs_fctrl_io *fio;
366
367 /* see enqueue_cc */
368 GETFIO(fd);
369
370 pufbuf->pcc = NULL;
371 pufbuf->fcb = fcb;
372 pufbuf->fcb_arg = arg;
373
374 pufbuf->offset = 0;
375 pufbuf->istat |= ISTAT_NODESTROY;
376
377 if (flags & PUFFS_FBQUEUE_URGENT)
378 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
379 else
380 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
381
382 return 0;
383 }
384
385 int
386 puffs_framev_enqueue_justsend(struct puffs_usermount *pu, int fd,
387 struct puffs_framebuf *pufbuf, int reply, int flags)
388 {
389 struct puffs_fctrl_io *fio;
390
391 GETFIO(fd);
392
393 pufbuf->pcc = NULL;
394 pufbuf->fcb = NULL;
395 pufbuf->fcb_arg = NULL;
396
397 pufbuf->offset = 0;
398 pufbuf->istat |= ISTAT_NODESTROY;
399 if (!reply)
400 pufbuf->istat |= ISTAT_NOREPLY;
401
402 if (flags & PUFFS_FBQUEUE_URGENT)
403 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
404 else
405 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
406
407 return 0;
408 }
409
410 /* ARGSUSED */
411 int
412 puffs_framev_enqueue_directreceive(struct puffs_cc *pcc, int fd,
413 struct puffs_framebuf *pufbuf, int flags /* used in the future */)
414 {
415 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
416 struct puffs_fctrl_io *fio;
417
418 fio = getfiobyfd(pu, fd);
419 if (fio == NULL) {
420 errno = EINVAL;
421 return -1;
422 }
423
424 /* XXX: should have cur_in queue */
425 assert(fio->cur_in == NULL);
426 fio->cur_in = pufbuf;
427
428 pufbuf->pcc = pcc;
429 pufbuf->fcb = NULL;
430 pufbuf->fcb_arg = NULL;
431
432 pufbuf->offset = 0;
433 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
434
435 puffs_cc_yield(pcc);
436 pufbuf->istat &= ~ISTAT_NODESTROY; /* XXX: not the right place */
437 if (pufbuf->rv) {
438 errno = pufbuf->rv;
439 return -1;
440 }
441
442 return 0;
443 }
444
445 int
446 puffs_framev_enqueue_directsend(struct puffs_cc *pcc, int fd,
447 struct puffs_framebuf *pufbuf, int flags)
448 {
449 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
450 struct puffs_fctrl_io *fio;
451
452 if (flags & PUFFS_FBQUEUE_URGENT)
453 abort(); /* EOPNOTSUPP for now */
454
455 GETFIO(fd);
456
457 pufbuf->pcc = pcc;
458 pufbuf->fcb = NULL;
459 pufbuf->fcb_arg = NULL;
460
461 pufbuf->offset = 0;
462 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
463
464 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
465
466 puffs_cc_yield(pcc);
467 if (pufbuf->rv) {
468 pufbuf->istat &= ~ISTAT_NODESTROY;
469 errno = pufbuf->rv;
470 return -1;
471 }
472
473 return 0;
474 }
475
476 /*
477 * this beauty shall remain undocumented for now
478 */
479 int
480 puffs_framev_framebuf_ccpromote(struct puffs_framebuf *pufbuf,
481 struct puffs_cc *pcc)
482 {
483
484 if ((pufbuf->istat & ISTAT_ONQUEUE) == 0) {
485 errno = EBUSY;
486 return -1;
487 }
488
489 pufbuf->pcc = pcc;
490 pufbuf->fcb = NULL;
491 pufbuf->fcb_arg = NULL;
492 pufbuf->istat &= ~ISTAT_NOREPLY;
493
494 puffs_cc_yield(pcc);
495
496 return 0;
497 }
498
499 int
500 puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what)
501 {
502 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
503 struct puffs_fctrl_io *fio;
504 struct puffs_fbevent feb;
505 struct kevent kev;
506 int rv, svwhat;
507
508 svwhat = *what;
509
510 if (*what == 0) {
511 errno = EINVAL;
512 return -1;
513 }
514
515 fio = getfiobyfd(pu, fd);
516 if (fio == NULL) {
517 errno = EINVAL;
518 return -1;
519 }
520
521 feb.pcc = pcc;
522 feb.what = *what & (PUFFS_FBIO_READ|PUFFS_FBIO_WRITE|PUFFS_FBIO_ERROR);
523
524 if (*what & PUFFS_FBIO_READ)
525 if ((fio->stat & FIO_ENABLE_R) == 0)
526 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE,
527 0, 0, (uintptr_t)fio);
528
529 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
530 if (rv != 0)
531 return errno;
532
533 if (*what & PUFFS_FBIO_READ)
534 fio->rwait++;
535 if (*what & PUFFS_FBIO_WRITE)
536 fio->wwait++;
537
538 LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries);
539 puffs_cc_yield(pcc);
540
541 assert(svwhat == *what);
542
543 if (*what & PUFFS_FBIO_READ) {
544 fio->rwait--;
545 if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) {
546 EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE,
547 0, 0, (uintptr_t)fio);
548 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
549 #if 0
550 if (rv != 0)
551 /* XXXXX oh dear */;
552 #endif
553 }
554 }
555 if (*what & PUFFS_FBIO_WRITE)
556 fio->wwait--;
557
558 if (feb.rv == 0)
559 *what = feb.what;
560 else
561 *what = POLLERR;
562
563 return feb.rv;
564 }
565
566 void
567 puffs_framev_notify(struct puffs_fctrl_io *fio, int what)
568 {
569 struct puffs_fbevent *fbevp;
570
571 restart:
572 LIST_FOREACH(fbevp, &fio->ev_qing, pfe_entries) {
573 if (fbevp->what & what) {
574 fbevp->what = what;
575 fbevp->rv = 0;
576 LIST_REMOVE(fbevp, pfe_entries);
577 puffs_cc_continue(fbevp->pcc);
578 goto restart;
579 }
580 }
581 }
582
583 static struct puffs_framebuf *
584 findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
585 struct puffs_fctrl_io *fio, struct puffs_framebuf *findme)
586 {
587 struct puffs_framebuf *cand;
588
589 TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries)
590 if (fctrl->cmpfb(pu, findme, cand) == 0)
591 break;
592
593 if (cand == NULL)
594 return NULL;
595
596 TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries);
597 return cand;
598 }
599
600 static void
601 moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to)
602 {
603
604 assert(from->istat & ISTAT_INTERNAL);
605
606 /* migrate buffer */
607 free(to->buf);
608 to->buf = from->buf;
609 from->buf = NULL;
610
611 /* migrate buffer info */
612 to->len = from->len;
613 to->offset = from->offset;
614 to->maxoff = from->maxoff;
615 }
616
617 void
618 puffs_framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
619 struct puffs_fctrl_io *fio, struct puffs_putreq *ppr)
620 {
621 struct puffs_framebuf *pufbuf, *appbuf;
622 int rv, complete;
623
624 while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) {
625 if ((pufbuf = fio->cur_in) == NULL) {
626 pufbuf = puffs_framebuf_make();
627 if (pufbuf == NULL)
628 return;
629 pufbuf->istat |= ISTAT_INTERNAL;
630 fio->cur_in = pufbuf;
631 }
632
633 complete = 0;
634 rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete);
635
636 /* error */
637 if (rv) {
638 puffs_framev_readclose(pu, fio, rv);
639 fio->cur_in = NULL;
640 if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
641 assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
642 puffs_framebuf_destroy(pufbuf);
643 }
644 return;
645 }
646
647 /* partial read, come back to fight another day */
648 if (complete == 0)
649 break;
650
651 /* else: full read, process */
652 if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
653 appbuf = findbuf(pu, fctrl, fio, pufbuf);
654
655 /* XXX: error delivery? */
656 if (appbuf == NULL) {
657 /* errno = ENOMSG; */
658 return;
659 }
660
661 moveinfo(pufbuf, appbuf);
662 puffs_framebuf_destroy(pufbuf);
663 } else {
664 appbuf = pufbuf;
665 }
666 appbuf->istat &= ~ISTAT_NODESTROY;
667 fio->cur_in = NULL;
668
669 if (appbuf->pcc) {
670 puffs_docc(appbuf->pcc, ppr);
671 } else if (appbuf->fcb) {
672 appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0);
673 } else {
674 puffs_framebuf_destroy(appbuf);
675 }
676
677 /* hopeless romantics, here we go again */
678 }
679 }
680
681 int
682 puffs_framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
683 struct puffs_fctrl_io *fio, struct puffs_putreq *ppr)
684 {
685 struct puffs_framebuf *pufbuf, *pufbuf_next;
686 int rv, complete, done;
687
688 if (fio->stat & FIO_DEAD)
689 return 0;
690
691 for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0;
692 pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W;
693 pufbuf = pufbuf_next) {
694 complete = 0;
695 pufbuf_next = TAILQ_NEXT(pufbuf, pfb_entries);
696 rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete);
697
698 if (rv) {
699 puffs_framev_writeclose(pu, fio, rv);
700 done = 1;
701 break;
702 }
703
704 /* partial write */
705 if (complete == 0)
706 return done;
707
708 /* else, complete write */
709 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
710
711 /* can't wait for result if we can't read */
712 if (fio->stat & FIO_RDGONE) {
713 errnotify(pufbuf, ENXIO);
714 done = 1;
715 } else if ((pufbuf->istat & ISTAT_DIRECT)) {
716 pufbuf->istat &= ~ISTAT_NODESTROY;
717 puffs_docc(pufbuf->pcc, ppr);
718 done = 1;
719 } else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) {
720 TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf,
721 pfb_entries);
722 } else {
723 pufbuf->istat &= ~ISTAT_NODESTROY;
724 puffs_framebuf_destroy(pufbuf);
725 }
726
727 /* omstart! */
728 }
729
730 return done;
731 }
732
733 int
734 puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what)
735 {
736 struct puffs_framectrl *pfctrl = &pu->pu_framectrl;
737 struct puffs_fctrl_io *fio;
738 struct kevent *newevs;
739 struct kevent kev[2];
740 size_t nfds;
741 int rv, readenable;
742
743 nfds = pfctrl->nfds+1;
744 newevs = realloc(pfctrl->evs, (2*nfds+1) * sizeof(struct kevent));
745 if (newevs == NULL)
746 return -1;
747 pfctrl->evs = newevs;
748
749 fio = malloc(sizeof(struct puffs_fctrl_io));
750 if (fio == NULL)
751 return -1;
752 memset(fio, 0, sizeof(struct puffs_fctrl_io));
753 fio->io_fd = fd;
754 fio->cur_in = NULL;
755 TAILQ_INIT(&fio->snd_qing);
756 TAILQ_INIT(&fio->res_qing);
757 LIST_INIT(&fio->ev_qing);
758
759 readenable = 0;
760 if ((what & PUFFS_FBIO_READ) == 0)
761 readenable = EV_DISABLE;
762
763 if (pu->pu_state & PU_INLOOP) {
764 EV_SET(&kev[0], fd, EVFILT_READ,
765 EV_ADD|readenable, 0, 0, (intptr_t)fio);
766 EV_SET(&kev[1], fd, EVFILT_WRITE,
767 EV_ADD|EV_DISABLE, 0, 0, (intptr_t)fio);
768 rv = kevent(pu->pu_kq, kev, 2, NULL, 0, NULL);
769 if (rv == -1) {
770 free(fio);
771 return -1;
772 }
773 }
774 if (what & PUFFS_FBIO_READ)
775 fio->stat |= FIO_ENABLE_R;
776 if (what & PUFFS_FBIO_WRITE)
777 fio->stat |= FIO_ENABLE_W;
778
779 LIST_INSERT_HEAD(&pfctrl->fb_ios, fio, fio_entries);
780 pfctrl->nfds = nfds;
781
782 return 0;
783 }
784
785 /*
786 * XXX: the following en/disable should be coalesced and executed
787 * only during the actual kevent call. So feel free to fix if
788 * threatened by mindblowing boredom.
789 */
790
791 int
792 puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what)
793 {
794 struct kevent kev;
795 struct puffs_fctrl_io *fio;
796 int rv = 0;
797
798 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
799
800 fio = getfiobyfd(pu, fd);
801 if (fio == NULL) {
802 errno = ENXIO;
803 return -1;
804 }
805
806 /* write is enabled in the event loop if there is output */
807 if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
808 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, (uintptr_t)fio);
809 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
810 }
811
812 if (rv == 0) {
813 if (what & PUFFS_FBIO_READ)
814 fio->stat |= FIO_ENABLE_R;
815 if (what & PUFFS_FBIO_WRITE)
816 fio->stat |= FIO_ENABLE_W;
817 }
818
819 return rv;
820 }
821
822 int
823 puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what)
824 {
825 struct kevent kev[2];
826 struct puffs_fctrl_io *fio;
827 size_t i;
828 int rv;
829
830 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
831
832 fio = getfiobyfd(pu, fd);
833 if (fio == NULL) {
834 errno = ENXIO;
835 return -1;
836 }
837
838 i = 0;
839 if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
840 EV_SET(&kev[0], fd,
841 EVFILT_READ, EV_DISABLE, 0, 0, (uintptr_t)fio);
842 i++;
843 }
844 if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) {
845 EV_SET(&kev[1], fd,
846 EVFILT_WRITE, EV_DISABLE, 0, 0, (uintptr_t)fio);
847 i++;
848 }
849 if (i)
850 rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL);
851 else
852 rv = 0;
853
854 if (rv == 0) {
855 if (what & PUFFS_FBIO_READ)
856 fio->stat &= ~FIO_ENABLE_R;
857 if (what & PUFFS_FBIO_WRITE)
858 fio->stat &= ~FIO_ENABLE_W;
859 }
860
861 return rv;
862 }
863
864 void
865 puffs_framev_readclose(struct puffs_usermount *pu,
866 struct puffs_fctrl_io *fio, int error)
867 {
868 struct puffs_framebuf *pufbuf;
869 struct kevent kev;
870 int notflag;
871
872 if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD)
873 return;
874 fio->stat |= FIO_RDGONE;
875
876 if (fio->cur_in) {
877 if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) {
878 puffs_framebuf_destroy(fio->cur_in);
879 fio->cur_in = NULL;
880 } else {
881 errnotify(fio->cur_in, error);
882 }
883 }
884
885 while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) {
886 TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries);
887 errnotify(pufbuf, error);
888 }
889
890 EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
891 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
892
893 notflag = PUFFS_FBIO_READ;
894 if (fio->stat & FIO_WRGONE)
895 notflag |= PUFFS_FBIO_WRITE;
896
897 if (pu->pu_framectrl.fdnotfn)
898 pu->pu_framectrl.fdnotfn(pu, fio->io_fd, notflag);
899 }
900
901 void
902 puffs_framev_writeclose(struct puffs_usermount *pu,
903 struct puffs_fctrl_io *fio, int error)
904 {
905 struct puffs_framebuf *pufbuf;
906 struct kevent kev;
907 int notflag;
908
909 if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD)
910 return;
911 fio->stat |= FIO_WRGONE;
912
913 while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) {
914 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
915 errnotify(pufbuf, error);
916 }
917
918 EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
919 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
920
921 notflag = PUFFS_FBIO_WRITE;
922 if (fio->stat & FIO_RDGONE)
923 notflag |= PUFFS_FBIO_READ;
924
925 if (pu->pu_framectrl.fdnotfn)
926 pu->pu_framectrl.fdnotfn(pu, fio->io_fd, notflag);
927 }
928
929 static int
930 removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error)
931 {
932 struct puffs_framectrl *pfctrl = &pu->pu_framectrl;
933 struct puffs_fbevent *fbevp;
934
935 LIST_REMOVE(fio, fio_entries);
936 if (pu->pu_state & PU_INLOOP) {
937 puffs_framev_readclose(pu, fio, error);
938 puffs_framev_writeclose(pu, fio, error);
939 }
940
941 while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) {
942 fbevp->rv = error;
943 LIST_REMOVE(fbevp, pfe_entries);
944 puffs_goto(fbevp->pcc);
945 }
946
947 /* don't bother with realloc */
948 pfctrl->nfds--;
949
950 /* don't free us yet, might have some references in event arrays */
951 fio->stat |= FIO_DEAD;
952 LIST_INSERT_HEAD(&pfctrl->fb_ios_rmlist, fio, fio_entries);
953
954 return 0;
955
956 }
957
958 int
959 puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error)
960 {
961 struct puffs_fctrl_io *fio;
962
963 fio = getfiobyfd(pu, fd);
964 if (fio == NULL) {
965 errno = ENXIO;
966 return -1;
967 }
968
969 return removefio(pu, fio, error ? error : ECONNRESET);
970 }
971
972 void
973 puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what)
974 {
975
976 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
977 (void) puffs_framev_removefd(pu, fd, ECONNRESET);
978 }
979
980 void
981 puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what)
982 {
983
984 /* XXX & X: unmount is non-sensible */
985 puffs_framev_removeonclose(pu, fd, what);
986 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
987 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
988 }
989
990 void
991 puffs_framev_init(struct puffs_usermount *pu,
992 puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb,
993 puffs_framev_cmpframe_fn cmpfb, puffs_framev_fdnotify_fn fdnotfn)
994 {
995 struct puffs_framectrl *pfctrl;
996
997 pfctrl = &pu->pu_framectrl;
998 pfctrl->rfb = rfb;
999 pfctrl->wfb = wfb;
1000 pfctrl->cmpfb = cmpfb;
1001 pfctrl->fdnotfn = fdnotfn;
1002 }
1003
1004 void
1005 puffs_framev_exit(struct puffs_usermount *pu)
1006 {
1007 struct puffs_framectrl *pfctrl = &pu->pu_framectrl;
1008 struct puffs_fctrl_io *fio;
1009
1010 while ((fio = LIST_FIRST(&pfctrl->fb_ios)) != NULL)
1011 removefio(pu, fio, ENXIO);
1012 free(pfctrl->evs);
1013
1014 /* closing pu->pu_kq takes care of puffsfd */
1015 }
1016