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