[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 22/31] libxl: event API: new facilities for waiting for subprocesses
On Tue, 2012-04-10 at 20:07 +0100, Ian Jackson wrote: > The current arrangements in libxl for spawning subprocesses have two > key problems: (i) they make unwarranted (and largely undocumented) > assumptions about the caller's use of subprocesses, (ii) they aren't > integrated into the event system and can't be made asynchronous etc. > > So replace them with a new set of facilities. > > Primarily, from the point of view of code inside libxl, this is > libxl__ev_child_fork which is both (a) a version of fork() and (b) an > event source which generates a callback when the child dies. > > From the point of view of the application, we fully document our use > of SIGCHLD. The application can tell us whether it wants to own > SIGCHLD or not; if it does, it has to tell us about deaths of our > children. > > Currently there are no callers in libxl which use these facilities. > All code in libxl which forks needs to be converted and libxl_fork > needse to be be abolished. > > Signed-off-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> > Cc: Roger Pau Monne <roger.pau@xxxxxxxxxxxxx> Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx> > --- > tools/libxl/libxl.c | 17 +++- > tools/libxl/libxl.h | 1 + > tools/libxl/libxl_event.c | 53 +++++++-- > tools/libxl/libxl_event.h | 147 +++++++++++++++++++++++- > tools/libxl/libxl_fork.c | 255 > ++++++++++++++++++++++++++++++++++++++++++ > tools/libxl/libxl_internal.h | 59 +++++++++- > 6 files changed, 512 insertions(+), 20 deletions(-) > > diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c > index 60dbfdc..42ac89f 100644 > --- a/tools/libxl/libxl.c > +++ b/tools/libxl/libxl.c > @@ -39,7 +39,7 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, > memset(ctx, 0, sizeof(libxl_ctx)); > ctx->lg = lg; > > - /* First initialise pointers (cannot fail) */ > + /* First initialise pointers etc. (cannot fail) */ > > LIBXL_TAILQ_INIT(&ctx->occurred); > > @@ -58,6 +58,11 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, > LIBXL_TAILQ_INIT(&ctx->death_list); > libxl__ev_xswatch_init(&ctx->death_watch); > > + ctx->childproc_hooks = &libxl__childproc_default_hooks; > + ctx->childproc_user = 0; > + > + ctx->sigchld_selfpipe[0] = -1; > + > /* The mutex is special because we can't idempotently destroy it */ > > if (libxl__init_recursive_mutex(ctx, &ctx->lock) < 0) { > @@ -160,6 +165,16 @@ int libxl_ctx_free(libxl_ctx *ctx) > > discard_events(&ctx->occurred); > > + /* If we have outstanding children, then the application inherits > + * them; we wish the application good luck with understanding > + * this if and when it reaps them. */ > + libxl__sigchld_removehandler(ctx); > + > + if (ctx->sigchld_selfpipe[0] >= 0) { > + close(ctx->sigchld_selfpipe[0]); > + close(ctx->sigchld_selfpipe[1]); > + } > + > pthread_mutex_destroy(&ctx->lock); > > GC_FREE; > diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h > index edbca53..03e71f6 100644 > --- a/tools/libxl/libxl.h > +++ b/tools/libxl/libxl.h > @@ -380,6 +380,7 @@ enum { > ERROR_NOT_READY = -11, > ERROR_OSEVENT_REG_FAIL = -12, > ERROR_BUFFERFULL = -13, > + ERROR_UNKNOWN_CHILD = -14, > }; > > > diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c > index 672e3fe..1b7495a 100644 > --- a/tools/libxl/libxl_event.c > +++ b/tools/libxl/libxl_event.c > @@ -623,6 +623,10 @@ static int beforepoll_internal(libxl__gc *gc, > libxl__poller *poller, > \ > REQUIRE_FD(poller->wakeup_pipe[0], POLLIN, BODY); \ > \ > + int selfpipe = libxl__fork_selfpipe_active(CTX); \ > + if (selfpipe >= 0) \ > + REQUIRE_FD(selfpipe, POLLIN, BODY); \ > + \ > }while(0) > > #define REQUIRE_FD(req_fd_, req_events_, BODY) do{ \ > @@ -762,10 +766,11 @@ static void afterpoll_internal(libxl__egc *egc, > libxl__poller *poller, > int nfds, const struct pollfd *fds, > struct timeval now) > { > + /* May make callbacks into the application for child processes. > + * ctx must be locked exactly once */ > EGC_GC; > libxl__ev_fd *efd; > > - > LIBXL_LIST_FOREACH(efd, &CTX->efds, entry) { > if (!efd->events) > continue; > @@ -776,11 +781,16 @@ static void afterpoll_internal(libxl__egc *egc, > libxl__poller *poller, > } > > if (afterpoll_check_fd(poller,fds,nfds, poller->wakeup_pipe[0],POLLIN)) { > - char buf[256]; > - int r = read(poller->wakeup_pipe[0], buf, sizeof(buf)); > - if (r < 0) > - if (errno != EINTR && errno != EWOULDBLOCK) > - LIBXL__EVENT_DISASTER(egc, "read wakeup", errno, 0); > + int e = libxl__self_pipe_eatall(poller->wakeup_pipe[0]); > + if (e) LIBXL__EVENT_DISASTER(egc, "read wakeup", e, 0); > + } > + > + int selfpipe = libxl__fork_selfpipe_active(CTX); > + if (selfpipe >= 0 && > + afterpoll_check_fd(poller,fds,nfds, selfpipe, POLLIN)) { > + int e = libxl__self_pipe_eatall(selfpipe); > + if (e) LIBXL__EVENT_DISASTER(egc, "read sigchld pipe", e, 0); > + libxl__fork_selfpipe_woken(egc); > } > > for (;;) { > @@ -1078,16 +1088,37 @@ void libxl__poller_put(libxl_ctx *ctx, libxl__poller > *p) > > void libxl__poller_wakeup(libxl__egc *egc, libxl__poller *p) > { > + int e = libxl__self_pipe_wakeup(p->wakeup_pipe[1]); > + if (e) LIBXL__EVENT_DISASTER(egc, "cannot poke watch pipe", e, 0); > +} > + > +int libxl__self_pipe_wakeup(int fd) > +{ > static const char buf[1] = ""; > > for (;;) { > - int r = write(p->wakeup_pipe[1], buf, 1); > - if (r==1) return; > + int r = write(fd, buf, 1); > + if (r==1) return 0; > assert(r==-1); > if (errno == EINTR) continue; > - if (errno == EWOULDBLOCK) return; > - LIBXL__EVENT_DISASTER(egc, "cannot poke watch pipe", errno, 0); > - return; > + if (errno == EWOULDBLOCK) return 0; > + assert(errno); > + return errno; > + } > +} > + > +int libxl__self_pipe_eatall(int fd) > +{ > + char buf[256]; > + for (;;) { > + int r = read(fd, buf, sizeof(buf)); > + if (r == sizeof(buf)) continue; > + if (r >= 0) return 0; > + assert(r == -1); > + if (errno == EINTR) continue; > + if (errno == EWOULDBLOCK) return 0; > + assert(errno); > + return errno; > } > } > > diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h > index 2d2196f..713d96d 100644 > --- a/tools/libxl/libxl_event.h > +++ b/tools/libxl/libxl_event.h > @@ -163,11 +163,6 @@ void libxl_event_register_callbacks(libxl_ctx *ctx, > * After libxl_ctx_free, all corresponding evgen handles become > * invalid and must no longer be passed to evdisable. > * > - * Events enabled with evenable prior to a fork and libxl_ctx_postfork > - * are no longer generated after the fork/postfork; however the evgen > - * structures are still valid and must be passed to evdisable if the > - * memory they use should not be leaked. > - * > * Applications should ensure that they eventually retrieve every > * event using libxl_event_check or libxl_event_wait, since events > * which occur but are not retreived by the application will be queued > @@ -372,6 +367,148 @@ void libxl_osevent_occurred_fd(libxl_ctx *ctx, void > *for_libxl, > void libxl_osevent_occurred_timeout(libxl_ctx *ctx, void *for_libxl); > > > +/*======================================================================*/ > + > +/* > + * Subprocess handling. > + * > + * Unfortunately the POSIX interface makes this very awkward. > + * > + * There are two possible arrangements for collecting statuses from > + * wait/waitpid. > + * > + * For naive programs: > + * > + * libxl will keep a SIGCHLD handler installed whenever it has an > + * active (unreaped) child. It will reap all children with > + * wait(); any children it does not recognise will be passed to > + * the application via an optional callback (and will result in > + * logged warnings if no callback is provided or the callback > + * denies responsibility for the child). > + * > + * libxl may have children whenever: > + * > + * - libxl is performing an operation which can be made > + * asynchronous; ie one taking a libxl_asyncop_how, even > + * if NULL is passed indicating that the operation is > + * synchronous; or > + * > + * - events of any kind are being generated, as requested > + * by libxl_evenable_.... > + * > + * A multithreaded application which is naive in this sense may > + * block SIGCHLD on some of its threads, but there must be at > + * least one thread that has SIGCHLD unblocked. libxl will not > + * modify the blocking flag for SIGCHLD (except that it may create > + * internal service threads with all signals blocked). > + * > + * A naive program must only have at any one time only > + * one libxl context which might have children. > + * > + * For programs which run their own children alongside libxl's: > + * > + * A program which does this must call libxl_childproc_setmode. > + * There are two options: > + * > + * libxl_sigchld_owner_mainloop: > + * The application must install a SIGCHLD handler and reap (at > + * least) all of libxl's children and pass their exit status > + * to libxl by calling libxl_childproc_exited. > + * > + * libxl_sigchld_owner_libxl_always: > + * The application expects libxl to reap all of its children, > + * and provides a callback to be notified of their exit > + * statues. > + * > + * An application which fails to call setmode, or which passes 0 for > + * hooks, while it uses any libxl operation which might > + * create or use child processes (see above): > + * - Must not have any child processes running. > + * - Must not install a SIGCHLD handler. > + * - Must not reap any children. > + */ > + > + > +typedef enum { > + /* libxl owns SIGCHLD whenever it has a child. */ > + libxl_sigchld_owner_libxl, > + > + /* Application promises to call libxl_childproc_exited but NOT > + * from within a signal handler. libxl will not itself arrange to > + * (un)block or catch SIGCHLD. */ > + libxl_sigchld_owner_mainloop, > + > + /* libxl owns SIGCHLD all the time, and the application is > + * relying on libxl's event loop for reaping its own children. */ > + libxl_sigchld_owner_libxl_always, > +} libxl_sigchld_owner; > + > +typedef struct { > + libxl_sigchld_owner chldowner; > + > + /* All of these are optional: */ > + > + /* Called by libxl instead of fork. Should behave exactly like > + * fork, including setting errno etc. May NOT reenter into libxl. > + * Application may use this to discover pids of libxl's children, > + * for example. > + */ > + pid_t (*fork_replacement)(void *user); > + > + /* With libxl_sigchld_owner_libxl, called by libxl when it has > + * reaped a pid. (Not permitted with _owner_mainloop.) > + * > + * Should return 0 if the child was recognised by the application > + * (or if the application does not keep those kind of records), > + * ERROR_UNKNOWN_CHILD if the application knows that the child is not > + * the application's; if it returns another error code it is a > + * disaster as described for libxl_event_register_callbacks. > + * (libxl will report unexpected children to its error log.) > + * > + * If not supplied, the application is assumed not to start > + * any children of its own. > + * > + * This function is NOT called from within the signal handler. > + * Rather it will be called from inside a libxl's event handling > + * code and thus only when libxl is running, for example from > + * within libxl_event_wait. (libxl uses the self-pipe trick > + * to implement this.) > + * > + * childproc_exited_callback may call back into libxl, but it > + * is best to avoid making long-running libxl calls as that might > + * stall the calling event loop while the nested operation > + * completes. > + */ > + int (*reaped_callback)(pid_t, int status, void *user); > +} libxl_childproc_hooks; > + > +/* hooks may be 0 in which is equivalent to &{ libxl_sigchld_owner_libxl, 0, > 0 } > + * > + * May not be called when libxl might have any child processes, or the > + * behaviour is undefined. So it is best to call this at > + * initialisation. > + */ > +void libxl_childproc_setmode(libxl_ctx *ctx, const libxl_childproc_hooks > *hooks, > + void *user); > + > +/* > + * This function is for an application which owns SIGCHLD and which > + * therefore reaps all of the process's children. > + * > + * May be called only by an application which has called setmode with > + * chldowner == libxl_sigchld_owner_mainloop. If pid was a process started > + * by this instance of libxl, returns 0 after doing whatever > + * processing is appropriate. Otherwise silently returns > + * ERROR_UNKNOWN_CHILD. No other error returns are possible. > + * > + * May NOT be called from within a signal handler which might > + * interrupt any libxl operation. The application will almost > + * certainly need to use the self-pipe trick (or a working pselect or > + * ppoll) to implement this. > + */ > +int libxl_childproc_reaped(libxl_ctx *ctx, pid_t, int status); > + > + > /* > * An application which initialises a libxl_ctx in a parent process > * and then forks a child which does not quickly exec, must > diff --git a/tools/libxl/libxl_fork.c b/tools/libxl/libxl_fork.c > index 4751ef4..aac9598 100644 > --- a/tools/libxl/libxl_fork.c > +++ b/tools/libxl/libxl_fork.c > @@ -46,6 +46,12 @@ static int atfork_registered; > static LIBXL_LIST_HEAD(, libxl__carefd) carefds = > LIBXL_LIST_HEAD_INITIALIZER(carefds); > > +/* non-null iff installed, protected by no_forking */ > +static libxl_ctx *sigchld_owner; > +static struct sigaction sigchld_saved_action; > + > +static void sigchld_removehandler_core(void); > + > static void atfork_lock(void) > { > int r = pthread_mutex_lock(&no_forking); > @@ -104,6 +110,7 @@ void libxl_postfork_child_noexec(libxl_ctx *ctx) > int r; > > atfork_lock(); > + > LIBXL_LIST_FOREACH_SAFE(cf, &carefds, entry, cf_tmp) { > if (cf->fd >= 0) { > r = close(cf->fd); > @@ -115,6 +122,10 @@ void libxl_postfork_child_noexec(libxl_ctx *ctx) > free(cf); > } > LIBXL_LIST_INIT(&carefds); > + > + if (sigchld_owner) > + sigchld_removehandler_core(); > + > atfork_unlock(); > } > > @@ -138,6 +149,250 @@ int libxl__carefd_fd(const libxl__carefd *cf) > } > > /* > + * Actual child process handling > + */ > + > +static void sigchld_handler(int signo) > +{ > + int e = libxl__self_pipe_wakeup(sigchld_owner->sigchld_selfpipe[1]); > + assert(!e); /* errors are probably EBADF, very bad */ > +} > + > +static void sigchld_removehandler_core(void) > +{ > + struct sigaction was; > + int r; > + > + r = sigaction(SIGCHLD, &sigchld_saved_action, &was); > + assert(!r); > + assert(!(was.sa_flags & SA_SIGINFO)); > + assert(was.sa_handler == sigchld_handler); > + sigchld_owner = 0; > +} > + > +void libxl__sigchld_removehandler(libxl_ctx *ctx) /* non-reentrant */ > +{ > + atfork_lock(); > + if (sigchld_owner == ctx) > + sigchld_removehandler_core(); > + atfork_unlock(); > +} > + > +int libxl__sigchld_installhandler(libxl_ctx *ctx) /* non-reentrant */ > +{ > + int r, rc; > + > + if (ctx->sigchld_selfpipe[0] < 0) { > + r = pipe(ctx->sigchld_selfpipe); > + if (r) { > + ctx->sigchld_selfpipe[0] = -1; > + LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, > + "failed to create sigchld pipe"); > + rc = ERROR_FAIL; > + goto out; > + } > + } > + > + atfork_lock(); > + if (sigchld_owner != ctx) { > + struct sigaction ours; > + > + assert(!sigchld_owner); > + sigchld_owner = ctx; > + > + memset(&ours,0,sizeof(ours)); > + ours.sa_handler = sigchld_handler; > + sigemptyset(&ours.sa_mask); > + ours.sa_flags = SA_NOCLDSTOP | SA_RESTART; > + r = sigaction(SIGCHLD, &ours, &sigchld_saved_action); > + assert(!r); > + > + assert(((void)"application must negotiate with libxl about SIGCHLD", > + !(sigchld_saved_action.sa_flags & SA_SIGINFO) && > + (sigchld_saved_action.sa_handler == SIG_DFL || > + sigchld_saved_action.sa_handler == SIG_IGN))); > + } > + atfork_unlock(); > + > + rc = 0; > + out: > + return rc; > +} > + > +static int chldmode_ours(libxl_ctx *ctx) > +{ > + return ctx->childproc_hooks->chldowner == libxl_sigchld_owner_libxl; > +} > + > +int libxl__fork_selfpipe_active(libxl_ctx *ctx) > +{ > + /* Returns the fd to read, or -1 */ > + if (!chldmode_ours(ctx)) > + return -1; > + > + if (LIBXL_LIST_EMPTY(&ctx->children)) > + return -1; > + > + return ctx->sigchld_selfpipe[0]; > +} > + > +static void perhaps_removehandler(libxl_ctx *ctx) > +{ > + if (LIBXL_LIST_EMPTY(&ctx->children) && > + ctx->childproc_hooks->chldowner != libxl_sigchld_owner_libxl_always) > + libxl__sigchld_removehandler(ctx); > +} > + > +static int childproc_reaped(libxl__egc *egc, pid_t pid, int status) > +{ > + EGC_GC; > + libxl__ev_child *ch; > + > + LIBXL_LIST_FOREACH(ch, &CTX->children, entry) > + if (ch->pid == pid) > + goto found; > + > + /* not found */ > + return ERROR_UNKNOWN_CHILD; > + > + found: > + LIBXL_LIST_REMOVE(ch, entry); > + ch->pid = -1; > + ch->callback(egc, ch, pid, status); > + > + perhaps_removehandler(CTX); > + > + return 0; > +} > + > +int libxl_childproc_reaped(libxl_ctx *ctx, pid_t pid, int status) > +{ > + EGC_INIT(ctx); > + CTX_LOCK; > + int rc = childproc_reaped(egc, pid, status); > + CTX_UNLOCK; > + EGC_FREE; > + return rc; > +} > + > +void libxl__fork_selfpipe_woken(libxl__egc *egc) > +{ > + /* May make callbacks into the application for child processes. > + * ctx must be locked EXACTLY ONCE */ > + EGC_GC; > + > + while (chldmode_ours(CTX) /* in case the app changes the mode */) { > + int status; > + pid_t pid = waitpid(-1, &status, WNOHANG); > + > + if (pid == 0) return; > + > + if (pid == -1) { > + if (errno == ECHILD) return; > + if (errno == EINTR) continue; > + LIBXL__EVENT_DISASTER(egc, "waitpid() failed", errno, 0); > + return; > + } > + > + int rc = childproc_reaped(egc, pid, status); > + > + if (rc) { > + if (CTX->childproc_hooks->reaped_callback) { > + CTX_UNLOCK; > + rc = CTX->childproc_hooks->reaped_callback > + (pid, status, CTX->childproc_user); > + CTX_LOCK; > + if (rc != 0 && rc != ERROR_UNKNOWN_CHILD) { > + char disasterbuf[200]; > + snprintf(disasterbuf, sizeof(disasterbuf), " reported by" > + " libxl_childproc_hooks->reaped_callback" > + " (for pid=%lu, status=%d; error code %d)", > + (unsigned long)pid, status, rc); > + LIBXL__EVENT_DISASTER(egc, disasterbuf, 0, 0); > + return; > + } > + } else { > + rc = ERROR_UNKNOWN_CHILD; > + } > + if (rc) > + libxl_report_child_exitstatus(CTX, XTL_WARN, > + "unknown child", (long)pid, status); > + } > + } > +} > + > +pid_t libxl__ev_child_fork(libxl__gc *gc, libxl__ev_child *ch, > + libxl__ev_child_callback *death) > +{ > + CTX_LOCK; > + int rc; > + > + if (chldmode_ours(CTX)) { > + rc = libxl__sigchld_installhandler(CTX); > + if (rc) goto out; > + } > + > + pid_t pid = > + CTX->childproc_hooks->fork_replacement > + ? CTX->childproc_hooks->fork_replacement(CTX->childproc_user) > + : fork(); > + if (pid == -1) { > + LOGE(ERROR, "fork failed"); > + rc = ERROR_FAIL; > + goto out; > + } > + > + if (!pid) { > + /* woohoo! */ > + return 0; /* Yes, CTX is left locked in the child. */ > + } > + > + ch->pid = pid; > + ch->callback = death; > + LIBXL_LIST_INSERT_HEAD(&CTX->children, ch, entry); > + rc = pid; > + > + out: > + perhaps_removehandler(CTX); > + CTX_UNLOCK; > + return rc; > +} > + > +void libxl_childproc_setmode(libxl_ctx *ctx, const libxl_childproc_hooks > *hooks, > + void *user) > +{ > + GC_INIT(ctx); > + CTX_LOCK; > + > + assert(LIBXL_LIST_EMPTY(&CTX->children)); > + > + if (!hooks) > + hooks = &libxl__childproc_default_hooks; > + > + ctx->childproc_hooks = hooks; > + ctx->childproc_user = user; > + > + switch (ctx->childproc_hooks->chldowner) { > + case libxl_sigchld_owner_mainloop: > + case libxl_sigchld_owner_libxl: > + libxl__sigchld_removehandler(ctx); > + break; > + case libxl_sigchld_owner_libxl_always: > + libxl__sigchld_installhandler(ctx); > + break; > + default: > + abort(); > + } > + > + CTX_UNLOCK; > + GC_FREE; > +} > + > +const libxl_childproc_hooks libxl__childproc_default_hooks = { > + libxl_sigchld_owner_libxl, 0, 0 > +}; > + > +/* > * Local variables: > * mode: C > * c-basic-offset: 4 > diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h > index 1a2139c..a60171c 100644 > --- a/tools/libxl/libxl_internal.h > +++ b/tools/libxl/libxl_internal.h > @@ -196,6 +196,19 @@ typedef struct libxl__ev_watch_slot { > libxl__ev_xswatch *libxl__watch_slot_contents(libxl__gc *gc, int slotnum); > > > +typedef struct libxl__ev_child libxl__ev_child; > +typedef void libxl__ev_child_callback(libxl__egc *egc, libxl__ev_child*, > + pid_t pid, int status); > +struct libxl__ev_child { > + /* caller should include this in their own struct */ > + /* read-only for caller: */ > + pid_t pid; /* -1 means unused ("unregistered", ie Idle) */ > + libxl__ev_child_callback *callback; > + /* remainder is private for libxl__ev_... */ > + LIBXL_LIST_ENTRY(struct libxl__ev_child) entry; > +}; > + > + > /* > * evgen structures, which are the state we use for generating > * events for the caller. > @@ -315,10 +328,14 @@ struct libxl__ctx { > > LIBXL_LIST_HEAD(, libxl_evgen_disk_eject) disk_eject_evgens; > > - /* for callers who reap children willy-nilly; caller must only > - * set this after libxl_init and before any other call - or > - * may leave them untouched */ > + const libxl_childproc_hooks *childproc_hooks; > + void *childproc_user; > + int sigchld_selfpipe[2]; /* [0]==-1 means handler not installed */ > + LIBXL_LIST_HEAD(, libxl__ev_child) children; > + > + /* This is obsolete and must be removed: */ > int (*waitpid_instead)(pid_t pid, int *status, int flags); > + > libxl_version_info version_info; > }; > > @@ -566,6 +583,33 @@ static inline int libxl__ev_xswatch_isregistered(const > libxl__ev_xswatch *xw) > > > /* > + * For making subprocesses. This is the only permitted mechanism for > + * code in libxl to do so. > + * > + * In the parent, returns the pid, filling in childw_out. > + * In the child, returns 0. > + * If it fails, returns a libxl error (all of which are -ve). > + * > + * The child should go on to exec (or exit) soon, and should not make > + * any further libxl event calls in the meantime. > + * > + * The parent may signal the child but it must not reap it. That will > + * be done by the event machinery. death may be NULL in which case > + * the child is still reaped but its death is ignored. > + * > + * It is not possible to "deregister" the child death event source. > + * It will generate exactly one event callback; until then the childw > + * is Active and may not be reused. > + */ > +_hidden pid_t libxl__ev_child_fork(libxl__gc *gc, libxl__ev_child > *childw_out, > + libxl__ev_child_callback *death); > +static inline void libxl__ev_child_init(libxl__ev_child *childw_out) > + { childw_out->pid = -1; } > +static inline int libxl__ev_child_inuse(libxl__ev_child *childw_out) > + { return childw_out->pid >= 0; } > + > + > +/* > * Other event-handling support provided by the libxl event core to > * the rest of libxl. > */ > @@ -619,6 +663,15 @@ void libxl__poller_put(libxl_ctx *ctx, libxl__poller *p); > * ctx must be locked. */ > void libxl__poller_wakeup(libxl__egc *egc, libxl__poller *p); > > +/* Internal to fork and child reaping machinery */ > +extern const libxl_childproc_hooks libxl__childproc_default_hooks; > +int libxl__sigchld_installhandler(libxl_ctx *ctx); /* non-reentrant;logs > errs */ > +void libxl__sigchld_removehandler(libxl_ctx *ctx); /* non-reentrant */ > +int libxl__fork_selfpipe_active(libxl_ctx *ctx); /* returns read fd or -1 */ > +void libxl__fork_selfpipe_woken(libxl__egc *egc); > +int libxl__self_pipe_wakeup(int fd); /* returns 0 or -1 setting errno */ > +int libxl__self_pipe_eatall(int fd); /* returns 0 or -1 setting errno */ > + > > int libxl__atfork_init(libxl_ctx *ctx); > > -- > 1.7.2.5 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@xxxxxxxxxxxxx > http://lists.xen.org/xen-devel _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |