[libvirt] [PATCH 1/7] Allow for multi-level inheritance of virObject classes

Daniel P. Berrange berrange at redhat.com
Fri Jan 11 12:13:05 UTC 2013


From: "Daniel P. Berrange" <berrange at redhat.com>

Currently all classes must directly inherit from virObject.
This allows for arbitrarily deep hierarchy. There's not much
too this aside from chaining up the 'dispose' handlers from
each class & providing APIs to check types.
---
 src/conf/domain_conf.c        |  3 +-
 src/datatypes.c               |  3 +-
 src/libvirt_private.syms      |  2 ++
 src/lxc/lxc_monitor.c         |  3 +-
 src/qemu/qemu_agent.c         |  3 +-
 src/qemu/qemu_capabilities.c  |  3 +-
 src/qemu/qemu_monitor.c       |  7 ++--
 src/rpc/virkeepalive.c        |  3 +-
 src/rpc/virnetclient.c        |  3 +-
 src/rpc/virnetclientprogram.c |  3 +-
 src/rpc/virnetclientstream.c  |  3 +-
 src/rpc/virnetsaslcontext.c   |  6 ++--
 src/rpc/virnetserver.c        |  3 +-
 src/rpc/virnetserverclient.c  |  3 +-
 src/rpc/virnetserverprogram.c |  3 +-
 src/rpc/virnetserverservice.c |  3 +-
 src/rpc/virnetsocket.c        |  3 +-
 src/rpc/virnetsshsession.c    |  3 +-
 src/rpc/virnettlscontext.c    |  6 ++--
 src/util/virdnsmasq.c         |  3 +-
 src/util/virobject.c          | 84 ++++++++++++++++++++++++++++++++++++++++---
 src/util/virobject.h          |  9 ++++-
 22 files changed, 134 insertions(+), 28 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b3a35b7..38dc334 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -695,7 +695,8 @@ static void virDomainObjDispose(void *obj);
 
 static int virDomainObjOnceInit(void)
 {
-    if (!(virDomainObjClass = virClassNew("virDomainObj",
+    if (!(virDomainObjClass = virClassNew(virClassForObject(),
+                                          "virDomainObj",
                                           sizeof(virDomainObj),
                                           virDomainObjDispose)))
         return -1;
diff --git a/src/datatypes.c b/src/datatypes.c
index 068233c..b04e100 100644
--- a/src/datatypes.c
+++ b/src/datatypes.c
@@ -64,7 +64,8 @@ static int
 virDataTypesOnceInit(void)
 {
 #define DECLARE_CLASS(basename)                                  \
-    if (!(basename ## Class = virClassNew(#basename,             \
+    if (!(basename ## Class = virClassNew(virClassForObject(),   \
+                                          #basename,             \
                                           sizeof(basename),      \
                                           basename ## Dispose))) \
         return -1;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d079cc9..092cb59 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1767,6 +1767,8 @@ virNodeSuspendGetTargetMask;
 
 
 # virobject.h
+virClassForObject;
+virClassIsDerivedFrom;
 virClassName;
 virClassNew;
 virObjectFreeCallback;
diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c
index 6971bcb..f697e09 100644
--- a/src/lxc/lxc_monitor.c
+++ b/src/lxc/lxc_monitor.c
@@ -50,7 +50,8 @@ static void virLXCMonitorDispose(void *obj);
 
 static int virLXCMonitorOnceInit(void)
 {
-    if (!(virLXCMonitorClass = virClassNew("virLXCMonitor",
+    if (!(virLXCMonitorClass = virClassNew(virClassForObject(),
+                                           "virLXCMonitor",
                                            sizeof(virLXCMonitor),
                                            virLXCMonitorDispose)))
         return -1;
diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c
index bb421bd..db4a0bc 100644
--- a/src/qemu/qemu_agent.c
+++ b/src/qemu/qemu_agent.c
@@ -121,7 +121,8 @@ static void qemuAgentDispose(void *obj);
 
 static int qemuAgentOnceInit(void)
 {
-    if (!(qemuAgentClass = virClassNew("qemuAgent",
+    if (!(qemuAgentClass = virClassNew(virClassForObject(),
+                                       "qemuAgent",
                                        sizeof(qemuAgent),
                                        qemuAgentDispose)))
         return -1;
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 320d8c8..29b5066 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -241,7 +241,8 @@ static void qemuCapsDispose(void *obj);
 
 static int qemuCapsOnceInit(void)
 {
-    if (!(qemuCapsClass = virClassNew("qemuCaps",
+    if (!(qemuCapsClass = virClassNew(virClassForObject(),
+                                      "qemuCaps",
                                       sizeof(qemuCaps),
                                       qemuCapsDispose)))
         return -1;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index cb5a3e2..d6176c7 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -86,9 +86,10 @@ static void qemuMonitorDispose(void *obj);
 
 static int qemuMonitorOnceInit(void)
 {
-    if (!(qemuMonitorClass = virClassNew("qemuMonitor",
-                                          sizeof(qemuMonitor),
-                                          qemuMonitorDispose)))
+    if (!(qemuMonitorClass = virClassNew(virClassForObject(),
+                                         "qemuMonitor",
+                                         sizeof(qemuMonitor),
+                                         qemuMonitorDispose)))
         return -1;
 
     return 0;
diff --git a/src/rpc/virkeepalive.c b/src/rpc/virkeepalive.c
index a8ceff5..04962d4 100644
--- a/src/rpc/virkeepalive.c
+++ b/src/rpc/virkeepalive.c
@@ -58,7 +58,8 @@ static void virKeepAliveDispose(void *obj);
 
 static int virKeepAliveOnceInit(void)
 {
-    if (!(virKeepAliveClass = virClassNew("virKeepAlive",
+    if (!(virKeepAliveClass = virClassNew(virClassForObject(),
+                                          "virKeepAlive",
                                           sizeof(virKeepAlive),
                                           virKeepAliveDispose)))
         return -1;
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index a79b79b..f281548 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -117,7 +117,8 @@ static void virNetClientDispose(void *obj);
 
 static int virNetClientOnceInit(void)
 {
-    if (!(virNetClientClass = virClassNew("virNetClient",
+    if (!(virNetClientClass = virClassNew(virClassForObject(),
+                                          "virNetClient",
                                           sizeof(virNetClient),
                                           virNetClientDispose)))
         return -1;
diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c
index 9410cff..2e6e4f6 100644
--- a/src/rpc/virnetclientprogram.c
+++ b/src/rpc/virnetclientprogram.c
@@ -52,7 +52,8 @@ static void virNetClientProgramDispose(void *obj);
 
 static int virNetClientProgramOnceInit(void)
 {
-    if (!(virNetClientProgramClass = virClassNew("virNetClientProgram",
+    if (!(virNetClientProgramClass = virClassNew(virClassForObject(),
+                                                 "virNetClientProgram",
                                                  sizeof(virNetClientProgram),
                                                  virNetClientProgramDispose)))
         return -1;
diff --git a/src/rpc/virnetclientstream.c b/src/rpc/virnetclientstream.c
index 15ed91a..e1ee30e 100644
--- a/src/rpc/virnetclientstream.c
+++ b/src/rpc/virnetclientstream.c
@@ -68,7 +68,8 @@ static void virNetClientStreamDispose(void *obj);
 
 static int virNetClientStreamOnceInit(void)
 {
-    if (!(virNetClientStreamClass = virClassNew("virNetClientStream",
+    if (!(virNetClientStreamClass = virClassNew(virClassForObject(),
+                                                "virNetClientStream",
                                                 sizeof(virNetClientStream),
                                                 virNetClientStreamDispose)))
         return -1;
diff --git a/src/rpc/virnetsaslcontext.c b/src/rpc/virnetsaslcontext.c
index cbf7261..41a69d1 100644
--- a/src/rpc/virnetsaslcontext.c
+++ b/src/rpc/virnetsaslcontext.c
@@ -55,12 +55,14 @@ static void virNetSASLSessionDispose(void *obj);
 
 static int virNetSASLContextOnceInit(void)
 {
-    if (!(virNetSASLContextClass = virClassNew("virNetSASLContext",
+    if (!(virNetSASLContextClass = virClassNew(virClassForObject(),
+                                               "virNetSASLContext",
                                                sizeof(virNetSASLContext),
                                                virNetSASLContextDispose)))
         return -1;
 
-    if (!(virNetSASLSessionClass = virClassNew("virNetSASLSession",
+    if (!(virNetSASLSessionClass = virClassNew(virClassForObject(),
+                                               "virNetSASLSession",
                                                sizeof(virNetSASLSession),
                                                virNetSASLSessionDispose)))
         return -1;
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
index b9df71b..03efbb8 100644
--- a/src/rpc/virnetserver.c
+++ b/src/rpc/virnetserver.c
@@ -119,7 +119,8 @@ static void virNetServerDispose(void *obj);
 
 static int virNetServerOnceInit(void)
 {
-    if (!(virNetServerClass = virClassNew("virNetServer",
+    if (!(virNetServerClass = virClassNew(virClassForObject(),
+                                          "virNetServer",
                                           sizeof(virNetServer),
                                           virNetServerDispose)))
         return -1;
diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c
index bf23d24..ce8bd6d 100644
--- a/src/rpc/virnetserverclient.c
+++ b/src/rpc/virnetserverclient.c
@@ -112,7 +112,8 @@ static void virNetServerClientDispose(void *obj);
 
 static int virNetServerClientOnceInit(void)
 {
-    if (!(virNetServerClientClass = virClassNew("virNetServerClient",
+    if (!(virNetServerClientClass = virClassNew(virClassForObject(),
+                                                "virNetServerClient",
                                                 sizeof(virNetServerClient),
                                                 virNetServerClientDispose)))
         return -1;
diff --git a/src/rpc/virnetserverprogram.c b/src/rpc/virnetserverprogram.c
index 06b6325..414b978 100644
--- a/src/rpc/virnetserverprogram.c
+++ b/src/rpc/virnetserverprogram.c
@@ -49,7 +49,8 @@ static void virNetServerProgramDispose(void *obj);
 
 static int virNetServerProgramOnceInit(void)
 {
-    if (!(virNetServerProgramClass = virClassNew("virNetServerProgram",
+    if (!(virNetServerProgramClass = virClassNew(virClassForObject(),
+                                                 "virNetServerProgram",
                                                  sizeof(virNetServerProgram),
                                                  virNetServerProgramDispose)))
         return -1;
diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c
index 61dd682..05fe41b 100644
--- a/src/rpc/virnetserverservice.c
+++ b/src/rpc/virnetserverservice.c
@@ -55,7 +55,8 @@ static void virNetServerServiceDispose(void *obj);
 
 static int virNetServerServiceOnceInit(void)
 {
-    if (!(virNetServerServiceClass = virClassNew("virNetServerService",
+    if (!(virNetServerServiceClass = virClassNew(virClassForObject(),
+                                                 "virNetServerService",
                                                  sizeof(virNetServerService),
                                                  virNetServerServiceDispose)))
         return -1;
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
index a817999..f96b47c 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -104,7 +104,8 @@ static void virNetSocketDispose(void *obj);
 
 static int virNetSocketOnceInit(void)
 {
-    if (!(virNetSocketClass = virClassNew("virNetSocket",
+    if (!(virNetSocketClass = virClassNew(virClassForObject(),
+                                          "virNetSocket",
                                           sizeof(virNetSocket),
                                           virNetSocketDispose)))
         return -1;
diff --git a/src/rpc/virnetsshsession.c b/src/rpc/virnetsshsession.c
index 661860f..ca7d52e 100644
--- a/src/rpc/virnetsshsession.c
+++ b/src/rpc/virnetsshsession.c
@@ -161,7 +161,8 @@ static virClassPtr virNetSSHSessionClass;
 static int
 virNetSSHSessionOnceInit(void)
 {
-    if (!(virNetSSHSessionClass = virClassNew("virNetSSHSession",
+    if (!(virNetSSHSessionClass = virClassNew(virClassForObject(),
+                                              "virNetSSHSession",
                                               sizeof(virNetSSHSession),
                                               virNetSSHSessionDispose)))
         return -1;
diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c
index 56e372b..3e194f9 100644
--- a/src/rpc/virnettlscontext.c
+++ b/src/rpc/virnettlscontext.c
@@ -85,12 +85,14 @@ static void virNetTLSSessionDispose(void *obj);
 
 static int virNetTLSContextOnceInit(void)
 {
-    if (!(virNetTLSContextClass = virClassNew("virNetTLSContext",
+    if (!(virNetTLSContextClass = virClassNew(virClassForObject(),
+                                              "virNetTLSContext",
                                               sizeof(virNetTLSContext),
                                               virNetTLSContextDispose)))
         return -1;
 
-    if (!(virNetTLSSessionClass = virClassNew("virNetTLSSession",
+    if (!(virNetTLSSessionClass = virClassNew(virClassForObject(),
+                                              "virNetTLSSession",
                                               sizeof(virNetTLSSession),
                                               virNetTLSSessionDispose)))
         return -1;
diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c
index 2d0f02c..6637a89 100644
--- a/src/util/virdnsmasq.c
+++ b/src/util/virdnsmasq.c
@@ -628,7 +628,8 @@ dnsmasqCapsDispose(void *obj)
 
 static int dnsmasqCapsOnceInit(void)
 {
-    if (!(dnsmasqCapsClass = virClassNew("dnsmasqCaps",
+    if (!(dnsmasqCapsClass = virClassNew(virClassForObject(),
+                                         "dnsmasqCaps",
                                          sizeof(dnsmasqCaps),
                                          dnsmasqCapsDispose))) {
         return -1;
diff --git a/src/util/virobject.c b/src/util/virobject.c
index f51b735..5f44ab2 100644
--- a/src/util/virobject.c
+++ b/src/util/virobject.c
@@ -33,6 +33,8 @@
 static unsigned int magicCounter = 0xCAFE0000;
 
 struct _virClass {
+    virClassPtr parent;
+
     unsigned int magic;
     const char *name;
     size_t objectSize;
@@ -40,9 +42,39 @@ struct _virClass {
     virObjectDisposeCallback dispose;
 };
 
+static virClassPtr virObjectClass;
+
+static int virObjectOnceInit(void)
+{
+    if (!(virObjectClass = virClassNew(NULL,
+                                       "virObject",
+                                       sizeof(virObject),
+                                       NULL)))
+        return -1;
+
+    return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(virObject);
+
+
+/**
+ * virClassForObject:
+ *
+ * Returns the class instance for the base virObject type
+ */
+virClassPtr virClassForObject(void)
+{
+    if (!virObjectInitialize() < 0)
+        return NULL;
+
+    return virObjectClass;
+}
+
 
 /**
  * virClassNew:
+ * @parent: the parent class
  * @name: the class name
  * @objectSize: total size of the object struct
  * @dispose: callback to run to free object fields
@@ -56,15 +88,29 @@ struct _virClass {
  *
  * Returns a new class instance
  */
-virClassPtr virClassNew(const char *name,
+virClassPtr virClassNew(virClassPtr parent,
+                        const char *name,
                         size_t objectSize,
                         virObjectDisposeCallback dispose)
 {
     virClassPtr klass;
 
+    if (parent == NULL &&
+        STRNEQ(name, "virObject")) {
+        virReportInvalidNonNullArg(parent);
+        return NULL;
+    } else if (parent &&
+               objectSize <= parent->objectSize) {
+        virReportInvalidArg(objectSize,
+                            _("object size %zu of %s is smaller than parent class %zu"),
+                            objectSize, name, parent->objectSize);
+        return NULL;
+    }
+
     if (VIR_ALLOC(klass) < 0)
         goto no_memory;
 
+    klass->parent = parent;
     if (!(klass->name = strdup(name)))
         goto no_memory;
     klass->magic = virAtomicIntInc(&magicCounter);
@@ -81,6 +127,27 @@ no_memory:
 
 
 /**
+ * virClassIsDerivedFrom:
+ * @klass: the klass to check
+ * @parent: the possible parent class
+ *
+ * Determine if @klass is derived from @parent
+ *
+ * Return true if @klass is derived from @parent, false otherwise
+ */
+bool virClassIsDerivedFrom(virClassPtr klass,
+                           virClassPtr parent)
+{
+    while (klass) {
+        if (klass->magic == parent->magic)
+            return true;
+        klass = klass->parent;
+    }
+    return false;
+}
+
+
+/**
  * virObjectNew:
  * @klass: the klass of object to create
  *
@@ -135,8 +202,14 @@ bool virObjectUnref(void *anyobj)
     PROBE(OBJECT_UNREF, "obj=%p", obj);
     if (lastRef) {
         PROBE(OBJECT_DISPOSE, "obj=%p", obj);
-        if (obj->klass->dispose)
-            obj->klass->dispose(obj);
+        virClassPtr klass = obj->klass;
+        while (klass) {
+            if (klass->dispose)
+                klass->dispose(obj);
+            klass = klass->parent;
+        }
+
+        virMutexDestroy(&obj->lock);
 
         /* Clear & poison object */
         memset(obj, 0, obj->klass->objectSize);
@@ -184,7 +257,10 @@ bool virObjectIsClass(void *anyobj,
                       virClassPtr klass)
 {
     virObjectPtr obj = anyobj;
-    return obj != NULL && (obj->magic == klass->magic) && (obj->klass == klass);
+    if (!obj)
+        return false;
+
+    return virClassIsDerivedFrom(obj->klass, klass);
 }
 
 
diff --git a/src/util/virobject.h b/src/util/virobject.h
index b2f7612..afeb4f5 100644
--- a/src/util/virobject.h
+++ b/src/util/virobject.h
@@ -38,7 +38,10 @@ struct _virObject {
     virClassPtr klass;
 };
 
-virClassPtr virClassNew(const char *name,
+virClassPtr virClassForObject(void);
+
+virClassPtr virClassNew(virClassPtr parent,
+                        const char *name,
                         size_t objectSize,
                         virObjectDisposeCallback dispose)
     ATTRIBUTE_NONNULL(1);
@@ -46,6 +49,10 @@ virClassPtr virClassNew(const char *name,
 const char *virClassName(virClassPtr klass)
     ATTRIBUTE_NONNULL(1);
 
+bool virClassIsDerivedFrom(virClassPtr klass,
+                           virClassPtr parent)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
 void *virObjectNew(virClassPtr klass)
     ATTRIBUTE_NONNULL(1);
 bool virObjectUnref(void *obj);
-- 
1.8.0.1




More information about the libvir-list mailing list