1 /*
2  * Copyright (C) 2012      Citrix Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; version 2.1 only. with the special
7  * exception on linking described in file LICENSE.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  */
14 /*
15  * Internal child process machinery for use by other parts of libxl
16  */
17 
18 #include "libxl_osdeps.h" /* must come before any other headers */
19 
20 #include "libxl_internal.h"
21 
22 /*
23  * carefd arrangements
24  *
25  * carefd_begin and _unlock take out the no_forking lock, which we
26  * also take and release in our pthread_atfork handlers.  So when this
27  * lock is held the whole process cannot fork.  We therefore protect
28  * our fds from leaking into children made by other threads.
29  *
30  * We maintain a list of all the carefds, so that if the application
31  * wants to fork a long-running but non-execing child, we can close
32  * them all.
33  *
34  * So the record function sets CLOEXEC for the benefit of execing
35  * children, and makes a note of the fd for the benefit of non-execing
36  * ones.
37  */
38 
39 struct libxl__carefd {
40     XEN_LIST_ENTRY(libxl__carefd) entry;
41     int fd;
42 };
43 
44 static pthread_mutex_t no_forking = PTHREAD_MUTEX_INITIALIZER;
45 static int atfork_registered;
46 static XEN_LIST_HEAD(, libxl__carefd) carefds =
47     XEN_LIST_HEAD_INITIALIZER(carefds);
48 
49 /* Protected against concurrency by no_forking.  sigchld_users is
50  * protected against being interrupted by SIGCHLD (and thus read
51  * asynchronously by the signal handler) by sigchld_defer (see
52  * below). */
53 static bool sigchld_installed; /* 0 means not */
54 static pthread_mutex_t sigchld_defer_mutex = PTHREAD_MUTEX_INITIALIZER;
55 static XEN_LIST_HEAD(, libxl_ctx) sigchld_users =
56     XEN_LIST_HEAD_INITIALIZER(sigchld_users);
57 static struct sigaction sigchld_saved_action;
58 
59 static void sigchld_removehandler_core(void); /* idempotent */
60 static void sigchld_user_remove(libxl_ctx *ctx); /* idempotent */
61 static void sigchld_sethandler_raw(void (*handler)(int), struct sigaction *old);
62 
63 static void defer_sigchld(void);
64 static void release_sigchld(void);
65 
atfork_lock(void)66 static void atfork_lock(void)
67 {
68     int r = pthread_mutex_lock(&no_forking);
69     assert(!r);
70 }
71 
atfork_unlock(void)72 static void atfork_unlock(void)
73 {
74     int r = pthread_mutex_unlock(&no_forking);
75     assert(!r);
76 }
77 
libxl__atfork_init(libxl_ctx * ctx)78 int libxl__atfork_init(libxl_ctx *ctx)
79 {
80     int r, rc;
81 
82     atfork_lock();
83     if (atfork_registered) { rc = 0; goto out; }
84 
85     r = pthread_atfork(atfork_lock, atfork_unlock, atfork_unlock);
86     if (r) {
87         assert(r == ENOMEM);
88         libxl__alloc_failed(ctx, __func__, 0,0);
89     }
90 
91     atfork_registered = 1;
92     rc = 0;
93  out:
94     atfork_unlock();
95     return rc;
96 }
97 
libxl__carefd_begin(void)98 void libxl__carefd_begin(void) { atfork_lock(); }
libxl__carefd_unlock(void)99 void libxl__carefd_unlock(void) { atfork_unlock(); }
100 
libxl__carefd_record(libxl_ctx * ctx,int fd)101 libxl__carefd *libxl__carefd_record(libxl_ctx *ctx, int fd)
102 {
103     libxl__carefd *cf = 0;
104 
105     libxl_fd_set_cloexec(ctx, fd, 1);
106     cf = libxl__zalloc(&ctx->nogc_gc, sizeof(*cf));
107     cf->fd = fd;
108     XEN_LIST_INSERT_HEAD(&carefds, cf, entry);
109     return cf;
110 }
111 
libxl__carefd_opened(libxl_ctx * ctx,int fd)112 libxl__carefd *libxl__carefd_opened(libxl_ctx *ctx, int fd)
113 {
114     libxl__carefd *cf = 0;
115     int saved_errno = errno;
116 
117     if (fd >= 0)
118         cf = libxl__carefd_record(ctx, fd);
119     libxl__carefd_unlock();
120     errno = saved_errno;
121     return cf;
122 }
123 
libxl_postfork_child_noexec(libxl_ctx * ctx)124 void libxl_postfork_child_noexec(libxl_ctx *ctx)
125 {
126     /*
127      * Anything running without the no_forking lock (atfork_lock)
128      * might be interrupted by fork.  But libxl functions other than
129      * this one are then forbidden to the child.
130      *
131      * Conversely, this function might interrupt any other libxl
132      * operation (even though that other operation has the libxl ctx
133      * lock).  We don't take the lock ourselves, since we are running
134      * in the child and if the lock is held the thread that took it no
135      * longer exists.  To prevent us being interrupted by another call
136      * to ourselves (whether in another thread or by virtue of another
137      * fork) we take the atfork lock ourselves.
138      */
139     libxl__carefd *cf, *cf_tmp;
140     int r;
141 
142     atfork_lock();
143 
144     XEN_LIST_FOREACH_SAFE(cf, &carefds, entry, cf_tmp) {
145         if (cf->fd >= 0) {
146             r = close(cf->fd);
147             if (r)
148                 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_WARNING,
149                                  "failed to close fd=%d"
150                                  " (perhaps of another libxl ctx)", cf->fd);
151         }
152         free(cf);
153     }
154     XEN_LIST_INIT(&carefds);
155 
156     if (sigchld_installed) {
157         /* We are in theory not at risk of concurrent execution of the
158          * SIGCHLD handler, because the application should call
159          * libxl_postfork_child_noexec before the child forks again.
160          * (If the SIGCHLD was in flight in the parent at the time of
161          * the fork, the thread it was delivered on exists only in the
162          * parent so is not our concern.)
163          *
164          * But in case the application violated this rule (and did so
165          * while multithreaded in the child), we use our deferral
166          * machinery.  The result is that the SIGCHLD may then be lost
167          * (i.e. signaled to the now-defunct libxl ctx(s)).  But at
168          * least we won't execute undefined behaviour (by examining
169          * the list in the signal handler concurrently with clearing
170          * it here), and since we won't actually reap the new children
171          * things will in fact go OK if the application doesn't try to
172          * use SIGCHLD, but instead just waits for the child(ren). */
173         defer_sigchld();
174 
175         XEN_LIST_INIT(&sigchld_users);
176         /* After this the ->sigchld_user_registered entries in the
177          * now-obsolete contexts may be lies.  But that's OK because
178          * no-one will look at them. */
179 
180         release_sigchld();
181         sigchld_removehandler_core();
182     }
183 
184     atfork_unlock();
185 }
186 
libxl__carefd_close(libxl__carefd * cf)187 int libxl__carefd_close(libxl__carefd *cf)
188 {
189     if (!cf) return 0;
190     atfork_lock();
191     int r = cf->fd < 0 ? 0 : close(cf->fd);
192     int esave = errno;
193     XEN_LIST_REMOVE(cf, entry);
194     atfork_unlock();
195     free(cf);
196     errno = esave;
197     return r;
198 }
199 
libxl__carefd_fd(const libxl__carefd * cf)200 int libxl__carefd_fd(const libxl__carefd *cf)
201 {
202     if (!cf) return -1;
203     return cf->fd;
204 }
205 
206 /*
207  * Low-level functions for child process handling, including
208  * the main SIGCHLD handler.
209  */
210 
211 /* Like waitpid(,,WNOHANG) but handles all errors except ECHILD. */
checked_waitpid(libxl__egc * egc,pid_t want,int * status)212 static pid_t checked_waitpid(libxl__egc *egc, pid_t want, int *status)
213 {
214     EGC_GC;
215     for (;;) {
216         pid_t got = waitpid(want, status, WNOHANG);
217         if (got != -1)
218             return got;
219         if (errno == ECHILD)
220             return got;
221         if (errno == EINTR)
222             continue;
223         LIBXL__EVENT_DISASTER(gc, "waitpid() failed", errno, 0);
224         return 0;
225     }
226 }
227 
228 static void sigchld_selfpipe_handler(libxl__egc *egc, libxl__ev_fd *ev,
229                                      int fd, short events, short revents);
230 
sigchld_handler(int signo)231 static void sigchld_handler(int signo)
232 {
233     /* This function has to be reentrant!  Luckily it is. */
234 
235     libxl_ctx *notify;
236     int esave = errno;
237 
238     int r = pthread_mutex_lock(&sigchld_defer_mutex);
239     assert(!r);
240 
241     XEN_LIST_FOREACH(notify, &sigchld_users, sigchld_users_entry) {
242         int e = libxl__self_pipe_wakeup(notify->sigchld_selfpipe[1]);
243         if (e) abort(); /* errors are probably EBADF, very bad */
244     }
245 
246     r = pthread_mutex_unlock(&sigchld_defer_mutex);
247     assert(!r);
248 
249     errno = esave;
250 }
251 
sigchld_sethandler_raw(void (* handler)(int),struct sigaction * old)252 static void sigchld_sethandler_raw(void (*handler)(int), struct sigaction *old)
253 {
254     struct sigaction ours;
255     int r;
256 
257     memset(&ours,0,sizeof(ours));
258     ours.sa_handler = handler;
259     sigemptyset(&ours.sa_mask);
260     ours.sa_flags = SA_NOCLDSTOP | SA_RESTART;
261     r = sigaction(SIGCHLD, &ours, old);
262     assert(!r);
263 }
264 
265 /*
266  * SIGCHLD deferral
267  *
268  * sigchld_defer and sigchld_release are a bit like using sigprocmask
269  * to block the signal only they work for the whole process.  Sadly
270  * this has to be done by setting a special handler that records the
271  * "pendingness" of the signal here in the program.  How tedious.
272  *
273  * A property of this approach is that the signal handler itself
274  * must be reentrant (see the comment in release_sigchld).
275  *
276  * Callers have the atfork_lock so there is no risk of concurrency
277  * within these functions, aside from the risk of being interrupted by
278  * the signal.  We use sigchld_defer_mutex to guard against the
279  * possibility of the real signal handler being still running on
280  * another thread.
281  */
282 
283 static volatile sig_atomic_t sigchld_occurred_while_deferred;
284 
sigchld_handler_when_deferred(int signo)285 static void sigchld_handler_when_deferred(int signo)
286 {
287     sigchld_occurred_while_deferred = 1;
288 }
289 
defer_sigchld(void)290 static void defer_sigchld(void)
291 {
292     assert(sigchld_installed);
293 
294     sigchld_sethandler_raw(sigchld_handler_when_deferred, 0);
295 
296     /* Now _this thread_ cannot any longer be interrupted by the
297      * signal, so we can take the mutex without risk of deadlock.  If
298      * another thread is in the signal handler, either it or we will
299      * block and wait for the other. */
300 
301     int r = pthread_mutex_lock(&sigchld_defer_mutex);
302     assert(!r);
303 }
304 
release_sigchld(void)305 static void release_sigchld(void)
306 {
307     assert(sigchld_installed);
308 
309     int r = pthread_mutex_unlock(&sigchld_defer_mutex);
310     assert(!r);
311 
312     sigchld_sethandler_raw(sigchld_handler, 0);
313     if (sigchld_occurred_while_deferred) {
314         sigchld_occurred_while_deferred = 0;
315         /* We might get another SIGCHLD here, in which case
316          * sigchld_handler will be interrupted and re-entered.
317          * This is OK. */
318         sigchld_handler(SIGCHLD);
319     }
320 }
321 
322 /*
323  * Meat of the child process handling.
324  */
325 
sigchld_removehandler_core(void)326 static void sigchld_removehandler_core(void) /* idempotent */
327 {
328     struct sigaction was;
329     int r;
330 
331     if (!sigchld_installed)
332         return;
333 
334     r = sigaction(SIGCHLD, &sigchld_saved_action, &was);
335     assert(!r);
336     assert(!(was.sa_flags & SA_SIGINFO));
337     assert(was.sa_handler == sigchld_handler);
338 
339     sigchld_installed = 0;
340 }
341 
sigchld_installhandler_core(void)342 static void sigchld_installhandler_core(void) /* idempotent */
343 {
344     if (sigchld_installed)
345         return;
346 
347     sigchld_installed = 1;
348 
349     sigchld_sethandler_raw(sigchld_handler, &sigchld_saved_action);
350 
351     assert(((void)"application must negotiate with libxl about SIGCHLD",
352             !(sigchld_saved_action.sa_flags & SA_SIGINFO) &&
353             (sigchld_saved_action.sa_handler == SIG_DFL ||
354              sigchld_saved_action.sa_handler == SIG_IGN)));
355 }
356 
sigchld_user_remove(libxl_ctx * ctx)357 static void sigchld_user_remove(libxl_ctx *ctx) /* idempotent */
358 {
359     if (!ctx->sigchld_user_registered)
360         return;
361 
362     atfork_lock();
363     defer_sigchld();
364 
365     XEN_LIST_REMOVE(ctx, sigchld_users_entry);
366 
367     release_sigchld();
368 
369     if (XEN_LIST_EMPTY(&sigchld_users))
370         sigchld_removehandler_core();
371 
372     atfork_unlock();
373 
374     ctx->sigchld_user_registered = 0;
375 }
376 
libxl__sigchld_notneeded(libxl__gc * gc)377 void libxl__sigchld_notneeded(libxl__gc *gc) /* non-reentrant, idempotent */
378 {
379     sigchld_user_remove(CTX);
380     libxl__ev_fd_deregister(gc, &CTX->sigchld_selfpipe_efd);
381 }
382 
libxl__sigchld_needed(libxl__gc * gc)383 int libxl__sigchld_needed(libxl__gc *gc) /* non-reentrant, idempotent */
384 {
385     int rc;
386 
387     if (CTX->sigchld_selfpipe[0] < 0) {
388         rc = libxl__pipe_nonblock(CTX, CTX->sigchld_selfpipe);
389         if (rc) goto out;
390         libxl_fd_set_cloexec(CTX, CTX->sigchld_selfpipe[0], 1);
391         libxl_fd_set_cloexec(CTX, CTX->sigchld_selfpipe[1], 1);
392     }
393     if (!libxl__ev_fd_isregistered(&CTX->sigchld_selfpipe_efd)) {
394         rc = libxl__ev_fd_register(gc, &CTX->sigchld_selfpipe_efd,
395                                    sigchld_selfpipe_handler,
396                                    CTX->sigchld_selfpipe[0], POLLIN);
397         if (rc) goto out;
398     } else {
399         rc = libxl__ev_fd_modify(gc, &CTX->sigchld_selfpipe_efd, POLLIN);
400         if (rc) goto out;
401     }
402     if (!CTX->sigchld_user_registered) {
403         atfork_lock();
404 
405         sigchld_installhandler_core();
406 
407         defer_sigchld();
408 
409         XEN_LIST_INSERT_HEAD(&sigchld_users, CTX, sigchld_users_entry);
410 
411         release_sigchld();
412         atfork_unlock();
413 
414         CTX->sigchld_user_registered = 1;
415     }
416 
417     rc = 0;
418  out:
419     return rc;
420 }
421 
chldmode_ours(libxl_ctx * ctx,bool creating)422 static bool chldmode_ours(libxl_ctx *ctx, bool creating)
423 {
424     switch (ctx->childproc_hooks->chldowner) {
425     case libxl_sigchld_owner_libxl:
426         return creating || !XEN_LIST_EMPTY(&ctx->children);
427     case libxl_sigchld_owner_mainloop:
428         return 0;
429     case libxl_sigchld_owner_libxl_always:
430     case libxl_sigchld_owner_libxl_always_selective_reap:
431         return 1;
432     }
433     abort();
434 }
435 
perhaps_sigchld_notneeded(libxl__gc * gc)436 static void perhaps_sigchld_notneeded(libxl__gc *gc)
437 {
438     if (!chldmode_ours(CTX, 0))
439         libxl__sigchld_notneeded(gc);
440 }
441 
perhaps_sigchld_needed(libxl__gc * gc,bool creating)442 static int perhaps_sigchld_needed(libxl__gc *gc, bool creating)
443 {
444     int rc;
445 
446     if (chldmode_ours(CTX, creating)) {
447         rc = libxl__sigchld_needed(gc);
448         if (rc) return rc;
449     }
450     return 0;
451 }
452 
childproc_reaped_ours(libxl__egc * egc,libxl__ev_child * ch,int status)453 static void childproc_reaped_ours(libxl__egc *egc, libxl__ev_child *ch,
454                                  int status)
455 {
456     pid_t pid = ch->pid;
457     XEN_LIST_REMOVE(ch, entry);
458     ch->pid = -1;
459     ch->callback(egc, ch, pid, status);
460 }
461 
childproc_reaped(libxl__egc * egc,pid_t pid,int status)462 static int childproc_reaped(libxl__egc *egc, pid_t pid, int status)
463 {
464     EGC_GC;
465     libxl__ev_child *ch;
466 
467     XEN_LIST_FOREACH(ch, &CTX->children, entry)
468         if (ch->pid == pid)
469             goto found;
470 
471     /* not found */
472     return ERROR_UNKNOWN_CHILD;
473 
474  found:
475     childproc_reaped_ours(egc, ch, status);
476 
477     perhaps_sigchld_notneeded(gc);
478 
479     return 0;
480 }
481 
libxl_childproc_reaped(libxl_ctx * ctx,pid_t pid,int status)482 int libxl_childproc_reaped(libxl_ctx *ctx, pid_t pid, int status)
483 {
484     EGC_INIT(ctx);
485     CTX_LOCK;
486     assert(CTX->childproc_hooks->chldowner
487            == libxl_sigchld_owner_mainloop);
488     int rc = childproc_reaped(egc, pid, status);
489     CTX_UNLOCK_EGC_FREE;
490     return rc;
491 }
492 
childproc_checkall(libxl__egc * egc)493 static void childproc_checkall(libxl__egc *egc)
494 {
495     EGC_GC;
496     libxl__ev_child *ch;
497 
498     for (;;) {
499         int status;
500         pid_t got;
501 
502         XEN_LIST_FOREACH(ch, &CTX->children, entry) {
503             got = checked_waitpid(egc, ch->pid, &status);
504             if (got)
505                 goto found;
506         }
507         /* not found */
508         return;
509 
510     found:
511         if (got == -1) {
512             LIBXL__EVENT_DISASTER
513                 (gc, "waitpid() gave ECHILD but we have a child",
514                  ECHILD, 0);
515             /* it must have finished but we don't know its status */
516             status = 255<<8; /* no wait.h macro for this! */
517             assert(WIFEXITED(status));
518             assert(WEXITSTATUS(status)==255);
519             assert(!WIFSIGNALED(status));
520             assert(!WIFSTOPPED(status));
521         }
522         childproc_reaped_ours(egc, ch, status);
523         /* we need to restart the loop, as children may have been edited */
524     }
525 }
526 
libxl_childproc_sigchld_occurred(libxl_ctx * ctx)527 void libxl_childproc_sigchld_occurred(libxl_ctx *ctx)
528 {
529     EGC_INIT(ctx);
530     CTX_LOCK;
531     assert(CTX->childproc_hooks->chldowner
532            == libxl_sigchld_owner_mainloop);
533     childproc_checkall(egc);
534     CTX_UNLOCK_EGC_FREE;
535 }
536 
sigchld_selfpipe_handler(libxl__egc * egc,libxl__ev_fd * ev,int fd,short events,short revents)537 static void sigchld_selfpipe_handler(libxl__egc *egc, libxl__ev_fd *ev,
538                                      int fd, short events, short revents)
539 {
540     /* May make callbacks into the application for child processes.
541      * So, this function may unlock and relock the CTX.  This is OK
542      * because event callback functions are always called with the CTX
543      * locked exactly once, and from code which copes with reentrancy.
544      * (See also the comment in afterpoll_internal.) */
545     EGC_GC;
546 
547     int selfpipe = CTX->sigchld_selfpipe[0];
548 
549     if (revents & ~POLLIN) {
550         LOG(ERROR, "unexpected poll event 0x%x on SIGCHLD self pipe", revents);
551         LIBXL__EVENT_DISASTER(gc,
552                               "unexpected poll event on SIGCHLD self pipe",
553                               0, 0);
554     }
555     assert(revents & POLLIN);
556 
557     int e = libxl__self_pipe_eatall(selfpipe);
558     if (e) LIBXL__EVENT_DISASTER(gc, "read sigchld pipe", e, 0);
559 
560     if (CTX->childproc_hooks->chldowner
561         == libxl_sigchld_owner_libxl_always_selective_reap) {
562         childproc_checkall(egc);
563         return;
564     }
565 
566     while (chldmode_ours(CTX, 0) /* in case the app changes the mode */) {
567         int status;
568         pid_t pid = checked_waitpid(egc, -1, &status);
569 
570         if (pid == 0 || pid == -1 /* ECHILD */)
571             return;
572 
573         int rc = childproc_reaped(egc, pid, status);
574 
575         if (rc) {
576             if (CTX->childproc_hooks->reaped_callback) {
577                 CTX_UNLOCK;
578                 rc = CTX->childproc_hooks->reaped_callback
579                         (pid, status, CTX->childproc_user);
580                 CTX_LOCK;
581                 if (rc != 0 && rc != ERROR_UNKNOWN_CHILD) {
582                     char disasterbuf[200];
583                     snprintf(disasterbuf, sizeof(disasterbuf), " reported by"
584                              " libxl_childproc_hooks->reaped_callback"
585                              " (for pid=%lu, status=%d; error code %d)",
586                              (unsigned long)pid, status, rc);
587                     LIBXL__EVENT_DISASTER(gc, disasterbuf, 0, 0);
588                     return;
589                 }
590             } else {
591                 rc = ERROR_UNKNOWN_CHILD;
592             }
593             if (rc)
594                 libxl_report_child_exitstatus(CTX, XTL_WARN,
595                                 "unknown child", (long)pid, status);
596         }
597     }
598 }
599 
libxl__ev_child_fork(libxl__gc * gc,libxl__ev_child * ch,libxl__ev_child_callback * death)600 pid_t libxl__ev_child_fork(libxl__gc *gc, libxl__ev_child *ch,
601                            libxl__ev_child_callback *death)
602 {
603     CTX_LOCK;
604     int rc;
605 
606     perhaps_sigchld_needed(gc, 1);
607 
608     pid_t pid =
609         CTX->childproc_hooks->fork_replacement
610         ? CTX->childproc_hooks->fork_replacement(CTX->childproc_user)
611         : fork();
612     if (pid == -1) {
613         LOGE(ERROR, "fork failed");
614         rc = ERROR_FAIL;
615         goto out;
616     }
617 
618     if (!pid) {
619         /* woohoo! */
620         if (CTX->xsh) {
621             xs_daemon_destroy_postfork(CTX->xsh);
622             CTX->xsh = NULL; /* turns mistakes into crashes */
623         }
624         /* Yes, CTX is left locked in the child. */
625         return 0;
626     }
627 
628     ch->pid = pid;
629     ch->callback = death;
630     XEN_LIST_INSERT_HEAD(&CTX->children, ch, entry);
631     rc = pid;
632 
633  out:
634     perhaps_sigchld_notneeded(gc);
635     CTX_UNLOCK;
636     return rc;
637 }
638 
libxl_childproc_setmode(libxl_ctx * ctx,const libxl_childproc_hooks * hooks,void * user)639 void libxl_childproc_setmode(libxl_ctx *ctx, const libxl_childproc_hooks *hooks,
640                              void *user)
641 {
642     GC_INIT(ctx);
643     CTX_LOCK;
644 
645     assert(XEN_LIST_EMPTY(&CTX->children));
646 
647     if (!hooks)
648         hooks = &libxl__childproc_default_hooks;
649 
650     ctx->childproc_hooks = hooks;
651     ctx->childproc_user = user;
652 
653     perhaps_sigchld_notneeded(gc);
654     perhaps_sigchld_needed(gc, 0); /* idempotent, ok to ignore errors for now */
655 
656     CTX_UNLOCK;
657     GC_FREE;
658 }
659 
660 const libxl_childproc_hooks libxl__childproc_default_hooks = {
661     libxl_sigchld_owner_libxl, 0, 0
662 };
663 
libxl__ev_child_xenstore_reopen(libxl__gc * gc,const char * what)664 int libxl__ev_child_xenstore_reopen(libxl__gc *gc, const char *what) {
665     int rc;
666 
667     assert(!CTX->xsh);
668     CTX->xsh = xs_open(0);
669     if (!CTX->xsh) {
670         LOGE(ERROR, "%s: xenstore reopen failed", what);
671         rc = ERROR_FAIL;  goto out;
672     }
673 
674     libxl_fd_set_cloexec(CTX, xs_fileno(CTX->xsh), 1);
675 
676     return 0;
677 
678  out:
679     return rc;
680 }
681 
682 typedef struct ev_child_killed {
683     libxl__ao *ao;
684     libxl__ev_child ch;
685 } ev_child_killed;
686 static void deregistered_child_callback(libxl__egc *, libxl__ev_child *,
687                                         pid_t, int status);
688 
libxl__ev_child_kill_deregister(libxl__ao * ao,libxl__ev_child * ch,int sig)689 void libxl__ev_child_kill_deregister(libxl__ao *ao, libxl__ev_child *ch,
690                                      int sig)
691 {
692     AO_GC;
693 
694     if (!libxl__ev_child_inuse(ch))
695         return;
696 
697     pid_t pid = ch->pid;
698 
699     ev_child_killed *new_ch = GCNEW(new_ch);
700     new_ch->ao = ao;
701     new_ch->ch.pid = pid;
702     new_ch->ch.callback = deregistered_child_callback;
703     XEN_LIST_INSERT_HEAD(&CTX->children, &new_ch->ch, entry);
704     ao->outstanding_killed_child++;
705 
706     XEN_LIST_REMOVE(ch, entry);
707     ch->pid = -1;
708     int r = kill(pid, sig);
709     if (r)
710         LOGED(ERROR, ao->domid,
711               "failed to kill child [%ld] with signal %d",
712              (unsigned long)pid, sig);
713 }
714 
deregistered_child_callback(libxl__egc * egc,libxl__ev_child * ch,pid_t pid,int status)715 static void deregistered_child_callback(libxl__egc *egc,
716                                         libxl__ev_child *ch,
717                                         pid_t pid,
718                                         int status)
719 {
720     ev_child_killed *ck = CONTAINER_OF(ch, *ck, ch);
721     EGC_GC;
722 
723     libxl_report_child_exitstatus(CTX, XTL_ERROR,
724                                   "killed fork (dying as expected)",
725                                   pid, status);
726     ck->ao->outstanding_killed_child--;
727     libxl__ao_complete_check_progress_reports(egc, ck->ao);
728 }
729 
730 /*
731  * Local variables:
732  * mode: C
733  * c-basic-offset: 4
734  * indent-tabs-mode: nil
735  * End:
736  */
737