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