[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC XEN PATCH for-4.13 1/4] libxl: Introduce libxl__ev_child_kill



Allow to kill a child and deregister the callback associated with it.

The death isn't immediate will need to be collected later, so the
ev_child machinery register its own callback.

libxl__ev_child_kill() might be called by an AO operation that is
finishing/cleaning up without a chance for libxl to be notified of the
child death (via SIGCHLD). So it is possible that the application
calls libxl_ctx_free() while there are still child around. To avoid
the application getting unexpected SIGCHLD, the libxl__ao responsible
for killing a child will have to wait until it has been properly
reaped.

Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
 tools/libxl/libxl_event.c    |  3 +-
 tools/libxl/libxl_fork.c     | 55 ++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_internal.h |  8 ++++++
 3 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c
index 0370b6acdd1c..f57c16da1fd9 100644
--- a/tools/libxl/libxl_event.c
+++ b/tools/libxl/libxl_event.c
@@ -1891,7 +1891,8 @@ static bool ao_work_outstanding(libxl__ao *ao)
      * decrement progress_reports_outstanding, and call
      * libxl__ao_complete_check_progress_reports.
      */
-    return !ao->complete || ao->progress_reports_outstanding;
+    return !ao->complete || ao->progress_reports_outstanding
+        || ao->outstanding_killed_child;
 }
 
 void libxl__ao_complete_check_progress_reports(libxl__egc *egc, libxl__ao *ao)
diff --git a/tools/libxl/libxl_fork.c b/tools/libxl/libxl_fork.c
index eea3d5d4e68e..d99d40107f71 100644
--- a/tools/libxl/libxl_fork.c
+++ b/tools/libxl/libxl_fork.c
@@ -678,6 +678,61 @@ int libxl__ev_child_xenstore_reopen(libxl__gc *gc, const 
char *what) {
     return rc;
 }
 
+typedef struct ev_child_killed {
+    libxl__ao *ao;
+    libxl__ev_child ch;
+} ev_child_killed;
+static void deregistered_child_callback(libxl__egc *, libxl__ev_child *,
+                                        pid_t, int status);
+
+/*
+ * Allow to send a SIGKILL signal to a child and deregister the death
+ * callback.
+ * state: Active/Idle -> Idle
+ */
+void libxl__ev_child_kill(libxl__ao *ao, libxl__ev_child *ch)
+{
+    AO_GC;
+
+    if (!libxl__ev_child_inuse(ch))
+        return;
+
+    pid_t pid = ch->pid;
+
+    ev_child_killed *new_ch = GCNEW(new_ch);
+    new_ch->ao = ao;
+    new_ch->ch.pid = pid;
+    new_ch->ch.callback = deregistered_child_callback;
+    LIBXL_LIST_INSERT_HEAD(&CTX->children, &new_ch->ch, entry);
+    ao->outstanding_killed_child++;
+
+    LIBXL_LIST_REMOVE(ch, entry);
+    ch->pid = -1;
+    int r = kill(pid, SIGKILL);
+    if (r)
+        LOGE(ERROR, "failed to kill child [%ld]",
+             (unsigned long)pid);
+}
+
+static void deregistered_child_callback(libxl__egc *egc,
+                                        libxl__ev_child *ch,
+                                        pid_t pid,
+                                        int status)
+{
+    ev_child_killed *ck = CONTAINER_OF(ch, *ck, ch);
+    EGC_GC;
+
+    if (status) {
+        libxl_report_child_exitstatus(CTX, XTL_ERROR,
+                                      "killed fork (dying as expected)",
+                                      pid, status);
+    } else {
+        LOG(DEBUG, "killed child exit cleanly, unexpected");
+    }
+    ck->ao->outstanding_killed_child--;
+    libxl__ao_complete_check_progress_reports(egc, ck->ao);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index d2d5af746b50..5823890703ad 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -727,6 +727,7 @@ struct libxl__ao {
     libxl__poller *poller;
     uint32_t domid;
     LIBXL_TAILQ_ENTRY(libxl__ao) entry_for_callback;
+    int outstanding_killed_child;
 };
 
 #define LIBXL_INIT_GC(gc,ctx) do{               \
@@ -1168,6 +1169,13 @@ static inline int libxl__ev_child_inuse(const 
libxl__ev_child *childw_out)
  * message>". */
 _hidden int libxl__ev_child_xenstore_reopen(libxl__gc *gc, const char *what);
 
+/*
+ * Allow to send a SIGKILL signal to a child and deregister the death
+ * callback.
+ * state: Active/Idle -> Idle
+ */
+_hidden void libxl__ev_child_kill(libxl__ao *ao, libxl__ev_child *ch);
+
 
 /*
  * Other event-handling support provided by the libxl event core to
-- 
Anthony PERARD

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.