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