framebuf.c revision 1.27 1 /* $NetBSD: framebuf.c,v 1.27 2008/01/28 18:35:50 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.27 2008/01/28 18:35:50 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 <stdio.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51
52 #include "puffs_priv.h"
53
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 */
59
60 uint8_t *buf; /* buffer base */
61 size_t len; /* total length */
62
63 size_t offset; /* cursor, telloff() */
64 size_t maxoff; /* maximum offset for data, tellsize() */
65
66 volatile int rv; /* errno value */
67
68 int istat;
69
70 TAILQ_ENTRY(puffs_framebuf) pfb_entries;
71 };
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 */
76
77 #define ISTAT_ONQUEUE ISTAT_NODESTROY /* alias */
78
79 #define PUFBUF_INCRALLOC 4096
80 #define PUFBUF_REMAIN(p) (p->len - p->offset)
81
82 /* for poll/kqueue */
83 struct puffs_fbevent {
84 struct puffs_cc *pcc;
85 int what;
86 volatile int rv;
87
88 LIST_ENTRY(puffs_fbevent) pfe_entries;
89 };
90
91 static struct puffs_fctrl_io *
92 getfiobyfd(struct puffs_usermount *pu, int fd)
93 {
94 struct puffs_fctrl_io *fio;
95
96 LIST_FOREACH(fio, &pu->pu_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_dup(struct puffs_framebuf *pb, struct puffs_framebuf **pbp)
170 {
171 struct puffs_framebuf *newpb;
172
173 newpb = puffs_framebuf_make();
174 if (newpb == NULL) {
175 errno = ENOMEM;
176 return -1;
177 }
178 memcpy(newpb, pb, sizeof(struct puffs_framebuf));
179
180 newpb->buf = NULL;
181 newpb->len = 0;
182 if (reservespace(newpb, 0, pb->maxoff) == -1) {
183 puffs_framebuf_destroy(newpb);
184 return -1;
185 }
186
187 memcpy(newpb->buf, pb->buf, pb->maxoff);
188 newpb->istat = 0;
189 *pbp = newpb;
190
191 return 0;
192 }
193
194 int
195 puffs_framebuf_reserve_space(struct puffs_framebuf *pufbuf, size_t wantsize)
196 {
197
198 return reservespace(pufbuf, pufbuf->offset, wantsize);
199 }
200
201 int
202 puffs_framebuf_putdata(struct puffs_framebuf *pufbuf,
203 const void *data, size_t dlen)
204 {
205
206 if (PUFBUF_REMAIN(pufbuf) < dlen)
207 if (puffs_framebuf_reserve_space(pufbuf, dlen) == -1)
208 return -1;
209
210 memcpy(pufbuf->buf + pufbuf->offset, data, dlen);
211 pufbuf->offset += dlen;
212
213 if (pufbuf->offset > pufbuf->maxoff)
214 pufbuf->maxoff = pufbuf->offset;
215
216 return 0;
217 }
218
219 int
220 puffs_framebuf_putdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
221 const void *data, size_t dlen)
222 {
223
224 if (reservespace(pufbuf, offset, dlen) == -1)
225 return -1;
226
227 memcpy(pufbuf->buf + offset, data, dlen);
228
229 if (offset + dlen > pufbuf->maxoff)
230 pufbuf->maxoff = offset + dlen;
231
232 return 0;
233 }
234
235 int
236 puffs_framebuf_getdata(struct puffs_framebuf *pufbuf, void *data, size_t dlen)
237 {
238
239 if (pufbuf->maxoff < pufbuf->offset + dlen) {
240 errno = ENOBUFS;
241 return -1;
242 }
243
244 memcpy(data, pufbuf->buf + pufbuf->offset, dlen);
245 pufbuf->offset += dlen;
246
247 return 0;
248 }
249
250 int
251 puffs_framebuf_getdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
252 void *data, size_t dlen)
253 {
254
255 if (pufbuf->maxoff < offset + dlen) {
256 errno = ENOBUFS;
257 return -1;
258 }
259
260 memcpy(data, pufbuf->buf + offset, dlen);
261 return 0;
262 }
263
264 size_t
265 puffs_framebuf_telloff(struct puffs_framebuf *pufbuf)
266 {
267
268 return pufbuf->offset;
269 }
270
271 size_t
272 puffs_framebuf_tellsize(struct puffs_framebuf *pufbuf)
273 {
274
275 return pufbuf->maxoff;
276 }
277
278 size_t
279 puffs_framebuf_remaining(struct puffs_framebuf *pufbuf)
280 {
281
282 return puffs_framebuf_tellsize(pufbuf) - puffs_framebuf_telloff(pufbuf);
283 }
284
285 int
286 puffs_framebuf_seekset(struct puffs_framebuf *pufbuf, size_t newoff)
287 {
288
289 if (reservespace(pufbuf, newoff, 0) == -1)
290 return -1;
291
292 pufbuf->offset = newoff;
293 return 0;
294 }
295
296 int
297 puffs_framebuf_getwindow(struct puffs_framebuf *pufbuf, size_t winoff,
298 void **data, size_t *dlen)
299 {
300 size_t winlen;
301
302 #ifdef WINTESTING
303 winlen = MIN(*dlen, 32);
304 #else
305 winlen = *dlen;
306 #endif
307
308 if (reservespace(pufbuf, winoff, winlen) == -1)
309 return -1;
310
311 *data = pufbuf->buf + winoff;
312 if (pufbuf->maxoff < winoff + winlen)
313 pufbuf->maxoff = winoff + winlen;
314
315 return 0;
316 }
317
318 void *
319 puffs__framebuf_getdataptr(struct puffs_framebuf *pufbuf)
320 {
321
322 return pufbuf->buf;
323 }
324
325 static void
326 errnotify(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, int error)
327 {
328
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);
338 }
339 }
340
341 #define GETFIO(fd) \
342 do { \
343 fio = getfiobyfd(pu, fd); \
344 if (fio == NULL) { \
345 errno = EINVAL; \
346 return -1; \
347 } \
348 if (fio->stat & FIO_WRGONE) { \
349 errno = ESHUTDOWN; \
350 return -1; \
351 } \
352 } while (/*CONSTCOND*/0)
353
354 int
355 puffs_framev_enqueue_cc(struct puffs_cc *pcc, int fd,
356 struct puffs_framebuf *pufbuf, int flags)
357 {
358 struct puffs_usermount *pu = pcc->pcc_pu;
359 struct puffs_fctrl_io *fio;
360
361 /*
362 * Technically we shouldn't allow this is 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.
367 */
368 GETFIO(fd);
369
370 pufbuf->pcc = pcc;
371 pufbuf->fcb = NULL;
372 pufbuf->fcb_arg = NULL;
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 puffs_cc_yield(pcc);
383 if (pufbuf->rv) {
384 pufbuf->istat &= ~ISTAT_NODESTROY;
385 errno = pufbuf->rv;
386 return -1;
387 }
388
389 return 0;
390 }
391
392 int
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)
396 {
397 struct puffs_fctrl_io *fio;
398
399 /* see enqueue_cc */
400 GETFIO(fd);
401
402 pufbuf->pcc = NULL;
403 pufbuf->fcb = fcb;
404 pufbuf->fcb_arg = arg;
405
406 pufbuf->offset = 0;
407 pufbuf->istat |= ISTAT_NODESTROY;
408
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);
413
414 return 0;
415 }
416
417 int
418 puffs_framev_enqueue_justsend(struct puffs_usermount *pu, int fd,
419 struct puffs_framebuf *pufbuf, int reply, int flags)
420 {
421 struct puffs_fctrl_io *fio;
422
423 GETFIO(fd);
424
425 pufbuf->pcc = NULL;
426 pufbuf->fcb = NULL;
427 pufbuf->fcb_arg = NULL;
428
429 pufbuf->offset = 0;
430 pufbuf->istat |= ISTAT_NODESTROY;
431 if (!reply)
432 pufbuf->istat |= ISTAT_NOREPLY;
433
434 if (flags & PUFFS_FBQUEUE_URGENT)
435 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
436 else
437 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
438
439 return 0;
440 }
441
442 /* ARGSUSED */
443 int
444 puffs_framev_enqueue_directreceive(struct puffs_cc *pcc, int fd,
445 struct puffs_framebuf *pufbuf, int flags /* used in the future */)
446 {
447 struct puffs_usermount *pu = pcc->pcc_pu;
448 struct puffs_fctrl_io *fio;
449
450 fio = getfiobyfd(pu, fd);
451 if (fio == NULL) {
452 errno = EINVAL;
453 return -1;
454 }
455
456 /* XXX: should have cur_in queue */
457 assert(fio->cur_in == NULL);
458 fio->cur_in = pufbuf;
459
460 pufbuf->pcc = pcc;
461 pufbuf->fcb = NULL;
462 pufbuf->fcb_arg = NULL;
463
464 pufbuf->offset = 0;
465 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
466
467 puffs_cc_yield(pcc);
468 pufbuf->istat &= ~ISTAT_NODESTROY; /* XXX: not the right place */
469 if (pufbuf->rv) {
470 errno = pufbuf->rv;
471 return -1;
472 }
473
474 return 0;
475 }
476
477 int
478 puffs_framev_enqueue_directsend(struct puffs_cc *pcc, int fd,
479 struct puffs_framebuf *pufbuf, int flags)
480 {
481 struct puffs_usermount *pu = pcc->pcc_pu;
482 struct puffs_fctrl_io *fio;
483
484 if (flags & PUFFS_FBQUEUE_URGENT)
485 abort(); /* EOPNOTSUPP for now */
486
487 GETFIO(fd);
488
489 pufbuf->pcc = pcc;
490 pufbuf->fcb = NULL;
491 pufbuf->fcb_arg = NULL;
492
493 pufbuf->offset = 0;
494 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
495
496 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
497
498 puffs_cc_yield(pcc);
499 if (pufbuf->rv) {
500 pufbuf->istat &= ~ISTAT_NODESTROY;
501 errno = pufbuf->rv;
502 return -1;
503 }
504
505 return 0;
506 }
507
508 int
509 puffs_framev_framebuf_ccpromote(struct puffs_framebuf *pufbuf,
510 struct puffs_cc *pcc)
511 {
512
513 if ((pufbuf->istat & ISTAT_ONQUEUE) == 0) {
514 errno = EBUSY;
515 return -1;
516 }
517
518 pufbuf->pcc = pcc;
519 pufbuf->fcb = NULL;
520 pufbuf->fcb_arg = NULL;
521 pufbuf->istat &= ~ISTAT_NOREPLY;
522
523 puffs_cc_yield(pcc);
524
525 return 0;
526 }
527
528 int
529 puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what)
530 {
531 struct puffs_usermount *pu = pcc->pcc_pu;
532 struct puffs_fctrl_io *fio;
533 struct puffs_fbevent feb;
534 struct kevent kev;
535 int rv, svwhat;
536
537 svwhat = *what;
538
539 if (*what == 0) {
540 errno = EINVAL;
541 return -1;
542 }
543
544 fio = getfiobyfd(pu, fd);
545 if (fio == NULL) {
546 errno = EINVAL;
547 return -1;
548 }
549
550 feb.pcc = pcc;
551 feb.what = *what & (PUFFS_FBIO_READ|PUFFS_FBIO_WRITE|PUFFS_FBIO_ERROR);
552
553 if (*what & PUFFS_FBIO_READ)
554 if ((fio->stat & FIO_ENABLE_R) == 0)
555 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE,
556 0, 0, (uintptr_t)fio);
557
558 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
559 if (rv != 0)
560 return errno;
561
562 if (*what & PUFFS_FBIO_READ)
563 fio->rwait++;
564 if (*what & PUFFS_FBIO_WRITE)
565 fio->wwait++;
566
567 LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries);
568 puffs_cc_yield(pcc);
569
570 assert(svwhat == *what);
571
572 if (*what & PUFFS_FBIO_READ) {
573 fio->rwait--;
574 if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) {
575 EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE,
576 0, 0, (uintptr_t)fio);
577 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
578 #if 0
579 if (rv != 0)
580 /* XXXXX oh dear */;
581 #endif
582 }
583 }
584 if (*what & PUFFS_FBIO_WRITE)
585 fio->wwait--;
586
587 if (feb.rv == 0) {
588 *what = feb.what;
589 rv = 0;
590 } else {
591 *what = PUFFS_FBIO_ERROR;
592 errno = feb.rv;
593 rv = -1;
594 }
595
596 return rv;
597 }
598
599 void
600 puffs__framev_notify(struct puffs_fctrl_io *fio, int what)
601 {
602 struct puffs_fbevent *fbevp;
603
604 restart:
605 LIST_FOREACH(fbevp, &fio->ev_qing, pfe_entries) {
606 if (fbevp->what & what) {
607 fbevp->what = what;
608 fbevp->rv = 0;
609 LIST_REMOVE(fbevp, pfe_entries);
610 puffs_cc_continue(fbevp->pcc);
611 goto restart;
612 }
613 }
614 }
615
616 static struct puffs_framebuf *
617 findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
618 struct puffs_fctrl_io *fio, struct puffs_framebuf *findme)
619 {
620 struct puffs_framebuf *cand;
621 int notresp = 0;
622
623 TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries)
624 if (fctrl->cmpfb(pu, findme, cand, ¬resp) == 0 || notresp)
625 break;
626
627 assert(!(notresp && cand == NULL));
628 if (notresp || cand == NULL)
629 return NULL;
630
631 TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries);
632 return cand;
633 }
634
635 void
636 puffs__framebuf_moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to)
637 {
638
639 assert(from->istat & ISTAT_INTERNAL);
640
641 /* migrate buffer */
642 free(to->buf);
643 to->buf = from->buf;
644
645 /* migrate buffer info */
646 to->len = from->len;
647 to->offset = from->offset;
648 to->maxoff = from->maxoff;
649
650 from->buf = NULL;
651 from->len = 0;
652 }
653
654 void
655 puffs__framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
656 struct puffs_fctrl_io *fio)
657 {
658 struct puffs_framebuf *pufbuf, *appbuf;
659 int rv, complete;
660
661 while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) {
662 if ((pufbuf = fio->cur_in) == NULL) {
663 pufbuf = puffs_framebuf_make();
664 if (pufbuf == NULL)
665 return;
666 pufbuf->istat |= ISTAT_INTERNAL;
667 fio->cur_in = pufbuf;
668 }
669
670 complete = 0;
671 rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete);
672
673 /* error */
674 if (rv) {
675 puffs__framev_readclose(pu, fio, rv);
676 fio->cur_in = NULL;
677 if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
678 assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
679 puffs_framebuf_destroy(pufbuf);
680 }
681 return;
682 }
683
684 /* partial read, come back to fight another day */
685 if (complete == 0)
686 break;
687
688 /* else: full read, process */
689 fio->cur_in = NULL;
690 if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
691 appbuf = findbuf(pu, fctrl, fio, pufbuf);
692
693 /*
694 * No request for this frame? If fs implements
695 * gotfb, give frame to that. Otherwise drop it.
696 */
697 if (appbuf == NULL) {
698 if (fctrl->gotfb)
699 fctrl->gotfb(pu, pufbuf);
700
701 /* XXX: ugly */
702 pufbuf->istat &= ~ISTAT_NODESTROY;
703 puffs_framebuf_destroy(pufbuf);
704 continue;
705 }
706
707 puffs__framebuf_moveinfo(pufbuf, appbuf);
708 puffs_framebuf_destroy(pufbuf);
709 } else {
710 appbuf = pufbuf;
711 }
712 appbuf->istat &= ~ISTAT_NODESTROY;
713
714 if (appbuf->pcc) {
715 puffs__cc_cont(appbuf->pcc);
716 } else if (appbuf->fcb) {
717 appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0);
718 } else {
719 puffs_framebuf_destroy(appbuf);
720 }
721
722 /* hopeless romantics, here we go again */
723 }
724 }
725
726 int
727 puffs__framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
728 struct puffs_fctrl_io *fio)
729 {
730 struct puffs_framebuf *pufbuf;
731 int rv, complete, done;
732
733 if (fio->stat & FIO_DEAD)
734 return 0;
735
736 for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0;
737 pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W;
738 pufbuf = TAILQ_FIRST(&fio->snd_qing)) {
739 complete = 0;
740 rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete);
741
742 if (rv) {
743 puffs__framev_writeclose(pu, fio, rv);
744 done = 1;
745 break;
746 }
747
748 /* partial write */
749 if (complete == 0)
750 return done;
751
752 /* else, complete write */
753 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
754
755 /* can't wait for result if we can't read */
756 if (fio->stat & FIO_RDGONE) {
757 errnotify(pu, pufbuf, ENXIO);
758 done = 1;
759 } else if ((pufbuf->istat & ISTAT_DIRECT)) {
760 pufbuf->istat &= ~ISTAT_NODESTROY;
761 done = 1;
762 puffs__cc_cont(pufbuf->pcc);
763 } else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) {
764 TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf,
765 pfb_entries);
766 } else {
767 pufbuf->istat &= ~ISTAT_NODESTROY;
768 puffs_framebuf_destroy(pufbuf);
769 }
770
771 /* omstart! */
772 }
773
774 return done;
775 }
776
777 int
778 puffs__framev_addfd_ctrl(struct puffs_usermount *pu, int fd, int what,
779 struct puffs_framectrl *pfctrl)
780 {
781 struct puffs_fctrl_io *fio;
782 struct kevent *newevs;
783 struct kevent kev[2];
784 size_t nfds;
785 int rv, readenable;
786
787 nfds = pu->pu_nfds+1;
788 newevs = realloc(pu->pu_evs, (2*nfds) * sizeof(struct kevent));
789 if (newevs == NULL)
790 return -1;
791 pu->pu_evs = newevs;
792
793 fio = malloc(sizeof(struct puffs_fctrl_io));
794 if (fio == NULL)
795 return -1;
796 memset(fio, 0, sizeof(struct puffs_fctrl_io));
797 fio->io_fd = fd;
798 fio->cur_in = NULL;
799 fio->fctrl = pfctrl;
800 TAILQ_INIT(&fio->snd_qing);
801 TAILQ_INIT(&fio->res_qing);
802 LIST_INIT(&fio->ev_qing);
803
804 readenable = 0;
805 if ((what & PUFFS_FBIO_READ) == 0)
806 readenable = EV_DISABLE;
807
808 if (pu->pu_state & PU_INLOOP) {
809 EV_SET(&kev[0], fd, EVFILT_READ,
810 EV_ADD|readenable, 0, 0, (intptr_t)fio);
811 EV_SET(&kev[1], fd, EVFILT_WRITE,
812 EV_ADD|EV_DISABLE, 0, 0, (intptr_t)fio);
813 rv = kevent(pu->pu_kq, kev, 2, NULL, 0, NULL);
814 if (rv == -1) {
815 free(fio);
816 return -1;
817 }
818 }
819 if (what & PUFFS_FBIO_READ)
820 fio->stat |= FIO_ENABLE_R;
821 if (what & PUFFS_FBIO_WRITE)
822 fio->stat |= FIO_ENABLE_W;
823
824 LIST_INSERT_HEAD(&pu->pu_ios, fio, fio_entries);
825 pu->pu_nfds = nfds;
826
827 return 0;
828 }
829
830 int
831 puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what)
832 {
833
834 return puffs__framev_addfd_ctrl(pu, fd, what,
835 &pu->pu_framectrl[PU_FRAMECTRL_USER]);
836 }
837
838 /*
839 * XXX: the following en/disable should be coalesced and executed
840 * only during the actual kevent call. So feel free to fix if
841 * threatened by mindblowing boredom.
842 */
843
844 int
845 puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what)
846 {
847 struct kevent kev;
848 struct puffs_fctrl_io *fio;
849 int rv = 0;
850
851 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
852
853 fio = getfiobyfd(pu, fd);
854 if (fio == NULL) {
855 errno = ENXIO;
856 return -1;
857 }
858
859 /* write is enabled in the event loop if there is output */
860 if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
861 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, (uintptr_t)fio);
862 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
863 }
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 int
876 puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what)
877 {
878 struct kevent kev[2];
879 struct puffs_fctrl_io *fio;
880 size_t i;
881 int rv;
882
883 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
884
885 fio = getfiobyfd(pu, fd);
886 if (fio == NULL) {
887 errno = ENXIO;
888 return -1;
889 }
890
891 i = 0;
892 if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
893 EV_SET(&kev[0], fd,
894 EVFILT_READ, EV_DISABLE, 0, 0, (uintptr_t)fio);
895 i++;
896 }
897 if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) {
898 EV_SET(&kev[1], fd,
899 EVFILT_WRITE, EV_DISABLE, 0, 0, (uintptr_t)fio);
900 i++;
901 }
902 if (i)
903 rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL);
904 else
905 rv = 0;
906
907 if (rv == 0) {
908 if (what & PUFFS_FBIO_READ)
909 fio->stat &= ~FIO_ENABLE_R;
910 if (what & PUFFS_FBIO_WRITE)
911 fio->stat &= ~FIO_ENABLE_W;
912 }
913
914 return rv;
915 }
916
917 void
918 puffs__framev_readclose(struct puffs_usermount *pu,
919 struct puffs_fctrl_io *fio, int error)
920 {
921 struct puffs_framebuf *pufbuf;
922 struct kevent kev;
923 int notflag;
924
925 if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD)
926 return;
927 fio->stat |= FIO_RDGONE;
928
929 if (fio->cur_in) {
930 if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) {
931 puffs_framebuf_destroy(fio->cur_in);
932 fio->cur_in = NULL;
933 } else {
934 errnotify(pu, fio->cur_in, error);
935 }
936 }
937
938 while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) {
939 TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries);
940 errnotify(pu, pufbuf, error);
941 }
942
943 EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
944 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
945
946 notflag = PUFFS_FBIO_READ;
947 if (fio->stat & FIO_WRGONE)
948 notflag |= PUFFS_FBIO_WRITE;
949
950 if (fio->fctrl->fdnotfn)
951 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag);
952 }
953
954 void
955 puffs__framev_writeclose(struct puffs_usermount *pu,
956 struct puffs_fctrl_io *fio, int error)
957 {
958 struct puffs_framebuf *pufbuf;
959 struct kevent kev;
960 int notflag;
961
962 if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD)
963 return;
964 fio->stat |= FIO_WRGONE;
965
966 while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) {
967 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
968 errnotify(pu, pufbuf, error);
969 }
970
971 EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
972 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
973
974 notflag = PUFFS_FBIO_WRITE;
975 if (fio->stat & FIO_RDGONE)
976 notflag |= PUFFS_FBIO_READ;
977
978 if (fio->fctrl->fdnotfn)
979 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag);
980 }
981
982 static int
983 removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error)
984 {
985 struct puffs_fbevent *fbevp;
986
987 LIST_REMOVE(fio, fio_entries);
988 if (pu->pu_state & PU_INLOOP) {
989 puffs__framev_readclose(pu, fio, error);
990 puffs__framev_writeclose(pu, fio, error);
991 }
992
993 while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) {
994 fbevp->rv = error;
995 LIST_REMOVE(fbevp, pfe_entries);
996 puffs__goto(fbevp->pcc);
997 }
998
999 /* don't bother with realloc */
1000 pu->pu_nfds--;
1001
1002 /* don't free us yet, might have some references in event arrays */
1003 fio->stat |= FIO_DEAD;
1004 LIST_INSERT_HEAD(&pu->pu_ios_rmlist, fio, fio_entries);
1005
1006 return 0;
1007
1008 }
1009
1010 int
1011 puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error)
1012 {
1013 struct puffs_fctrl_io *fio;
1014
1015 fio = getfiobyfd(pu, fd);
1016 if (fio == NULL) {
1017 errno = ENXIO;
1018 return -1;
1019 }
1020
1021 return removefio(pu, fio, error ? error : ECONNRESET);
1022 }
1023
1024 void
1025 puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what)
1026 {
1027
1028 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
1029 (void) puffs_framev_removefd(pu, fd, ECONNRESET);
1030 }
1031
1032 void
1033 puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what)
1034 {
1035
1036 /* XXX & X: unmount is non-sensible */
1037 puffs_framev_removeonclose(pu, fd, what);
1038 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
1039 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
1040 }
1041
1042 void
1043 puffs_framev_init(struct puffs_usermount *pu,
1044 puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb,
1045 puffs_framev_cmpframe_fn cmpfb, puffs_framev_gotframe_fn gotfb,
1046 puffs_framev_fdnotify_fn fdnotfn)
1047 {
1048 struct puffs_framectrl *pfctrl;
1049
1050 pfctrl = &pu->pu_framectrl[PU_FRAMECTRL_USER];
1051 pfctrl->rfb = rfb;
1052 pfctrl->wfb = wfb;
1053 pfctrl->cmpfb = cmpfb;
1054 pfctrl->gotfb = gotfb;
1055 pfctrl->fdnotfn = fdnotfn;
1056 }
1057
1058 void
1059 puffs__framev_exit(struct puffs_usermount *pu)
1060 {
1061 struct puffs_fctrl_io *fio;
1062
1063 while ((fio = LIST_FIRST(&pu->pu_ios)) != NULL)
1064 removefio(pu, fio, ENXIO);
1065 free(pu->pu_evs);
1066
1067 /* closing pu->pu_kq takes care of puffsfd */
1068 }
1069