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