1 /* $NetBSD: puffs.c,v 1.103 2010/01/07 22:49:19 pooka Exp $ */
4 * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
6 * Development of this software was supported by the
7 * Google Summer of Code program and the Ulla Tuominen Foundation.
8 * The Google SoC project was mentored by Bill Studenmund.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: puffs.c,v 1.103 2010/01/07 22:49:19 pooka Exp $");
37 #include <sys/param.h>
38 #include <sys/mount.h>
53 #include "puffs_priv.h"
55 /* Most file systems want this for opts, so just give it to them */
56 const struct mntopt puffsmopts
[] = {
62 #ifdef PUFFS_WITH_THREADS
64 pthread_mutex_t pu_lock
= PTHREAD_MUTEX_INITIALIZER
;
67 #define FILLOP(lower, upper) \
69 if (pops->puffs_node_##lower) \
70 opmask[PUFFS_VN_##upper] = 1; \
71 } while (/*CONSTCOND*/0)
73 fillvnopmask(struct puffs_ops
*pops
, uint8_t *opmask
)
76 memset(opmask
, 0, PUFFS_VN_MAX
);
78 FILLOP(create
, CREATE
);
82 FILLOP(access
, ACCESS
);
83 FILLOP(getattr
, GETATTR
);
84 FILLOP(setattr
, SETATTR
);
85 FILLOP(poll
, POLL
); /* XXX: not ready in kernel */
89 FILLOP(remove
, REMOVE
);
91 FILLOP(rename
, RENAME
);
94 FILLOP(symlink
, SYMLINK
);
95 FILLOP(readdir
, READDIR
);
96 FILLOP(readlink
, READLINK
);
97 FILLOP(reclaim
, RECLAIM
);
98 FILLOP(inactive
, INACTIVE
);
101 FILLOP(write
, WRITE
);
102 FILLOP(abortop
, ABORTOP
);
107 * Go over all framev entries and write everything we can. This is
108 * mostly for the benefit of delivering "unmount" to the kernel.
111 finalpush(struct puffs_usermount
*pu
)
113 struct puffs_fctrl_io
*fio
;
115 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
116 if (fio
->stat
& FIO_WRGONE
)
119 puffs__framev_output(pu
, fio
->fctrl
, fio
);
125 puffs_kernerr_abort(struct puffs_usermount
*pu
, uint8_t type
,
126 int error
, const char *str
, puffs_cookie_t cookie
)
129 fprintf(stderr
, "abort: type %d, error %d, cookie %p (%s)\n",
130 type
, error
, cookie
, str
);
136 puffs_kernerr_log(struct puffs_usermount
*pu
, uint8_t type
,
137 int error
, const char *str
, puffs_cookie_t cookie
)
140 syslog(LOG_WARNING
, "kernel: type %d, error %d, cookie %p (%s)\n",
141 type
, error
, cookie
, str
);
145 puffs_getselectable(struct puffs_usermount
*pu
)
152 puffs__nextreq(struct puffs_usermount
*pu
)
157 rv
= pu
->pu_nextreq
++ | (uint64_t)1<<63;
164 puffs_setblockingmode(struct puffs_usermount
*pu
, int mode
)
168 assert(puffs_getstate(pu
) == PUFFS_STATE_RUNNING
);
170 if (mode
!= PUFFSDEV_BLOCK
&& mode
!= PUFFSDEV_NONBLOCK
) {
176 rv
= ioctl(pu
->pu_fd
, FIONBIO
, &x
);
179 if (mode
== PUFFSDEV_BLOCK
)
180 pu
->pu_state
&= ~PU_ASYNCFD
;
182 pu
->pu_state
|= PU_ASYNCFD
;
189 puffs_getstate(struct puffs_usermount
*pu
)
192 return pu
->pu_state
& PU_STATEMASK
;
196 puffs_setstacksize(struct puffs_usermount
*pu
, size_t ss
)
202 assert(puffs_getstate(pu
) == PUFFS_STATE_BEFOREMOUNT
);
204 psize
= sysconf(_SC_PAGESIZE
);
206 if (ss
< (size_t)minsize
|| ss
== PUFFS_STACKSIZE_MIN
) {
207 if (ss
!= PUFFS_STACKSIZE_MIN
)
208 fprintf(stderr
, "puffs_setstacksize: adjusting "
209 "stacksize to minimum %ld\n", minsize
);
223 fprintf(stderr
, "puffs_setstacksize: using next power of two: "
224 "%d\n", 1<<stackshift
);
227 pu
->pu_cc_stackshift
= stackshift
;
230 struct puffs_pathobj
*
231 puffs_getrootpathobj(struct puffs_usermount
*pu
)
233 struct puffs_node
*pnr
;
235 pnr
= pu
->pu_pn_root
;
245 puffs_setroot(struct puffs_usermount
*pu
, struct puffs_node
*pn
)
252 puffs_getroot(struct puffs_usermount
*pu
)
255 return pu
->pu_pn_root
;
259 puffs_setrootinfo(struct puffs_usermount
*pu
, enum vtype vt
,
260 vsize_t vsize
, dev_t rdev
)
262 struct puffs_kargs
*pargs
= pu
->pu_kargp
;
264 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
) {
265 warnx("puffs_setrootinfo: call has effect only "
270 pargs
->pa_root_vtype
= vt
;
271 pargs
->pa_root_vsize
= vsize
;
272 pargs
->pa_root_rdev
= rdev
;
276 puffs_getspecific(struct puffs_usermount
*pu
)
279 return pu
->pu_privdata
;
283 puffs_setspecific(struct puffs_usermount
*pu
, void *privdata
)
286 pu
->pu_privdata
= privdata
;
290 puffs_setmntinfo(struct puffs_usermount
*pu
,
291 const char *mntfromname
, const char *puffsname
)
293 struct puffs_kargs
*pargs
= pu
->pu_kargp
;
295 (void)strlcpy(pargs
->pa_mntfromname
, mntfromname
,
296 sizeof(pargs
->pa_mntfromname
));
297 (void)strlcpy(pargs
->pa_typename
, puffsname
,
298 sizeof(pargs
->pa_typename
));
302 puffs_getmaxreqlen(struct puffs_usermount
*pu
)
305 return pu
->pu_maxreqlen
;
309 puffs_setmaxreqlen(struct puffs_usermount
*pu
, size_t reqlen
)
312 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
)
313 warnx("puffs_setmaxreqlen: call has effect only "
316 pu
->pu_kargp
->pa_maxmsglen
= reqlen
;
320 puffs_setfhsize(struct puffs_usermount
*pu
, size_t fhsize
, int flags
)
323 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
)
324 warnx("puffs_setfhsize: call has effect only before mount\n");
326 pu
->pu_kargp
->pa_fhsize
= fhsize
;
327 pu
->pu_kargp
->pa_fhflags
= flags
;
331 puffs_setncookiehash(struct puffs_usermount
*pu
, int nhash
)
334 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
)
335 warnx("puffs_setfhsize: call has effect only before mount\n");
337 pu
->pu_kargp
->pa_nhashbuckets
= nhash
;
341 puffs_set_pathbuild(struct puffs_usermount
*pu
, pu_pathbuild_fn fn
)
344 pu
->pu_pathbuild
= fn
;
348 puffs_set_pathtransform(struct puffs_usermount
*pu
, pu_pathtransform_fn fn
)
351 pu
->pu_pathtransform
= fn
;
355 puffs_set_pathcmp(struct puffs_usermount
*pu
, pu_pathcmp_fn fn
)
362 puffs_set_pathfree(struct puffs_usermount
*pu
, pu_pathfree_fn fn
)
365 pu
->pu_pathfree
= fn
;
369 puffs_set_namemod(struct puffs_usermount
*pu
, pu_namemod_fn fn
)
376 puffs_set_errnotify(struct puffs_usermount
*pu
, pu_errnotify_fn fn
)
379 pu
->pu_errnotify
= fn
;
383 puffs_set_cmap(struct puffs_usermount
*pu
, pu_cmap_fn fn
)
390 puffs_ml_setloopfn(struct puffs_usermount
*pu
, puffs_ml_loop_fn lfn
)
397 puffs_ml_settimeout(struct puffs_usermount
*pu
, struct timespec
*ts
)
401 pu
->pu_ml_timep
= NULL
;
403 pu
->pu_ml_timeout
= *ts
;
404 pu
->pu_ml_timep
= &pu
->pu_ml_timeout
;
409 puffs_set_prepost(struct puffs_usermount
*pu
,
410 pu_prepost_fn pre
, pu_prepost_fn pst
)
418 puffs_setback(struct puffs_cc
*pcc
, int whatback
)
420 struct puffs_req
*preq
= puffs__framebuf_getdataptr(pcc
->pcc_pb
);
422 assert(PUFFSOP_OPCLASS(preq
->preq_opclass
) == PUFFSOP_VN
&& (
423 preq
->preq_optype
== PUFFS_VN_OPEN
||
424 preq
->preq_optype
== PUFFS_VN_MMAP
||
425 preq
->preq_optype
== PUFFS_VN_REMOVE
||
426 preq
->preq_optype
== PUFFS_VN_RMDIR
||
427 preq
->preq_optype
== PUFFS_VN_INACTIVE
));
429 preq
->preq_setbacks
|= whatback
& PUFFS_SETBACK_MASK
;
433 puffs_daemon(struct puffs_usermount
*pu
, int nochdir
, int noclose
)
436 int parent
, value
, fd
;
438 if (pipe(pu
->pu_dpipe
) == -1)
451 pu
->pu_state
|= PU_PUFFSDAEMON
;
454 close(pu
->pu_dpipe
[1]);
455 n
= read(pu
->pu_dpipe
[0], &value
, sizeof(int));
457 err(1, "puffs_daemon");
458 if (n
!= sizeof(value
))
459 errx(1, "puffs_daemon got %ld bytes", n
);
462 err(1, "puffs_daemon");
473 fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
476 dup2(fd
, STDIN_FILENO
);
477 dup2(fd
, STDOUT_FILENO
);
478 dup2(fd
, STDERR_FILENO
);
479 if (fd
> STDERR_FILENO
)
486 n
= write(pu
->pu_dpipe
[1], &errno
, sizeof(int));
492 shutdaemon(struct puffs_usermount
*pu
, int error
)
496 n
= write(pu
->pu_dpipe
[1], &error
, sizeof(int));
498 close(pu
->pu_dpipe
[0]);
499 close(pu
->pu_dpipe
[1]);
500 pu
->pu_state
&= ~PU_PUFFSDAEMON
;
504 puffs_mount(struct puffs_usermount
*pu
, const char *dir
, int mntflags
,
505 puffs_cookie_t cookie
)
511 pu
->pu_kargp
->pa_root_cookie
= cookie
;
514 /* kauth doesn't provide this service any longer */
516 mntflags
|= MNT_NOSUID
| MNT_NODEV
;
518 if (realpath(dir
, rp
) == NULL
) {
523 if (strcmp(dir
, rp
) != 0) {
524 warnx("puffs_mount: \"%s\" is a relative path.", dir
);
525 warnx("puffs_mount: using \"%s\" instead.", rp
);
529 * Undocumented... Well, documented only here.
531 * This is used for imaginative purposes. If the env variable is
532 * set, puffs_mount() doesn't do the regular mount procedure.
533 * Rather, it crams the mount data down the comfd and sets comfd as
534 * the puffs descriptor.
536 * This shouldn't be used unless you can read my mind ( ... or write
537 * it, not to mention execute it, but that's starting to get silly).
539 if ((comfd
= getenv("PUFFS_COMFD")) != NULL
) {
542 if (sscanf(comfd
, "%d", &pu
->pu_fd
) != 1) {
547 /* check that what we got at least resembles an fd */
548 if (fcntl(pu
->pu_fd
, F_GETFL
) == -1) {
555 #define allwrite(buf, len) \
558 al_rv = write(pu->pu_fd, buf, len); \
559 if ((size_t)al_rv != len) { \
566 } while (/*CONSTCOND*/0)
567 allwrite(&len
, sizeof(len
));
569 len
= strlen(pu
->pu_kargp
->pa_mntfromname
)+1;
570 allwrite(&len
, sizeof(len
));
571 allwrite(pu
->pu_kargp
->pa_mntfromname
, len
);
572 allwrite(&mntflags
, sizeof(mntflags
));
573 allwrite(pu
->pu_kargp
, sizeof(*pu
->pu_kargp
));
574 allwrite(&pu
->pu_flags
, sizeof(pu
->pu_flags
));
579 fd
= open(_PATH_PUFFS
, O_RDWR
);
581 warnx("puffs_mount: cannot open %s", _PATH_PUFFS
);
586 warnx("puffs_mount: device fd %d (<= 2), sure this is "
587 "what you want?", fd
);
589 pu
->pu_kargp
->pa_fd
= pu
->pu_fd
= fd
;
590 if ((rv
= mount(MOUNT_PUFFS
, rp
, mntflags
,
591 pu
->pu_kargp
, sizeof(struct puffs_kargs
))) == -1)
595 PU_SETSTATE(pu
, PUFFS_STATE_RUNNING
);
605 if (pu
->pu_state
& PU_PUFFSDAEMON
)
606 shutdaemon(pu
, sverrno
);
613 struct puffs_usermount
*
614 _puffs_init(int dummy
, struct puffs_ops
*pops
, const char *mntfromname
,
615 const char *puffsname
, void *priv
, uint32_t pflags
)
617 struct puffs_usermount
*pu
;
618 struct puffs_kargs
*pargs
;
621 if (puffsname
== PUFFS_DEFER
)
623 if (mntfromname
== PUFFS_DEFER
)
625 if (priv
== PUFFS_DEFER
)
628 pu
= malloc(sizeof(struct puffs_usermount
));
631 memset(pu
, 0, sizeof(struct puffs_usermount
));
633 pargs
= pu
->pu_kargp
= malloc(sizeof(struct puffs_kargs
));
636 memset(pargs
, 0, sizeof(struct puffs_kargs
));
638 pargs
->pa_vers
= PUFFSDEVELVERS
| PUFFSVERSION
;
639 pargs
->pa_flags
= PUFFS_FLAG_KERN(pflags
);
640 fillvnopmask(pops
, pargs
->pa_vnopmask
);
641 puffs_setmntinfo(pu
, mntfromname
, puffsname
);
643 puffs_zerostatvfs(&pargs
->pa_svfsb
);
644 pargs
->pa_root_cookie
= NULL
;
645 pargs
->pa_root_vtype
= VDIR
;
646 pargs
->pa_root_vsize
= 0;
647 pargs
->pa_root_rdev
= 0;
648 pargs
->pa_maxmsglen
= 0;
650 pu
->pu_flags
= pflags
;
652 free(pops
); /* XXX */
654 pu
->pu_privdata
= priv
;
655 pu
->pu_cc_stackshift
= PUFFS_CC_STACKSHIFT_DEFAULT
;
656 LIST_INIT(&pu
->pu_pnodelst
);
657 LIST_INIT(&pu
->pu_ios
);
658 LIST_INIT(&pu
->pu_ios_rmlist
);
659 LIST_INIT(&pu
->pu_ccmagazin
);
660 TAILQ_INIT(&pu
->pu_sched
);
662 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].rfb
= puffs__fsframe_read
;
663 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].wfb
= puffs__fsframe_write
;
664 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].cmpfb
= puffs__fsframe_cmp
;
665 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].gotfb
= puffs__fsframe_gotframe
;
666 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].fdnotfn
= puffs_framev_unmountonclose
;
668 /* defaults for some user-settable translation functions */
669 pu
->pu_cmap
= NULL
; /* identity translation */
671 pu
->pu_pathbuild
= puffs_stdpath_buildpath
;
672 pu
->pu_pathfree
= puffs_stdpath_freepath
;
673 pu
->pu_pathcmp
= puffs_stdpath_cmppath
;
674 pu
->pu_pathtransform
= NULL
;
675 pu
->pu_namemod
= NULL
;
677 pu
->pu_errnotify
= puffs_kernerr_log
;
679 PU_SETSTATE(pu
, PUFFS_STATE_BEFOREMOUNT
);
684 /* can't unmount() from here for obvious reasons */
692 puffs_cancel(struct puffs_usermount
*pu
, int error
)
695 assert(puffs_getstate(pu
) < PUFFS_STATE_RUNNING
);
696 shutdaemon(pu
, error
);
702 puffs_exit(struct puffs_usermount
*pu
, int unused
/* strict compat */)
704 struct puffs_framebuf
*pb
;
705 struct puffs_req
*preq
;
710 pb
= puffs_framebuf_make();
716 winlen
= sizeof(struct puffs_req
);
717 if (puffs_framebuf_getwindow(pb
, 0, &winp
, &winlen
) == -1) {
719 puffs_framebuf_destroy(pb
);
725 preq
->preq_buflen
= sizeof(struct puffs_req
);
726 preq
->preq_opclass
= PUFFSOP_UNMOUNT
;
727 preq
->preq_id
= puffs__nextreq(pu
);
729 puffs_framev_enqueue_justsend(pu
, puffs_getselectable(pu
), pb
, 1, 0);
735 * Actual mainloop. This is called from a context which can block.
736 * It is called either from puffs_mainloop (indirectly, via
737 * puffs_cc_continue() or from puffs_cc_yield()).
740 puffs__theloop(struct puffs_cc
*pcc
)
742 struct puffs_usermount
*pu
= pcc
->pcc_pu
;
743 struct puffs_framectrl
*pfctrl
;
744 struct puffs_fctrl_io
*fio
;
745 struct kevent
*curev
;
749 while (puffs_getstate(pu
) != PUFFS_STATE_UNMOUNTED
) {
751 * Schedule existing requests.
753 while ((pcc
= TAILQ_FIRST(&pu
->pu_sched
)) != NULL
) {
754 TAILQ_REMOVE(&pu
->pu_sched
, pcc
, pcc_schedent
);
761 /* XXX: can we still do these optimizations? */
764 * Do this here, because:
765 * a) loopfunc might generate some results
766 * b) it's still "after" event handling (except for round 1)
768 if (puffs_req_putput(ppr
) == -1)
770 puffs_req_resetput(ppr
);
772 /* micro optimization: skip kevent syscall if possible */
773 if (pu
->pu_nfds
== 1 && pu
->pu_ml_timep
== NULL
774 && (pu
->pu_state
& PU_ASYNCFD
) == 0) {
776 puffs_framev_input(pu
, pfctrl
, XXX
);
781 /* else: do full processing */
782 /* Don't bother worrying about O(n) for now */
783 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
784 if (fio
->stat
& FIO_WRGONE
)
790 * Try to write out everything to avoid the
791 * need for enabling EVFILT_WRITE. The likely
792 * case is that we can fit everything into the
795 puffs__framev_output(pu
, pfctrl
, fio
);
799 * Build list of which to enable/disable in writecheck.
802 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
803 if (fio
->stat
& FIO_WRGONE
)
806 /* en/disable write checks for kqueue as needed */
807 assert((FIO_EN_WRITE(fio
) && FIO_RM_WRITE(fio
)) == 0);
808 if (FIO_EN_WRITE(fio
)) {
809 EV_SET(&pu
->pu_evs
[nchanges
], fio
->io_fd
,
810 EVFILT_WRITE
, EV_ENABLE
, 0, 0,
815 if (FIO_RM_WRITE(fio
)) {
816 EV_SET(&pu
->pu_evs
[nchanges
], fio
->io_fd
,
817 EVFILT_WRITE
, EV_DISABLE
, 0, 0,
819 fio
->stat
&= ~FIO_WR
;
822 assert(nchanges
<= pu
->pu_nfds
);
825 ndone
= kevent(pu
->pu_kq
, pu
->pu_evs
, nchanges
,
826 pu
->pu_evs
, 2*pu
->pu_nfds
, pu
->pu_ml_timep
);
839 /* iterate over the results */
840 for (curev
= pu
->pu_evs
; ndone
--; curev
++) {
844 /* get & possibly dispatch events from kernel */
845 if (curev
->ident
== puffsfd
) {
846 if (puffs_req_handle(pgr
, ppr
, 0) == -1)
852 fio
= (void *)curev
->udata
;
854 if (curev
->flags
& EV_ERROR
) {
855 assert(curev
->filter
== EVFILT_WRITE
);
856 fio
->stat
&= ~FIO_WR
;
858 /* XXX: how to know if it's a transient error */
859 puffs__framev_writeclose(pu
, fio
,
861 puffs__framev_notify(fio
, PUFFS_FBIO_ERROR
);
866 if (curev
->filter
== EVFILT_READ
) {
867 puffs__framev_input(pu
, pfctrl
, fio
);
868 what
|= PUFFS_FBIO_READ
;
871 else if (curev
->filter
== EVFILT_WRITE
) {
872 puffs__framev_output(pu
, pfctrl
, fio
);
873 what
|= PUFFS_FBIO_WRITE
;
876 puffs__framev_notify(fio
, what
);
880 * Really free fd's now that we don't have references
883 while ((fio
= LIST_FIRST(&pu
->pu_ios_rmlist
)) != NULL
) {
884 LIST_REMOVE(fio
, fio_entries
);
889 if (puffs__cc_restoremain(pu
) == -1)
890 warn("cannot restore main context. impending doom");
894 puffs_mainloop(struct puffs_usermount
*pu
)
896 struct puffs_fctrl_io
*fio
;
897 struct puffs_cc
*pcc
;
898 struct kevent
*curev
;
901 assert(puffs_getstate(pu
) >= PUFFS_STATE_RUNNING
);
903 pu
->pu_kq
= kqueue();
906 pu
->pu_state
|= PU_HASKQ
;
908 puffs_setblockingmode(pu
, PUFFSDEV_NONBLOCK
);
909 if (puffs__framev_addfd_ctrl(pu
, puffs_getselectable(pu
),
910 PUFFS_FBIO_READ
| PUFFS_FBIO_WRITE
,
911 &pu
->pu_framectrl
[PU_FRAMECTRL_FS
]) == -1)
914 curev
= realloc(pu
->pu_evs
, (2*pu
->pu_nfds
)*sizeof(struct kevent
));
919 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
920 EV_SET(curev
, fio
->io_fd
, EVFILT_READ
, EV_ADD
,
921 0, 0, (uintptr_t)fio
);
923 EV_SET(curev
, fio
->io_fd
, EVFILT_WRITE
, EV_ADD
| EV_DISABLE
,
924 0, 0, (uintptr_t)fio
);
927 if (kevent(pu
->pu_kq
, pu
->pu_evs
, 2*pu
->pu_nfds
, NULL
, 0, NULL
) == -1)
930 pu
->pu_state
|= PU_INLOOP
;
933 * Create alternate execution context and jump to it. Note
934 * that we come "out" of savemain twice. Where we come out
935 * of it depends on the architecture. If the return address is
936 * stored on the stack, we jump out from puffs_cc_continue(),
937 * for a register return address from puffs__cc_savemain().
938 * PU_MAINRESTORE makes sure we DTRT in both cases.
940 if (puffs__cc_create(pu
, puffs__theloop
, &pcc
) == -1) {
943 if (puffs__cc_savemain(pu
) == -1) {
946 if ((pu
->pu_state
& PU_MAINRESTORE
) == 0)
947 puffs_cc_continue(pcc
);
953 /* store the real error for a while */