From 69218922e80f108917110580e501d5faed08f071 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 9 Jan 2013 17:37:27 +0000 Subject: [PATCH] Allow for multi-level inheritance of virObject classes Currently all classes must directly inherit from virObject. This allows for arbitrarily deep hierarchy. There's not much to this aside from chaining up the 'dispose' handlers from each class & providing APIs to check types. Signed-off-by: Daniel P. Berrange --- po/POTFILES.in | 1 + 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 +++- 23 files changed, 135 insertions(+), 28 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 95619f9f05..3ca9b64005 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -165,6 +165,7 @@ src/util/virnetdevtap.c src/util/virnetdevvportprofile.c src/util/virnetlink.c src/util/virnodesuspend.c +src/util/virobject.c src/util/virpci.c src/util/virpidfile.c src/util/virprocess.c diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 6feded4042..8e087625a1 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -700,7 +700,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 068233c616..b04e10055e 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 7be58eed9d..70c1591074 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1769,6 +1769,8 @@ virNodeSuspendGetTargetMask; # virobject.h +virClassForObject; +virClassIsDerivedFrom; virClassName; virClassNew; virObjectFreeCallback; diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c index 6971bcbaed..f697e09ab9 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 bb421bd903..db4a0bc2fa 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 b166dd66b1..0e9ec9944a 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -244,7 +244,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 cb5a3e2838..d6176c7c56 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 a8ceff52fa..04962d4fc0 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 69c4478167..8305c61f2e 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 9410cffaf2..2e6e4f6422 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 15ed91aac8..e1ee30eb67 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 cbf7261a2f..41a69d12c5 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 a937eda720..73abb91cf8 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 bd4e66fd7d..2ba3a6daa2 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 06b6325de6..414b978898 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 2e024e1d08..2915355630 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 c31d383d0b..1708d1cd84 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 661860f13f..ca7d52e962 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 56e372b3b5..3e194f9fb5 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 2d0f02ce3a..6637a8977d 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 f51b73570e..5f44ab2d6d 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); @@ -80,6 +126,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 b2f761206b..afeb4f5626 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);