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