Home | History | Annotate | Line # | Download | only in libpuffs
framebuf.c revision 1.1
      1 /*	$NetBSD: framebuf.c,v 1.1 2007/05/05 15:48:18 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2007  Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by the
      7  * Finnish Cultural Foundation.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 #if !defined(lint)
     33 __RCSID("$NetBSD: framebuf.c,v 1.1 2007/05/05 15:48:18 pooka Exp $");
     34 #endif /* !lint */
     35 
     36 #include <sys/types.h>
     37 #include <sys/queue.h>
     38 
     39 #include <assert.h>
     40 #include <errno.h>
     41 #include <poll.h>
     42 #include <puffs.h>
     43 #include <stdlib.h>
     44 
     45 #include "puffs_priv.h"
     46 
     47 struct puffs_framebuf {
     48 	struct puffs_cc *pcc;	/* pcc to continue with */
     49 	/* OR */
     50 	puffs_framebuf_cb fcb;	/* non-blocking callback */
     51 	void *fcb_arg;		/* argument for previous */
     52 
     53 	uint8_t *buf;		/* buffer base */
     54 	size_t len;		/* total length */
     55 
     56 	size_t offset;		/* cursor, telloff() */
     57 	size_t maxoff;		/* maximum offset for data, tellsize() */
     58 
     59 	volatile int rv;	/* errno value for pcc framebufs */
     60 
     61 	int	istat;
     62 
     63 	TAILQ_ENTRY(puffs_framebuf) pfb_entries;
     64 };
     65 #define ISTAT_NODESTROY	0x01	/* indestructible by framebuf_destroy() */
     66 #define ISTAT_INTERNAL	0x02	/* never leaves library			*/
     67 #define ISTAT_NOREPLY	0x04	/* nuke after sending 			*/
     68 
     69 struct puffs_framectrl {
     70 	puffs_framebuf_readframe_fn rfb;
     71 	puffs_framebuf_writeframe_fn wfb;
     72 	puffs_framebuf_respcmp_fn cmpfb;
     73 	int io_fd;
     74 
     75 	struct puffs_framebuf *cur_in;
     76 
     77 	TAILQ_HEAD(, puffs_framebuf) snd_qing;	/* queueing to be sent */
     78 	TAILQ_HEAD(, puffs_framebuf) res_qing;	/* q'ing for rescue */
     79 };
     80 
     81 #define PUFBUF_INCRALLOC 65536	/* 64k ought to be enough for anyone */
     82 #define PUFBUF_REMAIN(p) (p->len - p->offset)
     83 
     84 struct puffs_framebuf *
     85 puffs_framebuf_make()
     86 {
     87 	struct puffs_framebuf *pufbuf;
     88 
     89 	pufbuf = malloc(sizeof(struct puffs_framebuf));
     90 	if (pufbuf == NULL)
     91 		return NULL;
     92 	memset(pufbuf, 0, sizeof(struct puffs_framebuf));
     93 
     94 	pufbuf->buf = malloc(PUFBUF_INCRALLOC);
     95 	pufbuf->len = PUFBUF_INCRALLOC;
     96 	if (pufbuf->buf == NULL) {
     97 		free(pufbuf);
     98 		return NULL;
     99 	}
    100 
    101 	puffs_framebuf_recycle(pufbuf);
    102 	return pufbuf;
    103 }
    104 
    105 void
    106 puffs_framebuf_destroy(struct puffs_framebuf *pufbuf)
    107 {
    108 
    109 	assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
    110 
    111 	free(pufbuf->buf);
    112 	free(pufbuf);
    113 }
    114 
    115 void
    116 puffs_framebuf_recycle(struct puffs_framebuf *pufbuf)
    117 {
    118 
    119 	assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
    120 
    121 	pufbuf->offset = 0;
    122 	pufbuf->maxoff = 0;
    123 	pufbuf->istat = 0;
    124 }
    125 
    126 static int
    127 reservespace(struct puffs_framebuf *pufbuf, size_t off, size_t wantsize)
    128 {
    129 	size_t incr;
    130 	void *nd;
    131 
    132 	if (off <= pufbuf->len && pufbuf->len - off >= wantsize)
    133 		return 0;
    134 
    135 	for (incr = PUFBUF_INCRALLOC;
    136 	    pufbuf->len + incr < off + wantsize;
    137 	    incr += PUFBUF_INCRALLOC)
    138 		continue;
    139 
    140 	nd = realloc(pufbuf->buf, pufbuf->offset + incr);
    141 	if (nd == NULL)
    142 		return -1;
    143 
    144 	pufbuf->buf = nd;
    145 	pufbuf->len += incr;
    146 
    147 	return 0;
    148 }
    149 
    150 int
    151 puffs_framebuf_reserve_space(struct puffs_framebuf *pufbuf, size_t wantsize)
    152 {
    153 
    154 	return reservespace(pufbuf, pufbuf->offset, wantsize);
    155 }
    156 
    157 int
    158 puffs_framebuf_putdata(struct puffs_framebuf *pufbuf,
    159 	const void *data, size_t dlen)
    160 {
    161 
    162 	if (PUFBUF_REMAIN(pufbuf) < dlen)
    163 		if (puffs_framebuf_reserve_space(pufbuf, dlen) == -1)
    164 			return -1;
    165 
    166 	memcpy(pufbuf->buf + pufbuf->offset, data, dlen);
    167 	pufbuf->offset += dlen;
    168 
    169 	if (pufbuf->offset > pufbuf->maxoff)
    170 		pufbuf->maxoff = pufbuf->offset;
    171 
    172 	return 0;
    173 }
    174 
    175 int
    176 puffs_framebuf_putdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
    177 	const void *data, size_t dlen)
    178 {
    179 
    180 	if (reservespace(pufbuf, offset, dlen) == -1)
    181 		return -1;
    182 
    183 	memcpy(pufbuf->buf + offset, data, dlen);
    184 
    185 	if (offset + dlen > pufbuf->maxoff)
    186 		pufbuf->maxoff = offset + dlen;
    187 
    188 	return 0;
    189 }
    190 
    191 int
    192 puffs_framebuf_getdata(struct puffs_framebuf *pufbuf, void *data, size_t dlen)
    193 {
    194 
    195 	if (pufbuf->maxoff < pufbuf->offset + dlen) {
    196 		errno = ENOBUFS;
    197 		return -1;
    198 	}
    199 
    200 	memcpy(data, pufbuf->buf + pufbuf->offset, dlen);
    201 	pufbuf->offset += dlen;
    202 
    203 	return 0;
    204 }
    205 
    206 int
    207 puffs_framebuf_getdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
    208 	void *data, size_t dlen)
    209 {
    210 
    211 	if (pufbuf->maxoff < offset + dlen) {
    212 		errno = ENOBUFS;
    213 		return -1;
    214 	}
    215 
    216 	memcpy(data, pufbuf->buf + offset, dlen);
    217 	return 0;
    218 }
    219 
    220 size_t
    221 puffs_framebuf_telloff(struct puffs_framebuf *pufbuf)
    222 {
    223 
    224 	return pufbuf->offset;
    225 }
    226 
    227 size_t
    228 puffs_framebuf_tellsize(struct puffs_framebuf *pufbuf)
    229 {
    230 
    231 	return pufbuf->maxoff;
    232 }
    233 
    234 int
    235 puffs_framebuf_seekset(struct puffs_framebuf *pufbuf, size_t newoff)
    236 {
    237 
    238 	if (reservespace(pufbuf, newoff, 0) == -1)
    239 		return -1;
    240 
    241 	pufbuf->offset = newoff;
    242 	return 0;
    243 }
    244 
    245 int
    246 puffs_framebuf_getwindow(struct puffs_framebuf *pufbuf, size_t winoff,
    247 	void **data, size_t *dlen)
    248 {
    249 	size_t winlen;
    250 
    251 #ifdef WINTESTING
    252 	winlen = MIN(*dlen, 32);
    253 #else
    254 	winlen = *dlen;
    255 #endif
    256 
    257 	if (reservespace(pufbuf, winoff, winlen) == -1)
    258 		return -1;
    259 
    260 	*data = pufbuf->buf + winoff;
    261 	if (pufbuf->maxoff < winoff + winlen)
    262 		pufbuf->maxoff = winoff + winlen;
    263 
    264 	return 0;
    265 }
    266 
    267 int
    268 puffs_framebuf_enqueue_cc(struct puffs_cc *pcc, struct puffs_framebuf *pufbuf)
    269 {
    270 	struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
    271 	struct puffs_framectrl *fctrl = pu->pu_framectrl;
    272 
    273 	pufbuf->pcc = pcc;
    274 	pufbuf->fcb = NULL;
    275 	pufbuf->fcb_arg = NULL;
    276 
    277 	pufbuf->offset = 0;
    278 	pufbuf->istat |= ISTAT_NODESTROY;
    279 
    280 	TAILQ_INSERT_TAIL(&fctrl->snd_qing, pufbuf, pfb_entries);
    281 
    282 	puffs_cc_yield(pcc);
    283 	if (pufbuf->rv) {
    284 		errno = pufbuf->rv;
    285 		return -1;
    286 	}
    287 
    288 	return 0;
    289 }
    290 
    291 void
    292 puffs_framebuf_enqueue_cb(struct puffs_usermount *pu,
    293 	struct puffs_framebuf *pufbuf, puffs_framebuf_cb fcb, void *arg)
    294 {
    295 	struct puffs_framectrl *fctrl = pu->pu_framectrl;
    296 
    297 	pufbuf->pcc = NULL;
    298 	pufbuf->fcb = fcb;
    299 	pufbuf->fcb_arg = arg;
    300 
    301 	pufbuf->offset = 0;
    302 	pufbuf->istat |= ISTAT_NODESTROY;
    303 
    304 	TAILQ_INSERT_TAIL(&fctrl->snd_qing, pufbuf, pfb_entries);
    305 }
    306 
    307 void
    308 puffs_framebuf_enqueue_justsend(struct puffs_usermount *pu,
    309 	struct puffs_framebuf *pufbuf, int reply)
    310 {
    311 	struct puffs_framectrl *fctrl = pu->pu_framectrl;
    312 
    313 	pufbuf->pcc = NULL;
    314 	pufbuf->fcb = NULL;
    315 	pufbuf->fcb_arg = NULL;
    316 
    317 	pufbuf->offset = 0;
    318 	pufbuf->istat |= ISTAT_NODESTROY;
    319 	if (!reply)
    320 		pufbuf->istat |= ISTAT_NOREPLY;
    321 
    322 	TAILQ_INSERT_TAIL(&fctrl->snd_qing, pufbuf, pfb_entries);
    323 }
    324 
    325 static struct puffs_framebuf *
    326 findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
    327 	struct puffs_framebuf *findme)
    328 {
    329 	struct puffs_framebuf *cand;
    330 
    331 	TAILQ_FOREACH(cand, &fctrl->res_qing, pfb_entries)
    332 		if (fctrl->cmpfb(pu, findme, cand))
    333 			break;
    334 
    335 	if (cand == NULL)
    336 		return NULL;
    337 
    338 	TAILQ_REMOVE(&fctrl->res_qing, cand, pfb_entries);
    339 	return cand;
    340 }
    341 
    342 static void
    343 moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to)
    344 {
    345 
    346 	assert(from->istat & ISTAT_INTERNAL);
    347 
    348 	/* migrate buffer */
    349 	free(to->buf);
    350 	to->buf = from->buf;
    351 	from->buf = NULL;
    352 
    353 	/* migrate buffer info */
    354 	to->len = from->len;
    355 	to->offset = from->offset;
    356 	to->maxoff = from->maxoff;
    357 }
    358 
    359 static int
    360 handle_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
    361 	struct puffs_putreq *ppr)
    362 {
    363 	struct puffs_framebuf *pufbuf, *appbuf;
    364 	int rv, complete;
    365 
    366 	for (;;) {
    367 		if ((pufbuf = fctrl->cur_in) == NULL) {
    368 			pufbuf = puffs_framebuf_make();
    369 			if (pufbuf == NULL)
    370 				return -1;
    371 			pufbuf->istat |= ISTAT_INTERNAL;
    372 			fctrl->cur_in = pufbuf;
    373 		}
    374 
    375 		complete = 0;
    376 		rv = fctrl->rfb(pu, pufbuf, fctrl->io_fd, &complete);
    377 
    378 		/* error */
    379 		if (rv) {
    380 			errno = rv;
    381 			return -1;
    382 		}
    383 
    384 		/* partial read, come back to fight another day */
    385 		if (complete == 0)
    386 			break;
    387 
    388 		/* else: full read, process */
    389 
    390 		appbuf = findbuf(pu, fctrl, pufbuf);
    391 		if (appbuf == NULL) {
    392 			errno = ENOMSG;
    393 			return -1;
    394 		}
    395 
    396 		appbuf->istat &= ~ISTAT_NODESTROY;
    397 		moveinfo(pufbuf, appbuf);
    398 		if (appbuf->pcc) {
    399 			puffs_docc(appbuf->pcc, ppr);
    400 		} else if (appbuf->fcb) {
    401 			appbuf->fcb(pu, appbuf, appbuf->fcb_arg);
    402 		} else {
    403 			puffs_framebuf_destroy(appbuf);
    404 		}
    405 		puffs_framebuf_destroy(pufbuf);
    406 
    407 		/* hopeless romantics, here we go again */
    408 		fctrl->cur_in = NULL;
    409 	}
    410 
    411 	return rv;
    412 }
    413 
    414 static int
    415 handle_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl)
    416 {
    417 	struct puffs_framebuf *pufbuf, *pufbuf_next;
    418 	int rv, complete;
    419 
    420 	for (pufbuf = TAILQ_FIRST(&fctrl->snd_qing);
    421 	    pufbuf;
    422 	    pufbuf = pufbuf_next) {
    423 		complete = 0;
    424 		pufbuf_next = TAILQ_NEXT(pufbuf, pfb_entries);
    425 		rv = fctrl->wfb(pu, pufbuf, fctrl->io_fd, &complete);
    426 
    427 		if (rv) {
    428 			TAILQ_REMOVE(&fctrl->snd_qing, pufbuf, pfb_entries);
    429 			pufbuf->rv = rv;
    430 			errno = rv;
    431 			return -1;
    432 		}
    433 
    434 		/* partial write */
    435 		if (complete == 0)
    436 			return 0;
    437 
    438 		/* else, complete write */
    439 		TAILQ_REMOVE(&fctrl->snd_qing, pufbuf, pfb_entries);
    440 
    441 		if ((pufbuf->istat & ISTAT_NOREPLY) == 0) {
    442 			TAILQ_INSERT_TAIL(&fctrl->res_qing, pufbuf,
    443 			    pfb_entries);
    444 		} else {
    445 			pufbuf->istat &= ~ISTAT_NODESTROY;
    446 			puffs_framebuf_destroy(pufbuf);
    447 		}
    448 	}
    449 
    450 	return 0;
    451 }
    452 
    453 #define FRAMEFD 0
    454 #define PUFFSFD 1
    455 int
    456 puffs_framebuf_eventloop(struct puffs_usermount *pu, int io_fd,
    457 	puffs_framebuf_readframe_fn rfb, puffs_framebuf_writeframe_fn wfb,
    458 	puffs_framebuf_respcmp_fn cmpfb,
    459 	puffs_framebuf_loop_fn lfb, void *lfb_arg)
    460 {
    461 	struct puffs_getreq *pgr = NULL;
    462 	struct puffs_putreq *ppr = NULL;
    463 	struct puffs_framectrl *pfctrl = NULL;
    464 	struct pollfd pfds[2];
    465 	int puffsfd, rv;
    466 
    467 	assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING);
    468 
    469 	pgr = puffs_req_makeget(pu, puffs_getmaxreqlen(pu), 0);
    470 	if (pgr == NULL)
    471 		goto out;
    472 
    473 	ppr = puffs_req_makeput(pu);
    474 	if (ppr == NULL)
    475 		goto out;
    476 
    477 	pfctrl = malloc(sizeof(struct puffs_framectrl));
    478 	if (pfctrl == NULL)
    479 		goto out;
    480 	pfctrl->rfb = rfb;
    481 	pfctrl->wfb = wfb;
    482 	pfctrl->cmpfb = cmpfb;
    483 	pfctrl->io_fd = io_fd;
    484 	TAILQ_INIT(&pfctrl->snd_qing);
    485 	TAILQ_INIT(&pfctrl->res_qing);
    486 	pu->pu_framectrl = pfctrl;
    487 
    488 	puffsfd = puffs_getselectable(pu);
    489 	while (puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED) {
    490 		if (lfb)
    491 			lfb(pu, lfb_arg);
    492 
    493 		memset(pfds, 0, sizeof(pfds));
    494 		pfds[FRAMEFD].events = POLLIN;
    495 		if (!TAILQ_EMPTY(&pfctrl->snd_qing))
    496 			pfds[FRAMEFD].events |= POLLOUT;
    497 		pfds[FRAMEFD].fd = io_fd;
    498 		pfds[PUFFSFD].events = POLLIN;
    499 		pfds[PUFFSFD].fd = puffsfd;
    500 
    501 		if (poll(pfds, 2, INFTIM) == -1)
    502 			goto out;
    503 
    504 		/* if there is room in the sucket for output ... */
    505 		if (pfds[FRAMEFD].revents & POLLOUT)
    506 			if (handle_output(pu, pfctrl) == -1)
    507 				goto out;
    508 
    509 		/* get & possibly dispatch events from kernel */
    510 		if (pfds[PUFFSFD].revents & POLLIN)
    511 			if (puffs_req_handle(pu, pgr, ppr, 0) == -1)
    512 				goto out;
    513 
    514 		/* get input from framefd, possibly build more responses */
    515 		if (pfds[FRAMEFD].revents & POLLIN)
    516 			if (handle_input(pu, pfctrl, ppr) == -1)
    517 				goto out;
    518 
    519 		/* it's likely we got outputtables, poke the ice with a stick */
    520 		if (handle_output(pu, pfctrl) == -1)
    521 			goto out;
    522 
    523 		/* stuff all replies from both of the above into kernel */
    524 		if (puffs_req_putput(ppr) == -1)
    525 			goto out;
    526 		puffs_req_resetput(ppr);
    527 	}
    528 	errno = 0;
    529 
    530  out:
    531 	rv = errno;
    532 	if (pfctrl) {
    533 		pu->pu_framectrl = NULL;
    534 		free(pfctrl);
    535 	}
    536 
    537 	if (ppr)
    538 		puffs_req_destroyput(ppr);
    539 	if (pgr)
    540 		puffs_req_destroyget(pgr);
    541 
    542 	return rv;
    543 }
    544