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

Re: [Libvir] [PATCH] lxc: handle SIGCHLD from exiting container



Jim Meyering wrote:
> Dave Leskovec <dlesko linux vnet ibm com> wrote:
> ...
>>>> +#ifndef	_SIGNAL_H
>>>> +#include <signal.h>
>>>> +#endif
>>> In practice it's fine to include <signal.h> unconditionally,
>>> and even multiple times.  Have you encountered a version of <signal.h>
>>> that may not be included twice?  If so, it probably deserves a comment
>>> with the details.
>> No, I don't have any special condition here.  This is probably some past
>> conditioning resurfacing briefly.  If I remember correctly, it had more to do
>> with compile efficiency rather than avoiding compile failures from multiple
>> inclusions.
> 
> Then don't bother.
> gcc performs a handy optimization whereby it doesn't even open
> the header file the second (and subsequent) time it's included, as
> long as it's entire contents is wrapped in the usual sort of guard:
> 
>   #ifndef SYM
>   #define SYM
>   ...
>   #endif

Thanks Jim.  I've attached an updated patch with those two changes.  While
making these changes, I noticed that I missed updating the storage drivers state
driver table.  I've fixed that as well.

-- 
Best Regards,
Dave Leskovec
IBM Linux Technology Center
Open Virtualization
---
 qemud/qemud.c           |   26 ++++++----
 src/driver.h            |    4 +
 src/internal.h          |    2 
 src/libvirt.c           |   11 ++++
 src/libvirt_sym.version |    1 
 src/lxc_driver.c        |  114 +++++++++++++++++++++++++++++++++++-------------
 src/qemu_driver.c       |    1 
 src/remote_internal.c   |    1 
 src/storage_driver.c    |    1 
 9 files changed, 120 insertions(+), 41 deletions(-)

Index: b/qemud/qemud.c
===================================================================
--- a/qemud/qemud.c	2008-04-28 02:09:52.000000000 -0700
+++ b/qemud/qemud.c	2008-04-30 15:34:29.000000000 -0700
@@ -109,16 +109,16 @@
 static sig_atomic_t sig_errors = 0;
 static int sig_lasterrno = 0;
 
-static void sig_handler(int sig) {
-    unsigned char sigc = sig;
+static void sig_handler(int sig, siginfo_t * siginfo,
+                        void* context ATTRIBUTE_UNUSED) {
     int origerrno;
     int r;
 
-    if (sig == SIGCHLD) /* We explicitly waitpid the child later */
-        return;
+    /* set the sig num in the struct */
+    siginfo->si_signo = sig;
 
     origerrno = errno;
-    r = safewrite(sigwrite, &sigc, 1);
+    r = safewrite(sigwrite, siginfo, sizeof(*siginfo));
     if (r == -1) {
         sig_errors++;
         sig_lasterrno = errno;
@@ -232,10 +232,10 @@
                                      int events ATTRIBUTE_UNUSED,
                                      void *opaque) {
     struct qemud_server *server = (struct qemud_server *)opaque;
-    unsigned char sigc;
+    siginfo_t siginfo;
     int ret;
 
-    if (read(server->sigread, &sigc, 1) != 1) {
+    if (read(server->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
         qemudLog(QEMUD_ERR, _("Failed to read from signal pipe: %s"),
                  strerror(errno));
         return;
@@ -243,7 +243,7 @@
 
     ret = 0;
 
-    switch (sigc) {
+    switch (siginfo.si_signo) {
     case SIGHUP:
         qemudLog(QEMUD_INFO, "%s", _("Reloading configuration on SIGHUP"));
         if (virStateReload() < 0)
@@ -253,11 +253,15 @@
     case SIGINT:
     case SIGQUIT:
     case SIGTERM:
-        qemudLog(QEMUD_WARN, _("Shutting down on signal %d"), sigc);
+        qemudLog(QEMUD_WARN, _("Shutting down on signal %d"),
+                 siginfo.si_signo);
         server->shutdown = 1;
         break;
 
     default:
+        qemudLog(QEMUD_INFO, _("Received signal %d, dispatching to drivers"),
+                 siginfo.si_signo);
+        virStateSigDispatcher(&siginfo);
         break;
     }
 
@@ -2186,8 +2190,8 @@
             goto error1;
     }
 
-    sig_action.sa_handler = sig_handler;
-    sig_action.sa_flags = 0;
+    sig_action.sa_sigaction = sig_handler;
+    sig_action.sa_flags = SA_SIGINFO;
     sigemptyset(&sig_action.sa_mask);
 
     sigaction(SIGHUP, &sig_action, NULL);
Index: b/src/driver.h
===================================================================
--- a/src/driver.h	2008-04-10 09:54:54.000000000 -0700
+++ b/src/driver.h	2008-05-05 23:28:40.000000000 -0700
@@ -11,6 +11,8 @@
 
 #include <libxml/uri.h>
 
+#include <signal.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -565,6 +567,7 @@
 typedef int (*virDrvStateCleanup) (void);
 typedef int (*virDrvStateReload) (void);
 typedef int (*virDrvStateActive) (void);
+typedef int (*virDrvSigHandler) (siginfo_t *siginfo);
 
 typedef struct _virStateDriver virStateDriver;
 typedef virStateDriver *virStateDriverPtr;
@@ -574,6 +577,7 @@
     virDrvStateCleanup     cleanup;
     virDrvStateReload      reload;
     virDrvStateActive      active;
+    virDrvSigHandler       sigHandler;
 };
 
 /*
Index: b/src/internal.h
===================================================================
--- a/src/internal.h	2008-04-28 14:44:54.000000000 -0700
+++ b/src/internal.h	2008-04-30 15:01:24.000000000 -0700
@@ -344,10 +344,12 @@
 int __virStateCleanup(void);
 int __virStateReload(void);
 int __virStateActive(void);
+int __virStateSigDispatcher(siginfo_t *siginfo);
 #define virStateInitialize() __virStateInitialize()
 #define virStateCleanup() __virStateCleanup()
 #define virStateReload() __virStateReload()
 #define virStateActive() __virStateActive()
+#define virStateSigDispatcher(s) __virStateSigDispatcher(s)
 
 int __virDrvSupportsFeature (virConnectPtr conn, int feature);
 
Index: b/src/libvirt.c
===================================================================
--- a/src/libvirt.c	2008-04-10 09:54:54.000000000 -0700
+++ b/src/libvirt.c	2008-04-30 15:01:24.000000000 -0700
@@ -607,6 +607,17 @@
     return ret;
 }
 
+int __virStateSigDispatcher(siginfo_t *siginfo) {
+    int i, ret = 0;
+
+    for (i = 0 ; i < virStateDriverTabCount ; i++) {
+        if (virStateDriverTab[i]->sigHandler &&
+            virStateDriverTab[i]->sigHandler(siginfo))
+            ret = 1;
+    }
+    return ret;
+}
+
 
 
 /**
Index: b/src/libvirt_sym.version
===================================================================
--- a/src/libvirt_sym.version	2008-04-28 08:14:59.000000000 -0700
+++ b/src/libvirt_sym.version	2008-04-30 15:01:24.000000000 -0700
@@ -170,6 +170,7 @@
 	__virStateCleanup;
 	__virStateReload;
 	__virStateActive;
+	__virStateSigDispatcher;
 
 	__virDrvSupportsFeature;
 
Index: b/src/lxc_driver.c
===================================================================
--- a/src/lxc_driver.c	2008-04-10 09:53:29.000000000 -0700
+++ b/src/lxc_driver.c	2008-05-05 23:21:56.000000000 -0700
@@ -841,55 +841,42 @@
 }
 
 /**
- * lxcDomainDestroy:
- * @dom: Ptr to domain to destroy
+ * lxcVmCleanup:
+ * @vm: Ptr to VM to clean up
  *
- * Sends SIGKILL to container root process to terminate the container
+ * waitpid() on the container process.  kill and wait the tty process
+ * This is called by boh lxcDomainDestroy and lxcSigHandler when a
+ * container exits.
  *
  * Returns 0 on success or -1 in case of error
  */
-static int lxcDomainDestroy(virDomainPtr dom)
+static int lxcVMCleanup(lxc_driver_t *driver, lxc_vm_t * vm)
 {
     int rc = -1;
     int waitRc;
-    lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData;
-    lxc_vm_t *vm = lxcFindVMByID(driver, dom->id);
-    int childStatus;
-
-    if (!vm) {
-        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
-                 _("no domain with id %d"), dom->id);
-        goto error_out;
-    }
-
-    if (0 > (kill(vm->def->id, SIGKILL))) {
-        if (ESRCH != errno) {
-            lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
-                     _("sending SIGKILL failed: %s"), strerror(errno));
-
-            goto error_out;
-        }
-    }
-
-    vm->state = VIR_DOMAIN_SHUTDOWN;
+    int childStatus = -1;
 
     while (((waitRc = waitpid(vm->def->id, &childStatus, 0)) == -1) &&
            errno == EINTR);
 
     if (waitRc != vm->def->id) {
-        lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                  _("waitpid failed to wait for container %d: %d %s"),
                  vm->def->id, waitRc, strerror(errno));
         goto kill_tty;
     }
 
-    rc = WEXITSTATUS(childStatus);
-    DEBUG("container exited with rc: %d", rc);
+    rc = 0;
+
+    if (WIFEXITED(childStatus)) {
+        rc = WEXITSTATUS(childStatus);
+        DEBUG("container exited with rc: %d", rc);
+    }
 
 kill_tty:
     if (0 > (kill(vm->pid, SIGKILL))) {
         if (ESRCH != errno) {
-            lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                      _("sending SIGKILL to tty process failed: %s"),
                      strerror(errno));
 
@@ -901,7 +888,7 @@
            errno == EINTR);
 
     if (waitRc != vm->pid) {
-        lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                  _("waitpid failed to wait for tty %d: %d %s"),
                  vm->pid, waitRc, strerror(errno));
     }
@@ -912,8 +899,43 @@
     vm->def->id = -1;
     driver->nactivevms--;
     driver->ninactivevms++;
+    lxcSaveConfig(NULL, driver, vm, vm->def);
 
-    rc = 0;
+    return rc;
+ }
+
+/**
+ * lxcDomainDestroy:
+ * @dom: Ptr to domain to destroy
+ *
+ * Sends SIGKILL to container root process to terminate the container
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcDomainDestroy(virDomainPtr dom)
+{
+    int rc = -1;
+    lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData;
+    lxc_vm_t *vm = lxcFindVMByID(driver, dom->id);
+
+    if (!vm) {
+        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
+                 _("no domain with id %d"), dom->id);
+        goto error_out;
+    }
+
+    if (0 > (kill(vm->def->id, SIGKILL))) {
+        if (ESRCH != errno) {
+            lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+                     _("sending SIGKILL failed: %s"), strerror(errno));
+
+            goto error_out;
+        }
+    }
+
+    vm->state = VIR_DOMAIN_SHUTDOWN;
+
+    rc = lxcVMCleanup(driver, vm);
 
 error_out:
     return rc;
@@ -993,6 +1015,37 @@
     return 0;
 }
 
+/**
+ * lxcSigHandler:
+ * @siginfo: Pointer to siginfo_t structure
+ *
+ * Handles signals received by libvirtd.  Currently this is used to
+ * catch SIGCHLD from an exiting container.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcSigHandler(siginfo_t *siginfo)
+{
+    int rc = -1;
+    lxc_vm_t *vm;
+
+    if (siginfo->si_signo == SIGCHLD) {
+        vm = lxcFindVMByID(lxc_driver, siginfo->si_pid);
+
+        if (NULL == vm) {
+            DEBUG("Ignoring SIGCHLD from non-container process %d\n",
+                  siginfo->si_pid);
+            goto cleanup;
+        }
+
+        rc = lxcVMCleanup(lxc_driver, vm);
+
+    }
+
+cleanup:
+    return rc;
+}
+
 
 /* Function Tables */
 static virDriver lxcDriver = {
@@ -1061,6 +1114,7 @@
     lxcShutdown,
     NULL, /* reload */
     lxcActive,
+    lxcSigHandler
 };
 
 int lxcRegister(void)
Index: b/src/qemu_driver.c
===================================================================
--- a/src/qemu_driver.c	2008-04-25 13:46:13.000000000 -0700
+++ b/src/qemu_driver.c	2008-04-30 15:01:24.000000000 -0700
@@ -3133,6 +3133,7 @@
     qemudShutdown,
     qemudReload,
     qemudActive,
+    NULL
 };
 
 int qemudRegister(void) {
Index: b/src/remote_internal.c
===================================================================
--- a/src/remote_internal.c	2008-04-29 12:43:57.000000000 -0700
+++ b/src/remote_internal.c	2008-05-05 23:17:43.000000000 -0700
@@ -4794,6 +4794,7 @@
     NULL,
     NULL,
     NULL,
+    NULL
 };
 
 
Index: b/src/storage_driver.c
===================================================================
--- a/src/storage_driver.c	2008-04-18 01:33:23.000000000 -0700
+++ b/src/storage_driver.c	2008-05-05 23:35:34.000000000 -0700
@@ -1245,6 +1245,7 @@
     storageDriverShutdown,
     storageDriverReload,
     storageDriverActive,
+    NULL
 };
 
 int storageRegister(void) {

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