[libvirt] [PATCH 4/6] qemu: use virObject to manage reference-counting for qemu monitor

Hu Tao hutao at cn.fujitsu.com
Wed Apr 6 07:19:55 UTC 2011


---
 src/qemu/qemu_domain.c    |   30 ++-----------
 src/qemu/qemu_migration.c |    2 -
 src/qemu/qemu_monitor.c   |  109 ++++++++++++++++++++++++--------------------
 src/qemu/qemu_monitor.h   |    4 +-
 src/qemu/qemu_process.c   |   32 +++++++-------
 5 files changed, 81 insertions(+), 96 deletions(-)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 3a3c953..d11dc5f 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -560,9 +560,8 @@ void qemuDomainObjEnterMonitor(virDomainObjPtr obj)
 {
     qemuDomainObjPrivatePtr priv = obj->privateData;
 
-    qemuMonitorLock(priv->mon);
-    qemuMonitorRef(priv->mon);
     virDomainObjUnlock(obj);
+    qemuMonitorLock(priv->mon);
 }
 
 
@@ -573,18 +572,9 @@ void qemuDomainObjEnterMonitor(virDomainObjPtr obj)
 void qemuDomainObjExitMonitor(virDomainObjPtr obj)
 {
     qemuDomainObjPrivatePtr priv = obj->privateData;
-    int refs;
-
-    refs = qemuMonitorUnref(priv->mon);
-
-    if (refs > 0)
-        qemuMonitorUnlock(priv->mon);
 
+    qemuMonitorUnlock(priv->mon);
     virDomainObjLock(obj);
-
-    if (refs == 0) {
-        priv->mon = NULL;
-    }
 }
 
 
@@ -601,10 +591,8 @@ void qemuDomainObjEnterMonitorWithDriver(struct qemud_driver *driver,
 {
     qemuDomainObjPrivatePtr priv = obj->privateData;
 
-    qemuMonitorLock(priv->mon);
-    qemuMonitorRef(priv->mon);
     virDomainObjUnlock(obj);
-    qemuDriverUnlock(driver);
+    qemuMonitorLock(priv->mon);
 }
 
 
@@ -617,19 +605,9 @@ void qemuDomainObjExitMonitorWithDriver(struct qemud_driver *driver,
                                         virDomainObjPtr obj)
 {
     qemuDomainObjPrivatePtr priv = obj->privateData;
-    int refs;
-
-    refs = qemuMonitorUnref(priv->mon);
-
-    if (refs > 0)
-        qemuMonitorUnlock(priv->mon);
 
-    qemuDriverLock(driver);
+    qemuMonitorUnlock(priv->mon);
     virDomainObjLock(obj);
-
-    if (refs == 0) {
-        priv->mon = NULL;
-    }
 }
 
 void qemuDomainObjEnterRemoteWithDriver(struct qemud_driver *driver,
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 462e6be..6af2e24 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -224,11 +224,9 @@ qemuMigrationWaitForCompletion(struct qemud_driver *driver, virDomainObjPtr vm)
         }
 
         virDomainObjUnlock(vm);
-        qemuDriverUnlock(driver);
 
         nanosleep(&ts, NULL);
 
-        qemuDriverLock(driver);
         virDomainObjLock(vm);
     }
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 2d28f8d..98c55e7 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -37,6 +37,7 @@
 #include "memory.h"
 #include "logging.h"
 #include "files.h"
+#include "virobject.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -44,11 +45,10 @@
 #define DEBUG_RAW_IO 0
 
 struct _qemuMonitor {
+    virObject obj;
     virMutex lock; /* also used to protect fd */
     virCond notify;
 
-    int refs;
-
     int fd;
     int watch;
     int hasSendFD;
@@ -203,35 +203,61 @@ void qemuMonitorUnlock(qemuMonitorPtr mon)
 }
 
 
-static void qemuMonitorFree(qemuMonitorPtr mon)
+static void doMonitorFree(virObjectPtr obj)
 {
+    qemuMonitorPtr mon = (qemuMonitorPtr)obj;
+
     VIR_DEBUG("mon=%p", mon);
     if (mon->cb && mon->cb->destroy)
         (mon->cb->destroy)(mon, mon->vm);
-    if (virCondDestroy(&mon->notify) < 0)
-    {}
+    ignore_value(virCondDestroy(&mon->notify));
     virMutexDestroy(&mon->lock);
     VIR_FREE(mon->buffer);
     VIR_FREE(mon);
 }
 
-int qemuMonitorRef(qemuMonitorPtr mon)
+static qemuMonitorPtr qemuMonitorAlloc(void)
 {
-    mon->refs++;
-    return mon->refs;
-}
+    qemuMonitorPtr mon;
 
-int qemuMonitorUnref(qemuMonitorPtr mon)
-{
-    mon->refs--;
+    if (VIR_ALLOC(mon) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
 
-    if (mon->refs == 0) {
-        qemuMonitorUnlock(mon);
-        qemuMonitorFree(mon);
-        return 0;
+    if (virObjectInit(&mon->obj, doMonitorFree)) {
+        VIR_FREE(mon);
+        return NULL;
+    }
+
+    if (virMutexInit(&mon->lock) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("cannot initialize monitor mutex"));
+        VIR_FREE(mon);
+        return NULL;
     }
 
-    return mon->refs;
+    if (virCondInit(&mon->notify) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("cannot initialize monitor condition"));
+        virMutexDestroy(&mon->lock);
+        VIR_FREE(mon);
+        return NULL;
+    }
+
+    mon->fd = -1;
+
+    return mon;
+}
+
+void qemuMonitorRef(qemuMonitorPtr mon)
+{
+    virObjectRef(&mon->obj);
+}
+
+void qemuMonitorUnref(qemuMonitorPtr mon)
+{
+    virObjectUnref(&mon->obj);
 }
 
 static void
@@ -239,9 +265,7 @@ qemuMonitorUnwatch(void *monitor)
 {
     qemuMonitorPtr mon = monitor;
 
-    qemuMonitorLock(mon);
-    if (qemuMonitorUnref(mon) > 0)
-        qemuMonitorUnlock(mon);
+    qemuMonitorUnref(mon);
 }
 
 static int
@@ -521,7 +545,6 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque) {
 
     /* lock access to the monitor and protect fd */
     qemuMonitorLock(mon);
-    qemuMonitorRef(mon);
 #if DEBUG_IO
     VIR_DEBUG("Monitor %p I/O on watch %d fd %d events %d", mon, watch, fd, events);
 #endif
@@ -598,13 +621,11 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque) {
 
         /* Make sure anyone waiting wakes up now */
         virCondSignal(&mon->notify);
-        if (qemuMonitorUnref(mon) > 0)
-            qemuMonitorUnlock(mon);
+        qemuMonitorUnlock(mon);
         VIR_DEBUG("Triggering EOF callback error? %d", failed);
         (eofNotify)(mon, vm, failed);
     } else {
-        if (qemuMonitorUnref(mon) > 0)
-            qemuMonitorUnlock(mon);
+        qemuMonitorUnlock(mon);
     }
 }
 
@@ -623,30 +644,13 @@ qemuMonitorOpen(virDomainObjPtr vm,
         return NULL;
     }
 
-    if (VIR_ALLOC(mon) < 0) {
-        virReportOOMError();
+    mon = qemuMonitorAlloc();
+    if (!mon)
         return NULL;
-    }
 
-    if (virMutexInit(&mon->lock) < 0) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("cannot initialize monitor mutex"));
-        VIR_FREE(mon);
-        return NULL;
-    }
-    if (virCondInit(&mon->notify) < 0) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("cannot initialize monitor condition"));
-        virMutexDestroy(&mon->lock);
-        VIR_FREE(mon);
-        return NULL;
-    }
-    mon->fd = -1;
-    mon->refs = 1;
     mon->vm = vm;
     mon->json = json;
     mon->cb = cb;
-    qemuMonitorLock(mon);
 
     switch (config->type) {
     case VIR_DOMAIN_CHR_TYPE_UNIX:
@@ -679,20 +683,25 @@ qemuMonitorOpen(virDomainObjPtr vm,
     }
 
 
+    /* mon will be accessed by qemuMonitorIO which is called in
+     * event thread, so ref it before passing it to the thread.
+     *
+     * Note: mon is unrefed in qemuMonitorUnwatch
+     */
+    qemuMonitorRef(mon);
     if ((mon->watch = virEventAddHandle(mon->fd,
                                         VIR_EVENT_HANDLE_HANGUP |
                                         VIR_EVENT_HANDLE_ERROR |
                                         VIR_EVENT_HANDLE_READABLE,
                                         qemuMonitorIO,
                                         mon, qemuMonitorUnwatch)) < 0) {
+        qemuMonitorUnref(mon);
         qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                         _("unable to register monitor events"));
         goto cleanup;
     }
-    qemuMonitorRef(mon);
 
     VIR_DEBUG("New mon %p fd =%d watch=%d", mon, mon->fd, mon->watch);
-    qemuMonitorUnlock(mon);
 
     return mon;
 
@@ -703,8 +712,8 @@ cleanup:
      * so kill the callbacks now.
      */
     mon->cb = NULL;
-    qemuMonitorUnlock(mon);
     qemuMonitorClose(mon);
+    qemuMonitorUnref(mon);
     return NULL;
 }
 
@@ -724,8 +733,8 @@ void qemuMonitorClose(qemuMonitorPtr mon)
         VIR_FORCE_CLOSE(mon->fd);
     }
 
-    if (qemuMonitorUnref(mon) > 0)
-        qemuMonitorUnlock(mon);
+    qemuMonitorUnlock(mon);
+    qemuMonitorUnref(mon);
 }
 
 
@@ -778,7 +787,7 @@ int qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon,
         if ((mon)->cb && (mon)->cb->callback)                   \
             (ret) = ((mon)->cb->callback)(mon, __VA_ARGS__);    \
         qemuMonitorLock(mon);                                   \
-        ignore_value(qemuMonitorUnref(mon));                    \
+        qemuMonitorUnref(mon);                    \
     } while (0)
 
 int qemuMonitorGetDiskSecret(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index c90219b..4498c49 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -132,8 +132,8 @@ int qemuMonitorCheckHMP(qemuMonitorPtr mon, const char *cmd);
 void qemuMonitorLock(qemuMonitorPtr mon);
 void qemuMonitorUnlock(qemuMonitorPtr mon);
 
-int qemuMonitorRef(qemuMonitorPtr mon);
-int qemuMonitorUnref(qemuMonitorPtr mon) ATTRIBUTE_RETURN_CHECK;
+void qemuMonitorRef(qemuMonitorPtr mon);
+void qemuMonitorUnref(qemuMonitorPtr mon);
 
 /* These APIs are for use by the internal Text/JSON monitor impl code only */
 int qemuMonitorSend(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 244b22a..4b9087f 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -107,7 +107,6 @@ qemuProcessHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
 
     VIR_DEBUG("Received EOF on %p '%s'", vm, vm->def->name);
 
-    qemuDriverLock(driver);
     virDomainObjLock(vm);
 
     if (!virDomainObjIsActive(vm)) {
@@ -133,15 +132,17 @@ qemuProcessHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     qemuProcessStop(driver, vm, 0);
     qemuAuditDomainStop(vm, hasError ? "failed" : "shutdown");
 
-    if (!vm->persistent)
+    if (!vm->persistent) {
+        qemuDriverLock(driver);
         virDomainRemoveInactive(&driver->domains, vm);
-    else
-        virDomainObjUnlock(vm);
+        qemuDriverUnlock(driver);
+    }
+
+    virDomainObjUnlock(vm);
 
     if (event) {
         qemuDomainEventQueue(driver, event);
     }
-    qemuDriverUnlock(driver);
 }
 
 
@@ -602,8 +603,10 @@ static void qemuProcessHandleMonitorDestroy(qemuMonitorPtr mon,
 
     virDomainObjLock(vm);
     priv = vm->privateData;
-    if (priv->mon == mon)
+    if (priv->mon == mon) {
         priv->mon = NULL;
+        qemuMonitorUnref(mon);
+    }
     virDomainObjUnlock(vm);
     virDomainObjUnref(vm);
 }
@@ -633,19 +636,11 @@ qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
         goto error;
     }
 
-    /* Hold an extra reference because we can't allow 'vm' to be
-     * deleted while the monitor is active */
-    virDomainObjRef(vm);
-
     priv->mon = qemuMonitorOpen(vm,
                                 priv->monConfig,
                                 priv->monJSON,
                                 &monitorCallbacks);
 
-    /* Safe to ignore value since ref count was incremented above */
-    if (priv->mon == NULL)
-        virDomainObjUnref(vm);
-
     if (virSecurityManagerClearSocketLabel(driver->securityManager, vm) < 0) {
         VIR_ERROR(_("Failed to clear security context for monitor for %s"),
                   vm->def->name);
@@ -657,6 +652,7 @@ qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
         goto error;
     }
 
+    qemuMonitorRef(priv->mon);
 
     qemuDomainObjEnterMonitorWithDriver(driver, vm);
     ret = qemuMonitorSetCapabilities(priv->mon);
@@ -2471,8 +2467,12 @@ void qemuProcessStop(struct qemud_driver *driver,
                              _("Failed to send SIGTERM to %s (%d)"),
                              vm->def->name, vm->pid);
 
-    if (priv->mon)
-        qemuMonitorClose(priv->mon);
+    if (priv->mon) {
+        qemuMonitorPtr mon = priv->mon;
+        priv->mon = NULL;
+        qemuMonitorClose(mon);
+        qemuMonitorUnref(mon);
+    }
 
     if (priv->monConfig) {
         if (priv->monConfig->type == VIR_DOMAIN_CHR_TYPE_UNIX)
-- 
1.7.3.1


-- 
Thanks,
Hu Tao




More information about the libvir-list mailing list