Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / lib / libpuffs / framebuf.c
blob831c9bf8285395e71662edf8a75d8fb96377e666
1 /* $NetBSD: framebuf.c,v 1.28 2008/01/29 10:07:29 pooka Exp $ */
3 /*
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
6 * Development of this software was supported by the
7 * Finnish Cultural Foundation.
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.
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.
32 * The event portion of this code is a twisty maze of pointers,
33 * flags, yields and continues. Sincere aplogies.
36 #include <sys/cdefs.h>
37 #if !defined(lint)
38 __RCSID("$NetBSD: framebuf.c,v 1.28 2008/01/29 10:07:29 pooka Exp $");
39 #endif /* !lint */
41 #include <sys/types.h>
42 #include <sys/queue.h>
44 #include <assert.h>
45 #include <errno.h>
46 #include <poll.h>
47 #include <puffs.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <unistd.h>
52 #include "puffs_priv.h"
54 struct puffs_framebuf {
55 struct puffs_cc *pcc; /* pcc to continue with */
56 /* OR */
57 puffs_framev_cb fcb; /* non-blocking callback */
58 void *fcb_arg; /* argument for previous */
60 uint8_t *buf; /* buffer base */
61 size_t len; /* total length */
63 size_t offset; /* cursor, telloff() */
64 size_t maxoff; /* maximum offset for data, tellsize() */
66 volatile int rv; /* errno value */
68 int istat;
70 TAILQ_ENTRY(puffs_framebuf) pfb_entries;
72 #define ISTAT_NODESTROY 0x01 /* indestructible by framebuf_destroy() */
73 #define ISTAT_INTERNAL 0x02 /* never leaves library */
74 #define ISTAT_NOREPLY 0x04 /* nuke after sending */
75 #define ISTAT_DIRECT 0x08 /* receive directly, no moveinfo */
77 #define ISTAT_ONQUEUE ISTAT_NODESTROY /* alias */
79 #define PUFBUF_INCRALLOC 4096
80 #define PUFBUF_REMAIN(p) (p->len - p->offset)
82 /* for poll/kqueue */
83 struct puffs_fbevent {
84 struct puffs_cc *pcc;
85 int what;
86 volatile int rv;
88 LIST_ENTRY(puffs_fbevent) pfe_entries;
91 static struct puffs_fctrl_io *
92 getfiobyfd(struct puffs_usermount *pu, int fd)
94 struct puffs_fctrl_io *fio;
96 LIST_FOREACH(fio, &pu->pu_ios, fio_entries)
97 if (fio->io_fd == fd)
98 return fio;
99 return NULL;
102 struct puffs_framebuf *
103 puffs_framebuf_make()
105 struct puffs_framebuf *pufbuf;
107 pufbuf = malloc(sizeof(struct puffs_framebuf));
108 if (pufbuf == NULL)
109 return NULL;
110 memset(pufbuf, 0, sizeof(struct puffs_framebuf));
112 pufbuf->buf = malloc(PUFBUF_INCRALLOC);
113 if (pufbuf->buf == NULL) {
114 free(pufbuf);
115 return NULL;
117 pufbuf->len = PUFBUF_INCRALLOC;
119 puffs_framebuf_recycle(pufbuf);
120 return pufbuf;
123 void
124 puffs_framebuf_destroy(struct puffs_framebuf *pufbuf)
127 assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
129 free(pufbuf->buf);
130 free(pufbuf);
133 void
134 puffs_framebuf_recycle(struct puffs_framebuf *pufbuf)
137 assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
139 pufbuf->offset = 0;
140 pufbuf->maxoff = 0;
141 pufbuf->istat = 0;
144 static int
145 reservespace(struct puffs_framebuf *pufbuf, size_t off, size_t wantsize)
147 size_t incr;
148 void *nd;
150 if (off <= pufbuf->len && pufbuf->len - off >= wantsize)
151 return 0;
153 for (incr = PUFBUF_INCRALLOC;
154 pufbuf->len + incr < off + wantsize;
155 incr += PUFBUF_INCRALLOC)
156 continue;
158 nd = realloc(pufbuf->buf, pufbuf->len + incr);
159 if (nd == NULL)
160 return -1;
162 pufbuf->buf = nd;
163 pufbuf->len += incr;
165 return 0;
169 puffs_framebuf_dup(struct puffs_framebuf *pb, struct puffs_framebuf **pbp)
171 struct puffs_framebuf *newpb;
173 newpb = puffs_framebuf_make();
174 if (newpb == NULL) {
175 errno = ENOMEM;
176 return -1;
178 memcpy(newpb, pb, sizeof(struct puffs_framebuf));
180 newpb->buf = NULL;
181 newpb->len = 0;
182 if (reservespace(newpb, 0, pb->maxoff) == -1) {
183 puffs_framebuf_destroy(newpb);
184 return -1;
187 memcpy(newpb->buf, pb->buf, pb->maxoff);
188 newpb->istat = 0;
189 *pbp = newpb;
191 return 0;
195 puffs_framebuf_reserve_space(struct puffs_framebuf *pufbuf, size_t wantsize)
198 return reservespace(pufbuf, pufbuf->offset, wantsize);
202 puffs_framebuf_putdata(struct puffs_framebuf *pufbuf,
203 const void *data, size_t dlen)
206 if (PUFBUF_REMAIN(pufbuf) < dlen)
207 if (puffs_framebuf_reserve_space(pufbuf, dlen) == -1)
208 return -1;
210 memcpy(pufbuf->buf + pufbuf->offset, data, dlen);
211 pufbuf->offset += dlen;
213 if (pufbuf->offset > pufbuf->maxoff)
214 pufbuf->maxoff = pufbuf->offset;
216 return 0;
220 puffs_framebuf_putdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
221 const void *data, size_t dlen)
224 if (reservespace(pufbuf, offset, dlen) == -1)
225 return -1;
227 memcpy(pufbuf->buf + offset, data, dlen);
229 if (offset + dlen > pufbuf->maxoff)
230 pufbuf->maxoff = offset + dlen;
232 return 0;
236 puffs_framebuf_getdata(struct puffs_framebuf *pufbuf, void *data, size_t dlen)
239 if (pufbuf->maxoff < pufbuf->offset + dlen) {
240 errno = ENOBUFS;
241 return -1;
244 memcpy(data, pufbuf->buf + pufbuf->offset, dlen);
245 pufbuf->offset += dlen;
247 return 0;
251 puffs_framebuf_getdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
252 void *data, size_t dlen)
255 if (pufbuf->maxoff < offset + dlen) {
256 errno = ENOBUFS;
257 return -1;
260 memcpy(data, pufbuf->buf + offset, dlen);
261 return 0;
264 size_t
265 puffs_framebuf_telloff(struct puffs_framebuf *pufbuf)
268 return pufbuf->offset;
271 size_t
272 puffs_framebuf_tellsize(struct puffs_framebuf *pufbuf)
275 return pufbuf->maxoff;
278 size_t
279 puffs_framebuf_remaining(struct puffs_framebuf *pufbuf)
282 return puffs_framebuf_tellsize(pufbuf) - puffs_framebuf_telloff(pufbuf);
286 puffs_framebuf_seekset(struct puffs_framebuf *pufbuf, size_t newoff)
289 if (reservespace(pufbuf, newoff, 0) == -1)
290 return -1;
292 pufbuf->offset = newoff;
293 return 0;
297 puffs_framebuf_getwindow(struct puffs_framebuf *pufbuf, size_t winoff,
298 void **data, size_t *dlen)
300 size_t winlen;
302 #ifdef WINTESTING
303 winlen = MIN(*dlen, 32);
304 #else
305 winlen = *dlen;
306 #endif
308 if (reservespace(pufbuf, winoff, winlen) == -1)
309 return -1;
311 *data = pufbuf->buf + winoff;
312 if (pufbuf->maxoff < winoff + winlen)
313 pufbuf->maxoff = winoff + winlen;
315 return 0;
318 void *
319 puffs__framebuf_getdataptr(struct puffs_framebuf *pufbuf)
322 return pufbuf->buf;
325 static void
326 errnotify(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, int error)
329 pufbuf->rv = error;
330 if (pufbuf->pcc) {
331 puffs__goto(pufbuf->pcc);
332 } else if (pufbuf->fcb) {
333 pufbuf->istat &= ~ISTAT_NODESTROY;
334 pufbuf->fcb(pu, pufbuf, pufbuf->fcb_arg, error);
335 } else {
336 pufbuf->istat &= ~ISTAT_NODESTROY;
337 puffs_framebuf_destroy(pufbuf);
341 #define GETFIO(fd) \
342 do { \
343 fio = getfiobyfd(pu, fd); \
344 if (fio == NULL) { \
345 errno = EINVAL; \
346 return -1; \
348 if (fio->stat & FIO_WRGONE) { \
349 errno = ESHUTDOWN; \
350 return -1; \
352 } while (/*CONSTCOND*/0)
355 puffs_framev_enqueue_cc(struct puffs_cc *pcc, int fd,
356 struct puffs_framebuf *pufbuf, int flags)
358 struct puffs_usermount *pu = pcc->pcc_pu;
359 struct puffs_fctrl_io *fio;
362 * Technically we shouldn't allow this if RDGONE, but it's
363 * difficult to trap write close without allowing writes.
364 * And besides, there's probably a disconnect sequence in
365 * the protocol, so unexpectedly getting a closed fd is
366 * most likely an error condition.
368 GETFIO(fd);
370 pufbuf->pcc = pcc;
371 pufbuf->fcb = NULL;
372 pufbuf->fcb_arg = NULL;
374 pufbuf->offset = 0;
375 pufbuf->istat |= ISTAT_NODESTROY;
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);
382 puffs_cc_yield(pcc);
383 if (pufbuf->rv) {
384 pufbuf->istat &= ~ISTAT_NODESTROY;
385 errno = pufbuf->rv;
386 return -1;
389 return 0;
393 puffs_framev_enqueue_cb(struct puffs_usermount *pu, int fd,
394 struct puffs_framebuf *pufbuf, puffs_framev_cb fcb, void *arg,
395 int flags)
397 struct puffs_fctrl_io *fio;
399 /* see enqueue_cc */
400 GETFIO(fd);
402 pufbuf->pcc = NULL;
403 pufbuf->fcb = fcb;
404 pufbuf->fcb_arg = arg;
406 pufbuf->offset = 0;
407 pufbuf->istat |= ISTAT_NODESTROY;
409 if (flags & PUFFS_FBQUEUE_URGENT)
410 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
411 else
412 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
414 return 0;
418 puffs_framev_enqueue_justsend(struct puffs_usermount *pu, int fd,
419 struct puffs_framebuf *pufbuf, int reply, int flags)
421 struct puffs_fctrl_io *fio;
423 assert((pufbuf->istat & ISTAT_INTERNAL) == 0);
425 GETFIO(fd);
427 pufbuf->pcc = NULL;
428 pufbuf->fcb = NULL;
429 pufbuf->fcb_arg = NULL;
431 pufbuf->offset = 0;
432 pufbuf->istat |= ISTAT_NODESTROY;
433 if (!reply)
434 pufbuf->istat |= ISTAT_NOREPLY;
436 if (flags & PUFFS_FBQUEUE_URGENT)
437 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
438 else
439 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
441 return 0;
444 /* ARGSUSED */
446 puffs_framev_enqueue_directreceive(struct puffs_cc *pcc, int fd,
447 struct puffs_framebuf *pufbuf, int flags /* used in the future */)
449 struct puffs_usermount *pu = pcc->pcc_pu;
450 struct puffs_fctrl_io *fio;
452 assert((pufbuf->istat & ISTAT_INTERNAL) == 0);
454 fio = getfiobyfd(pu, fd);
455 if (fio == NULL) {
456 errno = EINVAL;
457 return -1;
460 /* XXX: should have cur_in queue */
461 assert(fio->cur_in == NULL);
462 fio->cur_in = pufbuf;
464 pufbuf->pcc = pcc;
465 pufbuf->fcb = NULL;
466 pufbuf->fcb_arg = NULL;
468 pufbuf->offset = 0;
469 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
471 puffs_cc_yield(pcc);
472 pufbuf->istat &= ~ISTAT_NODESTROY; /* XXX: not the right place */
473 if (pufbuf->rv) {
474 errno = pufbuf->rv;
475 return -1;
478 return 0;
482 puffs_framev_enqueue_directsend(struct puffs_cc *pcc, int fd,
483 struct puffs_framebuf *pufbuf, int flags)
485 struct puffs_usermount *pu = pcc->pcc_pu;
486 struct puffs_fctrl_io *fio;
488 assert((pufbuf->istat & ISTAT_INTERNAL) == 0);
490 if (flags & PUFFS_FBQUEUE_URGENT)
491 abort(); /* EOPNOTSUPP for now */
493 GETFIO(fd);
495 pufbuf->pcc = pcc;
496 pufbuf->fcb = NULL;
497 pufbuf->fcb_arg = NULL;
499 pufbuf->offset = 0;
500 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
502 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
504 puffs_cc_yield(pcc);
505 if (pufbuf->rv) {
506 pufbuf->istat &= ~ISTAT_NODESTROY;
507 errno = pufbuf->rv;
508 return -1;
511 return 0;
515 puffs_framev_framebuf_ccpromote(struct puffs_framebuf *pufbuf,
516 struct puffs_cc *pcc)
519 if ((pufbuf->istat & ISTAT_ONQUEUE) == 0) {
520 errno = EBUSY;
521 return -1;
524 pufbuf->pcc = pcc;
525 pufbuf->fcb = NULL;
526 pufbuf->fcb_arg = NULL;
527 pufbuf->istat &= ~ISTAT_NOREPLY;
529 puffs_cc_yield(pcc);
531 return 0;
535 puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what)
537 struct puffs_usermount *pu = pcc->pcc_pu;
538 struct puffs_fctrl_io *fio;
539 struct puffs_fbevent feb;
540 struct kevent kev;
541 int rv, svwhat;
543 svwhat = *what;
545 if (*what == 0) {
546 errno = EINVAL;
547 return -1;
550 fio = getfiobyfd(pu, fd);
551 if (fio == NULL) {
552 errno = EINVAL;
553 return -1;
556 feb.pcc = pcc;
557 feb.what = *what & (PUFFS_FBIO_READ|PUFFS_FBIO_WRITE|PUFFS_FBIO_ERROR);
559 if (*what & PUFFS_FBIO_READ)
560 if ((fio->stat & FIO_ENABLE_R) == 0)
561 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE,
562 0, 0, (uintptr_t)fio);
564 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
565 if (rv != 0)
566 return errno;
568 if (*what & PUFFS_FBIO_READ)
569 fio->rwait++;
570 if (*what & PUFFS_FBIO_WRITE)
571 fio->wwait++;
573 LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries);
574 puffs_cc_yield(pcc);
576 assert(svwhat == *what);
578 if (*what & PUFFS_FBIO_READ) {
579 fio->rwait--;
580 if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) {
581 EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE,
582 0, 0, (uintptr_t)fio);
583 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
584 #if 0
585 if (rv != 0)
586 /* XXXXX oh dear */;
587 #endif
590 if (*what & PUFFS_FBIO_WRITE)
591 fio->wwait--;
593 if (feb.rv == 0) {
594 *what = feb.what;
595 rv = 0;
596 } else {
597 *what = PUFFS_FBIO_ERROR;
598 errno = feb.rv;
599 rv = -1;
602 return rv;
605 void
606 puffs__framev_notify(struct puffs_fctrl_io *fio, int what)
608 struct puffs_fbevent *fbevp;
610 restart:
611 LIST_FOREACH(fbevp, &fio->ev_qing, pfe_entries) {
612 if (fbevp->what & what) {
613 fbevp->what = what;
614 fbevp->rv = 0;
615 LIST_REMOVE(fbevp, pfe_entries);
616 puffs_cc_continue(fbevp->pcc);
617 goto restart;
622 static struct puffs_framebuf *
623 findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
624 struct puffs_fctrl_io *fio, struct puffs_framebuf *findme)
626 struct puffs_framebuf *cand;
627 int notresp = 0;
629 TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries)
630 if (fctrl->cmpfb(pu, findme, cand, &notresp) == 0 || notresp)
631 break;
633 assert(!(notresp && cand == NULL));
634 if (notresp || cand == NULL)
635 return NULL;
637 TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries);
638 return cand;
641 void
642 puffs__framebuf_moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to)
645 assert(from->istat & ISTAT_INTERNAL);
647 /* migrate buffer */
648 free(to->buf);
649 to->buf = from->buf;
651 /* migrate buffer info */
652 to->len = from->len;
653 to->offset = from->offset;
654 to->maxoff = from->maxoff;
656 from->buf = NULL;
657 from->len = 0;
660 void
661 puffs__framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
662 struct puffs_fctrl_io *fio)
664 struct puffs_framebuf *pufbuf, *appbuf;
665 int rv, complete;
667 while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) {
668 if ((pufbuf = fio->cur_in) == NULL) {
669 pufbuf = puffs_framebuf_make();
670 if (pufbuf == NULL)
671 return;
672 pufbuf->istat |= ISTAT_INTERNAL;
673 fio->cur_in = pufbuf;
676 complete = 0;
677 rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete);
679 /* error */
680 if (rv) {
681 puffs__framev_readclose(pu, fio, rv);
682 fio->cur_in = NULL;
683 return;
686 /* partial read, come back to fight another day */
687 if (complete == 0)
688 break;
690 /* else: full read, process */
691 fio->cur_in = NULL;
692 if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
693 appbuf = findbuf(pu, fctrl, fio, pufbuf);
696 * No request for this frame? If fs implements
697 * gotfb, give frame to that. Otherwise drop it.
699 if (appbuf == NULL) {
700 if (fctrl->gotfb) {
701 pufbuf->istat &= ~ISTAT_INTERNAL;
702 fctrl->gotfb(pu, pufbuf);
703 } else {
704 puffs_framebuf_destroy(pufbuf);
706 continue;
709 puffs__framebuf_moveinfo(pufbuf, appbuf);
710 puffs_framebuf_destroy(pufbuf);
711 } else {
712 appbuf = pufbuf;
714 appbuf->istat &= ~ISTAT_NODESTROY;
716 if (appbuf->pcc) {
717 puffs__cc_cont(appbuf->pcc);
718 } else if (appbuf->fcb) {
719 appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0);
720 } else {
721 puffs_framebuf_destroy(appbuf);
724 /* hopeless romantics, here we go again */
729 puffs__framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
730 struct puffs_fctrl_io *fio)
732 struct puffs_framebuf *pufbuf;
733 int rv, complete, done;
735 if (fio->stat & FIO_DEAD)
736 return 0;
738 for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0;
739 pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W;
740 pufbuf = TAILQ_FIRST(&fio->snd_qing)) {
741 complete = 0;
742 rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete);
744 if (rv) {
745 puffs__framev_writeclose(pu, fio, rv);
746 done = 1;
747 break;
750 /* partial write */
751 if (complete == 0)
752 return done;
754 /* else, complete write */
755 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
757 /* can't wait for result if we can't read */
758 if (fio->stat & FIO_RDGONE) {
759 errnotify(pu, pufbuf, ENXIO);
760 done = 1;
761 } else if ((pufbuf->istat & ISTAT_DIRECT)) {
762 pufbuf->istat &= ~ISTAT_NODESTROY;
763 done = 1;
764 puffs__cc_cont(pufbuf->pcc);
765 } else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) {
766 TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf,
767 pfb_entries);
768 } else {
769 pufbuf->istat &= ~ISTAT_NODESTROY;
770 puffs_framebuf_destroy(pufbuf);
773 /* omstart! */
776 return done;
780 puffs__framev_addfd_ctrl(struct puffs_usermount *pu, int fd, int what,
781 struct puffs_framectrl *pfctrl)
783 struct puffs_fctrl_io *fio;
784 struct kevent *newevs;
785 struct kevent kev[2];
786 size_t nfds;
787 int rv, readenable;
789 nfds = pu->pu_nfds+1;
790 newevs = realloc(pu->pu_evs, (2*nfds) * sizeof(struct kevent));
791 if (newevs == NULL)
792 return -1;
793 pu->pu_evs = newevs;
795 fio = malloc(sizeof(struct puffs_fctrl_io));
796 if (fio == NULL)
797 return -1;
798 memset(fio, 0, sizeof(struct puffs_fctrl_io));
799 fio->io_fd = fd;
800 fio->cur_in = NULL;
801 fio->fctrl = pfctrl;
802 TAILQ_INIT(&fio->snd_qing);
803 TAILQ_INIT(&fio->res_qing);
804 LIST_INIT(&fio->ev_qing);
806 readenable = 0;
807 if ((what & PUFFS_FBIO_READ) == 0)
808 readenable = EV_DISABLE;
810 if (pu->pu_state & PU_INLOOP) {
811 EV_SET(&kev[0], fd, EVFILT_READ,
812 EV_ADD|readenable, 0, 0, (intptr_t)fio);
813 EV_SET(&kev[1], fd, EVFILT_WRITE,
814 EV_ADD|EV_DISABLE, 0, 0, (intptr_t)fio);
815 rv = kevent(pu->pu_kq, kev, 2, NULL, 0, NULL);
816 if (rv == -1) {
817 free(fio);
818 return -1;
821 if (what & PUFFS_FBIO_READ)
822 fio->stat |= FIO_ENABLE_R;
823 if (what & PUFFS_FBIO_WRITE)
824 fio->stat |= FIO_ENABLE_W;
826 LIST_INSERT_HEAD(&pu->pu_ios, fio, fio_entries);
827 pu->pu_nfds = nfds;
829 return 0;
833 puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what)
836 return puffs__framev_addfd_ctrl(pu, fd, what,
837 &pu->pu_framectrl[PU_FRAMECTRL_USER]);
841 * XXX: the following en/disable should be coalesced and executed
842 * only during the actual kevent call. So feel free to fix if
843 * threatened by mindblowing boredom.
847 puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what)
849 struct kevent kev;
850 struct puffs_fctrl_io *fio;
851 int rv = 0;
853 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
855 fio = getfiobyfd(pu, fd);
856 if (fio == NULL) {
857 errno = ENXIO;
858 return -1;
861 /* write is enabled in the event loop if there is output */
862 if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
863 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, (uintptr_t)fio);
864 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
867 if (rv == 0) {
868 if (what & PUFFS_FBIO_READ)
869 fio->stat |= FIO_ENABLE_R;
870 if (what & PUFFS_FBIO_WRITE)
871 fio->stat |= FIO_ENABLE_W;
874 return rv;
878 puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what)
880 struct kevent kev[2];
881 struct puffs_fctrl_io *fio;
882 size_t i;
883 int rv;
885 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
887 fio = getfiobyfd(pu, fd);
888 if (fio == NULL) {
889 errno = ENXIO;
890 return -1;
893 i = 0;
894 if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
895 EV_SET(&kev[0], fd,
896 EVFILT_READ, EV_DISABLE, 0, 0, (uintptr_t)fio);
897 i++;
899 if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) {
900 EV_SET(&kev[1], fd,
901 EVFILT_WRITE, EV_DISABLE, 0, 0, (uintptr_t)fio);
902 i++;
904 if (i)
905 rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL);
906 else
907 rv = 0;
909 if (rv == 0) {
910 if (what & PUFFS_FBIO_READ)
911 fio->stat &= ~FIO_ENABLE_R;
912 if (what & PUFFS_FBIO_WRITE)
913 fio->stat &= ~FIO_ENABLE_W;
916 return rv;
919 void
920 puffs__framev_readclose(struct puffs_usermount *pu,
921 struct puffs_fctrl_io *fio, int error)
923 struct puffs_framebuf *pufbuf;
924 struct kevent kev;
925 int notflag;
927 if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD)
928 return;
929 fio->stat |= FIO_RDGONE;
931 if (fio->cur_in) {
932 if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) {
933 puffs_framebuf_destroy(fio->cur_in);
934 fio->cur_in = NULL;
935 } else {
936 errnotify(pu, fio->cur_in, error);
940 while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) {
941 TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries);
942 errnotify(pu, pufbuf, error);
945 EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
946 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
948 notflag = PUFFS_FBIO_READ;
949 if (fio->stat & FIO_WRGONE)
950 notflag |= PUFFS_FBIO_WRITE;
952 if (fio->fctrl->fdnotfn)
953 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag);
956 void
957 puffs__framev_writeclose(struct puffs_usermount *pu,
958 struct puffs_fctrl_io *fio, int error)
960 struct puffs_framebuf *pufbuf;
961 struct kevent kev;
962 int notflag;
964 if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD)
965 return;
966 fio->stat |= FIO_WRGONE;
968 while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) {
969 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
970 errnotify(pu, pufbuf, error);
973 EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
974 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
976 notflag = PUFFS_FBIO_WRITE;
977 if (fio->stat & FIO_RDGONE)
978 notflag |= PUFFS_FBIO_READ;
980 if (fio->fctrl->fdnotfn)
981 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag);
984 static int
985 removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error)
987 struct puffs_fbevent *fbevp;
989 LIST_REMOVE(fio, fio_entries);
990 if (pu->pu_state & PU_INLOOP) {
991 puffs__framev_readclose(pu, fio, error);
992 puffs__framev_writeclose(pu, fio, error);
995 while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) {
996 fbevp->rv = error;
997 LIST_REMOVE(fbevp, pfe_entries);
998 puffs__goto(fbevp->pcc);
1001 /* don't bother with realloc */
1002 pu->pu_nfds--;
1004 /* don't free us yet, might have some references in event arrays */
1005 fio->stat |= FIO_DEAD;
1006 LIST_INSERT_HEAD(&pu->pu_ios_rmlist, fio, fio_entries);
1008 return 0;
1013 puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error)
1015 struct puffs_fctrl_io *fio;
1017 fio = getfiobyfd(pu, fd);
1018 if (fio == NULL) {
1019 errno = ENXIO;
1020 return -1;
1023 return removefio(pu, fio, error ? error : ECONNRESET);
1026 void
1027 puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what)
1030 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
1031 (void) puffs_framev_removefd(pu, fd, ECONNRESET);
1034 void
1035 puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what)
1038 /* XXX & X: unmount is non-sensible */
1039 puffs_framev_removeonclose(pu, fd, what);
1040 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
1041 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
1044 void
1045 puffs_framev_init(struct puffs_usermount *pu,
1046 puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb,
1047 puffs_framev_cmpframe_fn cmpfb, puffs_framev_gotframe_fn gotfb,
1048 puffs_framev_fdnotify_fn fdnotfn)
1050 struct puffs_framectrl *pfctrl;
1052 pfctrl = &pu->pu_framectrl[PU_FRAMECTRL_USER];
1053 pfctrl->rfb = rfb;
1054 pfctrl->wfb = wfb;
1055 pfctrl->cmpfb = cmpfb;
1056 pfctrl->gotfb = gotfb;
1057 pfctrl->fdnotfn = fdnotfn;
1060 void
1061 puffs__framev_exit(struct puffs_usermount *pu)
1063 struct puffs_fctrl_io *fio;
1065 while ((fio = LIST_FIRST(&pu->pu_ios)) != NULL)
1066 removefio(pu, fio, ENXIO);
1067 free(pu->pu_evs);
1069 /* closing pu->pu_kq takes care of puffsfd */