[libvirt] PATCH: Prevent libvirtd 100% CPU usage when --timeout is used

Daniel P. Berrange berrange at redhat.com
Wed Feb 4 14:46:58 UTC 2009


A couple of bugs conspired to make libvirtd use 100% CPU usage when the
--timeout option is used. This is the default for qemu:///session instance
which are auto-spawned, so quite annoying!

eg   libvirt --timeout=30


 - The qemudRunLoop() method was registering a timeout on every
   iteration of the loop, when it considered itself inactive,
   even if already registered
 - virEventInteruptLocked() was looking at eventLoop.leader
   and comparing to pthread_self() before anyone used the 
   event loop. 'leader' was 0 at this point so it thought it
   had to wake someone up even though no one was waiting in
   the event loop.

The latter bug conspired with the former, so the act of registering
the timeout, caused it to immediately see a wakeup signal on the
following poll. So it did another loop iteration, adding another
timer, getting woken up again, etc 100% cpu follows.

Another minor problem was that when completing an event loop
iteration, we reset eventloop.leader to '0'. It is not safe to
assume that pthread_t is an integer like this. The solution is
to track when something is using the event loop explicitly, and
not rely on the 'leader' variable, unless we know a thread is
active.

Finally we never de-registered the shutdown timeout if a new
client turned up while we were counting down.

This patch addresses all these flaws

Daniel

Index: qemud/event.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/event.c,v
retrieving revision 1.17
diff -u -p -u -r1.17 event.c
--- qemud/event.c	22 Dec 2008 12:55:47 -0000	1.17
+++ qemud/event.c	4 Feb 2009 14:40:09 -0000
@@ -68,6 +68,7 @@ struct virEventTimeout {
 /* State for the main event loop */
 struct virEventLoop {
     pthread_mutex_t lock;
+    int running;
     pthread_t leader;
     int wakeupfd[2];
     int handlesCount;
@@ -521,6 +522,7 @@ int virEventRunOnce(void) {
     int ret, timeout, nfds;
 
     virEventLock();
+    eventLoop.running = 1;
     eventLoop.leader = pthread_self();
     if ((nfds = virEventMakePollFDs(&fds)) < 0) {
         virEventUnlock();
@@ -572,7 +574,7 @@ int virEventRunOnce(void) {
         return -1;
     }
 
-    eventLoop.leader = 0;
+    eventLoop.running = 0;
     virEventUnlock();
     return 0;
 }
@@ -611,7 +613,9 @@ int virEventInit(void)
 static int virEventInterruptLocked(void)
 {
     char c = '\0';
-    if (pthread_self() == eventLoop.leader)
+
+    if (!eventLoop.running ||
+        pthread_self() == eventLoop.leader)
         return 0;
 
     if (safewrite(eventLoop.wakeupfd[1], &c, sizeof(c)) != sizeof(c))
Index: qemud/qemud.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/qemud.c,v
retrieving revision 1.138
diff -u -p -u -r1.138 qemud.c
--- qemud/qemud.c	28 Jan 2009 11:31:39 -0000	1.138
+++ qemud/qemud.c	4 Feb 2009 14:40:09 -0000
@@ -2048,9 +2048,18 @@ static void qemudFreeClient(struct qemud
 static int qemudRunLoop(struct qemud_server *server) {
     int timerid = -1;
     int ret = -1, i;
+    int timerActive = 0;
 
     virMutexLock(&server->lock);
 
+    if (timeout > 0 &&
+        (timerid = virEventAddTimeoutImpl(-1,
+                                          qemudInactiveTimer,
+                                          server, NULL)) < 0) {
+        VIR_ERROR0(_("Failed to register shutdown timeout"));
+        return -1;
+    }
+
     if (min_workers > max_workers)
         max_workers = min_workers;
 
@@ -2071,11 +2080,21 @@ static int qemudRunLoop(struct qemud_ser
          * if any drivers have active state, if not
          * shutdown after timeout seconds
          */
-        if (timeout > 0 && !virStateActive() && !server->clients) {
-            timerid = virEventAddTimeoutImpl(timeout*1000,
-                                             qemudInactiveTimer,
-                                             server, NULL);
-            DEBUG("Scheduling shutdown timer %d", timerid);
+        if (timeout > 0) {
+            if (timerActive) {
+                if (server->clients) {
+                    DEBUG("Deactivating shutdown timer %d", timerid);
+                    virEventUpdateTimeoutImpl(timerid, -1);
+                    timerActive = 0;
+                }
+            } else {
+                if (!virStateActive() &&
+                    !server->clients) {
+                    DEBUG("Activating shutdown timer %d", timerid);
+                    virEventUpdateTimeoutImpl(timerid, timeout * 1000);
+                    timerActive = 1;
+                }
+            }
         }
 
         virMutexUnlock(&server->lock);

-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list