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