[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] xl: track child processes for the benefit of libxl
On Wed, 2012-05-16 at 21:40 +0100, Ian Jackson wrote: > Each time xl forks, it needs to record the pid, so that its exit > status can be preserved if it happens that libxl's event loop reaped > it. Consequently we also have a new wrapper for waitpid, which in > that case returns the previously-reaped status. > > When we get a console ready callback from libxl, check to see if we > have spawned but not reaped a previous console client, and if so reap > it now. (This is necessary to prevent improper use of the xlchild > struct, but has the happy consequence of checking the exit status of > the first console client in the pygrub case.) > > Refactor the two calls to libxl_ctx_alloc into a new function > xl_ctx_alloc which also sets the child reaped handler callback. > > All of this has the effect of suppressing a message > unknown child [nnnn] unexpected exited status zero > which would sometimes (depending on a race) appear with `xl create -c' > and pygrub. > > Signed-off-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> > Reported-by: Ian Campbell <ian.campbell@xxxxxxxxxx> > Cc: Roger Pau Monne <roger.pau@xxxxxxxxxx> > > --- > tools/libxl/xl.c | 80 ++++++++++++++++++++++++++++++++++++++------- > tools/libxl/xl.h | 29 +++++++++++++++- > tools/libxl/xl_cmdimpl.c | 80 ++++++++++++++++++++++++++------------------- > 3 files changed, 140 insertions(+), 49 deletions(-) > > diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c > index 750a61c..66499dd 100644 > --- a/tools/libxl/xl.c > +++ b/tools/libxl/xl.c > @@ -102,22 +102,79 @@ void postfork(void) > libxl_postfork_child_noexec(ctx); /* in case we don't exit/exec */ > ctx = 0; > > - if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (xentoollog_logger*)logger)) > { > - fprintf(stderr, "cannot reinit xl context after fork\n"); > - exit(-1); > - } > + xl_ctx_alloc(); > } > > -pid_t xl_fork(libxl_ctx *ctx) { > - pid_t pid; > +pid_t xl_fork(xlchild *ch) { > + assert(!ch->pid); > + ch->reaped = 0; > > - pid = fork(); > - if (pid == -1) { > + ch->pid = fork(); > + if (ch->pid == -1) { > perror("fork failed"); > exit(-1); > } > > - return pid; > + if (!ch->pid) { > +#define CHILD_FORGET(other) \ > + other.pid = 0; > +CHILD_LIST(CHILD_FORGET) This clears every xlchild in the CHILD_LIST? Why? Oh, because this is now the child and so those aren't our children any more. A comment would be nice here, took me a little while to figure out. Is there some reason to not indent CHILD_LIST? (You've done it more than once, so I guess so) > + } > + > + return ch->pid; > +} > + > +pid_t xl_waitpid(xlchild *child, int *status, int flags) > +{ > + pid_t got = child->pid; > + assert(got); > + if (child->reaped) { > + *status = child->status; > + child->pid = 0; > + return got; > + } > + for (;;) { > + got = waitpid(child->pid, status, flags); > + if (got < 0 && errno == EINTR) continue; > + if (got > 0) { > + assert(got == child->pid); > + child->pid = 0; > + } > + return got; > + } > +} > + > +static int reaped_callback_child_check(xlchild *ch, pid_t got, int status) > +{ > + if (ch->pid != got) > + return 0; > + ch->reaped = 1; > + ch->status = status; > + return 1; > +} > + > +static int xl_reaped_callback(pid_t got, int status, void *user) > +{ > + assert(got); > + return ( > +#define CHILD_CHECK(ch) \ > + reaped_callback_child_check(&ch, got, status) || > +CHILD_LIST(CHILD_CHECK) > + 0) ? 0 : ERROR_UNKNOWN_CHILD; > +} > + > +static const libxl_childproc_hooks childproc_hooks = { > + .chldowner = libxl_sigchld_owner_libxl, > + .reaped_callback = xl_reaped_callback, > +}; > + > +void xl_ctx_alloc(void) { > + if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (xentoollog_logger*)logger)) > { > + fprintf(stderr, "cannot init xl context\n"); > + exit(1); > + } > + > + libxl_childproc_setmode(ctx, &childproc_hooks, 0); > } > > int main(int argc, char **argv) > @@ -159,10 +216,7 @@ int main(int argc, char **argv) > logger = xtl_createlogger_stdiostream(stderr, minmsglevel, 0); > if (!logger) exit(1); > > - if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (xentoollog_logger*)logger)) > { > - fprintf(stderr, "cannot init xl context\n"); > - exit(1); > - } > + xl_ctx_alloc(); > > /* Read global config file options */ > ret = asprintf(&config_file, "%s/xl.conf", libxl_xen_config_dir_path()); > diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h > index 5d0d504..a00309c 100644 > --- a/tools/libxl/xl.h > +++ b/tools/libxl/xl.h > @@ -15,6 +15,8 @@ > #ifndef XL_H > #define XL_H > > +#include <assert.h> > + > #include "xentoollog.h" > > struct cmd_spec { > @@ -105,8 +107,31 @@ struct cmd_spec *cmdtable_lookup(const char *s); > > extern libxl_ctx *ctx; > extern xentoollog_logger_stdiostream *logger; > -pid_t xl_fork(libxl_ctx *ctx); /* like fork, but prints and dies if it fails > */ > -void postfork(void); > + > +void xl_ctx_alloc(void); > + > +/* child processes */ > + > +typedef struct { > + /* every struct like this must be in XLCHILD_LIST */ > + pid_t pid; /* 0: not in use */ > + int reaped; > + int status; /* valid iff pid==-1 */ > +} xlchild; > + > +/* our child processes */ > +#define CHILD_LIST(_) \ > + _(child_console) \ > + _(child_waitdaemon) \ > + _(migration_child) Is using "_" like this valid? (i.e. not reserved by C or POSIX or something) > + > +#define CHILD_DECLARE(ch) \ > +extern xlchild ch; > +CHILD_LIST(CHILD_DECLARE); > + > +pid_t xl_fork(xlchild*); /* like fork, but prints and dies if it fails */ > +void postfork(void); /* needed only if we aren't going to exec right away */ > +pid_t xl_waitpid(xlchild*, int *status, int flags); /* handles EINTR */ > > /* global options */ > extern int autoballoon; > diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c > index 9f182c2..de1f2d8 100644 > --- a/tools/libxl/xl_cmdimpl.c > +++ b/tools/libxl/xl_cmdimpl.c > @@ -17,7 +17,6 @@ > #include "libxl_osdeps.h" > > #include <stdio.h> > -#include <assert.h> > #include <stdlib.h> > #include <string.h> > #include <unistd.h> > @@ -66,6 +65,13 @@ int logfile = 2; > /* every libxl action in xl uses this same libxl context */ > libxl_ctx *ctx; > > +#define CHILD_DEFINE(ch) \ > +xlchild ch; > +CHILD_LIST(CHILD_DEFINE); > + > +xlchild child_console; > +xlchild child_waitdaemon; Aren't these redundant with the definition from the preceding CHILD_LIST? This CHILD_LIST thing is clever but it isn't half opaque for the reader. I'd say we'd be better off open coding them. Either we say: There are only 3 of them, we can put the functions which deal with them near each other and have a comment saying "update all these". or we can add a proper list (LIBXL_LIST based?) which we add them to and manage explicitly from xlfork and reap/xlwaitpid. > + > /* when we operate on a domain, it is this one: */ > static uint32_t domid; > static const char *common_domname; > @@ -1457,19 +1463,33 @@ static int freemem(libxl_domain_build_info *b_info) > return ERROR_NOMEM; > } > > +static void console_child_report(void) > +{ > + if (child_console.pid) { > + int status; > + pid_t got = xl_waitpid(&child_console, &status, 0); > + if (got < 0) > + perror("xl: warning, failed to waitpid for console child"); > + else if (status) > + libxl_report_child_exitstatus(ctx, XTL_ERROR, "console child", > + child_console.pid, status); > + } > +} > + > static void autoconnect_console(libxl_ctx *ctx_ignored, > libxl_event *ev, void *priv) > { > - pid_t *pid = priv; > uint32_t bldomid = ev->domid; > > libxl_event_free(ctx, ev); > > - *pid = fork(); > - if (*pid < 0) { > + console_child_report(); > + > + pid_t pid = xl_fork(&child_console); console_child_report doesn't seem to reset child_config.pid and xlfork has an assert(!foo.pid) in it, so how does this work on the second time? > + if (pid < 0) { > perror("unable to fork xenconsole"); > return; > - } else if (*pid > 0) > + } else if (pid > 0) > return; > > postfork(); > libxl_evdisable_domain_death(ctx, deathw); [...] _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |