Annotation of src/lib/libpuffs/framebuf.c, Revision 1.1
1.1 ! pooka 1: /* $NetBSD$ */
! 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$");
! 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: }
CVSweb <webmaster@jp.NetBSD.org>