]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Move most of qemuProcessKill into virProcessKillPainfully
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 26 Sep 2012 14:42:58 +0000 (15:42 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Thu, 27 Sep 2012 09:11:44 +0000 (10:11 +0100)
In the cgroups APIs we have a virCgroupKillPainfully function
which does the loop sending SIGTERM, then SIGKILL and waiting
for the process to exit. There is similar functionality for
simple processes in qemuProcessKill, but it is tangled with
the QEMU code. Untangle it to provide a virProcessKillPainfuly
function

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
src/libvirt_private.syms
src/qemu/qemu_driver.c
src/qemu/qemu_process.c
src/util/virprocess.c
src/util/virprocess.h

index 4635a4d7705b4dff37cafecf518d3ed0c7da7a19..dab607af14970ab2429754b1e37f1361ad35a468 100644 (file)
@@ -1708,6 +1708,7 @@ virPidFileDeletePath;
 # virprocess.h
 virProcessAbort;
 virProcessKill;
+virProcessKillPainfully;
 virProcessTranslateStatus;
 virProcessWait;
 
index eb61a9642638ee49660099b33f03ff997c54a74d..22fef7ab718d51a30a340612255ab9c9c664c994 100644 (file)
@@ -2006,17 +2006,11 @@ qemuDomainDestroyFlags(virDomainPtr dom,
      * it now means the job will be released
      */
     if (flags & VIR_DOMAIN_DESTROY_GRACEFUL) {
-        if (qemuProcessKill(driver, vm, 0) < 0) {
-            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                           _("failed to kill qemu process with SIGTERM"));
+        if (qemuProcessKill(driver, vm, 0) < 0)
             goto cleanup;
-        }
     } else {
-        if (qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
-            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                           _("failed to kill qemu process with SIGTERM"));
+        if (qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0)
             goto cleanup;
-        }
     }
 
     /* We need to prevent monitor EOF callback from doing our work (and sending
index 3cd30afb79cf6922a93ce87dc00f01d00feed559..70b72afa00f33330b5c72f7a7dc9d9c0ce4858e5 100644 (file)
@@ -3877,9 +3877,7 @@ int
 qemuProcessKill(struct qemud_driver *driver,
                 virDomainObjPtr vm, unsigned int flags)
 {
-    int i, ret = -1;
-    const char *signame = "TERM";
-    bool driver_unlocked = false;
+    int ret;
 
     VIR_DEBUG("vm=%s pid=%d flags=%x",
               vm->def->name, vm->pid, flags);
@@ -3891,78 +3889,27 @@ qemuProcessKill(struct qemud_driver *driver,
         }
     }
 
-    /* This loop sends SIGTERM (or SIGKILL if flags has
-     * VIR_QEMU_PROCESS_KILL_FORCE and VIR_QEMU_PROCESS_KILL_NOWAIT),
-     * then waits a few iterations (10 seconds) to see if it dies. If
-     * the qemu process still hasn't exited, and
-     * VIR_QEMU_PROCESS_KILL_FORCE is requested, a SIGKILL will then
-     * be sent, and qemuProcessKill will wait up to 5 seconds more for
-     * the process to exit before returning.  Note that the FORCE mode
-     * could result in lost data in the guest, so it should only be
-     * used if the guest is hung and can't be destroyed in any other
-     * manner.
-     */
-    for (i = 0 ; i < 75; i++) {
-        int signum;
-        if (i == 0) {
-            if ((flags & VIR_QEMU_PROCESS_KILL_FORCE) &&
-                (flags & VIR_QEMU_PROCESS_KILL_NOWAIT)) {
-                signum = SIGKILL; /* kill it immediately */
-                signame="KILL";
-            } else {
-                signum = SIGTERM; /* kindly suggest it should exit */
-            }
-        } else if ((i == 50) & (flags & VIR_QEMU_PROCESS_KILL_FORCE)) {
-            VIR_WARN("Timed out waiting after SIG%s to process %d, "
-                     "sending SIGKILL", signame, vm->pid);
-            signum = SIGKILL; /* kill it after a grace period */
-            signame="KILL";
-        } else {
-            signum = 0; /* Just check for existence */
-        }
-
-        if (virProcessKill(vm->pid, signum) < 0) {
-            if (errno != ESRCH) {
-                char ebuf[1024];
-                VIR_WARN("Failed to terminate process %d with SIG%s: %s",
-                         vm->pid, signame,
-                         virStrerror(errno, ebuf, sizeof(ebuf)));
-                goto cleanup;
-            }
-            ret = 0;
-            goto cleanup; /* process is dead */
-        }
+    if ((flags & VIR_QEMU_PROCESS_KILL_NOWAIT)) {
+        virProcessKill(vm->pid,
+                       (flags & VIR_QEMU_PROCESS_KILL_FORCE) ?
+                       SIGKILL : SIGTERM);
+        return 0;
+    }
 
-        if (i == 0 && (flags & VIR_QEMU_PROCESS_KILL_NOWAIT)) {
-            ret = 0;
-            goto cleanup;
-        }
+    if (driver)
+        qemuDriverUnlock(driver);
 
-        if (driver && !driver_unlocked) {
-            /* THREADS.txt says we can't hold the driver lock while sleeping */
-            qemuDriverUnlock(driver);
-            driver_unlocked = true;
-        }
+    ret = virProcessKillPainfully(vm->pid,
+                                  !!(flags & VIR_QEMU_PROCESS_KILL_FORCE));
 
-        usleep(200 * 1000);
-    }
-    VIR_WARN("Timed out waiting after SIG%s to process %d", signame, vm->pid);
-cleanup:
-    if (driver_unlocked) {
-        /* We had unlocked the driver, so re-lock it. THREADS.txt says
-         * we can't have the domain locked when locking the driver, so
-         * we must first unlock the domain. BUT, before we can unlock
-         * the domain, we need to add a ref to it in case there aren't
-         * any active jobs (analysis of all callers didn't reveal such
-         * a case, but there are too many to maintain certainty, so we
-         * will do this as a precaution).
-         */
+    if (driver) {
         virObjectRef(vm);
         virDomainObjUnlock(vm);
         qemuDriverLock(driver);
         virDomainObjLock(vm);
         virObjectUnref(vm);
     }
+
     return ret;
 }
 
index 958f5f7960e86d52baf39a753902718fd2659416..c70aa58dbb2076aa356330c55e2bf9b9df3f7853 100644 (file)
@@ -235,3 +235,60 @@ int virProcessKill(pid_t pid, int sig)
     return kill(pid, sig);
 #endif
 }
+
+
+/*
+ * Try to kill the process and verify it has exited
+ *
+ * Returns 0 if it was killed gracefully, 1 if it
+ * was killed forcably, -1 if it is still alive,
+ * or another error occurred.
+ */
+int
+virProcessKillPainfully(pid_t pid, bool force)
+{
+    int i, ret = -1;
+    const char *signame = "TERM";
+
+    VIR_DEBUG("vpid=%d force=%d", pid, force);
+
+    /* This loop sends SIGTERM, then waits a few iterations (10 seconds)
+     * to see if it dies. If the process still hasn't exited, and
+     * @force is requested, a SIGKILL will be sent, and this will
+     * wait upto 5 seconds more for the process to exit before
+     * returning.
+     *
+     * Note that setting @force could result in dataloss for the process.
+     */
+    for (i = 0 ; i < 75; i++) {
+        int signum;
+        if (i == 0) {
+            signum = SIGTERM; /* kindly suggest it should exit */
+        } else if ((i == 50) & force) {
+            VIR_DEBUG("Timed out waiting after SIGTERM to process %d, "
+                      "sending SIGKILL", pid);
+            signum = SIGKILL; /* kill it after a grace period */
+            signame = "KILL";
+        } else {
+            signum = 0; /* Just check for existence */
+        }
+
+        if (virProcessKill(pid, signum) < 0) {
+            if (errno != ESRCH) {
+                virReportSystemError(errno,
+                                     _("Failed to terminate process %d with SIG%s"),
+                                     pid, signame);
+                goto cleanup;
+            }
+            ret = signum == SIGTERM ? 0 : 1;
+            goto cleanup; /* process is dead */
+        }
+
+        usleep(200 * 1000);
+    }
+
+    VIR_DEBUG("Timed out waiting after SIGKILL to process %d", pid);
+
+cleanup:
+    return ret;
+}
index 048a73c0717db81fee43eee1e79cedfd27098bb6..d537d92be5f667ade0243a75b1e8822a1c8b9331 100644 (file)
@@ -38,5 +38,7 @@ virProcessWait(pid_t pid, int *exitstatus)
 
 int virProcessKill(pid_t pid, int sig);
 
+int virProcessKillPainfully(pid_t pid, bool force);
+
 
 #endif /* __VIR_PROCESS_H__ */