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