1 /* $NetBSD: framebuf.c,v 1.25 2007/12/04 21:24:11 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.25 2007/12/04 21:24:11 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 = puffs_cc_getusermount(pcc); 359 struct puffs_fctrl_io *fio; 360 361 /* 362 * Technically we shouldn't allow this is 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 GETFIO(fd); 424 425 pufbuf->pcc = NULL; 426 pufbuf->fcb = NULL; 427 pufbuf->fcb_arg = NULL; 428 429 pufbuf->offset = 0; 430 pufbuf->istat |= ISTAT_NODESTROY; 431 if (!reply) 432 pufbuf->istat |= ISTAT_NOREPLY; 433 434 if (flags & PUFFS_FBQUEUE_URGENT) 435 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries); 436 else 437 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries); 438 439 return 0; 440 } 441 442 /* ARGSUSED */ 443 int 444 puffs_framev_enqueue_directreceive(struct puffs_cc *pcc, int fd, 445 struct puffs_framebuf *pufbuf, int flags /* used in the future */) 446 { 447 struct puffs_usermount *pu = puffs_cc_getusermount(pcc); 448 struct puffs_fctrl_io *fio; 449 450 fio = getfiobyfd(pu, fd); 451 if (fio == NULL) { 452 errno = EINVAL; 453 return -1; 454 } 455 456 /* XXX: should have cur_in queue */ 457 assert(fio->cur_in == NULL); 458 fio->cur_in = pufbuf; 459 460 pufbuf->pcc = pcc; 461 pufbuf->fcb = NULL; 462 pufbuf->fcb_arg = NULL; 463 464 pufbuf->offset = 0; 465 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT; 466 467 puffs_cc_yield(pcc); 468 pufbuf->istat &= ~ISTAT_NODESTROY; /* XXX: not the right place */ 469 if (pufbuf->rv) { 470 errno = pufbuf->rv; 471 return -1; 472 } 473 474 return 0; 475 } 476 477 int 478 puffs_framev_enqueue_directsend(struct puffs_cc *pcc, int fd, 479 struct puffs_framebuf *pufbuf, int flags) 480 { 481 struct puffs_usermount *pu = puffs_cc_getusermount(pcc); 482 struct puffs_fctrl_io *fio; 483 484 if (flags & PUFFS_FBQUEUE_URGENT) 485 abort(); /* EOPNOTSUPP for now */ 486 487 GETFIO(fd); 488 489 pufbuf->pcc = pcc; 490 pufbuf->fcb = NULL; 491 pufbuf->fcb_arg = NULL; 492 493 pufbuf->offset = 0; 494 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT; 495 496 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries); 497 498 puffs_cc_yield(pcc); 499 if (pufbuf->rv) { 500 pufbuf->istat &= ~ISTAT_NODESTROY; 501 errno = pufbuf->rv; 502 return -1; 503 } 504 505 return 0; 506 } 507 508 int 509 puffs_framev_framebuf_ccpromote(struct puffs_framebuf *pufbuf, 510 struct puffs_cc *pcc) 511 { 512 513 if ((pufbuf->istat & ISTAT_ONQUEUE) == 0) { 514 errno = EBUSY; 515 return -1; 516 } 517 518 pufbuf->pcc = pcc; 519 pufbuf->fcb = NULL; 520 pufbuf->fcb_arg = NULL; 521 pufbuf->istat &= ~ISTAT_NOREPLY; 522 523 puffs_cc_yield(pcc); 524 525 return 0; 526 } 527 528 int 529 puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what) 530 { 531 struct puffs_usermount *pu = puffs_cc_getusermount(pcc); 532 struct puffs_fctrl_io *fio; 533 struct puffs_fbevent feb; 534 struct kevent kev; 535 int rv, svwhat; 536 537 svwhat = *what; 538 539 if (*what == 0) { 540 errno = EINVAL; 541 return -1; 542 } 543 544 fio = getfiobyfd(pu, fd); 545 if (fio == NULL) { 546 errno = EINVAL; 547 return -1; 548 } 549 550 feb.pcc = pcc; 551 feb.what = *what & (PUFFS_FBIO_READ|PUFFS_FBIO_WRITE|PUFFS_FBIO_ERROR); 552 553 if (*what & PUFFS_FBIO_READ) 554 if ((fio->stat & FIO_ENABLE_R) == 0) 555 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 556 0, 0, (uintptr_t)fio); 557 558 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 559 if (rv != 0) 560 return errno; 561 562 if (*what & PUFFS_FBIO_READ) 563 fio->rwait++; 564 if (*what & PUFFS_FBIO_WRITE) 565 fio->wwait++; 566 567 LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries); 568 puffs_cc_yield(pcc); 569 570 assert(svwhat == *what); 571 572 if (*what & PUFFS_FBIO_READ) { 573 fio->rwait--; 574 if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) { 575 EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE, 576 0, 0, (uintptr_t)fio); 577 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 578 #if 0 579 if (rv != 0) 580 /* XXXXX oh dear */; 581 #endif 582 } 583 } 584 if (*what & PUFFS_FBIO_WRITE) 585 fio->wwait--; 586 587 if (feb.rv == 0) { 588 *what = feb.what; 589 rv = 0; 590 } else { 591 *what = PUFFS_FBIO_ERROR; 592 errno = feb.rv; 593 rv = -1; 594 } 595 596 return rv; 597 } 598 599 void 600 puffs_framev_notify(struct puffs_fctrl_io *fio, int what) 601 { 602 struct puffs_fbevent *fbevp; 603 604 restart: 605 LIST_FOREACH(fbevp, &fio->ev_qing, pfe_entries) { 606 if (fbevp->what & what) { 607 fbevp->what = what; 608 fbevp->rv = 0; 609 LIST_REMOVE(fbevp, pfe_entries); 610 puffs_cc_continue(fbevp->pcc); 611 goto restart; 612 } 613 } 614 } 615 616 static struct puffs_framebuf * 617 findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 618 struct puffs_fctrl_io *fio, struct puffs_framebuf *findme) 619 { 620 struct puffs_framebuf *cand; 621 int notresp = 0; 622 623 TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries) 624 if (fctrl->cmpfb(pu, findme, cand, ¬resp) == 0 || notresp) 625 break; 626 627 assert(!(notresp && cand == NULL)); 628 if (notresp || cand == NULL) 629 return NULL; 630 631 TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries); 632 return cand; 633 } 634 635 void 636 puffs__framebuf_moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to) 637 { 638 639 assert(from->istat & ISTAT_INTERNAL); 640 641 /* migrate buffer */ 642 free(to->buf); 643 to->buf = from->buf; 644 645 /* migrate buffer info */ 646 to->len = from->len; 647 to->offset = from->offset; 648 to->maxoff = from->maxoff; 649 650 from->buf = NULL; 651 from->len = 0; 652 } 653 654 void 655 puffs_framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 656 struct puffs_fctrl_io *fio) 657 { 658 struct puffs_framebuf *pufbuf, *appbuf; 659 int rv, complete; 660 661 while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) { 662 if ((pufbuf = fio->cur_in) == NULL) { 663 pufbuf = puffs_framebuf_make(); 664 if (pufbuf == NULL) 665 return; 666 pufbuf->istat |= ISTAT_INTERNAL; 667 fio->cur_in = pufbuf; 668 } 669 670 complete = 0; 671 rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete); 672 673 /* error */ 674 if (rv) { 675 puffs_framev_readclose(pu, fio, rv); 676 fio->cur_in = NULL; 677 if ((pufbuf->istat & ISTAT_DIRECT) == 0) { 678 assert((pufbuf->istat & ISTAT_NODESTROY) == 0); 679 puffs_framebuf_destroy(pufbuf); 680 } 681 return; 682 } 683 684 /* partial read, come back to fight another day */ 685 if (complete == 0) 686 break; 687 688 /* else: full read, process */ 689 fio->cur_in = NULL; 690 if ((pufbuf->istat & ISTAT_DIRECT) == 0) { 691 appbuf = findbuf(pu, fctrl, fio, pufbuf); 692 693 /* 694 * No request for this frame? If fs implements 695 * gotfb, give frame to that. Otherwise drop it. 696 */ 697 if (appbuf == NULL) { 698 if (fctrl->gotfb) 699 fctrl->gotfb(pu, pufbuf); 700 701 /* XXX: ugly */ 702 pufbuf->istat &= ~ISTAT_NODESTROY; 703 puffs_framebuf_destroy(pufbuf); 704 continue; 705 } 706 707 puffs__framebuf_moveinfo(pufbuf, appbuf); 708 puffs_framebuf_destroy(pufbuf); 709 } else { 710 appbuf = pufbuf; 711 } 712 appbuf->istat &= ~ISTAT_NODESTROY; 713 714 if (appbuf->pcc) { 715 puffs_docc(appbuf->pcc); 716 } else if (appbuf->fcb) { 717 appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0); 718 } else { 719 puffs_framebuf_destroy(appbuf); 720 } 721 722 /* hopeless romantics, here we go again */ 723 } 724 } 725 726 int 727 puffs_framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 728 struct puffs_fctrl_io *fio) 729 { 730 struct puffs_framebuf *pufbuf; 731 int rv, complete, done; 732 733 if (fio->stat & FIO_DEAD) 734 return 0; 735 736 for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0; 737 pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W; 738 pufbuf = TAILQ_FIRST(&fio->snd_qing)) { 739 complete = 0; 740 rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete); 741 742 if (rv) { 743 puffs_framev_writeclose(pu, fio, rv); 744 done = 1; 745 break; 746 } 747 748 /* partial write */ 749 if (complete == 0) 750 return done; 751 752 /* else, complete write */ 753 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries); 754 755 /* can't wait for result if we can't read */ 756 if (fio->stat & FIO_RDGONE) { 757 errnotify(pu, pufbuf, ENXIO); 758 done = 1; 759 } else if ((pufbuf->istat & ISTAT_DIRECT)) { 760 pufbuf->istat &= ~ISTAT_NODESTROY; 761 puffs_docc(pufbuf->pcc); 762 done = 1; 763 } else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) { 764 TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf, 765 pfb_entries); 766 } else { 767 pufbuf->istat &= ~ISTAT_NODESTROY; 768 puffs_framebuf_destroy(pufbuf); 769 } 770 771 /* omstart! */ 772 } 773 774 return done; 775 } 776 777 int 778 puffs__framev_addfd_ctrl(struct puffs_usermount *pu, int fd, int what, 779 struct puffs_framectrl *pfctrl) 780 { 781 struct puffs_fctrl_io *fio; 782 struct kevent *newevs; 783 struct kevent kev[2]; 784 size_t nfds; 785 int rv, readenable; 786 787 nfds = pu->pu_nfds+1; 788 newevs = realloc(pu->pu_evs, (2*nfds) * sizeof(struct kevent)); 789 if (newevs == NULL) 790 return -1; 791 pu->pu_evs = newevs; 792 793 fio = malloc(sizeof(struct puffs_fctrl_io)); 794 if (fio == NULL) 795 return -1; 796 memset(fio, 0, sizeof(struct puffs_fctrl_io)); 797 fio->io_fd = fd; 798 fio->cur_in = NULL; 799 fio->fctrl = pfctrl; 800 TAILQ_INIT(&fio->snd_qing); 801 TAILQ_INIT(&fio->res_qing); 802 LIST_INIT(&fio->ev_qing); 803 804 readenable = 0; 805 if ((what & PUFFS_FBIO_READ) == 0) 806 readenable = EV_DISABLE; 807 808 if (pu->pu_state & PU_INLOOP) { 809 EV_SET(&kev[0], fd, EVFILT_READ, 810 EV_ADD|readenable, 0, 0, (intptr_t)fio); 811 EV_SET(&kev[1], fd, EVFILT_WRITE, 812 EV_ADD|EV_DISABLE, 0, 0, (intptr_t)fio); 813 rv = kevent(pu->pu_kq, kev, 2, NULL, 0, NULL); 814 if (rv == -1) { 815 free(fio); 816 return -1; 817 } 818 } 819 if (what & PUFFS_FBIO_READ) 820 fio->stat |= FIO_ENABLE_R; 821 if (what & PUFFS_FBIO_WRITE) 822 fio->stat |= FIO_ENABLE_W; 823 824 LIST_INSERT_HEAD(&pu->pu_ios, fio, fio_entries); 825 pu->pu_nfds = nfds; 826 827 return 0; 828 } 829 830 int 831 puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what) 832 { 833 834 return puffs__framev_addfd_ctrl(pu, fd, what, 835 &pu->pu_framectrl[PU_FRAMECTRL_USER]); 836 } 837 838 /* 839 * XXX: the following en/disable should be coalesced and executed 840 * only during the actual kevent call. So feel free to fix if 841 * threatened by mindblowing boredom. 842 */ 843 844 int 845 puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what) 846 { 847 struct kevent kev; 848 struct puffs_fctrl_io *fio; 849 int rv = 0; 850 851 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0); 852 853 fio = getfiobyfd(pu, fd); 854 if (fio == NULL) { 855 errno = ENXIO; 856 return -1; 857 } 858 859 /* write is enabled in the event loop if there is output */ 860 if (what & PUFFS_FBIO_READ && fio->rwait == 0) { 861 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, (uintptr_t)fio); 862 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 863 } 864 865 if (rv == 0) { 866 if (what & PUFFS_FBIO_READ) 867 fio->stat |= FIO_ENABLE_R; 868 if (what & PUFFS_FBIO_WRITE) 869 fio->stat |= FIO_ENABLE_W; 870 } 871 872 return rv; 873 } 874 875 int 876 puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what) 877 { 878 struct kevent kev[2]; 879 struct puffs_fctrl_io *fio; 880 size_t i; 881 int rv; 882 883 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0); 884 885 fio = getfiobyfd(pu, fd); 886 if (fio == NULL) { 887 errno = ENXIO; 888 return -1; 889 } 890 891 i = 0; 892 if (what & PUFFS_FBIO_READ && fio->rwait == 0) { 893 EV_SET(&kev[0], fd, 894 EVFILT_READ, EV_DISABLE, 0, 0, (uintptr_t)fio); 895 i++; 896 } 897 if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) { 898 EV_SET(&kev[1], fd, 899 EVFILT_WRITE, EV_DISABLE, 0, 0, (uintptr_t)fio); 900 i++; 901 } 902 if (i) 903 rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL); 904 else 905 rv = 0; 906 907 if (rv == 0) { 908 if (what & PUFFS_FBIO_READ) 909 fio->stat &= ~FIO_ENABLE_R; 910 if (what & PUFFS_FBIO_WRITE) 911 fio->stat &= ~FIO_ENABLE_W; 912 } 913 914 return rv; 915 } 916 917 void 918 puffs_framev_readclose(struct puffs_usermount *pu, 919 struct puffs_fctrl_io *fio, int error) 920 { 921 struct puffs_framebuf *pufbuf; 922 struct kevent kev; 923 int notflag; 924 925 if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD) 926 return; 927 fio->stat |= FIO_RDGONE; 928 929 if (fio->cur_in) { 930 if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) { 931 puffs_framebuf_destroy(fio->cur_in); 932 fio->cur_in = NULL; 933 } else { 934 errnotify(pu, fio->cur_in, error); 935 } 936 } 937 938 while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) { 939 TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries); 940 errnotify(pu, pufbuf, error); 941 } 942 943 EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0); 944 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 945 946 notflag = PUFFS_FBIO_READ; 947 if (fio->stat & FIO_WRGONE) 948 notflag |= PUFFS_FBIO_WRITE; 949 950 if (fio->fctrl->fdnotfn) 951 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag); 952 } 953 954 void 955 puffs_framev_writeclose(struct puffs_usermount *pu, 956 struct puffs_fctrl_io *fio, int error) 957 { 958 struct puffs_framebuf *pufbuf; 959 struct kevent kev; 960 int notflag; 961 962 if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD) 963 return; 964 fio->stat |= FIO_WRGONE; 965 966 while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) { 967 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries); 968 errnotify(pu, pufbuf, error); 969 } 970 971 EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); 972 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 973 974 notflag = PUFFS_FBIO_WRITE; 975 if (fio->stat & FIO_RDGONE) 976 notflag |= PUFFS_FBIO_READ; 977 978 if (fio->fctrl->fdnotfn) 979 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag); 980 } 981 982 static int 983 removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error) 984 { 985 struct puffs_fbevent *fbevp; 986 987 LIST_REMOVE(fio, fio_entries); 988 if (pu->pu_state & PU_INLOOP) { 989 puffs_framev_readclose(pu, fio, error); 990 puffs_framev_writeclose(pu, fio, error); 991 } 992 993 while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) { 994 fbevp->rv = error; 995 LIST_REMOVE(fbevp, pfe_entries); 996 puffs_goto(fbevp->pcc); 997 } 998 999 /* don't bother with realloc */ 1000 pu->pu_nfds--; 1001 1002 /* don't free us yet, might have some references in event arrays */ 1003 fio->stat |= FIO_DEAD; 1004 LIST_INSERT_HEAD(&pu->pu_ios_rmlist, fio, fio_entries); 1005 1006 return 0; 1007 1008 } 1009 1010 int 1011 puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error) 1012 { 1013 struct puffs_fctrl_io *fio; 1014 1015 fio = getfiobyfd(pu, fd); 1016 if (fio == NULL) { 1017 errno = ENXIO; 1018 return -1; 1019 } 1020 1021 return removefio(pu, fio, error ? error : ECONNRESET); 1022 } 1023 1024 void 1025 puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what) 1026 { 1027 1028 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) 1029 (void) puffs_framev_removefd(pu, fd, ECONNRESET); 1030 } 1031 1032 void 1033 puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what) 1034 { 1035 1036 /* XXX & X: unmount is non-sensible */ 1037 puffs_framev_removeonclose(pu, fd, what); 1038 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) 1039 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED); 1040 } 1041 1042 void 1043 puffs_framev_init(struct puffs_usermount *pu, 1044 puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb, 1045 puffs_framev_cmpframe_fn cmpfb, puffs_framev_gotframe_fn gotfb, 1046 puffs_framev_fdnotify_fn fdnotfn) 1047 { 1048 struct puffs_framectrl *pfctrl; 1049 1050 pfctrl = &pu->pu_framectrl[PU_FRAMECTRL_USER]; 1051 pfctrl->rfb = rfb; 1052 pfctrl->wfb = wfb; 1053 pfctrl->cmpfb = cmpfb; 1054 pfctrl->gotfb = gotfb; 1055 pfctrl->fdnotfn = fdnotfn; 1056 } 1057 1058 void 1059 puffs_framev_exit(struct puffs_usermount *pu) 1060 { 1061 struct puffs_fctrl_io *fio; 1062 1063 while ((fio = LIST_FIRST(&pu->pu_ios)) != NULL) 1064 removefio(pu, fio, ENXIO); 1065 free(pu->pu_evs); 1066 1067 /* closing pu->pu_kq takes care of puffsfd */ 1068 } 1069