mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 12:35:17 +00:00
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:
parent
098ba1a433
commit
94311de539
14
ChangeLog
14
ChangeLog
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -170,6 +170,7 @@
|
||||
__virStateCleanup;
|
||||
__virStateReload;
|
||||
__virStateActive;
|
||||
__virStateSigDispatcher;
|
||||
|
||||
__virDrvSupportsFeature;
|
||||
|
||||
|
140
src/lxc_driver.c
140
src/lxc_driver.c
@ -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)
|
||||
|
@ -3198,6 +3198,7 @@ static virStateDriver qemuStateDriver = {
|
||||
qemudShutdown,
|
||||
qemudReload,
|
||||
qemudActive,
|
||||
NULL
|
||||
};
|
||||
|
||||
int qemudRegister(void) {
|
||||
|
@ -4793,6 +4793,7 @@ static virStateDriver state_driver = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
|
@ -1245,6 +1245,7 @@ static virStateDriver stateDriver = {
|
||||
storageDriverShutdown,
|
||||
storageDriverReload,
|
||||
storageDriverActive,
|
||||
NULL
|
||||
};
|
||||
|
||||
int storageRegister(void) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user