Enable libvirtd drivers to handle signals, in lxc, sigchld triggers vm cleanup

Mon May 12 23:32:21 PST 2008 David L. Leskovec <dlesko@linux.vnet.ibm.com>

	* qemud/qemud.c: get siginfo with signals, distribute to drivers that
    register a handler
	* src/driver.h: add sighandler function to state driver table
	* src/internal.h: define virStateSigDispatcher functions
	* src/libvirt.c: add __virStateSigDispatcher function
	* src/libvirt_sym.version: add __virStateSigDispatcher
	* src/lxc_driver.c: add sig handler function, cleanup vm when sigchld
    received from container process
	* src/qemu_driver.c: NULL for sig handler (no handler) in state driver
	* src/remote_internal.c: NULL for sig handler (no handler) in state driver
	* src/storage_driver.c: NULL for sig handler (no handler) in state driver
This commit is contained in:
David L. Leskovec 2008-05-13 06:30:58 +00:00
parent 098ba1a433
commit 94311de539
10 changed files with 147 additions and 54 deletions

View File

@ -1,3 +1,17 @@
Mon May 12 23:32:21 PST 2008 David L. Leskovec <dlesko@linux.vnet.ibm.com>
* qemud/qemud.c: get siginfo with signals, distribute to drivers that
register a handler
* src/driver.h: add sighandler function to state driver table
* src/internal.h: define virStateSigDispatcher functions
* src/libvirt.c: add __virStateSigDispatcher function
* src/libvirt_sym.version: add __virStateSigDispatcher
* src/lxc_driver.c: add sig handler function, cleanup vm when sigchld
received from container process
* src/qemu_driver.c: NULL for sig handler (no handler) in state driver
* src/remote_internal.c: NULL for sig handler (no handler) in state driver
* src/storage_driver.c: NULL for sig handler (no handler) in state driver
Thu May 9 12:40:11 EST 2008 Daniel P. Berrange <berrange@redhat.com>
* bootstrap: Added verify module

View File

@ -109,16 +109,16 @@ static gnutls_dh_params_t dh_params;
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 @@ static void qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED,
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 (saferead(server->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
qemudLog(QEMUD_ERR, _("Failed to read from signal pipe: %s"),
strerror(errno));
return;
@ -243,7 +243,7 @@ static void qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED,
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 @@ static void qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED,
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 @@ int main(int argc, char **argv) {
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);

View File

@ -11,6 +11,8 @@
#include <libxml/uri.h>
#include <signal.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -565,6 +567,7 @@ typedef int (*virDrvStateInitialize) (void);
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 @@ struct _virStateDriver {
virDrvStateCleanup cleanup;
virDrvStateReload reload;
virDrvStateActive active;
virDrvSigHandler sigHandler;
};
/*

View File

@ -344,10 +344,12 @@ int __virStateInitialize(void);
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);

View File

@ -607,6 +607,17 @@ int __virStateActive(void) {
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;
}
/**

View File

@ -170,6 +170,7 @@
__virStateCleanup;
__virStateReload;
__virStateActive;
__virStateSigDispatcher;
__virDrvSupportsFeature;

View File

@ -924,6 +924,70 @@ error_out:
return rc;
}
/**
* lxcVmCleanup:
* @vm: Ptr to VM to clean up
*
* 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 lxcVMCleanup(lxc_driver_t *driver, lxc_vm_t * vm)
{
int rc = -1;
int waitRc;
int childStatus = -1;
while (((waitRc = waitpid(vm->def->id, &childStatus, 0)) == -1) &&
errno == EINTR);
if (waitRc != vm->def->id) {
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 = 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(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("sending SIGKILL to tty process failed: %s"),
strerror(errno));
goto tty_error_out;
}
}
while (((waitRc = waitpid(vm->pid, &childStatus, 0)) == -1) &&
errno == EINTR);
if (waitRc != vm->pid) {
lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("waitpid failed to wait for tty %d: %d %s"),
vm->pid, waitRc, strerror(errno));
}
tty_error_out:
vm->state = VIR_DOMAIN_SHUTOFF;
vm->pid = -1;
vm->def->id = -1;
driver->nactivevms--;
driver->ninactivevms++;
lxcSaveConfig(NULL, driver, vm, vm->def);
return rc;
}
/**
* lxcDomainDestroy:
* @dom: Ptr to domain to destroy
@ -935,10 +999,8 @@ error_out:
static int lxcDomainDestroy(virDomainPtr dom)
{
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,
@ -957,47 +1019,7 @@ static int lxcDomainDestroy(virDomainPtr dom)
vm->state = VIR_DOMAIN_SHUTDOWN;
while (((waitRc = waitpid(vm->def->id, &childStatus, 0)) == -1) &&
errno == EINTR);
if (waitRc != vm->def->id) {
lxcError(dom->conn, dom, 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);
kill_tty:
if (0 > (kill(vm->pid, SIGKILL))) {
if (ESRCH != errno) {
lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
_("sending SIGKILL to tty process failed: %s"),
strerror(errno));
goto tty_error_out;
}
}
while (((waitRc = waitpid(vm->pid, &childStatus, 0)) == -1) &&
errno == EINTR);
if (waitRc != vm->pid) {
lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
_("waitpid failed to wait for tty %d: %d %s"),
vm->pid, waitRc, strerror(errno));
}
tty_error_out:
vm->state = VIR_DOMAIN_SHUTOFF;
vm->pid = -1;
vm->def->id = -1;
driver->nactivevms--;
driver->ninactivevms++;
rc = 0;
rc = lxcVMCleanup(driver, vm);
error_out:
return rc;
@ -1077,6 +1099,37 @@ lxcActive(void) {
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 = {
@ -1145,6 +1198,7 @@ static virStateDriver lxcStateDriver = {
lxcShutdown,
NULL, /* reload */
lxcActive,
lxcSigHandler
};
int lxcRegister(void)

View File

@ -3198,6 +3198,7 @@ static virStateDriver qemuStateDriver = {
qemudShutdown,
qemudReload,
qemudActive,
NULL
};
int qemudRegister(void) {

View File

@ -4793,6 +4793,7 @@ static virStateDriver state_driver = {
NULL,
NULL,
NULL,
NULL
};

View File

@ -1245,6 +1245,7 @@ static virStateDriver stateDriver = {
storageDriverShutdown,
storageDriverReload,
storageDriverActive,
NULL
};
int storageRegister(void) {