mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
libxl: fork: Provide libxl_childproc_sigchld_occurred
Applications exist which don't keep track of all their child processes in a manner suitable for coherent dispatch of their termination. In such a situation, nothing in the whole process may call wait, or waitpid(-1,,). Doing so reaps processes belonging to other parts of the application and there is then no way to deliver the exit status to the right place. To facilitate this, provide a facility for such an application to ask libxl to call waitpid on each of its children individually. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Jim Fehlig <jfehlig@suse.com> Cc: Ian Campbell <Ian.Campbell@citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
1 parent
7916a9023c
commit
ee84b79fbd
2 files changed
+70
-4
No files matched your search
@@ -482,9 +482,10 @@ typedef enum {
|
||||
* all children, including those not spawned by libxl. */
|
||||
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. */
|
||||
/* Application promises to discover when SIGCHLD occurs and call
|
||||
* libxl_childproc_exited or libxl_childproc_sigchld_occurred (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
|
||||
@@ -542,7 +543,8 @@ void libxl_childproc_setmode(libxl_ctx *ctx, const libxl_childproc_hooks *hooks,
|
||||
|
||||
/*
|
||||
* This function is for an application which owns SIGCHLD and which
|
||||
* therefore reaps all of the process's children.
|
||||
* reaps all of the process's children, and dispatches the exit status
|
||||
* to the correct place inside the application.
|
||||
*
|
||||
* May be called only by an application which has called setmode with
|
||||
* chldowner == libxl_sigchld_owner_mainloop. If pid was a process started
|
||||
@@ -558,6 +560,25 @@ void libxl_childproc_setmode(libxl_ctx *ctx, const libxl_childproc_hooks *hooks,
|
||||
int libxl_childproc_reaped(libxl_ctx *ctx, pid_t, int status)
|
||||
LIBXL_EXTERNAL_CALLERS_ONLY;
|
||||
|
||||
/*
|
||||
* This function is for an application which owns SIGCHLD but which
|
||||
* doesn't keep track of all of its own children in a manner suitable
|
||||
* for reaping all of them and then dispatching them.
|
||||
*
|
||||
* Such an the application must notify libxl, by calling this
|
||||
* function, that a SIGCHLD occurred. libxl will then check all its
|
||||
* children, reap any that are ready, and take any action necessary -
|
||||
* but it will not reap anything else.
|
||||
*
|
||||
* May be called only by an application which has called setmode with
|
||||
* chldowner == libxl_sigchld_owner_mainloop.
|
||||
*
|
||||
* May NOT be called from within a signal handler which might
|
||||
* interrupt any libxl operation (just like libxl_childproc_reaped).
|
||||
*/
|
||||
void libxl_childproc_sigchld_occurred(libxl_ctx *ctx)
|
||||
LIBXL_EXTERNAL_CALLERS_ONLY;
|
||||
|
||||
|
||||
/*
|
||||
* An application which initialises a libxl_ctx in a parent process
|
||||
|
||||
@@ -330,6 +330,51 @@ int libxl_childproc_reaped(libxl_ctx *ctx, pid_t pid, int status)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void childproc_checkall(libxl__egc *egc)
|
||||
{
|
||||
EGC_GC;
|
||||
libxl__ev_child *ch;
|
||||
|
||||
for (;;) {
|
||||
int status;
|
||||
pid_t got;
|
||||
|
||||
LIBXL_LIST_FOREACH(ch, &CTX->children, entry) {
|
||||
got = checked_waitpid(egc, ch->pid, &status);
|
||||
if (got)
|
||||
goto found;
|
||||
}
|
||||
/* not found */
|
||||
return;
|
||||
|
||||
found:
|
||||
if (got == -1) {
|
||||
LIBXL__EVENT_DISASTER
|
||||
(egc, "waitpid() gave ECHILD but we have a child",
|
||||
ECHILD, 0);
|
||||
/* it must have finished but we don't know its status */
|
||||
status = 255<<8; /* no wait.h macro for this! */
|
||||
assert(WIFEXITED(status));
|
||||
assert(WEXITSTATUS(status)==255);
|
||||
assert(!WIFSIGNALED(status));
|
||||
assert(!WIFSTOPPED(status));
|
||||
}
|
||||
childproc_reaped_ours(egc, ch, status);
|
||||
/* we need to restart the loop, as children may have been edited */
|
||||
}
|
||||
}
|
||||
|
||||
void libxl_childproc_sigchld_occurred(libxl_ctx *ctx)
|
||||
{
|
||||
EGC_INIT(ctx);
|
||||
CTX_LOCK;
|
||||
assert(CTX->childproc_hooks->chldowner
|
||||
== libxl_sigchld_owner_mainloop);
|
||||
childproc_checkall(egc);
|
||||
CTX_UNLOCK;
|
||||
EGC_FREE;
|
||||
}
|
||||
|
||||
static void sigchld_selfpipe_handler(libxl__egc *egc, libxl__ev_fd *ev,
|
||||
int fd, short events, short revents)
|
||||
{
|
||||
|
||||