[libvirt] [PATCH] Move most of qemuProcessKill into virProcessKillPainfully

Daniel P. Berrange berrange at redhat.com
Fri Sep 28 08:00:50 UTC 2012


On Thu, Sep 27, 2012 at 04:31:10PM -0400, Laine Stump wrote:
> On 09/26/2012 10:44 AM, Daniel P. Berrange wrote:
> > From: "Daniel P. Berrange" <berrange at redhat.com>
> >
> > 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
> > ---
> >  src/libvirt_private.syms |  1 +
> >  src/qemu/qemu_driver.c   |  8 ++---
> >  src/qemu/qemu_process.c  | 79 ++++++++----------------------------------------
> >  src/util/virprocess.c    | 57 ++++++++++++++++++++++++++++++++++
> >  src/util/virprocess.h    |  2 ++
> >  5 files changed, 76 insertions(+), 71 deletions(-)
> >
> > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> > index 4635a4d..dab607a 100644
> > --- a/src/libvirt_private.syms
> > +++ b/src/libvirt_private.syms
> > @@ -1708,6 +1708,7 @@ virPidFileDeletePath;
> >  # virprocess.h
> >  virProcessAbort;
> >  virProcessKill;
> > +virProcessKillPainfully;
> >  virProcessTranslateStatus;
> >  virProcessWait;
> >  
> > diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> > index 7ac53ac..22fef7a 100644
> > --- a/src/qemu/qemu_driver.c
> > +++ b/src/qemu/qemu_driver.c
> > @@ -2006,13 +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 {
> > -        ignore_value(qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE));
> > +        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
> > diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> > index 3cd30af..70b72af 100644
> > --- a/src/qemu/qemu_process.c
> > +++ b/src/qemu/qemu_process.c
> > @@ -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;
> >  }
> >  
> > diff --git a/src/util/virprocess.c b/src/util/virprocess.c
> > index 958f5f7..c70aa58 100644
> > --- a/src/util/virprocess.c
> > +++ b/src/util/virprocess.c
> > @@ -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 */
> > +        }
> 
> Hmm. I just added a similar kill loop in bridge_driver.c. The main
> difference is that it doesn't wait as long (not for any particular
> reason, though).
> 
> I guess I should change it to use this. (I actually considered making a
> utility function at the time, but it was too close to release, so I
> didn't want to touch other drivers...)

Yep, sounds good.


Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list