- Fix for possible unset uid/gid in toproto
 - Fix for default mtree style
 - Update libelf
 - Importing libexecinfo
 - Resynchronize GCC, mpc, gmp, mpfr
 - build.sh: Replace params with show-params.
     This has been done as the make target has been renamed in the same
     way, while a new target named params has been added. This new
     target generates a file containing all the parameters, instead of
     printing it on the console.
 - Update test48 with new etc/services (Fix by Ben Gras <ben@minix3.org)
     get getservbyport() out of the inner loop
Change-Id: Ie6ad5226fa2621ff9f0dee8782ea48f9443d2091
		
	
			
		
			
				
	
	
		
			1070 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1070 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*	$NetBSD: framebuf.c,v 1.32 2012/06/25 22:32:47 abs Exp $	*/
 | 
						|
 | 
						|
/*
 | 
						|
 * Copyright (c) 2007  Antti Kantee.  All Rights Reserved.
 | 
						|
 *
 | 
						|
 * Development of this software was supported by the
 | 
						|
 * Finnish Cultural Foundation.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 | 
						|
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
						|
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
						|
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 | 
						|
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
						|
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
						|
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
						|
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
 * SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * The event portion of this code is a twisty maze of pointers,
 | 
						|
 * flags, yields and continues.  Sincere aplogies.
 | 
						|
 */
 | 
						|
 | 
						|
#include <sys/cdefs.h>
 | 
						|
#if !defined(lint)
 | 
						|
__RCSID("$NetBSD: framebuf.c,v 1.32 2012/06/25 22:32:47 abs Exp $");
 | 
						|
#endif /* !lint */
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/queue.h>
 | 
						|
 | 
						|
#include <assert.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <poll.h>
 | 
						|
#include <puffs.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <unistd.h>
 | 
						|
 | 
						|
#include "puffs_priv.h"
 | 
						|
 | 
						|
struct puffs_framebuf {
 | 
						|
	struct puffs_cc *pcc;	/* pcc to continue with */
 | 
						|
	/* OR */
 | 
						|
	puffs_framev_cb fcb;	/* non-blocking callback */
 | 
						|
	void *fcb_arg;		/* argument for previous */
 | 
						|
 | 
						|
	uint8_t *buf;		/* buffer base */
 | 
						|
	size_t len;		/* total length */
 | 
						|
 | 
						|
	size_t offset;		/* cursor, telloff() */
 | 
						|
	size_t maxoff;		/* maximum offset for data, tellsize() */
 | 
						|
 | 
						|
	volatile int rv;	/* errno value */
 | 
						|
 | 
						|
	int	istat;
 | 
						|
 | 
						|
	TAILQ_ENTRY(puffs_framebuf) pfb_entries;
 | 
						|
};
 | 
						|
#define ISTAT_NODESTROY	0x01	/* indestructible by framebuf_destroy() */
 | 
						|
#define ISTAT_INTERNAL	0x02	/* never leaves library			*/
 | 
						|
#define ISTAT_NOREPLY	0x04	/* nuke after sending 			*/
 | 
						|
#define ISTAT_DIRECT	0x08	/* receive directly, no moveinfo	*/
 | 
						|
 | 
						|
#define ISTAT_ONQUEUE	ISTAT_NODESTROY	/* alias */
 | 
						|
 | 
						|
#define PUFBUF_INCRALLOC 4096
 | 
						|
#define PUFBUF_REMAIN(p) (p->len - p->offset)
 | 
						|
 | 
						|
/* for poll/kqueue */
 | 
						|
struct puffs_fbevent {
 | 
						|
	struct puffs_cc	*pcc;
 | 
						|
	int what;
 | 
						|
	volatile int rv;
 | 
						|
 | 
						|
	LIST_ENTRY(puffs_fbevent) pfe_entries;
 | 
						|
};
 | 
						|
 | 
						|
static struct puffs_fctrl_io *
 | 
						|
getfiobyfd(struct puffs_usermount *pu, int fd)
 | 
						|
{
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
 | 
						|
	LIST_FOREACH(fio, &pu->pu_ios, fio_entries)
 | 
						|
		if (fio->io_fd == fd)
 | 
						|
			return fio;
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
struct puffs_framebuf *
 | 
						|
puffs_framebuf_make(void)
 | 
						|
{
 | 
						|
	struct puffs_framebuf *pufbuf;
 | 
						|
 | 
						|
	pufbuf = malloc(sizeof(struct puffs_framebuf));
 | 
						|
	if (pufbuf == NULL)
 | 
						|
		return NULL;
 | 
						|
	memset(pufbuf, 0, sizeof(struct puffs_framebuf));
 | 
						|
 | 
						|
	pufbuf->buf = malloc(PUFBUF_INCRALLOC);
 | 
						|
	if (pufbuf->buf == NULL) {
 | 
						|
		free(pufbuf);
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	pufbuf->len = PUFBUF_INCRALLOC;
 | 
						|
 | 
						|
	puffs_framebuf_recycle(pufbuf);
 | 
						|
	return pufbuf;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs_framebuf_destroy(struct puffs_framebuf *pufbuf)
 | 
						|
{
 | 
						|
 | 
						|
	assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
 | 
						|
 | 
						|
	free(pufbuf->buf);
 | 
						|
	free(pufbuf);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs_framebuf_recycle(struct puffs_framebuf *pufbuf)
 | 
						|
{
 | 
						|
 | 
						|
	assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
 | 
						|
 | 
						|
	pufbuf->offset = 0;
 | 
						|
	pufbuf->maxoff = 0;
 | 
						|
	pufbuf->istat = 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
reservespace(struct puffs_framebuf *pufbuf, size_t off, size_t wantsize)
 | 
						|
{
 | 
						|
	size_t incr;
 | 
						|
	void *nd;
 | 
						|
 | 
						|
	if (off <= pufbuf->len && pufbuf->len - off >= wantsize)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	for (incr = PUFBUF_INCRALLOC;
 | 
						|
	    pufbuf->len + incr < off + wantsize;
 | 
						|
	    incr += PUFBUF_INCRALLOC)
 | 
						|
		continue;
 | 
						|
 | 
						|
	nd = realloc(pufbuf->buf, pufbuf->len + incr);
 | 
						|
	if (nd == NULL)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	pufbuf->buf = nd;
 | 
						|
	pufbuf->len += incr;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framebuf_dup(struct puffs_framebuf *pb, struct puffs_framebuf **pbp)
 | 
						|
{
 | 
						|
	struct puffs_framebuf *newpb;
 | 
						|
 | 
						|
	newpb = puffs_framebuf_make();
 | 
						|
	if (newpb == NULL) {
 | 
						|
		errno = ENOMEM;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
	memcpy(newpb, pb, sizeof(struct puffs_framebuf));
 | 
						|
 | 
						|
	newpb->buf = NULL;
 | 
						|
	newpb->len = 0;
 | 
						|
	if (reservespace(newpb, 0, pb->maxoff) == -1) {
 | 
						|
		puffs_framebuf_destroy(newpb);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	memcpy(newpb->buf, pb->buf, pb->maxoff);
 | 
						|
	newpb->istat = 0;
 | 
						|
	*pbp = newpb;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framebuf_reserve_space(struct puffs_framebuf *pufbuf, size_t wantsize)
 | 
						|
{
 | 
						|
 | 
						|
	return reservespace(pufbuf, pufbuf->offset, wantsize);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framebuf_putdata(struct puffs_framebuf *pufbuf,
 | 
						|
	const void *data, size_t dlen)
 | 
						|
{
 | 
						|
 | 
						|
	if (PUFBUF_REMAIN(pufbuf) < dlen)
 | 
						|
		if (puffs_framebuf_reserve_space(pufbuf, dlen) == -1)
 | 
						|
			return -1;
 | 
						|
 | 
						|
	memcpy(pufbuf->buf + pufbuf->offset, data, dlen);
 | 
						|
	pufbuf->offset += dlen;
 | 
						|
 | 
						|
	if (pufbuf->offset > pufbuf->maxoff)
 | 
						|
		pufbuf->maxoff = pufbuf->offset;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framebuf_putdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
 | 
						|
	const void *data, size_t dlen)
 | 
						|
{
 | 
						|
 | 
						|
	if (reservespace(pufbuf, offset, dlen) == -1)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	memcpy(pufbuf->buf + offset, data, dlen);
 | 
						|
 | 
						|
	if (offset + dlen > pufbuf->maxoff)
 | 
						|
		pufbuf->maxoff = offset + dlen;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framebuf_getdata(struct puffs_framebuf *pufbuf, void *data, size_t dlen)
 | 
						|
{
 | 
						|
 | 
						|
	if (pufbuf->maxoff < pufbuf->offset + dlen) {
 | 
						|
		errno = ENOBUFS;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	memcpy(data, pufbuf->buf + pufbuf->offset, dlen);
 | 
						|
	pufbuf->offset += dlen;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framebuf_getdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
 | 
						|
	void *data, size_t dlen)
 | 
						|
{
 | 
						|
 | 
						|
	if (pufbuf->maxoff < offset + dlen) {
 | 
						|
		errno = ENOBUFS;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	memcpy(data, pufbuf->buf + offset, dlen);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
size_t
 | 
						|
puffs_framebuf_telloff(struct puffs_framebuf *pufbuf)
 | 
						|
{
 | 
						|
 | 
						|
	return pufbuf->offset;
 | 
						|
}
 | 
						|
 | 
						|
size_t
 | 
						|
puffs_framebuf_tellsize(struct puffs_framebuf *pufbuf)
 | 
						|
{
 | 
						|
 | 
						|
	return pufbuf->maxoff;
 | 
						|
}
 | 
						|
 | 
						|
size_t
 | 
						|
puffs_framebuf_remaining(struct puffs_framebuf *pufbuf)
 | 
						|
{
 | 
						|
 | 
						|
	return puffs_framebuf_tellsize(pufbuf) - puffs_framebuf_telloff(pufbuf);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framebuf_seekset(struct puffs_framebuf *pufbuf, size_t newoff)
 | 
						|
{
 | 
						|
 | 
						|
	if (reservespace(pufbuf, newoff, 0) == -1)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	pufbuf->offset = newoff;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framebuf_getwindow(struct puffs_framebuf *pufbuf, size_t winoff,
 | 
						|
	void **data, size_t *dlen)
 | 
						|
{
 | 
						|
	size_t winlen;
 | 
						|
 | 
						|
#ifdef WINTESTING
 | 
						|
	winlen = MIN(*dlen, 32);
 | 
						|
#else
 | 
						|
	winlen = *dlen;
 | 
						|
#endif
 | 
						|
 | 
						|
	if (reservespace(pufbuf, winoff, winlen) == -1)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	*data = pufbuf->buf + winoff;
 | 
						|
	if (pufbuf->maxoff < winoff + winlen)
 | 
						|
		pufbuf->maxoff = winoff + winlen;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void *
 | 
						|
puffs__framebuf_getdataptr(struct puffs_framebuf *pufbuf)
 | 
						|
{
 | 
						|
 | 
						|
	return pufbuf->buf;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
errnotify(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, int error)
 | 
						|
{
 | 
						|
 | 
						|
	pufbuf->rv = error;
 | 
						|
	if (pufbuf->pcc) {
 | 
						|
		puffs__goto(pufbuf->pcc);
 | 
						|
	} else if (pufbuf->fcb) {
 | 
						|
		pufbuf->istat &= ~ISTAT_NODESTROY;
 | 
						|
		pufbuf->fcb(pu, pufbuf, pufbuf->fcb_arg, error);
 | 
						|
	} else {
 | 
						|
		pufbuf->istat &= ~ISTAT_NODESTROY;
 | 
						|
		puffs_framebuf_destroy(pufbuf);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#define GETFIO(fd)							\
 | 
						|
do {									\
 | 
						|
	fio = getfiobyfd(pu, fd);					\
 | 
						|
	if (fio == NULL) {						\
 | 
						|
		errno = EINVAL;						\
 | 
						|
		return -1;						\
 | 
						|
	}								\
 | 
						|
	if (fio->stat & FIO_WRGONE) {					\
 | 
						|
		errno = ESHUTDOWN;					\
 | 
						|
		return -1;						\
 | 
						|
	}								\
 | 
						|
} while (/*CONSTCOND*/0)
 | 
						|
 | 
						|
int
 | 
						|
puffs_framev_enqueue_cc(struct puffs_cc *pcc, int fd,
 | 
						|
	struct puffs_framebuf *pufbuf, int flags)
 | 
						|
{
 | 
						|
	struct puffs_usermount *pu = pcc->pcc_pu;
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Technically we shouldn't allow this if RDGONE, but it's
 | 
						|
	 * difficult to trap write close without allowing writes.
 | 
						|
	 * And besides, there's probably a disconnect sequence in
 | 
						|
	 * the protocol, so unexpectedly getting a closed fd is
 | 
						|
	 * most likely an error condition.
 | 
						|
	 */
 | 
						|
	GETFIO(fd);
 | 
						|
 | 
						|
	pufbuf->pcc = pcc;
 | 
						|
	pufbuf->fcb = NULL;
 | 
						|
	pufbuf->fcb_arg = NULL;
 | 
						|
 | 
						|
	pufbuf->offset = 0;
 | 
						|
	pufbuf->istat |= ISTAT_NODESTROY;
 | 
						|
 | 
						|
	if (flags & PUFFS_FBQUEUE_URGENT)
 | 
						|
		TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
 | 
						|
	else
 | 
						|
		TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
 | 
						|
 | 
						|
	puffs_cc_yield(pcc);
 | 
						|
	if (pufbuf->rv) {
 | 
						|
		pufbuf->istat &= ~ISTAT_NODESTROY;
 | 
						|
		errno = pufbuf->rv;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framev_enqueue_cb(struct puffs_usermount *pu, int fd,
 | 
						|
	struct puffs_framebuf *pufbuf, puffs_framev_cb fcb, void *arg,
 | 
						|
	int flags)
 | 
						|
{
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
 | 
						|
	/* see enqueue_cc */
 | 
						|
	GETFIO(fd);
 | 
						|
 | 
						|
	pufbuf->pcc = NULL;
 | 
						|
	pufbuf->fcb = fcb;
 | 
						|
	pufbuf->fcb_arg = arg;
 | 
						|
 | 
						|
	pufbuf->offset = 0;
 | 
						|
	pufbuf->istat |= ISTAT_NODESTROY;
 | 
						|
 | 
						|
	if (flags & PUFFS_FBQUEUE_URGENT)
 | 
						|
		TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
 | 
						|
	else
 | 
						|
		TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framev_enqueue_justsend(struct puffs_usermount *pu, int fd,
 | 
						|
	struct puffs_framebuf *pufbuf, int reply, int flags)
 | 
						|
{
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
 | 
						|
	assert((pufbuf->istat & ISTAT_INTERNAL) == 0);
 | 
						|
 | 
						|
	GETFIO(fd);
 | 
						|
 | 
						|
	pufbuf->pcc = NULL;
 | 
						|
	pufbuf->fcb = NULL;
 | 
						|
	pufbuf->fcb_arg = NULL;
 | 
						|
 | 
						|
	pufbuf->offset = 0;
 | 
						|
	pufbuf->istat |= ISTAT_NODESTROY;
 | 
						|
	if (!reply)
 | 
						|
		pufbuf->istat |= ISTAT_NOREPLY;
 | 
						|
 | 
						|
	if (flags & PUFFS_FBQUEUE_URGENT)
 | 
						|
		TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
 | 
						|
	else
 | 
						|
		TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* ARGSUSED */
 | 
						|
int
 | 
						|
puffs_framev_enqueue_directreceive(struct puffs_cc *pcc, int fd,
 | 
						|
	struct puffs_framebuf *pufbuf, int flags /* used in the future */)
 | 
						|
{
 | 
						|
	struct puffs_usermount *pu = pcc->pcc_pu;
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
 | 
						|
	assert((pufbuf->istat & ISTAT_INTERNAL) == 0);
 | 
						|
 | 
						|
	fio = getfiobyfd(pu, fd);
 | 
						|
	if (fio == NULL) {
 | 
						|
		errno = EINVAL;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* XXX: should have cur_in queue */
 | 
						|
	assert(fio->cur_in == NULL);
 | 
						|
	fio->cur_in = pufbuf;
 | 
						|
 | 
						|
	pufbuf->pcc = pcc;
 | 
						|
	pufbuf->fcb = NULL;
 | 
						|
	pufbuf->fcb_arg = NULL;
 | 
						|
 | 
						|
	pufbuf->offset = 0;
 | 
						|
	pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
 | 
						|
 | 
						|
	puffs_cc_yield(pcc);
 | 
						|
	pufbuf->istat &= ~ISTAT_NODESTROY; /* XXX: not the right place */
 | 
						|
	if (pufbuf->rv) {
 | 
						|
		errno = pufbuf->rv;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framev_enqueue_directsend(struct puffs_cc *pcc, int fd,
 | 
						|
	struct puffs_framebuf *pufbuf, int flags)
 | 
						|
{
 | 
						|
	struct puffs_usermount *pu = pcc->pcc_pu;
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
 | 
						|
	assert((pufbuf->istat & ISTAT_INTERNAL) == 0);
 | 
						|
 | 
						|
	if (flags & PUFFS_FBQUEUE_URGENT)
 | 
						|
		abort(); /* EOPNOTSUPP for now */
 | 
						|
 | 
						|
	GETFIO(fd);
 | 
						|
 | 
						|
	pufbuf->pcc = pcc;
 | 
						|
	pufbuf->fcb = NULL;
 | 
						|
	pufbuf->fcb_arg = NULL;
 | 
						|
 | 
						|
	pufbuf->offset = 0;
 | 
						|
	pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
 | 
						|
 | 
						|
	TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
 | 
						|
 | 
						|
	puffs_cc_yield(pcc);
 | 
						|
	if (pufbuf->rv) {
 | 
						|
		pufbuf->istat &= ~ISTAT_NODESTROY;
 | 
						|
		errno = pufbuf->rv;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framev_framebuf_ccpromote(struct puffs_framebuf *pufbuf,
 | 
						|
	struct puffs_cc *pcc)
 | 
						|
{
 | 
						|
 | 
						|
	if ((pufbuf->istat & ISTAT_ONQUEUE) == 0) {
 | 
						|
		errno = EBUSY;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	pufbuf->pcc = pcc;
 | 
						|
	pufbuf->fcb = NULL;
 | 
						|
	pufbuf->fcb_arg = NULL;
 | 
						|
	pufbuf->istat &= ~ISTAT_NOREPLY;
 | 
						|
 | 
						|
	puffs_cc_yield(pcc);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what)
 | 
						|
{
 | 
						|
	struct puffs_usermount *pu = pcc->pcc_pu;
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
	struct puffs_fbevent feb;
 | 
						|
	struct kevent kev;
 | 
						|
	int rv, svwhat;
 | 
						|
 | 
						|
	svwhat = *what;
 | 
						|
 | 
						|
	if (*what == 0) {
 | 
						|
		errno = EINVAL;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	fio = getfiobyfd(pu, fd);
 | 
						|
	if (fio == NULL) {
 | 
						|
		errno = EINVAL;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	feb.pcc = pcc;
 | 
						|
	feb.what = *what & (PUFFS_FBIO_READ|PUFFS_FBIO_WRITE|PUFFS_FBIO_ERROR);
 | 
						|
 | 
						|
	if (*what & PUFFS_FBIO_READ)
 | 
						|
		if ((fio->stat & FIO_ENABLE_R) == 0)
 | 
						|
			EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE,
 | 
						|
			    0, 0, (uintptr_t)fio);
 | 
						|
 | 
						|
	if (kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL) == -1)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	if (*what & PUFFS_FBIO_READ)
 | 
						|
		fio->rwait++;
 | 
						|
	if (*what & PUFFS_FBIO_WRITE)
 | 
						|
		fio->wwait++;
 | 
						|
 | 
						|
	LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries);
 | 
						|
	puffs_cc_yield(pcc);
 | 
						|
 | 
						|
	assert(svwhat == *what);
 | 
						|
 | 
						|
	if (*what & PUFFS_FBIO_READ) {
 | 
						|
		fio->rwait--;
 | 
						|
		if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) {
 | 
						|
			EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE,
 | 
						|
			    0, 0, (uintptr_t)fio);
 | 
						|
			rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
 | 
						|
#if 0
 | 
						|
			if (rv != 0)
 | 
						|
				/* XXXXX oh dear */;
 | 
						|
#endif
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (*what & PUFFS_FBIO_WRITE)
 | 
						|
		fio->wwait--;
 | 
						|
 | 
						|
	if (feb.rv == 0) {
 | 
						|
		*what = feb.what;
 | 
						|
		rv = 0;
 | 
						|
	} else {
 | 
						|
		*what = PUFFS_FBIO_ERROR;
 | 
						|
		errno = feb.rv;
 | 
						|
		rv = -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return rv;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs__framev_notify(struct puffs_fctrl_io *fio, int what)
 | 
						|
{
 | 
						|
	struct puffs_fbevent *fbevp;
 | 
						|
 | 
						|
 restart:
 | 
						|
	LIST_FOREACH(fbevp, &fio->ev_qing, pfe_entries) {
 | 
						|
		if (fbevp->what & what) {
 | 
						|
			fbevp->what = what;
 | 
						|
			fbevp->rv = 0;
 | 
						|
			LIST_REMOVE(fbevp, pfe_entries);
 | 
						|
			puffs_cc_continue(fbevp->pcc);
 | 
						|
			goto restart;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static struct puffs_framebuf *
 | 
						|
findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
 | 
						|
	struct puffs_fctrl_io *fio, struct puffs_framebuf *findme)
 | 
						|
{
 | 
						|
	struct puffs_framebuf *cand;
 | 
						|
	int notresp = 0;
 | 
						|
 | 
						|
	TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries)
 | 
						|
		if (fctrl->cmpfb(pu, findme, cand, ¬resp) == 0 || notresp)
 | 
						|
			break;
 | 
						|
 | 
						|
	assert(!(notresp && cand == NULL));
 | 
						|
	if (notresp || cand == NULL)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries);
 | 
						|
	return cand;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs__framebuf_moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to)
 | 
						|
{
 | 
						|
 | 
						|
	assert(from->istat & ISTAT_INTERNAL);
 | 
						|
 | 
						|
	/* migrate buffer */
 | 
						|
	free(to->buf);
 | 
						|
	to->buf = from->buf;
 | 
						|
 | 
						|
	/* migrate buffer info */
 | 
						|
	to->len = from->len;
 | 
						|
	to->offset = from->offset;
 | 
						|
	to->maxoff = from->maxoff;
 | 
						|
 | 
						|
	from->buf = NULL;
 | 
						|
	from->len = 0;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs__framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
 | 
						|
	struct puffs_fctrl_io *fio)
 | 
						|
{
 | 
						|
	struct puffs_framebuf *pufbuf, *appbuf;
 | 
						|
	int rv, complete;
 | 
						|
 | 
						|
	while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) {
 | 
						|
		if ((pufbuf = fio->cur_in) == NULL) {
 | 
						|
			pufbuf = puffs_framebuf_make();
 | 
						|
			if (pufbuf == NULL)
 | 
						|
				return;
 | 
						|
			pufbuf->istat |= ISTAT_INTERNAL;
 | 
						|
			fio->cur_in = pufbuf;
 | 
						|
		}
 | 
						|
 | 
						|
		complete = 0;
 | 
						|
		rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete);
 | 
						|
 | 
						|
		/* error */
 | 
						|
		if (rv) {
 | 
						|
			puffs__framev_readclose(pu, fio, rv);
 | 
						|
			fio->cur_in = NULL;
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		/* partial read, come back to fight another day */
 | 
						|
		if (complete == 0)
 | 
						|
			break;
 | 
						|
 | 
						|
		/* else: full read, process */
 | 
						|
		fio->cur_in = NULL;
 | 
						|
		if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
 | 
						|
			appbuf = findbuf(pu, fctrl, fio, pufbuf);
 | 
						|
 | 
						|
			/*
 | 
						|
			 * No request for this frame?  If fs implements
 | 
						|
			 * gotfb, give frame to that.  Otherwise drop it.
 | 
						|
			 */
 | 
						|
			if (appbuf == NULL) {
 | 
						|
				if (fctrl->gotfb) {
 | 
						|
					pufbuf->istat &= ~ISTAT_INTERNAL;
 | 
						|
					fctrl->gotfb(pu, pufbuf);
 | 
						|
				} else {
 | 
						|
					puffs_framebuf_destroy(pufbuf);
 | 
						|
				}
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			
 | 
						|
			puffs__framebuf_moveinfo(pufbuf, appbuf);
 | 
						|
			puffs_framebuf_destroy(pufbuf);
 | 
						|
		} else {
 | 
						|
			appbuf = pufbuf;
 | 
						|
		}
 | 
						|
		appbuf->istat &= ~ISTAT_NODESTROY;
 | 
						|
	
 | 
						|
		if (appbuf->pcc) {
 | 
						|
			puffs__cc_cont(appbuf->pcc);
 | 
						|
		} else if (appbuf->fcb) {
 | 
						|
			appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0);
 | 
						|
		} else {
 | 
						|
			puffs_framebuf_destroy(appbuf);
 | 
						|
		}
 | 
						|
 | 
						|
		/* hopeless romantics, here we go again */
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs__framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
 | 
						|
	struct puffs_fctrl_io *fio)
 | 
						|
{
 | 
						|
	struct puffs_framebuf *pufbuf;
 | 
						|
	int rv, complete, done;
 | 
						|
 | 
						|
	if (fio->stat & FIO_DEAD)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0;
 | 
						|
	    pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W;
 | 
						|
	    pufbuf = TAILQ_FIRST(&fio->snd_qing)) {
 | 
						|
		complete = 0;
 | 
						|
		rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete);
 | 
						|
 | 
						|
		if (rv) {
 | 
						|
			puffs__framev_writeclose(pu, fio, rv);
 | 
						|
			done = 1;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		/* partial write */
 | 
						|
		if (complete == 0)
 | 
						|
			return done;
 | 
						|
 | 
						|
		/* else, complete write */
 | 
						|
		TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
 | 
						|
 | 
						|
		/* can't wait for result if we can't read */
 | 
						|
		if (fio->stat & FIO_RDGONE) {
 | 
						|
			errnotify(pu, pufbuf, ENXIO);
 | 
						|
			done = 1;
 | 
						|
		} else if ((pufbuf->istat & ISTAT_DIRECT)) {
 | 
						|
			pufbuf->istat &= ~ISTAT_NODESTROY;
 | 
						|
			done = 1;
 | 
						|
			puffs__cc_cont(pufbuf->pcc);
 | 
						|
		} else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) {
 | 
						|
			TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf,
 | 
						|
			    pfb_entries);
 | 
						|
		} else {
 | 
						|
			pufbuf->istat &= ~ISTAT_NODESTROY;
 | 
						|
			puffs_framebuf_destroy(pufbuf);
 | 
						|
		}
 | 
						|
 | 
						|
		/* omstart! */
 | 
						|
	}
 | 
						|
 | 
						|
	return done;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs__framev_addfd_ctrl(struct puffs_usermount *pu, int fd, int what,
 | 
						|
	struct puffs_framectrl *pfctrl)
 | 
						|
{
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
	struct kevent *newevs;
 | 
						|
	struct kevent kev[2];
 | 
						|
	size_t nevs;
 | 
						|
	int rv, readenable;
 | 
						|
 | 
						|
	nevs = pu->pu_nevs+2;
 | 
						|
	newevs = realloc(pu->pu_evs, nevs*sizeof(struct kevent));
 | 
						|
	if (newevs == NULL)
 | 
						|
		return -1;
 | 
						|
	pu->pu_evs = newevs;
 | 
						|
 | 
						|
	fio = malloc(sizeof(struct puffs_fctrl_io));
 | 
						|
	if (fio == NULL)
 | 
						|
		return -1;
 | 
						|
	memset(fio, 0, sizeof(struct puffs_fctrl_io));
 | 
						|
	fio->io_fd = fd;
 | 
						|
	fio->cur_in = NULL;
 | 
						|
	fio->fctrl = pfctrl;
 | 
						|
	TAILQ_INIT(&fio->snd_qing);
 | 
						|
	TAILQ_INIT(&fio->res_qing);
 | 
						|
	LIST_INIT(&fio->ev_qing);
 | 
						|
 | 
						|
	readenable = 0;
 | 
						|
	if ((what & PUFFS_FBIO_READ) == 0)
 | 
						|
		readenable = EV_DISABLE;
 | 
						|
 | 
						|
	if (pu->pu_state & PU_INLOOP) {
 | 
						|
		EV_SET(&kev[0], fd, EVFILT_READ,
 | 
						|
		    EV_ADD|readenable, 0, 0, (intptr_t)fio);
 | 
						|
		EV_SET(&kev[1], fd, EVFILT_WRITE,
 | 
						|
		    EV_ADD|EV_DISABLE, 0, 0, (intptr_t)fio);
 | 
						|
		rv = kevent(pu->pu_kq, kev, 2, NULL, 0, NULL);
 | 
						|
		if (rv == -1) {
 | 
						|
			free(fio);
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (what & PUFFS_FBIO_READ)
 | 
						|
		fio->stat |= FIO_ENABLE_R;
 | 
						|
	if (what & PUFFS_FBIO_WRITE)
 | 
						|
		fio->stat |= FIO_ENABLE_W;
 | 
						|
 | 
						|
	LIST_INSERT_HEAD(&pu->pu_ios, fio, fio_entries);
 | 
						|
	pu->pu_nevs = nevs;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what)
 | 
						|
{
 | 
						|
 | 
						|
	return puffs__framev_addfd_ctrl(pu, fd, what,
 | 
						|
	    &pu->pu_framectrl[PU_FRAMECTRL_USER]);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * XXX: the following en/disable should be coalesced and executed
 | 
						|
 * only during the actual kevent call.  So feel free to fix if
 | 
						|
 * threatened by mindblowing boredom.
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what)
 | 
						|
{
 | 
						|
	struct kevent kev;
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
	int rv = 0;
 | 
						|
 | 
						|
	assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
 | 
						|
 | 
						|
	fio = getfiobyfd(pu, fd);
 | 
						|
	if (fio == NULL) {
 | 
						|
		errno = ENXIO;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* write is enabled in the event loop if there is output */
 | 
						|
	if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
 | 
						|
		EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, (uintptr_t)fio);
 | 
						|
		rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
 | 
						|
	}
 | 
						|
 | 
						|
	if (rv == 0) {
 | 
						|
		if (what & PUFFS_FBIO_READ)
 | 
						|
			fio->stat |= FIO_ENABLE_R;
 | 
						|
		if (what & PUFFS_FBIO_WRITE)
 | 
						|
			fio->stat |= FIO_ENABLE_W;
 | 
						|
	}
 | 
						|
 | 
						|
	return rv;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what)
 | 
						|
{
 | 
						|
	struct kevent kev[2];
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
	size_t i;
 | 
						|
	int rv;
 | 
						|
 | 
						|
	assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
 | 
						|
 | 
						|
	fio = getfiobyfd(pu, fd);
 | 
						|
	if (fio == NULL) {
 | 
						|
		errno = ENXIO;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	i = 0;
 | 
						|
	if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
 | 
						|
		EV_SET(&kev[0], fd,
 | 
						|
		    EVFILT_READ, EV_DISABLE, 0, 0, (uintptr_t)fio);
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
	if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) {
 | 
						|
		EV_SET(&kev[1], fd,
 | 
						|
		    EVFILT_WRITE, EV_DISABLE, 0, 0, (uintptr_t)fio);
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
	if (i)
 | 
						|
		rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL);
 | 
						|
	else
 | 
						|
		rv = 0;
 | 
						|
 | 
						|
	if (rv == 0) {
 | 
						|
		if (what & PUFFS_FBIO_READ)
 | 
						|
			fio->stat &= ~FIO_ENABLE_R;
 | 
						|
		if (what & PUFFS_FBIO_WRITE)
 | 
						|
			fio->stat &= ~FIO_ENABLE_W;
 | 
						|
	}
 | 
						|
 | 
						|
	return rv;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs__framev_readclose(struct puffs_usermount *pu,
 | 
						|
	struct puffs_fctrl_io *fio, int error)
 | 
						|
{
 | 
						|
	struct puffs_framebuf *pufbuf;
 | 
						|
	struct kevent kev;
 | 
						|
	int notflag;
 | 
						|
 | 
						|
	if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD)
 | 
						|
		return;
 | 
						|
	fio->stat |= FIO_RDGONE;
 | 
						|
 | 
						|
	if (fio->cur_in) {
 | 
						|
		if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) {
 | 
						|
			puffs_framebuf_destroy(fio->cur_in);
 | 
						|
			fio->cur_in = NULL;
 | 
						|
		} else {
 | 
						|
			errnotify(pu, fio->cur_in, error);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) {
 | 
						|
		TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries);
 | 
						|
		errnotify(pu, pufbuf, error);
 | 
						|
	}
 | 
						|
 | 
						|
	EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
 | 
						|
	(void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
 | 
						|
 | 
						|
	notflag = PUFFS_FBIO_READ;
 | 
						|
	if (fio->stat & FIO_WRGONE)
 | 
						|
		notflag |= PUFFS_FBIO_WRITE;
 | 
						|
 | 
						|
	if (fio->fctrl->fdnotfn)
 | 
						|
		fio->fctrl->fdnotfn(pu, fio->io_fd, notflag);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs__framev_writeclose(struct puffs_usermount *pu,
 | 
						|
	struct puffs_fctrl_io *fio, int error)
 | 
						|
{
 | 
						|
	struct puffs_framebuf *pufbuf;
 | 
						|
	struct kevent kev;
 | 
						|
	int notflag;
 | 
						|
 | 
						|
	if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD)
 | 
						|
		return;
 | 
						|
	fio->stat |= FIO_WRGONE;
 | 
						|
 | 
						|
	while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) {
 | 
						|
		TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
 | 
						|
		errnotify(pu, pufbuf, error);
 | 
						|
	}
 | 
						|
 | 
						|
	EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
 | 
						|
	(void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
 | 
						|
 | 
						|
	notflag = PUFFS_FBIO_WRITE;
 | 
						|
	if (fio->stat & FIO_RDGONE)
 | 
						|
		notflag |= PUFFS_FBIO_READ;
 | 
						|
 | 
						|
	if (fio->fctrl->fdnotfn)
 | 
						|
		fio->fctrl->fdnotfn(pu, fio->io_fd, notflag);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error)
 | 
						|
{
 | 
						|
	struct puffs_fbevent *fbevp;
 | 
						|
 | 
						|
	LIST_REMOVE(fio, fio_entries);
 | 
						|
	if (pu->pu_state & PU_INLOOP) {
 | 
						|
		puffs__framev_readclose(pu, fio, error);
 | 
						|
		puffs__framev_writeclose(pu, fio, error);
 | 
						|
	}
 | 
						|
 | 
						|
	while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) {
 | 
						|
		fbevp->rv = error;
 | 
						|
		LIST_REMOVE(fbevp, pfe_entries);
 | 
						|
		puffs__goto(fbevp->pcc);
 | 
						|
	}
 | 
						|
 | 
						|
	/* don't bother with realloc */
 | 
						|
	pu->pu_nevs -= 2;
 | 
						|
 | 
						|
	/* don't free us yet, might have some references in event arrays */
 | 
						|
	fio->stat |= FIO_DEAD;
 | 
						|
	LIST_INSERT_HEAD(&pu->pu_ios_rmlist, fio, fio_entries);
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error)
 | 
						|
{
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
 | 
						|
	fio = getfiobyfd(pu, fd);
 | 
						|
	if (fio == NULL) {
 | 
						|
		errno = ENXIO;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return removefio(pu, fio, error ? error : ECONNRESET);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what)
 | 
						|
{
 | 
						|
 | 
						|
	if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
 | 
						|
		(void) puffs_framev_removefd(pu, fd, ECONNRESET);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what)
 | 
						|
{
 | 
						|
 | 
						|
	/* XXX & X: unmount is non-sensible */
 | 
						|
	puffs_framev_removeonclose(pu, fd, what);
 | 
						|
	if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
 | 
						|
		PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs_framev_init(struct puffs_usermount *pu,
 | 
						|
	puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb,
 | 
						|
	puffs_framev_cmpframe_fn cmpfb, puffs_framev_gotframe_fn gotfb,
 | 
						|
	puffs_framev_fdnotify_fn fdnotfn)
 | 
						|
{
 | 
						|
	struct puffs_framectrl *pfctrl;
 | 
						|
 | 
						|
	pfctrl = &pu->pu_framectrl[PU_FRAMECTRL_USER];
 | 
						|
	pfctrl->rfb = rfb;
 | 
						|
	pfctrl->wfb = wfb;
 | 
						|
	pfctrl->cmpfb = cmpfb;
 | 
						|
	pfctrl->gotfb = gotfb;
 | 
						|
	pfctrl->fdnotfn = fdnotfn;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
puffs__framev_exit(struct puffs_usermount *pu)
 | 
						|
{
 | 
						|
	struct puffs_fctrl_io *fio;
 | 
						|
 | 
						|
	while ((fio = LIST_FIRST(&pu->pu_ios)) != NULL)
 | 
						|
		removefio(pu, fio, ENXIO);
 | 
						|
	free(pu->pu_evs);
 | 
						|
 | 
						|
	/* closing pu->pu_kq takes care of puffsfd */
 | 
						|
}
 |