[patch 8/9] Implement better signal handling

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

 



Handle SIGHUP by shutting down all guests and networks
and re-loading configs

Handle SIGTERM/SIGINT by cleanly shutting down

Signed-off-by: Mark McLoughlin <markmc@xxxxxxxxxx>

Index: libvirt/qemud/internal.h
===================================================================
--- libvirt.orig/qemud/internal.h
+++ libvirt/qemud/internal.h
@@ -275,6 +275,7 @@ struct qemud_server {
     int qemuVersion;
     int nclients;
     struct qemud_client *clients;
+    int sigread;
     int nvmfds;
     int nactivevms;
     struct qemud_vm *activevms;
@@ -291,6 +292,7 @@ struct qemud_server {
     char networkConfigDir[PATH_MAX];
     char errorMessage[QEMUD_MAX_ERROR_LEN];
     int errorCode;
+    unsigned int shutdown : 1;
 };
 
 int qemudStartVMDaemon(struct qemud_server *server,
Index: libvirt/qemud/qemud.c
===================================================================
--- libvirt.orig/qemud/qemud.c
+++ libvirt/qemud/qemud.c
@@ -52,9 +52,85 @@
 #include "conf.h"
 #include "iptables.h"
 
-static void reapchild(int sig ATTRIBUTE_UNUSED) {
-    /* We explicitly waitpid the child later */
+static int sigwrite = -1;
+
+static void sig_handler(int sig) {
+    unsigned char sigc = sig;
+    int origerrno;
+
+    if (sig == SIGCHLD) /* We explicitly waitpid the child later */
+        return;
+
+    origerrno = errno;
+    write(sigwrite, &sigc, 1);
+    errno = origerrno;
+}
+
+static int qemudDispatchSignal(struct qemud_server *server)
+{
+    unsigned char sigc;
+    struct qemud_vm *vm;
+    struct qemud_network *network;
+    int ret;
+
+    if (read(server->sigread, &sigc, 1) != 1)
+        return -1;
+
+    /* shutdown active VMs */
+    vm = server->activevms;
+    while (vm) {
+        struct qemud_vm *next = vm->next;
+        qemudShutdownVMDaemon(server, vm);
+        vm = next;
+    }
+
+    /* free inactive VMs */
+    vm = server->inactivevms;
+    while (vm) {
+        struct qemud_vm *next = vm->next;
+        qemudFreeVM(vm);
+        vm = next;
+    }
+    server->inactivevms = NULL;
+    server->ninactivevms = 0;
+
+    /* shutdown active networks */
+    network = server->activenetworks;
+    while (network) {
+        struct qemud_network *next = network->next;
+        qemudShutdownNetworkDaemon(server, network);
+        network = next;
+    }
+
+    /* free inactive networks */
+    network = server->inactivenetworks;
+    while (network) {
+        struct qemud_network *next = network->next;
+        qemudFreeNetwork(network);
+        network = next;
+    }
+    server->inactivenetworks = NULL;
+    server->ninactivenetworks = 0;
+
+    ret = 0;
+
+    switch (sigc) {
+    case SIGHUP:
+        ret = qemudScanConfigs(server);
+        break;
+
+    case SIGINT:
+    case SIGTERM:
+        server->shutdown = 1;
+        break;
+
+    default:
+        break;
+    }
+
+    return ret;
 }
+
 static int qemudSetCloseExec(int fd) {
     int flags;
     if ((flags = fcntl(fd, F_GETFD)) < 0) {
@@ -230,7 +306,7 @@ static int qemudListen(struct qemud_serv
     return 0;
 }
 
-static struct qemud_server *qemudInitialize(int sys) {
+static struct qemud_server *qemudInitialize(int sys, int sigread) {
     struct qemud_server *server;
     char libvirtConf[PATH_MAX];
 
@@ -241,6 +317,7 @@ static struct qemud_server *qemudInitial
     server->qemuVersion = (0*1000000)+(8*1000)+(0);
     /* We don't have a dom-0, so start from 1 */
     server->nextvmid = 1;
+    server->sigread = sigread;
 
     if (sys) {
         if (snprintf(libvirtConf, sizeof(libvirtConf), "%s/libvirt", SYSCONF_DIR) >= (int)sizeof(libvirtConf)) {
@@ -1141,6 +1218,12 @@ static int qemudDispatchPoll(struct qemu
     int ret = 0;
     int fd = 0;
 
+    if (fds[fd++].revents && qemudDispatchSignal(server) < 0)
+        return -1;
+
+    if (server->shutdown)
+        return 0;
+
     while (sock) {
         struct qemud_socket *next = sock->next;
         if (fds[fd].revents)
@@ -1249,6 +1332,10 @@ static void qemudPreparePoll(struct qemu
     struct qemud_client *client;
     struct qemud_vm *vm;
 
+    fds[fd].fd = server->sigread;
+    fds[fd].events = POLLIN;
+    fd++;
+
     for (sock = server->sockets ; sock ; sock = sock->next) {
         fds[fd].fd = sock->fd;
         fds[fd].events = POLLIN;
@@ -1282,7 +1369,7 @@ static void qemudPreparePoll(struct qemu
 
 
 static int qemudOneLoop(struct qemud_server *server, int timeout) {
-    int nfds = server->nsockets + server->nclients + server->nvmfds;
+    int nfds = server->nsockets + server->nclients + server->nvmfds + 1; /* server->sigread */
     struct pollfd fds[nfds];
     int thistimeout = -1;
     int ret;
@@ -1318,7 +1405,7 @@ static int qemudOneLoop(struct qemud_ser
 static int qemudRunLoop(struct qemud_server *server, int timeout) {
     int ret;
 
-    while ((ret = qemudOneLoop(server, timeout)) == 0)
+    while ((ret = qemudOneLoop(server, timeout)) == 0 && !server->shutdown)
         ;
 
     return ret == -1 ? -1 : 0;
@@ -1326,6 +1413,7 @@ static int qemudRunLoop(struct qemud_ser
 
 static void qemudCleanup(struct qemud_server *server) {
     struct qemud_socket *sock = server->sockets;
+    close(server->sigread);
     while (sock) {
         close(sock->fd);
         sock = sock->next;
@@ -1344,6 +1432,8 @@ int main(int argc, char **argv) {
     int sys = 0;
     int timeout = -1;
     struct qemud_server *server;
+    struct sigaction sig_action;
+    int sigpipe[2];
 
     struct option opts[] = {
         { "verbose", no_argument, &verbose, 1},
@@ -1394,10 +1484,24 @@ int main(int argc, char **argv) {
         }
     }
 
-    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
-        return 3;
-    if (signal(SIGCHLD, reapchild) == SIG_ERR)
-        return 3;
+    if (pipe(sigpipe) < 0 ||
+        qemudSetNonBlock(sigpipe[0]) < 0 ||
+        qemudSetNonBlock(sigpipe[1]) < 0)
+        return 1;
+
+    sigwrite = sigpipe[1];
+
+    sig_action.sa_handler = sig_handler;
+    sig_action.sa_flags = 0;
+    sigemptyset(&sig_action.sa_mask);
+
+    sigaction(SIGHUP, &sig_action, NULL);
+    sigaction(SIGINT, &sig_action, NULL);
+    sigaction(SIGTERM, &sig_action, NULL);
+    sigaction(SIGCHLD, &sig_action, NULL);
+
+    sig_action.sa_handler = SIG_IGN;
+    sigaction(SIGPIPE, &sig_action, NULL);
 
     if (godaemon) {
         int pid = qemudGoDaemon();
@@ -1407,13 +1511,15 @@ int main(int argc, char **argv) {
             return 0;
     }
 
-    if (!(server = qemudInitialize(sys)))
+    if (!(server = qemudInitialize(sys, sigpipe[0])))
         return 2;
 
     qemudRunLoop(server, timeout);
 
     qemudCleanup(server);
 
+    close(sigwrite);
+
     return 0;
 }
 

-- 


[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]