This patch allows the lxc driver to handle SIGCHLD signals from exiting containers. The handling will perform some cleanup such as waiting for the container process and killing/waiting the tty process. This is also required as a first step towards providing some kind of client container exit notification. Additional support is needed for that but this SIGCHLD handling is what would trigger the notification. libvirtd was already catching SIGCHLD although it was just ignoring it. I implemented a mechanism to distribute the signal to any other drivers in the daemon that registered a function to handle them. This required some changes to the way libvirtd was catching signals (to get the pid of the sending process) as well as an addition to the state driver structure. The intent was to provide future drivers access to signals as well. -- Best Regards, Dave Leskovec IBM Linux Technology Center Open Virtualization
--- qemud/qemud.c | 26 ++++++---- src/driver.h | 6 ++ 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 8 files changed, 121 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-04-30 15:36:47.000000000 -0700 @@ -11,6 +11,10 @@ #include <libxml/uri.h> +#ifndef _SIGNAL_H +#include <signal.h> +#endif + #ifdef __cplusplus extern "C" { #endif @@ -565,6 +569,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 +579,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-04-30 17:37:09.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); + if (WIFEXITED(childStatus)) { + rc = WEXITSTATUS(childStatus); + DEBUG("container exited with rc: %d", rc); + } + + rc = 0; 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-04-30 17:37:14.000000000 -0700 @@ -4794,6 +4794,7 @@ NULL, NULL, NULL, + NULL };
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list