1 /* $NetBSD: framebuf.c,v 1.30 2010/01/12 18:42:38 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.30 2010/01/12 18:42:38 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 <stdio.h> 49 #include <stdlib.h> 50 #include <unistd.h> 51 52 #include "puffs_priv.h" 53 54 struct puffs_framebuf { 55 struct puffs_cc *pcc; /* pcc to continue with */ 56 /* OR */ 57 puffs_framev_cb fcb; /* non-blocking callback */ 58 void *fcb_arg; /* argument for previous */ 59 60 uint8_t *buf; /* buffer base */ 61 size_t len; /* total length */ 62 63 size_t offset; /* cursor, telloff() */ 64 size_t maxoff; /* maximum offset for data, tellsize() */ 65 66 volatile int rv; /* errno value */ 67 68 int istat; 69 70 TAILQ_ENTRY(puffs_framebuf) pfb_entries; 71 }; 72 #define ISTAT_NODESTROY 0x01 /* indestructible by framebuf_destroy() */ 73 #define ISTAT_INTERNAL 0x02 /* never leaves library */ 74 #define ISTAT_NOREPLY 0x04 /* nuke after sending */ 75 #define ISTAT_DIRECT 0x08 /* receive directly, no moveinfo */ 76 77 #define ISTAT_ONQUEUE ISTAT_NODESTROY /* alias */ 78 79 #define PUFBUF_INCRALLOC 4096 80 #define PUFBUF_REMAIN(p) (p->len - p->offset) 81 82 /* for poll/kqueue */ 83 struct puffs_fbevent { 84 struct puffs_cc *pcc; 85 int what; 86 volatile int rv; 87 88 LIST_ENTRY(puffs_fbevent) pfe_entries; 89 }; 90 91 static struct puffs_fctrl_io * 92 getfiobyfd(struct puffs_usermount *pu, int fd) 93 { 94 struct puffs_fctrl_io *fio; 95 96 LIST_FOREACH(fio, &pu->pu_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->len + 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_dup(struct puffs_framebuf *pb, struct puffs_framebuf **pbp) 170 { 171 struct puffs_framebuf *newpb; 172 173 newpb = puffs_framebuf_make(); 174 if (newpb == NULL) { 175 errno = ENOMEM; 176 return -1; 177 } 178 memcpy(newpb, pb, sizeof(struct puffs_framebuf)); 179 180 newpb->buf = NULL; 181 newpb->len = 0; 182 if (reservespace(newpb, 0, pb->maxoff) == -1) { 183 puffs_framebuf_destroy(newpb); 184 return -1; 185 } 186 187 memcpy(newpb->buf, pb->buf, pb->maxoff); 188 newpb->istat = 0; 189 *pbp = newpb; 190 191 return 0; 192 } 193 194 int 195 puffs_framebuf_reserve_space(struct puffs_framebuf *pufbuf, size_t wantsize) 196 { 197 198 return reservespace(pufbuf, pufbuf->offset, wantsize); 199 } 200 201 int 202 puffs_framebuf_putdata(struct puffs_framebuf *pufbuf, 203 const void *data, size_t dlen) 204 { 205 206 if (PUFBUF_REMAIN(pufbuf) < dlen) 207 if (puffs_framebuf_reserve_space(pufbuf, dlen) == -1) 208 return -1; 209 210 memcpy(pufbuf->buf + pufbuf->offset, data, dlen); 211 pufbuf->offset += dlen; 212 213 if (pufbuf->offset > pufbuf->maxoff) 214 pufbuf->maxoff = pufbuf->offset; 215 216 return 0; 217 } 218 219 int 220 puffs_framebuf_putdata_atoff(struct puffs_framebuf *pufbuf, size_t offset, 221 const void *data, size_t dlen) 222 { 223 224 if (reservespace(pufbuf, offset, dlen) == -1) 225 return -1; 226 227 memcpy(pufbuf->buf + offset, data, dlen); 228 229 if (offset + dlen > pufbuf->maxoff) 230 pufbuf->maxoff = offset + dlen; 231 232 return 0; 233 } 234 235 int 236 puffs_framebuf_getdata(struct puffs_framebuf *pufbuf, void *data, size_t dlen) 237 { 238 239 if (pufbuf->maxoff < pufbuf->offset + dlen) { 240 errno = ENOBUFS; 241 return -1; 242 } 243 244 memcpy(data, pufbuf->buf + pufbuf->offset, dlen); 245 pufbuf->offset += dlen; 246 247 return 0; 248 } 249 250 int 251 puffs_framebuf_getdata_atoff(struct puffs_framebuf *pufbuf, size_t offset, 252 void *data, size_t dlen) 253 { 254 255 if (pufbuf->maxoff < offset + dlen) { 256 errno = ENOBUFS; 257 return -1; 258 } 259 260 memcpy(data, pufbuf->buf + offset, dlen); 261 return 0; 262 } 263 264 size_t 265 puffs_framebuf_telloff(struct puffs_framebuf *pufbuf) 266 { 267 268 return pufbuf->offset; 269 } 270 271 size_t 272 puffs_framebuf_tellsize(struct puffs_framebuf *pufbuf) 273 { 274 275 return pufbuf->maxoff; 276 } 277 278 size_t 279 puffs_framebuf_remaining(struct puffs_framebuf *pufbuf) 280 { 281 282 return puffs_framebuf_tellsize(pufbuf) - puffs_framebuf_telloff(pufbuf); 283 } 284 285 int 286 puffs_framebuf_seekset(struct puffs_framebuf *pufbuf, size_t newoff) 287 { 288 289 if (reservespace(pufbuf, newoff, 0) == -1) 290 return -1; 291 292 pufbuf->offset = newoff; 293 return 0; 294 } 295 296 int 297 puffs_framebuf_getwindow(struct puffs_framebuf *pufbuf, size_t winoff, 298 void **data, size_t *dlen) 299 { 300 size_t winlen; 301 302 #ifdef WINTESTING 303 winlen = MIN(*dlen, 32); 304 #else 305 winlen = *dlen; 306 #endif 307 308 if (reservespace(pufbuf, winoff, winlen) == -1) 309 return -1; 310 311 *data = pufbuf->buf + winoff; 312 if (pufbuf->maxoff < winoff + winlen) 313 pufbuf->maxoff = winoff + winlen; 314 315 return 0; 316 } 317 318 void * 319 puffs__framebuf_getdataptr(struct puffs_framebuf *pufbuf) 320 { 321 322 return pufbuf->buf; 323 } 324 325 static void 326 errnotify(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, int error) 327 { 328 329 pufbuf->rv = error; 330 if (pufbuf->pcc) { 331 puffs__goto(pufbuf->pcc); 332 } else if (pufbuf->fcb) { 333 pufbuf->istat &= ~ISTAT_NODESTROY; 334 pufbuf->fcb(pu, pufbuf, pufbuf->fcb_arg, error); 335 } else { 336 pufbuf->istat &= ~ISTAT_NODESTROY; 337 puffs_framebuf_destroy(pufbuf); 338 } 339 } 340 341 #define GETFIO(fd) \ 342 do { \ 343 fio = getfiobyfd(pu, fd); \ 344 if (fio == NULL) { \ 345 errno = EINVAL; \ 346 return -1; \ 347 } \ 348 if (fio->stat & FIO_WRGONE) { \ 349 errno = ESHUTDOWN; \ 350 return -1; \ 351 } \ 352 } while (/*CONSTCOND*/0) 353 354 int 355 puffs_framev_enqueue_cc(struct puffs_cc *pcc, int fd, 356 struct puffs_framebuf *pufbuf, int flags) 357 { 358 struct puffs_usermount *pu = pcc->pcc_pu; 359 struct puffs_fctrl_io *fio; 360 361 /* 362 * Technically we shouldn't allow this if RDGONE, but it's 363 * difficult to trap write close without allowing writes. 364 * And besides, there's probably a disconnect sequence in 365 * the protocol, so unexpectedly getting a closed fd is 366 * most likely an error condition. 367 */ 368 GETFIO(fd); 369 370 pufbuf->pcc = pcc; 371 pufbuf->fcb = NULL; 372 pufbuf->fcb_arg = NULL; 373 374 pufbuf->offset = 0; 375 pufbuf->istat |= ISTAT_NODESTROY; 376 377 if (flags & PUFFS_FBQUEUE_URGENT) 378 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries); 379 else 380 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries); 381 382 puffs_cc_yield(pcc); 383 if (pufbuf->rv) { 384 pufbuf->istat &= ~ISTAT_NODESTROY; 385 errno = pufbuf->rv; 386 return -1; 387 } 388 389 return 0; 390 } 391 392 int 393 puffs_framev_enqueue_cb(struct puffs_usermount *pu, int fd, 394 struct puffs_framebuf *pufbuf, puffs_framev_cb fcb, void *arg, 395 int flags) 396 { 397 struct puffs_fctrl_io *fio; 398 399 /* see enqueue_cc */ 400 GETFIO(fd); 401 402 pufbuf->pcc = NULL; 403 pufbuf->fcb = fcb; 404 pufbuf->fcb_arg = arg; 405 406 pufbuf->offset = 0; 407 pufbuf->istat |= ISTAT_NODESTROY; 408 409 if (flags & PUFFS_FBQUEUE_URGENT) 410 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries); 411 else 412 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries); 413 414 return 0; 415 } 416 417 int 418 puffs_framev_enqueue_justsend(struct puffs_usermount *pu, int fd, 419 struct puffs_framebuf *pufbuf, int reply, int flags) 420 { 421 struct puffs_fctrl_io *fio; 422 423 assert((pufbuf->istat & ISTAT_INTERNAL) == 0); 424 425 GETFIO(fd); 426 427 pufbuf->pcc = NULL; 428 pufbuf->fcb = NULL; 429 pufbuf->fcb_arg = NULL; 430 431 pufbuf->offset = 0; 432 pufbuf->istat |= ISTAT_NODESTROY; 433 if (!reply) 434 pufbuf->istat |= ISTAT_NOREPLY; 435 436 if (flags & PUFFS_FBQUEUE_URGENT) 437 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries); 438 else 439 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries); 440 441 return 0; 442 } 443 444 /* ARGSUSED */ 445 int 446 puffs_framev_enqueue_directreceive(struct puffs_cc *pcc, int fd, 447 struct puffs_framebuf *pufbuf, int flags /* used in the future */) 448 { 449 struct puffs_usermount *pu = pcc->pcc_pu; 450 struct puffs_fctrl_io *fio; 451 452 assert((pufbuf->istat & ISTAT_INTERNAL) == 0); 453 454 fio = getfiobyfd(pu, fd); 455 if (fio == NULL) { 456 errno = EINVAL; 457 return -1; 458 } 459 460 /* XXX: should have cur_in queue */ 461 assert(fio->cur_in == NULL); 462 fio->cur_in = pufbuf; 463 464 pufbuf->pcc = pcc; 465 pufbuf->fcb = NULL; 466 pufbuf->fcb_arg = NULL; 467 468 pufbuf->offset = 0; 469 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT; 470 471 puffs_cc_yield(pcc); 472 pufbuf->istat &= ~ISTAT_NODESTROY; /* XXX: not the right place */ 473 if (pufbuf->rv) { 474 errno = pufbuf->rv; 475 return -1; 476 } 477 478 return 0; 479 } 480 481 int 482 puffs_framev_enqueue_directsend(struct puffs_cc *pcc, int fd, 483 struct puffs_framebuf *pufbuf, int flags) 484 { 485 struct puffs_usermount *pu = pcc->pcc_pu; 486 struct puffs_fctrl_io *fio; 487 488 assert((pufbuf->istat & ISTAT_INTERNAL) == 0); 489 490 if (flags & PUFFS_FBQUEUE_URGENT) 491 abort(); /* EOPNOTSUPP for now */ 492 493 GETFIO(fd); 494 495 pufbuf->pcc = pcc; 496 pufbuf->fcb = NULL; 497 pufbuf->fcb_arg = NULL; 498 499 pufbuf->offset = 0; 500 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT; 501 502 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries); 503 504 puffs_cc_yield(pcc); 505 if (pufbuf->rv) { 506 pufbuf->istat &= ~ISTAT_NODESTROY; 507 errno = pufbuf->rv; 508 return -1; 509 } 510 511 return 0; 512 } 513 514 int 515 puffs_framev_framebuf_ccpromote(struct puffs_framebuf *pufbuf, 516 struct puffs_cc *pcc) 517 { 518 519 if ((pufbuf->istat & ISTAT_ONQUEUE) == 0) { 520 errno = EBUSY; 521 return -1; 522 } 523 524 pufbuf->pcc = pcc; 525 pufbuf->fcb = NULL; 526 pufbuf->fcb_arg = NULL; 527 pufbuf->istat &= ~ISTAT_NOREPLY; 528 529 puffs_cc_yield(pcc); 530 531 return 0; 532 } 533 534 int 535 puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what) 536 { 537 struct puffs_usermount *pu = pcc->pcc_pu; 538 struct puffs_fctrl_io *fio; 539 struct puffs_fbevent feb; 540 struct kevent kev; 541 int rv, svwhat; 542 543 svwhat = *what; 544 545 if (*what == 0) { 546 errno = EINVAL; 547 return -1; 548 } 549 550 fio = getfiobyfd(pu, fd); 551 if (fio == NULL) { 552 errno = EINVAL; 553 return -1; 554 } 555 556 feb.pcc = pcc; 557 feb.what = *what & (PUFFS_FBIO_READ|PUFFS_FBIO_WRITE|PUFFS_FBIO_ERROR); 558 559 if (*what & PUFFS_FBIO_READ) 560 if ((fio->stat & FIO_ENABLE_R) == 0) 561 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 562 0, 0, (uintptr_t)fio); 563 564 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 565 if (rv != 0) 566 return errno; 567 568 if (*what & PUFFS_FBIO_READ) 569 fio->rwait++; 570 if (*what & PUFFS_FBIO_WRITE) 571 fio->wwait++; 572 573 LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries); 574 puffs_cc_yield(pcc); 575 576 assert(svwhat == *what); 577 578 if (*what & PUFFS_FBIO_READ) { 579 fio->rwait--; 580 if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) { 581 EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE, 582 0, 0, (uintptr_t)fio); 583 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 584 #if 0 585 if (rv != 0) 586 /* XXXXX oh dear */; 587 #endif 588 } 589 } 590 if (*what & PUFFS_FBIO_WRITE) 591 fio->wwait--; 592 593 if (feb.rv == 0) { 594 *what = feb.what; 595 rv = 0; 596 } else { 597 *what = PUFFS_FBIO_ERROR; 598 errno = feb.rv; 599 rv = -1; 600 } 601 602 return rv; 603 } 604 605 void 606 puffs__framev_notify(struct puffs_fctrl_io *fio, int what) 607 { 608 struct puffs_fbevent *fbevp; 609 610 restart: 611 LIST_FOREACH(fbevp, &fio->ev_qing, pfe_entries) { 612 if (fbevp->what & what) { 613 fbevp->what = what; 614 fbevp->rv = 0; 615 LIST_REMOVE(fbevp, pfe_entries); 616 puffs_cc_continue(fbevp->pcc); 617 goto restart; 618 } 619 } 620 } 621 622 static struct puffs_framebuf * 623 findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 624 struct puffs_fctrl_io *fio, struct puffs_framebuf *findme) 625 { 626 struct puffs_framebuf *cand; 627 int notresp = 0; 628 629 TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries) 630 if (fctrl->cmpfb(pu, findme, cand, ¬resp) == 0 || notresp) 631 break; 632 633 assert(!(notresp && cand == NULL)); 634 if (notresp || cand == NULL) 635 return NULL; 636 637 TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries); 638 return cand; 639 } 640 641 void 642 puffs__framebuf_moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to) 643 { 644 645 assert(from->istat & ISTAT_INTERNAL); 646 647 /* migrate buffer */ 648 free(to->buf); 649 to->buf = from->buf; 650 651 /* migrate buffer info */ 652 to->len = from->len; 653 to->offset = from->offset; 654 to->maxoff = from->maxoff; 655 656 from->buf = NULL; 657 from->len = 0; 658 } 659 660 void 661 puffs__framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 662 struct puffs_fctrl_io *fio) 663 { 664 struct puffs_framebuf *pufbuf, *appbuf; 665 int rv, complete; 666 667 while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) { 668 if ((pufbuf = fio->cur_in) == NULL) { 669 pufbuf = puffs_framebuf_make(); 670 if (pufbuf == NULL) 671 return; 672 pufbuf->istat |= ISTAT_INTERNAL; 673 fio->cur_in = pufbuf; 674 } 675 676 complete = 0; 677 rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete); 678 679 /* error */ 680 if (rv) { 681 puffs__framev_readclose(pu, fio, rv); 682 fio->cur_in = NULL; 683 return; 684 } 685 686 /* partial read, come back to fight another day */ 687 if (complete == 0) 688 break; 689 690 /* else: full read, process */ 691 fio->cur_in = NULL; 692 if ((pufbuf->istat & ISTAT_DIRECT) == 0) { 693 appbuf = findbuf(pu, fctrl, fio, pufbuf); 694 695 /* 696 * No request for this frame? If fs implements 697 * gotfb, give frame to that. Otherwise drop it. 698 */ 699 if (appbuf == NULL) { 700 if (fctrl->gotfb) { 701 pufbuf->istat &= ~ISTAT_INTERNAL; 702 fctrl->gotfb(pu, pufbuf); 703 } else { 704 puffs_framebuf_destroy(pufbuf); 705 } 706 continue; 707 } 708 709 puffs__framebuf_moveinfo(pufbuf, appbuf); 710 puffs_framebuf_destroy(pufbuf); 711 } else { 712 appbuf = pufbuf; 713 } 714 appbuf->istat &= ~ISTAT_NODESTROY; 715 716 if (appbuf->pcc) { 717 puffs__cc_cont(appbuf->pcc); 718 } else if (appbuf->fcb) { 719 appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0); 720 } else { 721 puffs_framebuf_destroy(appbuf); 722 } 723 724 /* hopeless romantics, here we go again */ 725 } 726 } 727 728 int 729 puffs__framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 730 struct puffs_fctrl_io *fio) 731 { 732 struct puffs_framebuf *pufbuf; 733 int rv, complete, done; 734 735 if (fio->stat & FIO_DEAD) 736 return 0; 737 738 for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0; 739 pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W; 740 pufbuf = TAILQ_FIRST(&fio->snd_qing)) { 741 complete = 0; 742 rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete); 743 744 if (rv) { 745 puffs__framev_writeclose(pu, fio, rv); 746 done = 1; 747 break; 748 } 749 750 /* partial write */ 751 if (complete == 0) 752 return done; 753 754 /* else, complete write */ 755 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries); 756 757 /* can't wait for result if we can't read */ 758 if (fio->stat & FIO_RDGONE) { 759 errnotify(pu, pufbuf, ENXIO); 760 done = 1; 761 } else if ((pufbuf->istat & ISTAT_DIRECT)) { 762 pufbuf->istat &= ~ISTAT_NODESTROY; 763 done = 1; 764 puffs__cc_cont(pufbuf->pcc); 765 } else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) { 766 TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf, 767 pfb_entries); 768 } else { 769 pufbuf->istat &= ~ISTAT_NODESTROY; 770 puffs_framebuf_destroy(pufbuf); 771 } 772 773 /* omstart! */ 774 } 775 776 return done; 777 } 778 779 int 780 puffs__framev_addfd_ctrl(struct puffs_usermount *pu, int fd, int what, 781 struct puffs_framectrl *pfctrl) 782 { 783 struct puffs_fctrl_io *fio; 784 struct kevent *newevs; 785 struct kevent kev[2]; 786 size_t nevs; 787 int rv, readenable; 788 789 nevs = pu->pu_nevs+2; 790 newevs = realloc(pu->pu_evs, nevs*sizeof(struct kevent)); 791 if (newevs == NULL) 792 return -1; 793 pu->pu_evs = newevs; 794 795 fio = malloc(sizeof(struct puffs_fctrl_io)); 796 if (fio == NULL) 797 return -1; 798 memset(fio, 0, sizeof(struct puffs_fctrl_io)); 799 fio->io_fd = fd; 800 fio->cur_in = NULL; 801 fio->fctrl = pfctrl; 802 TAILQ_INIT(&fio->snd_qing); 803 TAILQ_INIT(&fio->res_qing); 804 LIST_INIT(&fio->ev_qing); 805 806 readenable = 0; 807 if ((what & PUFFS_FBIO_READ) == 0) 808 readenable = EV_DISABLE; 809 810 if (pu->pu_state & PU_INLOOP) { 811 EV_SET(&kev[0], fd, EVFILT_READ, 812 EV_ADD|readenable, 0, 0, (intptr_t)fio); 813 EV_SET(&kev[1], fd, EVFILT_WRITE, 814 EV_ADD|EV_DISABLE, 0, 0, (intptr_t)fio); 815 rv = kevent(pu->pu_kq, kev, 2, NULL, 0, NULL); 816 if (rv == -1) { 817 free(fio); 818 return -1; 819 } 820 } 821 if (what & PUFFS_FBIO_READ) 822 fio->stat |= FIO_ENABLE_R; 823 if (what & PUFFS_FBIO_WRITE) 824 fio->stat |= FIO_ENABLE_W; 825 826 LIST_INSERT_HEAD(&pu->pu_ios, fio, fio_entries); 827 pu->pu_nevs = nevs; 828 829 return 0; 830 } 831 832 int 833 puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what) 834 { 835 836 return puffs__framev_addfd_ctrl(pu, fd, what, 837 &pu->pu_framectrl[PU_FRAMECTRL_USER]); 838 } 839 840 /* 841 * XXX: the following en/disable should be coalesced and executed 842 * only during the actual kevent call. So feel free to fix if 843 * threatened by mindblowing boredom. 844 */ 845 846 int 847 puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what) 848 { 849 struct kevent kev; 850 struct puffs_fctrl_io *fio; 851 int rv = 0; 852 853 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0); 854 855 fio = getfiobyfd(pu, fd); 856 if (fio == NULL) { 857 errno = ENXIO; 858 return -1; 859 } 860 861 /* write is enabled in the event loop if there is output */ 862 if (what & PUFFS_FBIO_READ && fio->rwait == 0) { 863 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, (uintptr_t)fio); 864 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 865 } 866 867 if (rv == 0) { 868 if (what & PUFFS_FBIO_READ) 869 fio->stat |= FIO_ENABLE_R; 870 if (what & PUFFS_FBIO_WRITE) 871 fio->stat |= FIO_ENABLE_W; 872 } 873 874 return rv; 875 } 876 877 int 878 puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what) 879 { 880 struct kevent kev[2]; 881 struct puffs_fctrl_io *fio; 882 size_t i; 883 int rv; 884 885 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0); 886 887 fio = getfiobyfd(pu, fd); 888 if (fio == NULL) { 889 errno = ENXIO; 890 return -1; 891 } 892 893 i = 0; 894 if (what & PUFFS_FBIO_READ && fio->rwait == 0) { 895 EV_SET(&kev[0], fd, 896 EVFILT_READ, EV_DISABLE, 0, 0, (uintptr_t)fio); 897 i++; 898 } 899 if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) { 900 EV_SET(&kev[1], fd, 901 EVFILT_WRITE, EV_DISABLE, 0, 0, (uintptr_t)fio); 902 i++; 903 } 904 if (i) 905 rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL); 906 else 907 rv = 0; 908 909 if (rv == 0) { 910 if (what & PUFFS_FBIO_READ) 911 fio->stat &= ~FIO_ENABLE_R; 912 if (what & PUFFS_FBIO_WRITE) 913 fio->stat &= ~FIO_ENABLE_W; 914 } 915 916 return rv; 917 } 918 919 void 920 puffs__framev_readclose(struct puffs_usermount *pu, 921 struct puffs_fctrl_io *fio, int error) 922 { 923 struct puffs_framebuf *pufbuf; 924 struct kevent kev; 925 int notflag; 926 927 if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD) 928 return; 929 fio->stat |= FIO_RDGONE; 930 931 if (fio->cur_in) { 932 if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) { 933 puffs_framebuf_destroy(fio->cur_in); 934 fio->cur_in = NULL; 935 } else { 936 errnotify(pu, fio->cur_in, error); 937 } 938 } 939 940 while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) { 941 TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries); 942 errnotify(pu, pufbuf, error); 943 } 944 945 EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0); 946 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 947 948 notflag = PUFFS_FBIO_READ; 949 if (fio->stat & FIO_WRGONE) 950 notflag |= PUFFS_FBIO_WRITE; 951 952 if (fio->fctrl->fdnotfn) 953 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag); 954 } 955 956 void 957 puffs__framev_writeclose(struct puffs_usermount *pu, 958 struct puffs_fctrl_io *fio, int error) 959 { 960 struct puffs_framebuf *pufbuf; 961 struct kevent kev; 962 int notflag; 963 964 if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD) 965 return; 966 fio->stat |= FIO_WRGONE; 967 968 while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) { 969 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries); 970 errnotify(pu, pufbuf, error); 971 } 972 973 EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); 974 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 975 976 notflag = PUFFS_FBIO_WRITE; 977 if (fio->stat & FIO_RDGONE) 978 notflag |= PUFFS_FBIO_READ; 979 980 if (fio->fctrl->fdnotfn) 981 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag); 982 } 983 984 static int 985 removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error) 986 { 987 struct puffs_fbevent *fbevp; 988 989 LIST_REMOVE(fio, fio_entries); 990 if (pu->pu_state & PU_INLOOP) { 991 puffs__framev_readclose(pu, fio, error); 992 puffs__framev_writeclose(pu, fio, error); 993 } 994 995 while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) { 996 fbevp->rv = error; 997 LIST_REMOVE(fbevp, pfe_entries); 998 puffs__goto(fbevp->pcc); 999 } 1000 1001 /* don't bother with realloc */ 1002 pu->pu_nevs -= 2; 1003 1004 /* don't free us yet, might have some references in event arrays */ 1005 fio->stat |= FIO_DEAD; 1006 LIST_INSERT_HEAD(&pu->pu_ios_rmlist, fio, fio_entries); 1007 1008 return 0; 1009 1010 } 1011 1012 int 1013 puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error) 1014 { 1015 struct puffs_fctrl_io *fio; 1016 1017 fio = getfiobyfd(pu, fd); 1018 if (fio == NULL) { 1019 errno = ENXIO; 1020 return -1; 1021 } 1022 1023 return removefio(pu, fio, error ? error : ECONNRESET); 1024 } 1025 1026 void 1027 puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what) 1028 { 1029 1030 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) 1031 (void) puffs_framev_removefd(pu, fd, ECONNRESET); 1032 } 1033 1034 void 1035 puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what) 1036 { 1037 1038 /* XXX & X: unmount is non-sensible */ 1039 puffs_framev_removeonclose(pu, fd, what); 1040 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) 1041 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED); 1042 } 1043 1044 void 1045 puffs_framev_init(struct puffs_usermount *pu, 1046 puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb, 1047 puffs_framev_cmpframe_fn cmpfb, puffs_framev_gotframe_fn gotfb, 1048 puffs_framev_fdnotify_fn fdnotfn) 1049 { 1050 struct puffs_framectrl *pfctrl; 1051 1052 pfctrl = &pu->pu_framectrl[PU_FRAMECTRL_USER]; 1053 pfctrl->rfb = rfb; 1054 pfctrl->wfb = wfb; 1055 pfctrl->cmpfb = cmpfb; 1056 pfctrl->gotfb = gotfb; 1057 pfctrl->fdnotfn = fdnotfn; 1058 } 1059 1060 void 1061 puffs__framev_exit(struct puffs_usermount *pu) 1062 { 1063 struct puffs_fctrl_io *fio; 1064 1065 while ((fio = LIST_FIRST(&pu->pu_ios)) != NULL) 1066 removefio(pu, fio, ENXIO); 1067 free(pu->pu_evs); 1068 1069 /* closing pu->pu_kq takes care of puffsfd */ 1070 } 1071