1 /* $NetBSD: framebuf.c,v 1.35 2017/06/14 16:39:41 christos 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.35 2017/06/14 16:39:41 christos 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(void) 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, 0, 0, fio); 562 563 if (kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL) == -1) 564 return -1; 565 566 if (*what & PUFFS_FBIO_READ) 567 fio->rwait++; 568 if (*what & PUFFS_FBIO_WRITE) 569 fio->wwait++; 570 571 LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries); 572 puffs_cc_yield(pcc); 573 574 assert(svwhat == *what); 575 576 if (*what & PUFFS_FBIO_READ) { 577 fio->rwait--; 578 if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) { 579 EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE, 0, 0, fio); 580 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 581 #if 0 582 if (rv != 0) 583 /* XXXXX oh dear */; 584 #endif 585 } 586 } 587 if (*what & PUFFS_FBIO_WRITE) 588 fio->wwait--; 589 590 if (feb.rv == 0) { 591 *what = feb.what; 592 rv = 0; 593 } else { 594 *what = PUFFS_FBIO_ERROR; 595 errno = feb.rv; 596 rv = -1; 597 } 598 599 return rv; 600 } 601 602 void 603 puffs__framev_notify(struct puffs_fctrl_io *fio, int what) 604 { 605 struct puffs_fbevent *fbevp; 606 607 restart: 608 LIST_FOREACH(fbevp, &fio->ev_qing, pfe_entries) { 609 if (fbevp->what & what) { 610 fbevp->what = what; 611 fbevp->rv = 0; 612 LIST_REMOVE(fbevp, pfe_entries); 613 puffs_cc_continue(fbevp->pcc); 614 goto restart; 615 } 616 } 617 } 618 619 static struct puffs_framebuf * 620 findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 621 struct puffs_fctrl_io *fio, struct puffs_framebuf *findme) 622 { 623 struct puffs_framebuf *cand; 624 int notresp = 0; 625 626 TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries) 627 if (fctrl->cmpfb(pu, findme, cand, ¬resp) == 0 || notresp) 628 break; 629 630 assert(!(notresp && cand == NULL)); 631 if (notresp || cand == NULL) 632 return NULL; 633 634 TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries); 635 return cand; 636 } 637 638 void 639 puffs__framebuf_moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to) 640 { 641 642 assert(from->istat & ISTAT_INTERNAL); 643 644 /* migrate buffer */ 645 free(to->buf); 646 to->buf = from->buf; 647 648 /* migrate buffer info */ 649 to->len = from->len; 650 to->offset = from->offset; 651 to->maxoff = from->maxoff; 652 653 from->buf = NULL; 654 from->len = 0; 655 } 656 657 void 658 puffs__framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 659 struct puffs_fctrl_io *fio) 660 { 661 struct puffs_framebuf *pufbuf, *appbuf; 662 int rv, complete; 663 664 while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) { 665 if ((pufbuf = fio->cur_in) == NULL) { 666 pufbuf = puffs_framebuf_make(); 667 if (pufbuf == NULL) 668 return; 669 pufbuf->istat |= ISTAT_INTERNAL; 670 fio->cur_in = pufbuf; 671 } 672 673 complete = 0; 674 rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete); 675 676 /* error */ 677 if (rv) { 678 puffs__framev_readclose(pu, fio, rv); 679 fio->cur_in = NULL; 680 return; 681 } 682 683 /* partial read, come back to fight another day */ 684 if (complete == 0) 685 break; 686 687 /* else: full read, process */ 688 fio->cur_in = NULL; 689 if ((pufbuf->istat & ISTAT_DIRECT) == 0) { 690 appbuf = findbuf(pu, fctrl, fio, pufbuf); 691 692 /* 693 * No request for this frame? If fs implements 694 * gotfb, give frame to that. Otherwise drop it. 695 */ 696 if (appbuf == NULL) { 697 if (fctrl->gotfb) { 698 pufbuf->istat &= ~ISTAT_INTERNAL; 699 fctrl->gotfb(pu, pufbuf); 700 } else { 701 puffs_framebuf_destroy(pufbuf); 702 } 703 continue; 704 } 705 706 puffs__framebuf_moveinfo(pufbuf, appbuf); 707 puffs_framebuf_destroy(pufbuf); 708 } else { 709 appbuf = pufbuf; 710 } 711 appbuf->istat &= ~ISTAT_NODESTROY; 712 713 if (appbuf->pcc) { 714 puffs__cc_cont(appbuf->pcc); 715 } else if (appbuf->fcb) { 716 appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0); 717 } else { 718 puffs_framebuf_destroy(appbuf); 719 } 720 721 /* hopeless romantics, here we go again */ 722 } 723 } 724 725 int 726 puffs__framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 727 struct puffs_fctrl_io *fio) 728 { 729 struct puffs_framebuf *pufbuf; 730 int rv, complete, done; 731 732 if (fio->stat & FIO_DEAD) 733 return 0; 734 735 for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0; 736 pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W; 737 pufbuf = TAILQ_FIRST(&fio->snd_qing)) { 738 complete = 0; 739 rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete); 740 741 if (rv) { 742 puffs__framev_writeclose(pu, fio, rv); 743 done = 1; 744 break; 745 } 746 747 /* partial write */ 748 if (complete == 0) 749 return done; 750 751 /* else, complete write */ 752 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries); 753 754 /* can't wait for result if we can't read */ 755 if (fio->stat & FIO_RDGONE) { 756 errnotify(pu, pufbuf, ENXIO); 757 done = 1; 758 } else if ((pufbuf->istat & ISTAT_DIRECT)) { 759 pufbuf->istat &= ~ISTAT_NODESTROY; 760 done = 1; 761 puffs__cc_cont(pufbuf->pcc); 762 } else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) { 763 TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf, 764 pfb_entries); 765 } else { 766 pufbuf->istat &= ~ISTAT_NODESTROY; 767 puffs_framebuf_destroy(pufbuf); 768 } 769 770 /* omstart! */ 771 } 772 773 return done; 774 } 775 776 int 777 puffs__framev_addfd_ctrl(struct puffs_usermount *pu, int fd, int what, 778 struct puffs_framectrl *pfctrl) 779 { 780 struct puffs_fctrl_io *fio; 781 struct kevent *newevs; 782 struct kevent kev[2]; 783 size_t nevs; 784 int rv, readenable; 785 786 nevs = pu->pu_nevs+2; 787 newevs = realloc(pu->pu_evs, nevs*sizeof(struct kevent)); 788 if (newevs == NULL) 789 return -1; 790 pu->pu_evs = newevs; 791 792 fio = malloc(sizeof(struct puffs_fctrl_io)); 793 if (fio == NULL) 794 return -1; 795 memset(fio, 0, sizeof(struct puffs_fctrl_io)); 796 fio->io_fd = fd; 797 fio->cur_in = NULL; 798 fio->fctrl = pfctrl; 799 TAILQ_INIT(&fio->snd_qing); 800 TAILQ_INIT(&fio->res_qing); 801 LIST_INIT(&fio->ev_qing); 802 803 readenable = 0; 804 if ((what & PUFFS_FBIO_READ) == 0) 805 readenable = EV_DISABLE; 806 807 if (pu->pu_state & PU_INLOOP) { 808 struct stat st; 809 size_t nf = 0; 810 811 if (fstat(fd, &st) == -1) 812 goto out; 813 EV_SET(&kev[nf], fd, EVFILT_READ, EV_ADD|readenable, 0, 0, fio); 814 nf++; 815 if (S_ISSOCK(st.st_mode)) { 816 EV_SET(&kev[nf], fd, EVFILT_WRITE, 817 EV_ADD|EV_DISABLE, 0, 0, fio); 818 nf++; 819 } 820 rv = kevent(pu->pu_kq, kev, nf, NULL, 0, NULL); 821 if (rv == -1) 822 goto out; 823 } 824 if (what & PUFFS_FBIO_READ) 825 fio->stat |= FIO_ENABLE_R; 826 if (what & PUFFS_FBIO_WRITE) 827 fio->stat |= FIO_ENABLE_W; 828 829 LIST_INSERT_HEAD(&pu->pu_ios, fio, fio_entries); 830 pu->pu_nevs = nevs; 831 832 return 0; 833 out: 834 free(fio); 835 return -1; 836 } 837 838 int 839 puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what) 840 { 841 842 return puffs__framev_addfd_ctrl(pu, fd, what, 843 &pu->pu_framectrl[PU_FRAMECTRL_USER]); 844 } 845 846 /* 847 * XXX: the following en/disable should be coalesced and executed 848 * only during the actual kevent call. So feel free to fix if 849 * threatened by mindblowing boredom. 850 */ 851 852 int 853 puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what) 854 { 855 struct kevent kev; 856 struct puffs_fctrl_io *fio; 857 int rv = 0; 858 859 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0); 860 861 fio = getfiobyfd(pu, fd); 862 if (fio == NULL) { 863 errno = ENXIO; 864 return -1; 865 } 866 867 /* write is enabled in the event loop if there is output */ 868 if (what & PUFFS_FBIO_READ && fio->rwait == 0) { 869 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, fio); 870 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 871 } 872 873 if (rv == 0) { 874 if (what & PUFFS_FBIO_READ) 875 fio->stat |= FIO_ENABLE_R; 876 if (what & PUFFS_FBIO_WRITE) 877 fio->stat |= FIO_ENABLE_W; 878 } 879 880 return rv; 881 } 882 883 int 884 puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what) 885 { 886 struct kevent kev[2]; 887 struct puffs_fctrl_io *fio; 888 size_t i; 889 int rv; 890 891 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0); 892 893 fio = getfiobyfd(pu, fd); 894 if (fio == NULL) { 895 errno = ENXIO; 896 return -1; 897 } 898 899 i = 0; 900 if (what & PUFFS_FBIO_READ && fio->rwait == 0) { 901 EV_SET(&kev[0], fd, EVFILT_READ, EV_DISABLE, 0, 0, fio); 902 i++; 903 } 904 if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) { 905 EV_SET(&kev[1], fd, EVFILT_WRITE, EV_DISABLE, 0, 0, fio); 906 i++; 907 } 908 if (i) 909 rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL); 910 else 911 rv = 0; 912 913 if (rv == 0) { 914 if (what & PUFFS_FBIO_READ) 915 fio->stat &= ~FIO_ENABLE_R; 916 if (what & PUFFS_FBIO_WRITE) 917 fio->stat &= ~FIO_ENABLE_W; 918 } 919 920 return rv; 921 } 922 923 void 924 puffs__framev_readclose(struct puffs_usermount *pu, 925 struct puffs_fctrl_io *fio, int error) 926 { 927 struct puffs_framebuf *pufbuf; 928 struct kevent kev; 929 int notflag; 930 931 if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD) 932 return; 933 fio->stat |= FIO_RDGONE; 934 935 if (fio->cur_in) { 936 if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) { 937 puffs_framebuf_destroy(fio->cur_in); 938 fio->cur_in = NULL; 939 } else { 940 errnotify(pu, fio->cur_in, error); 941 } 942 } 943 944 while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) { 945 TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries); 946 errnotify(pu, pufbuf, error); 947 } 948 949 EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0); 950 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 951 952 notflag = PUFFS_FBIO_READ; 953 if (fio->stat & FIO_WRGONE) 954 notflag |= PUFFS_FBIO_WRITE; 955 956 if (fio->fctrl->fdnotfn) 957 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag); 958 } 959 960 void 961 puffs__framev_writeclose(struct puffs_usermount *pu, 962 struct puffs_fctrl_io *fio, int error) 963 { 964 struct puffs_framebuf *pufbuf; 965 struct kevent kev; 966 int notflag; 967 968 if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD) 969 return; 970 fio->stat |= FIO_WRGONE; 971 972 while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) { 973 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries); 974 errnotify(pu, pufbuf, error); 975 } 976 977 EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); 978 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 979 980 notflag = PUFFS_FBIO_WRITE; 981 if (fio->stat & FIO_RDGONE) 982 notflag |= PUFFS_FBIO_READ; 983 984 if (fio->fctrl->fdnotfn) 985 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag); 986 } 987 988 static int 989 removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error) 990 { 991 struct puffs_fbevent *fbevp; 992 993 LIST_REMOVE(fio, fio_entries); 994 if (pu->pu_state & PU_INLOOP) { 995 puffs__framev_readclose(pu, fio, error); 996 puffs__framev_writeclose(pu, fio, error); 997 } 998 999 while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) { 1000 fbevp->rv = error; 1001 LIST_REMOVE(fbevp, pfe_entries); 1002 puffs__goto(fbevp->pcc); 1003 } 1004 1005 /* don't bother with realloc */ 1006 pu->pu_nevs -= 2; 1007 1008 /* don't free us yet, might have some references in event arrays */ 1009 fio->stat |= FIO_DEAD; 1010 LIST_INSERT_HEAD(&pu->pu_ios_rmlist, fio, fio_entries); 1011 1012 return 0; 1013 1014 } 1015 1016 int 1017 puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error) 1018 { 1019 struct puffs_fctrl_io *fio; 1020 1021 fio = getfiobyfd(pu, fd); 1022 if (fio == NULL) { 1023 errno = ENXIO; 1024 return -1; 1025 } 1026 1027 return removefio(pu, fio, error ? error : ECONNRESET); 1028 } 1029 1030 void 1031 puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what) 1032 { 1033 1034 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) 1035 (void) puffs_framev_removefd(pu, fd, ECONNRESET); 1036 } 1037 1038 void 1039 puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what) 1040 { 1041 1042 /* XXX & X: unmount is non-sensible */ 1043 puffs_framev_removeonclose(pu, fd, what); 1044 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) 1045 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED); 1046 } 1047 1048 void 1049 puffs_framev_init(struct puffs_usermount *pu, 1050 puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb, 1051 puffs_framev_cmpframe_fn cmpfb, puffs_framev_gotframe_fn gotfb, 1052 puffs_framev_fdnotify_fn fdnotfn) 1053 { 1054 struct puffs_framectrl *pfctrl; 1055 1056 pfctrl = &pu->pu_framectrl[PU_FRAMECTRL_USER]; 1057 pfctrl->rfb = rfb; 1058 pfctrl->wfb = wfb; 1059 pfctrl->cmpfb = cmpfb; 1060 pfctrl->gotfb = gotfb; 1061 pfctrl->fdnotfn = fdnotfn; 1062 } 1063 1064 void 1065 puffs__framev_exit(struct puffs_usermount *pu) 1066 { 1067 struct puffs_fctrl_io *fio; 1068 1069 while ((fio = LIST_FIRST(&pu->pu_ios)) != NULL) 1070 removefio(pu, fio, ENXIO); 1071 free(pu->pu_evs); 1072 1073 /* closing pu->pu_kq takes care of puffsfd */ 1074 } 1075