framebuf.c revision 1.21 1 /* $NetBSD: framebuf.c,v 1.21 2007/09/01 16:42:42 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.21 2007/09/01 16:42:42 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_usermount *pu, 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(pu, pufbuf, pufbuf->fcb_arg, error);
302 } else {
303 pufbuf->istat &= ~ISTAT_NODESTROY;
304 puffs_framebuf_destroy(pufbuf);
305 }
306 }
307
308 #define GETFIO(fd) \
309 do { \
310 fio = getfiobyfd(pu, fd); \
311 if (fio == NULL) { \
312 errno = EINVAL; \
313 return -1; \
314 } \
315 if (fio->stat & FIO_WRGONE) { \
316 errno = ESHUTDOWN; \
317 return -1; \
318 } \
319 } while (/*CONSTCOND*/0)
320
321 int
322 puffs_framev_enqueue_cc(struct puffs_cc *pcc, int fd,
323 struct puffs_framebuf *pufbuf, int flags)
324 {
325 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
326 struct puffs_fctrl_io *fio;
327
328 /*
329 * Technically we shouldn't allow this is RDGONE, but it's
330 * difficult to trap write close without allowing writes.
331 * And besides, there's probably a disconnect sequence in
332 * the protocol, so unexpectedly getting a closed fd is
333 * most likely an error condition.
334 */
335 GETFIO(fd);
336
337 pufbuf->pcc = pcc;
338 pufbuf->fcb = NULL;
339 pufbuf->fcb_arg = NULL;
340
341 pufbuf->offset = 0;
342 pufbuf->istat |= ISTAT_NODESTROY;
343
344 if (flags & PUFFS_FBQUEUE_URGENT)
345 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
346 else
347 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
348
349 puffs_cc_yield(pcc);
350 if (pufbuf->rv) {
351 pufbuf->istat &= ~ISTAT_NODESTROY;
352 errno = pufbuf->rv;
353 return -1;
354 }
355
356 return 0;
357 }
358
359 int
360 puffs_framev_enqueue_cb(struct puffs_usermount *pu, int fd,
361 struct puffs_framebuf *pufbuf, puffs_framev_cb fcb, void *arg,
362 int flags)
363 {
364 struct puffs_fctrl_io *fio;
365
366 /* see enqueue_cc */
367 GETFIO(fd);
368
369 pufbuf->pcc = NULL;
370 pufbuf->fcb = fcb;
371 pufbuf->fcb_arg = arg;
372
373 pufbuf->offset = 0;
374 pufbuf->istat |= ISTAT_NODESTROY;
375
376 if (flags & PUFFS_FBQUEUE_URGENT)
377 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
378 else
379 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
380
381 return 0;
382 }
383
384 int
385 puffs_framev_enqueue_justsend(struct puffs_usermount *pu, int fd,
386 struct puffs_framebuf *pufbuf, int reply, int flags)
387 {
388 struct puffs_fctrl_io *fio;
389
390 GETFIO(fd);
391
392 pufbuf->pcc = NULL;
393 pufbuf->fcb = NULL;
394 pufbuf->fcb_arg = NULL;
395
396 pufbuf->offset = 0;
397 pufbuf->istat |= ISTAT_NODESTROY;
398 if (!reply)
399 pufbuf->istat |= ISTAT_NOREPLY;
400
401 if (flags & PUFFS_FBQUEUE_URGENT)
402 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
403 else
404 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
405
406 return 0;
407 }
408
409 /* ARGSUSED */
410 int
411 puffs_framev_enqueue_directreceive(struct puffs_cc *pcc, int fd,
412 struct puffs_framebuf *pufbuf, int flags /* used in the future */)
413 {
414 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
415 struct puffs_fctrl_io *fio;
416
417 fio = getfiobyfd(pu, fd);
418 if (fio == NULL) {
419 errno = EINVAL;
420 return -1;
421 }
422
423 /* XXX: should have cur_in queue */
424 assert(fio->cur_in == NULL);
425 fio->cur_in = pufbuf;
426
427 pufbuf->pcc = pcc;
428 pufbuf->fcb = NULL;
429 pufbuf->fcb_arg = NULL;
430
431 pufbuf->offset = 0;
432 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
433
434 puffs_cc_yield(pcc);
435 pufbuf->istat &= ~ISTAT_NODESTROY; /* XXX: not the right place */
436 if (pufbuf->rv) {
437 errno = pufbuf->rv;
438 return -1;
439 }
440
441 return 0;
442 }
443
444 int
445 puffs_framev_enqueue_directsend(struct puffs_cc *pcc, int fd,
446 struct puffs_framebuf *pufbuf, int flags)
447 {
448 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
449 struct puffs_fctrl_io *fio;
450
451 if (flags & PUFFS_FBQUEUE_URGENT)
452 abort(); /* EOPNOTSUPP for now */
453
454 GETFIO(fd);
455
456 pufbuf->pcc = pcc;
457 pufbuf->fcb = NULL;
458 pufbuf->fcb_arg = NULL;
459
460 pufbuf->offset = 0;
461 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
462
463 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
464
465 puffs_cc_yield(pcc);
466 if (pufbuf->rv) {
467 pufbuf->istat &= ~ISTAT_NODESTROY;
468 errno = pufbuf->rv;
469 return -1;
470 }
471
472 return 0;
473 }
474
475 /*
476 * this beauty shall remain undocumented for now
477 */
478 int
479 puffs_framev_framebuf_ccpromote(struct puffs_framebuf *pufbuf,
480 struct puffs_cc *pcc)
481 {
482
483 if ((pufbuf->istat & ISTAT_ONQUEUE) == 0) {
484 errno = EBUSY;
485 return -1;
486 }
487
488 pufbuf->pcc = pcc;
489 pufbuf->fcb = NULL;
490 pufbuf->fcb_arg = NULL;
491 pufbuf->istat &= ~ISTAT_NOREPLY;
492
493 puffs_cc_yield(pcc);
494
495 return 0;
496 }
497
498 int
499 puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what)
500 {
501 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
502 struct puffs_fctrl_io *fio;
503 struct puffs_fbevent feb;
504 struct kevent kev;
505 int rv, svwhat;
506
507 svwhat = *what;
508
509 if (*what == 0) {
510 errno = EINVAL;
511 return -1;
512 }
513
514 fio = getfiobyfd(pu, fd);
515 if (fio == NULL) {
516 errno = EINVAL;
517 return -1;
518 }
519
520 feb.pcc = pcc;
521 feb.what = *what & (PUFFS_FBIO_READ|PUFFS_FBIO_WRITE|PUFFS_FBIO_ERROR);
522
523 if (*what & PUFFS_FBIO_READ)
524 if ((fio->stat & FIO_ENABLE_R) == 0)
525 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE,
526 0, 0, (uintptr_t)fio);
527
528 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
529 if (rv != 0)
530 return errno;
531
532 if (*what & PUFFS_FBIO_READ)
533 fio->rwait++;
534 if (*what & PUFFS_FBIO_WRITE)
535 fio->wwait++;
536
537 LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries);
538 puffs_cc_yield(pcc);
539
540 assert(svwhat == *what);
541
542 if (*what & PUFFS_FBIO_READ) {
543 fio->rwait--;
544 if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) {
545 EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE,
546 0, 0, (uintptr_t)fio);
547 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
548 #if 0
549 if (rv != 0)
550 /* XXXXX oh dear */;
551 #endif
552 }
553 }
554 if (*what & PUFFS_FBIO_WRITE)
555 fio->wwait--;
556
557 if (feb.rv == 0) {
558 *what = feb.what;
559 rv = 0;
560 } else {
561 *what = PUFFS_FBIO_ERROR;
562 errno = feb.rv;
563 rv = -1;
564 }
565
566 return rv;
567 }
568
569 void
570 puffs_framev_notify(struct puffs_fctrl_io *fio, int what)
571 {
572 struct puffs_fbevent *fbevp;
573
574 restart:
575 LIST_FOREACH(fbevp, &fio->ev_qing, pfe_entries) {
576 if (fbevp->what & what) {
577 fbevp->what = what;
578 fbevp->rv = 0;
579 LIST_REMOVE(fbevp, pfe_entries);
580 puffs_cc_continue(fbevp->pcc);
581 goto restart;
582 }
583 }
584 }
585
586 static struct puffs_framebuf *
587 findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
588 struct puffs_fctrl_io *fio, struct puffs_framebuf *findme)
589 {
590 struct puffs_framebuf *cand;
591
592 TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries)
593 if (fctrl->cmpfb(pu, findme, cand) == 0)
594 break;
595
596 if (cand == NULL)
597 return NULL;
598
599 TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries);
600 return cand;
601 }
602
603 static void
604 moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to)
605 {
606
607 assert(from->istat & ISTAT_INTERNAL);
608
609 /* migrate buffer */
610 free(to->buf);
611 to->buf = from->buf;
612 from->buf = NULL;
613
614 /* migrate buffer info */
615 to->len = from->len;
616 to->offset = from->offset;
617 to->maxoff = from->maxoff;
618 }
619
620 void
621 puffs_framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
622 struct puffs_fctrl_io *fio, struct puffs_putreq *ppr)
623 {
624 struct puffs_framebuf *pufbuf, *appbuf;
625 int rv, complete;
626
627 while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) {
628 if ((pufbuf = fio->cur_in) == NULL) {
629 pufbuf = puffs_framebuf_make();
630 if (pufbuf == NULL)
631 return;
632 pufbuf->istat |= ISTAT_INTERNAL;
633 fio->cur_in = pufbuf;
634 }
635
636 complete = 0;
637 rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete);
638
639 /* error */
640 if (rv) {
641 puffs_framev_readclose(pu, fio, rv);
642 fio->cur_in = NULL;
643 if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
644 assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
645 puffs_framebuf_destroy(pufbuf);
646 }
647 return;
648 }
649
650 /* partial read, come back to fight another day */
651 if (complete == 0)
652 break;
653
654 /* else: full read, process */
655 if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
656 appbuf = findbuf(pu, fctrl, fio, pufbuf);
657
658 /*
659 * No request for this frame? If fs implements
660 * gotfb, give frame to that. Otherwise drop it.
661 */
662 if (appbuf == NULL) {
663 if (fctrl->gotfb)
664 fctrl->gotfb(pu, pufbuf);
665
666 /* XXX: ugly */
667 pufbuf->istat &= ~ISTAT_NODESTROY;
668 fio->cur_in = NULL;
669 puffs_framebuf_destroy(pufbuf);
670 continue;
671 }
672
673 moveinfo(pufbuf, appbuf);
674 puffs_framebuf_destroy(pufbuf);
675 } else {
676 appbuf = pufbuf;
677 }
678 appbuf->istat &= ~ISTAT_NODESTROY;
679 fio->cur_in = NULL;
680
681 if (appbuf->pcc) {
682 puffs_docc(appbuf->pcc, ppr);
683 } else if (appbuf->fcb) {
684 appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0);
685 } else {
686 puffs_framebuf_destroy(appbuf);
687 }
688
689 /* hopeless romantics, here we go again */
690 }
691 }
692
693 int
694 puffs_framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
695 struct puffs_fctrl_io *fio, struct puffs_putreq *ppr)
696 {
697 struct puffs_framebuf *pufbuf;
698 int rv, complete, done;
699
700 if (fio->stat & FIO_DEAD)
701 return 0;
702
703 for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0;
704 pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W;
705 pufbuf = TAILQ_FIRST(&fio->snd_qing)) {
706 complete = 0;
707 rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete);
708
709 if (rv) {
710 puffs_framev_writeclose(pu, fio, rv);
711 done = 1;
712 break;
713 }
714
715 /* partial write */
716 if (complete == 0)
717 return done;
718
719 /* else, complete write */
720 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
721
722 /* can't wait for result if we can't read */
723 if (fio->stat & FIO_RDGONE) {
724 errnotify(pu, pufbuf, ENXIO);
725 done = 1;
726 } else if ((pufbuf->istat & ISTAT_DIRECT)) {
727 pufbuf->istat &= ~ISTAT_NODESTROY;
728 puffs_docc(pufbuf->pcc, ppr);
729 done = 1;
730 } else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) {
731 TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf,
732 pfb_entries);
733 } else {
734 pufbuf->istat &= ~ISTAT_NODESTROY;
735 puffs_framebuf_destroy(pufbuf);
736 }
737
738 /* omstart! */
739 }
740
741 return done;
742 }
743
744 int
745 puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what)
746 {
747 struct puffs_framectrl *pfctrl = &pu->pu_framectrl;
748 struct puffs_fctrl_io *fio;
749 struct kevent *newevs;
750 struct kevent kev[2];
751 size_t nfds;
752 int rv, readenable;
753
754 nfds = pfctrl->nfds+1;
755 newevs = realloc(pfctrl->evs, (2*nfds+1) * sizeof(struct kevent));
756 if (newevs == NULL)
757 return -1;
758 pfctrl->evs = newevs;
759
760 fio = malloc(sizeof(struct puffs_fctrl_io));
761 if (fio == NULL)
762 return -1;
763 memset(fio, 0, sizeof(struct puffs_fctrl_io));
764 fio->io_fd = fd;
765 fio->cur_in = NULL;
766 TAILQ_INIT(&fio->snd_qing);
767 TAILQ_INIT(&fio->res_qing);
768 LIST_INIT(&fio->ev_qing);
769
770 readenable = 0;
771 if ((what & PUFFS_FBIO_READ) == 0)
772 readenable = EV_DISABLE;
773
774 if (pu->pu_state & PU_INLOOP) {
775 EV_SET(&kev[0], fd, EVFILT_READ,
776 EV_ADD|readenable, 0, 0, (intptr_t)fio);
777 EV_SET(&kev[1], fd, EVFILT_WRITE,
778 EV_ADD|EV_DISABLE, 0, 0, (intptr_t)fio);
779 rv = kevent(pu->pu_kq, kev, 2, NULL, 0, NULL);
780 if (rv == -1) {
781 free(fio);
782 return -1;
783 }
784 }
785 if (what & PUFFS_FBIO_READ)
786 fio->stat |= FIO_ENABLE_R;
787 if (what & PUFFS_FBIO_WRITE)
788 fio->stat |= FIO_ENABLE_W;
789
790 LIST_INSERT_HEAD(&pfctrl->fb_ios, fio, fio_entries);
791 pfctrl->nfds = nfds;
792
793 return 0;
794 }
795
796 /*
797 * XXX: the following en/disable should be coalesced and executed
798 * only during the actual kevent call. So feel free to fix if
799 * threatened by mindblowing boredom.
800 */
801
802 int
803 puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what)
804 {
805 struct kevent kev;
806 struct puffs_fctrl_io *fio;
807 int rv = 0;
808
809 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
810
811 fio = getfiobyfd(pu, fd);
812 if (fio == NULL) {
813 errno = ENXIO;
814 return -1;
815 }
816
817 /* write is enabled in the event loop if there is output */
818 if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
819 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, (uintptr_t)fio);
820 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
821 }
822
823 if (rv == 0) {
824 if (what & PUFFS_FBIO_READ)
825 fio->stat |= FIO_ENABLE_R;
826 if (what & PUFFS_FBIO_WRITE)
827 fio->stat |= FIO_ENABLE_W;
828 }
829
830 return rv;
831 }
832
833 int
834 puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what)
835 {
836 struct kevent kev[2];
837 struct puffs_fctrl_io *fio;
838 size_t i;
839 int rv;
840
841 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
842
843 fio = getfiobyfd(pu, fd);
844 if (fio == NULL) {
845 errno = ENXIO;
846 return -1;
847 }
848
849 i = 0;
850 if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
851 EV_SET(&kev[0], fd,
852 EVFILT_READ, EV_DISABLE, 0, 0, (uintptr_t)fio);
853 i++;
854 }
855 if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) {
856 EV_SET(&kev[1], fd,
857 EVFILT_WRITE, EV_DISABLE, 0, 0, (uintptr_t)fio);
858 i++;
859 }
860 if (i)
861 rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL);
862 else
863 rv = 0;
864
865 if (rv == 0) {
866 if (what & PUFFS_FBIO_READ)
867 fio->stat &= ~FIO_ENABLE_R;
868 if (what & PUFFS_FBIO_WRITE)
869 fio->stat &= ~FIO_ENABLE_W;
870 }
871
872 return rv;
873 }
874
875 void
876 puffs_framev_readclose(struct puffs_usermount *pu,
877 struct puffs_fctrl_io *fio, int error)
878 {
879 struct puffs_framebuf *pufbuf;
880 struct kevent kev;
881 int notflag;
882
883 if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD)
884 return;
885 fio->stat |= FIO_RDGONE;
886
887 if (fio->cur_in) {
888 if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) {
889 puffs_framebuf_destroy(fio->cur_in);
890 fio->cur_in = NULL;
891 } else {
892 errnotify(pu, fio->cur_in, error);
893 }
894 }
895
896 while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) {
897 TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries);
898 errnotify(pu, pufbuf, error);
899 }
900
901 EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
902 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
903
904 notflag = PUFFS_FBIO_READ;
905 if (fio->stat & FIO_WRGONE)
906 notflag |= PUFFS_FBIO_WRITE;
907
908 if (pu->pu_framectrl.fdnotfn)
909 pu->pu_framectrl.fdnotfn(pu, fio->io_fd, notflag);
910 }
911
912 void
913 puffs_framev_writeclose(struct puffs_usermount *pu,
914 struct puffs_fctrl_io *fio, int error)
915 {
916 struct puffs_framebuf *pufbuf;
917 struct kevent kev;
918 int notflag;
919
920 if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD)
921 return;
922 fio->stat |= FIO_WRGONE;
923
924 while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) {
925 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
926 errnotify(pu, pufbuf, error);
927 }
928
929 EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
930 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
931
932 notflag = PUFFS_FBIO_WRITE;
933 if (fio->stat & FIO_RDGONE)
934 notflag |= PUFFS_FBIO_READ;
935
936 if (pu->pu_framectrl.fdnotfn)
937 pu->pu_framectrl.fdnotfn(pu, fio->io_fd, notflag);
938 }
939
940 static int
941 removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error)
942 {
943 struct puffs_framectrl *pfctrl = &pu->pu_framectrl;
944 struct puffs_fbevent *fbevp;
945
946 LIST_REMOVE(fio, fio_entries);
947 if (pu->pu_state & PU_INLOOP) {
948 puffs_framev_readclose(pu, fio, error);
949 puffs_framev_writeclose(pu, fio, error);
950 }
951
952 while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) {
953 fbevp->rv = error;
954 LIST_REMOVE(fbevp, pfe_entries);
955 puffs_goto(fbevp->pcc);
956 }
957
958 /* don't bother with realloc */
959 pfctrl->nfds--;
960
961 /* don't free us yet, might have some references in event arrays */
962 fio->stat |= FIO_DEAD;
963 LIST_INSERT_HEAD(&pfctrl->fb_ios_rmlist, fio, fio_entries);
964
965 return 0;
966
967 }
968
969 int
970 puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error)
971 {
972 struct puffs_fctrl_io *fio;
973
974 fio = getfiobyfd(pu, fd);
975 if (fio == NULL) {
976 errno = ENXIO;
977 return -1;
978 }
979
980 return removefio(pu, fio, error ? error : ECONNRESET);
981 }
982
983 void
984 puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what)
985 {
986
987 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
988 (void) puffs_framev_removefd(pu, fd, ECONNRESET);
989 }
990
991 void
992 puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what)
993 {
994
995 /* XXX & X: unmount is non-sensible */
996 puffs_framev_removeonclose(pu, fd, what);
997 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
998 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
999 }
1000
1001 void
1002 puffs_framev_init(struct puffs_usermount *pu,
1003 puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb,
1004 puffs_framev_cmpframe_fn cmpfb, puffs_framev_gotframe_fn gotfb,
1005 puffs_framev_fdnotify_fn fdnotfn)
1006 {
1007 struct puffs_framectrl *pfctrl;
1008
1009 pfctrl = &pu->pu_framectrl;
1010 pfctrl->rfb = rfb;
1011 pfctrl->wfb = wfb;
1012 pfctrl->cmpfb = cmpfb;
1013 pfctrl->gotfb = gotfb;
1014 pfctrl->fdnotfn = fdnotfn;
1015 }
1016
1017 void
1018 puffs_framev_exit(struct puffs_usermount *pu)
1019 {
1020 struct puffs_framectrl *pfctrl = &pu->pu_framectrl;
1021 struct puffs_fctrl_io *fio;
1022
1023 while ((fio = LIST_FIRST(&pfctrl->fb_ios)) != NULL)
1024 removefio(pu, fio, ENXIO);
1025 free(pfctrl->evs);
1026
1027 /* closing pu->pu_kq takes care of puffsfd */
1028 }
1029