framebuf.c revision 1.24 1 /* $NetBSD: framebuf.c,v 1.24 2007/12/04 17:21:24 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.24 2007/12/04 17:21:24 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->len + 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 int
476 puffs_framev_framebuf_ccpromote(struct puffs_framebuf *pufbuf,
477 struct puffs_cc *pcc)
478 {
479
480 if ((pufbuf->istat & ISTAT_ONQUEUE) == 0) {
481 errno = EBUSY;
482 return -1;
483 }
484
485 pufbuf->pcc = pcc;
486 pufbuf->fcb = NULL;
487 pufbuf->fcb_arg = NULL;
488 pufbuf->istat &= ~ISTAT_NOREPLY;
489
490 puffs_cc_yield(pcc);
491
492 return 0;
493 }
494
495 int
496 puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what)
497 {
498 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
499 struct puffs_fctrl_io *fio;
500 struct puffs_fbevent feb;
501 struct kevent kev;
502 int rv, svwhat;
503
504 svwhat = *what;
505
506 if (*what == 0) {
507 errno = EINVAL;
508 return -1;
509 }
510
511 fio = getfiobyfd(pu, fd);
512 if (fio == NULL) {
513 errno = EINVAL;
514 return -1;
515 }
516
517 feb.pcc = pcc;
518 feb.what = *what & (PUFFS_FBIO_READ|PUFFS_FBIO_WRITE|PUFFS_FBIO_ERROR);
519
520 if (*what & PUFFS_FBIO_READ)
521 if ((fio->stat & FIO_ENABLE_R) == 0)
522 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE,
523 0, 0, (uintptr_t)fio);
524
525 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
526 if (rv != 0)
527 return errno;
528
529 if (*what & PUFFS_FBIO_READ)
530 fio->rwait++;
531 if (*what & PUFFS_FBIO_WRITE)
532 fio->wwait++;
533
534 LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries);
535 puffs_cc_yield(pcc);
536
537 assert(svwhat == *what);
538
539 if (*what & PUFFS_FBIO_READ) {
540 fio->rwait--;
541 if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) {
542 EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE,
543 0, 0, (uintptr_t)fio);
544 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
545 #if 0
546 if (rv != 0)
547 /* XXXXX oh dear */;
548 #endif
549 }
550 }
551 if (*what & PUFFS_FBIO_WRITE)
552 fio->wwait--;
553
554 if (feb.rv == 0) {
555 *what = feb.what;
556 rv = 0;
557 } else {
558 *what = PUFFS_FBIO_ERROR;
559 errno = feb.rv;
560 rv = -1;
561 }
562
563 return 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 int notresp = 0;
589
590 TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries)
591 if (fctrl->cmpfb(pu, findme, cand, ¬resp) == 0 || notresp)
592 break;
593
594 assert(!(notresp && cand == NULL));
595 if (notresp || cand == NULL)
596 return NULL;
597
598 TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries);
599 return cand;
600 }
601
602 static void
603 moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to)
604 {
605
606 assert(from->istat & ISTAT_INTERNAL);
607
608 /* migrate buffer */
609 free(to->buf);
610 to->buf = from->buf;
611 from->buf = NULL;
612
613 /* migrate buffer info */
614 to->len = from->len;
615 to->offset = from->offset;
616 to->maxoff = from->maxoff;
617 }
618
619 void
620 puffs_framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
621 struct puffs_fctrl_io *fio, struct puffs_putreq *ppr)
622 {
623 struct puffs_framebuf *pufbuf, *appbuf;
624 int rv, complete;
625
626 while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) {
627 if ((pufbuf = fio->cur_in) == NULL) {
628 pufbuf = puffs_framebuf_make();
629 if (pufbuf == NULL)
630 return;
631 pufbuf->istat |= ISTAT_INTERNAL;
632 fio->cur_in = pufbuf;
633 }
634
635 complete = 0;
636 rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete);
637
638 /* error */
639 if (rv) {
640 puffs_framev_readclose(pu, fio, rv);
641 fio->cur_in = NULL;
642 if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
643 assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
644 puffs_framebuf_destroy(pufbuf);
645 }
646 return;
647 }
648
649 /* partial read, come back to fight another day */
650 if (complete == 0)
651 break;
652
653 /* else: full read, process */
654 if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
655 appbuf = findbuf(pu, fctrl, fio, pufbuf);
656
657 /*
658 * No request for this frame? If fs implements
659 * gotfb, give frame to that. Otherwise drop it.
660 */
661 if (appbuf == NULL) {
662 if (fctrl->gotfb)
663 fctrl->gotfb(pu, pufbuf);
664
665 /* XXX: ugly */
666 pufbuf->istat &= ~ISTAT_NODESTROY;
667 fio->cur_in = NULL;
668 puffs_framebuf_destroy(pufbuf);
669 continue;
670 }
671
672 moveinfo(pufbuf, appbuf);
673 puffs_framebuf_destroy(pufbuf);
674 } else {
675 appbuf = pufbuf;
676 }
677 appbuf->istat &= ~ISTAT_NODESTROY;
678 fio->cur_in = NULL;
679
680 if (appbuf->pcc) {
681 puffs_docc(appbuf->pcc, ppr);
682 } else if (appbuf->fcb) {
683 appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0);
684 } else {
685 puffs_framebuf_destroy(appbuf);
686 }
687
688 /* hopeless romantics, here we go again */
689 }
690 }
691
692 int
693 puffs_framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
694 struct puffs_fctrl_io *fio, struct puffs_putreq *ppr)
695 {
696 struct puffs_framebuf *pufbuf;
697 int rv, complete, done;
698
699 if (fio->stat & FIO_DEAD)
700 return 0;
701
702 for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0;
703 pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W;
704 pufbuf = TAILQ_FIRST(&fio->snd_qing)) {
705 complete = 0;
706 rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete);
707
708 if (rv) {
709 puffs_framev_writeclose(pu, fio, rv);
710 done = 1;
711 break;
712 }
713
714 /* partial write */
715 if (complete == 0)
716 return done;
717
718 /* else, complete write */
719 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
720
721 /* can't wait for result if we can't read */
722 if (fio->stat & FIO_RDGONE) {
723 errnotify(pu, pufbuf, ENXIO);
724 done = 1;
725 } else if ((pufbuf->istat & ISTAT_DIRECT)) {
726 pufbuf->istat &= ~ISTAT_NODESTROY;
727 puffs_docc(pufbuf->pcc, ppr);
728 done = 1;
729 } else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) {
730 TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf,
731 pfb_entries);
732 } else {
733 pufbuf->istat &= ~ISTAT_NODESTROY;
734 puffs_framebuf_destroy(pufbuf);
735 }
736
737 /* omstart! */
738 }
739
740 return done;
741 }
742
743 int
744 puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what)
745 {
746 struct puffs_framectrl *pfctrl = &pu->pu_framectrl;
747 struct puffs_fctrl_io *fio;
748 struct kevent *newevs;
749 struct kevent kev[2];
750 size_t nfds;
751 int rv, readenable;
752
753 nfds = pfctrl->nfds+1;
754 newevs = realloc(pfctrl->evs, (2*nfds+1) * sizeof(struct kevent));
755 if (newevs == NULL)
756 return -1;
757 pfctrl->evs = newevs;
758
759 fio = malloc(sizeof(struct puffs_fctrl_io));
760 if (fio == NULL)
761 return -1;
762 memset(fio, 0, sizeof(struct puffs_fctrl_io));
763 fio->io_fd = fd;
764 fio->cur_in = NULL;
765 TAILQ_INIT(&fio->snd_qing);
766 TAILQ_INIT(&fio->res_qing);
767 LIST_INIT(&fio->ev_qing);
768
769 readenable = 0;
770 if ((what & PUFFS_FBIO_READ) == 0)
771 readenable = EV_DISABLE;
772
773 if (pu->pu_state & PU_INLOOP) {
774 EV_SET(&kev[0], fd, EVFILT_READ,
775 EV_ADD|readenable, 0, 0, (intptr_t)fio);
776 EV_SET(&kev[1], fd, EVFILT_WRITE,
777 EV_ADD|EV_DISABLE, 0, 0, (intptr_t)fio);
778 rv = kevent(pu->pu_kq, kev, 2, NULL, 0, NULL);
779 if (rv == -1) {
780 free(fio);
781 return -1;
782 }
783 }
784 if (what & PUFFS_FBIO_READ)
785 fio->stat |= FIO_ENABLE_R;
786 if (what & PUFFS_FBIO_WRITE)
787 fio->stat |= FIO_ENABLE_W;
788
789 LIST_INSERT_HEAD(&pfctrl->fb_ios, fio, fio_entries);
790 pfctrl->nfds = nfds;
791
792 return 0;
793 }
794
795 /*
796 * XXX: the following en/disable should be coalesced and executed
797 * only during the actual kevent call. So feel free to fix if
798 * threatened by mindblowing boredom.
799 */
800
801 int
802 puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what)
803 {
804 struct kevent kev;
805 struct puffs_fctrl_io *fio;
806 int rv = 0;
807
808 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
809
810 fio = getfiobyfd(pu, fd);
811 if (fio == NULL) {
812 errno = ENXIO;
813 return -1;
814 }
815
816 /* write is enabled in the event loop if there is output */
817 if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
818 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, (uintptr_t)fio);
819 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
820 }
821
822 if (rv == 0) {
823 if (what & PUFFS_FBIO_READ)
824 fio->stat |= FIO_ENABLE_R;
825 if (what & PUFFS_FBIO_WRITE)
826 fio->stat |= FIO_ENABLE_W;
827 }
828
829 return rv;
830 }
831
832 int
833 puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what)
834 {
835 struct kevent kev[2];
836 struct puffs_fctrl_io *fio;
837 size_t i;
838 int rv;
839
840 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
841
842 fio = getfiobyfd(pu, fd);
843 if (fio == NULL) {
844 errno = ENXIO;
845 return -1;
846 }
847
848 i = 0;
849 if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
850 EV_SET(&kev[0], fd,
851 EVFILT_READ, EV_DISABLE, 0, 0, (uintptr_t)fio);
852 i++;
853 }
854 if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) {
855 EV_SET(&kev[1], fd,
856 EVFILT_WRITE, EV_DISABLE, 0, 0, (uintptr_t)fio);
857 i++;
858 }
859 if (i)
860 rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL);
861 else
862 rv = 0;
863
864 if (rv == 0) {
865 if (what & PUFFS_FBIO_READ)
866 fio->stat &= ~FIO_ENABLE_R;
867 if (what & PUFFS_FBIO_WRITE)
868 fio->stat &= ~FIO_ENABLE_W;
869 }
870
871 return rv;
872 }
873
874 void
875 puffs_framev_readclose(struct puffs_usermount *pu,
876 struct puffs_fctrl_io *fio, int error)
877 {
878 struct puffs_framebuf *pufbuf;
879 struct kevent kev;
880 int notflag;
881
882 if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD)
883 return;
884 fio->stat |= FIO_RDGONE;
885
886 if (fio->cur_in) {
887 if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) {
888 puffs_framebuf_destroy(fio->cur_in);
889 fio->cur_in = NULL;
890 } else {
891 errnotify(pu, fio->cur_in, error);
892 }
893 }
894
895 while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) {
896 TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries);
897 errnotify(pu, pufbuf, error);
898 }
899
900 EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
901 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
902
903 notflag = PUFFS_FBIO_READ;
904 if (fio->stat & FIO_WRGONE)
905 notflag |= PUFFS_FBIO_WRITE;
906
907 if (pu->pu_framectrl.fdnotfn)
908 pu->pu_framectrl.fdnotfn(pu, fio->io_fd, notflag);
909 }
910
911 void
912 puffs_framev_writeclose(struct puffs_usermount *pu,
913 struct puffs_fctrl_io *fio, int error)
914 {
915 struct puffs_framebuf *pufbuf;
916 struct kevent kev;
917 int notflag;
918
919 if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD)
920 return;
921 fio->stat |= FIO_WRGONE;
922
923 while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) {
924 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
925 errnotify(pu, pufbuf, error);
926 }
927
928 EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
929 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
930
931 notflag = PUFFS_FBIO_WRITE;
932 if (fio->stat & FIO_RDGONE)
933 notflag |= PUFFS_FBIO_READ;
934
935 if (pu->pu_framectrl.fdnotfn)
936 pu->pu_framectrl.fdnotfn(pu, fio->io_fd, notflag);
937 }
938
939 static int
940 removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error)
941 {
942 struct puffs_framectrl *pfctrl = &pu->pu_framectrl;
943 struct puffs_fbevent *fbevp;
944
945 LIST_REMOVE(fio, fio_entries);
946 if (pu->pu_state & PU_INLOOP) {
947 puffs_framev_readclose(pu, fio, error);
948 puffs_framev_writeclose(pu, fio, error);
949 }
950
951 while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) {
952 fbevp->rv = error;
953 LIST_REMOVE(fbevp, pfe_entries);
954 puffs_goto(fbevp->pcc);
955 }
956
957 /* don't bother with realloc */
958 pfctrl->nfds--;
959
960 /* don't free us yet, might have some references in event arrays */
961 fio->stat |= FIO_DEAD;
962 LIST_INSERT_HEAD(&pfctrl->fb_ios_rmlist, fio, fio_entries);
963
964 return 0;
965
966 }
967
968 int
969 puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error)
970 {
971 struct puffs_fctrl_io *fio;
972
973 fio = getfiobyfd(pu, fd);
974 if (fio == NULL) {
975 errno = ENXIO;
976 return -1;
977 }
978
979 return removefio(pu, fio, error ? error : ECONNRESET);
980 }
981
982 void
983 puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what)
984 {
985
986 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
987 (void) puffs_framev_removefd(pu, fd, ECONNRESET);
988 }
989
990 void
991 puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what)
992 {
993
994 /* XXX & X: unmount is non-sensible */
995 puffs_framev_removeonclose(pu, fd, what);
996 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
997 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
998 }
999
1000 void
1001 puffs_framev_init(struct puffs_usermount *pu,
1002 puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb,
1003 puffs_framev_cmpframe_fn cmpfb, puffs_framev_gotframe_fn gotfb,
1004 puffs_framev_fdnotify_fn fdnotfn)
1005 {
1006 struct puffs_framectrl *pfctrl;
1007
1008 pfctrl = &pu->pu_framectrl;
1009 pfctrl->rfb = rfb;
1010 pfctrl->wfb = wfb;
1011 pfctrl->cmpfb = cmpfb;
1012 pfctrl->gotfb = gotfb;
1013 pfctrl->fdnotfn = fdnotfn;
1014 }
1015
1016 void
1017 puffs_framev_exit(struct puffs_usermount *pu)
1018 {
1019 struct puffs_framectrl *pfctrl = &pu->pu_framectrl;
1020 struct puffs_fctrl_io *fio;
1021
1022 while ((fio = LIST_FIRST(&pfctrl->fb_ios)) != NULL)
1023 removefio(pu, fio, ENXIO);
1024 free(pfctrl->evs);
1025
1026 /* closing pu->pu_kq takes care of puffsfd */
1027 }
1028