[libvirt] [PATCH 00/13 v2] Introduce a virObject module fo reference counting

A followup to https://www.redhat.com/archives/libvir-list/2012-July/msg00476.html Notable changes - Change virAtomicIntInc to return new value, instead of void for compat with existing API - Use verify_true instead of verify in macros - Most other fixes from previous series

From: "Daniel P. Berrange" <berrange@redhat.com> Remove the use of a manually run virLogStartup and virNodeSuspendInitialize methods. Instead make sure they are automatically run using VIR_ONCE_GLOBAL_INIT Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- daemon/libvirtd.c | 1 - src/libvirt.c | 4 +--- src/libvirt_private.syms | 3 --- src/util/logging.c | 54 +++++++++++++-------------------------------- src/util/logging.h | 2 -- src/util/virnodesuspend.c | 25 +++++++++++---------- src/util/virnodesuspend.h | 1 - 7 files changed, 29 insertions(+), 61 deletions(-) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index ffbe067..ba0cc1f 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -1349,7 +1349,6 @@ cleanup: VIR_FREE(run_dir); daemonConfigFree(config); - virLogShutdown(); return ret; } diff --git a/src/libvirt.c b/src/libvirt.c index 8e789be..4368b99 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -53,7 +53,6 @@ #include "conf.h" #include "rpc/virnettlscontext.h" #include "command.h" -#include "virnodesuspend.h" #include "virrandom.h" #include "viruri.h" @@ -407,8 +406,7 @@ virInitialize(void) if (virThreadInitialize() < 0 || virErrorInitialize() < 0 || - virRandomInitialize(time(NULL) ^ getpid()) || - virNodeSuspendInit() < 0) + virRandomInitialize(time(NULL) ^ getpid())) return -1; gcry_control(GCRYCTL_SET_THREAD_CBS, &virTLSThreadImpl); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ac392fe..8b9e2c0 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -761,8 +761,6 @@ virLogReset; virLogSetBufferSize; virLogSetDefaultPriority; virLogSetFromEnv; -virLogShutdown; -virLogStartup; virLogUnlock; @@ -1608,7 +1606,6 @@ virNetTLSSessionWrite; # virnodesuspend.h nodeSuspendForDuration; -virNodeSuspendInit; virNodeSuspendGetTargetMask; diff --git a/src/util/logging.c b/src/util/logging.c index 73e7eb6..a7f6b65 100644 --- a/src/util/logging.c +++ b/src/util/logging.c @@ -147,25 +147,14 @@ static const char *virLogPriorityString(virLogPriority lvl) { return "unknown"; } -static int virLogInitialized = 0; -/** - * virLogStartup: - * - * Initialize the logging module - * - * Returns 0 if successful, and -1 in case or error - */ -int virLogStartup(void) { +static int virLogOnceInit(void) +{ const char *pbm = NULL; - if (virLogInitialized) - return -1; - if (virMutexInit(&virLogMutex) < 0) return -1; - virLogInitialized = 1; virLogLock(); if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) { /* @@ -191,6 +180,8 @@ int virLogStartup(void) { return 0; } +VIR_ONCE_GLOBAL_INIT(virLog) + /** * virLogSetBufferSize: * @size: size of the buffer in kilobytes or <= 0 to deactivate @@ -211,7 +202,10 @@ virLogSetBufferSize(int size) { if (size < 0) size = 0; - if ((virLogInitialized == 0) || (size * 1024 == virLogSize)) + if (virLogInitialize() < 0) + return -1; + + if (size * 1024 == virLogSize) return ret; virLogLock(); @@ -253,8 +247,8 @@ error: * Returns 0 if successful, and -1 in case or error */ int virLogReset(void) { - if (!virLogInitialized) - return virLogStartup(); + if (virLogInitialize() < 0) + return -1; virLogLock(); virLogResetFilters(); @@ -266,25 +260,6 @@ int virLogReset(void) { virLogUnlock(); return 0; } -/** - * virLogShutdown: - * - * Shutdown the logging module - */ -void virLogShutdown(void) { - if (!virLogInitialized) - return; - virLogLock(); - virLogResetFilters(); - virLogResetOutputs(); - virLogLen = 0; - virLogStart = 0; - virLogEnd = 0; - VIR_FREE(virLogBuffer); - virLogUnlock(); - virMutexDestroy(&virLogMutex); - virLogInitialized = 0; -} /* * Store a string in the ring buffer @@ -450,8 +425,9 @@ int virLogSetDefaultPriority(int priority) { VIR_WARN("Ignoring invalid log level setting."); return -1; } - if (!virLogInitialized) - virLogStartup(); + if (virLogInitialize() < 0) + return -1; + virLogDefaultPriority = priority; return 0; } @@ -723,8 +699,8 @@ void virLogVMessage(const char *category, int priority, const char *funcname, int emit = 1; unsigned int filterflags = 0; - if (!virLogInitialized) - virLogStartup(); + if (virLogInitialize() < 0) + return; if (fmt == NULL) goto cleanup; diff --git a/src/util/logging.h b/src/util/logging.h index d2bedcf..137bad2 100644 --- a/src/util/logging.h +++ b/src/util/logging.h @@ -135,9 +135,7 @@ extern int virLogDefineOutput(virLogOutputFunc f, virLogCloseFunc c, void *data, extern void virLogLock(void); extern void virLogUnlock(void); -extern int virLogStartup(void); extern int virLogReset(void); -extern void virLogShutdown(void); extern int virLogParseDefaultPriority(const char *priority); extern int virLogParseFilters(const char *filters); extern int virLogParseOutputs(const char *output); diff --git a/src/util/virnodesuspend.c b/src/util/virnodesuspend.c index 91dfdf6..914ce56 100644 --- a/src/util/virnodesuspend.c +++ b/src/util/virnodesuspend.c @@ -59,24 +59,19 @@ static void virNodeSuspendUnlock(void) } -/** - * virNodeSuspendInit: - * - * Get the system-wide sleep states supported by the host, such as - * Suspend-to-RAM, Suspend-to-Disk, or Hybrid-Suspend, so that a request - * to suspend/hibernate the host can be handled appropriately based on - * this information. - * - * Returns 0 if successful, and -1 in case of error. - */ -int virNodeSuspendInit(void) +static int virNodeSuspendOnceInit(void) { - if (virMutexInit(&virNodeSuspendMutex) < 0) + if (virMutexInit(&virNodeSuspendMutex) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to initialize mutex")); return -1; + } return 0; } +VIR_ONCE_GLOBAL_INIT(virNodeSuspend) + /** * virNodeSuspendSetNodeWakeup: @@ -182,6 +177,9 @@ int nodeSuspendForDuration(virConnectPtr conn ATTRIBUTE_UNUSED, virCheckFlags(0, -1); + if (virNodeSuspendInitialize() < 0) + return -1; + if (virNodeSuspendGetTargetMask(&supported) < 0) return -1; @@ -268,6 +266,9 @@ virNodeSuspendSupportsTarget(unsigned int target, bool *supported) int status; int ret = -1; + if (virNodeSuspendInitialize() < 0) + return -1; + *supported = false; switch (target) { diff --git a/src/util/virnodesuspend.h b/src/util/virnodesuspend.h index a6927ac..76497d8 100644 --- a/src/util/virnodesuspend.h +++ b/src/util/virnodesuspend.h @@ -30,7 +30,6 @@ int nodeSuspendForDuration(virConnectPtr conn, unsigned long long duration, unsigned int flags); -int virNodeSuspendInit(void); int virNodeSuspendGetTargetMask(unsigned int *bitmask); #endif /* __VIR_NODE_SUSPEND_H__ */ -- 1.7.10.4

On 07/31/2012 10:58 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Remove the use of a manually run virLogStartup and virNodeSuspendInitialize methods. Instead make sure they are automatically run using VIR_ONCE_GLOBAL_INIT
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- daemon/libvirtd.c | 1 - src/libvirt.c | 4 +--- src/libvirt_private.syms | 3 --- src/util/logging.c | 54 +++++++++++++-------------------------------- src/util/logging.h | 2 -- src/util/virnodesuspend.c | 25 +++++++++++---------- src/util/virnodesuspend.h | 1 - 7 files changed, 29 insertions(+), 61 deletions(-)
ACK, what you have is a strict improvement. But given commit a22a36e8,
@@ -407,8 +406,7 @@ virInitialize(void)
if (virThreadInitialize() < 0 || virErrorInitialize() < 0 || - virRandomInitialize(time(NULL) ^ getpid()) || - virNodeSuspendInit() < 0) + virRandomInitialize(time(NULL) ^ getpid()))
...should we be getting rid of virRandomInitialize and doing that in a one-shot initializer as well, since at least seclabeltest would have benefitted from it? -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Tue, Jul 31, 2012 at 01:06:59PM -0600, Eric Blake wrote:
On 07/31/2012 10:58 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Remove the use of a manually run virLogStartup and virNodeSuspendInitialize methods. Instead make sure they are automatically run using VIR_ONCE_GLOBAL_INIT
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- daemon/libvirtd.c | 1 - src/libvirt.c | 4 +--- src/libvirt_private.syms | 3 --- src/util/logging.c | 54 +++++++++++++-------------------------------- src/util/logging.h | 2 -- src/util/virnodesuspend.c | 25 +++++++++++---------- src/util/virnodesuspend.h | 1 - 7 files changed, 29 insertions(+), 61 deletions(-)
ACK, what you have is a strict improvement. But given commit a22a36e8,
@@ -407,8 +406,7 @@ virInitialize(void)
if (virThreadInitialize() < 0 || virErrorInitialize() < 0 || - virRandomInitialize(time(NULL) ^ getpid()) || - virNodeSuspendInit() < 0) + virRandomInitialize(time(NULL) ^ getpid()))
...should we be getting rid of virRandomInitialize and doing that in a one-shot initializer as well, since at least seclabeltest would have benefitted from it?
I did wonder about that when I wrote this. I didn't do it because obviously virRandomInitialize has a parameter passed in. Now I see that every single caller just does the same 'time(NULL) ^ getpid()' we might as well just make virRandomInitialize be 'void' and used the fixed pattern for seed. I'll do this as a followup patch though 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 :|

On 07/31/2012 01:17 PM, Daniel P. Berrange wrote:
On Tue, Jul 31, 2012 at 01:06:59PM -0600, Eric Blake wrote:
On 07/31/2012 10:58 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
- virRandomInitialize(time(NULL) ^ getpid()) || - virNodeSuspendInit() < 0) + virRandomInitialize(time(NULL) ^ getpid()))
...should we be getting rid of virRandomInitialize and doing that in a one-shot initializer as well, since at least seclabeltest would have benefitted from it?
I did wonder about that when I wrote this. I didn't do it because obviously virRandomInitialize has a parameter passed in. Now I see that every single caller just does the same 'time(NULL) ^ getpid()' we might as well just make virRandomInitialize be 'void' and used the fixed pattern for seed.
I'll do this as a followup patch though
Agreed. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

All callers used the same initialization seed (well, the new viratomictest forgot to look at getpid()); so we might as well make this value automatic. And while it may feel like we are giving up functionality, I documented how to get it back in the unlikely case that you actually need to debug with a fixed pseudo-random sequence. I left that crippled by default, so that a stray environment variable doesn't cause a lack of randomness to become a security issue. * src/util/virrandom.c (virRandomInitialize): Rename... (virRandomOnceInit): ...and make static, with one-shot call. Document how to do fixed-seed debugging. * src/util/virrandom.h (virRandomInitialize): Drop prototype. * src/libvirt_private.syms (virrandom.h): Don't export it. * src/libvirt.c (virInitialize): Adjust caller. * src/lxc/lxc_controller.c (main): Likewise. * src/security/virt-aa-helper.c (main): Likewise. * src/util/iohelper.c (main): Likewise. * tests/seclabeltest.c (main): Likewise. * tests/testutils.c (virtTestMain): Likewise. * tests/viratomictest.c (mymain): Likewise. --- src/libvirt.c | 3 +-- src/libvirt_private.syms | 1 - src/lxc/lxc_controller.c | 5 ++--- src/security/virt-aa-helper.c | 3 --- src/util/iohelper.c | 5 ++--- src/util/virrandom.c | 25 ++++++++++++++++++++++++- src/util/virrandom.h | 1 - tests/seclabeltest.c | 3 +-- tests/testutils.c | 3 +-- tests/viratomictest.c | 2 -- 10 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index 3c4bf8c..0a91d0f 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -408,8 +408,7 @@ virInitialize(void) initialized = 1; if (virThreadInitialize() < 0 || - virErrorInitialize() < 0 || - virRandomInitialize(time(NULL) ^ getpid())) + virErrorInitialize() < 0) return -1; gcry_control(GCRYCTL_SET_THREAD_CBS, &virTLSThreadImpl); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 44b6652..6b98c9c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1663,7 +1663,6 @@ virPidFileDeletePath; # virrandom.h virRandomBits; virRandomGenerateWWN; -virRandomInitialize; # virsocketaddr.h diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 56ed7d3..8ff925e 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2010-2012 Red Hat, Inc. * Copyright IBM Corp. 2008 * * lxc_controller.c: linux container process controller @@ -1480,8 +1480,7 @@ int main(int argc, char *argv[]) if (setlocale(LC_ALL, "") == NULL || bindtextdomain(PACKAGE, LOCALEDIR) == NULL || - textdomain(PACKAGE) == NULL || - virRandomInitialize(time(NULL) ^ getpid())) { + textdomain(PACKAGE) == NULL) { fprintf(stderr, _("%s: initialization failed\n"), argv[0]); exit(EXIT_FAILURE); } diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 5352a4a..4c2f487 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -1199,9 +1199,6 @@ main(int argc, char **argv) memset(ctl, 0, sizeof(vahControl)); - if (virRandomInitialize(time(NULL) ^ getpid()) < 0) - vah_error(ctl, 1, _("could not initialize random generator")); - if (vahParseArgv(ctl, argc, argv) != 0) vah_error(ctl, 1, _("could not parse arguments")); diff --git a/src/util/iohelper.c b/src/util/iohelper.c index 0732cac..4791234 100644 --- a/src/util/iohelper.c +++ b/src/util/iohelper.c @@ -1,7 +1,7 @@ /* * iohelper.c: Helper program to perform I/O operations on files * - * Copyright (C) 2011 Red Hat, Inc. + * Copyright (C) 2011-2012 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -230,8 +230,7 @@ main(int argc, char **argv) } if (virThreadInitialize() < 0 || - virErrorInitialize() < 0 || - virRandomInitialize(time(NULL) ^ getpid())) { + virErrorInitialize() < 0) { fprintf(stderr, _("%s: initialization failed\n"), program_name); exit(EXIT_FAILURE); } diff --git a/src/util/virrandom.c b/src/util/virrandom.c index b815ce2..50bed46 100644 --- a/src/util/virrandom.c +++ b/src/util/virrandom.c @@ -29,6 +29,7 @@ #include "count-one-bits.h" #include "util.h" #include "virterror_internal.h" +#include "logging.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -37,8 +38,21 @@ static struct random_data randomData; static virMutex randomLock; -int virRandomInitialize(uint32_t seed) +static int +virRandomOnceInit(void) { + unsigned int seed = time(NULL) ^ getpid(); + +#if 0 + /* Normally we want a decent seed. But if reproducible debugging + * of a fixed pseudo-random sequence is ever required, uncomment + * this block to let an environment variable force the seed. */ + const char *debug = getenv("VIR_DEBUG_RANDOM_SEED"); + + if (debug && virStrToLong_ui(debug, NULL, 0, &seed) < 0) + return -1; +#endif + if (virMutexInit(&randomLock) < 0) return -1; @@ -51,6 +65,8 @@ int virRandomInitialize(uint32_t seed) return 0; } +VIR_ONCE_GLOBAL_INIT(virRandom) + /* The algorithm of virRandomBits requires that RAND_MAX == 2^n-1 for * some n; gnulib's random_r meets this property. */ verify(((RAND_MAX + 1U) & RAND_MAX) == 0); @@ -70,6 +86,13 @@ uint64_t virRandomBits(int nbits) uint64_t ret = 0; int32_t bits; + if (virRandomInitialize() < 0) { + /* You're already hosed, so this particular non-random value + * isn't any worse. */ + VIR_WARN("random number generation is broken"); + return 0; + } + virMutexLock(&randomLock); while (nbits > bits_per_iter) { diff --git a/src/util/virrandom.h b/src/util/virrandom.h index aa2c8b4..8d3cad7 100644 --- a/src/util/virrandom.h +++ b/src/util/virrandom.h @@ -25,7 +25,6 @@ # include "internal.h" # include <stdint.h> -int virRandomInitialize(uint32_t seed) ATTRIBUTE_RETURN_CHECK; uint64_t virRandomBits(int nbits); int virRandomGenerateWWN(char **wwn, const char *virt_type); diff --git a/tests/seclabeltest.c b/tests/seclabeltest.c index 45ab8e4..81ef323 100644 --- a/tests/seclabeltest.c +++ b/tests/seclabeltest.c @@ -14,8 +14,7 @@ main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) virSecurityManagerPtr mgr; const char *doi, *model; - if (virThreadInitialize() < 0 || - virRandomInitialize(time(NULL) ^ getpid())) + if (virThreadInitialize() < 0) exit(EXIT_FAILURE); mgr = virSecurityManagerNew(NULL, "QEMU", false, true, false); diff --git a/tests/testutils.c b/tests/testutils.c index 171321f..ecd3d2d 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -603,8 +603,7 @@ int virtTestMain(int argc, fprintf(stderr, "TEST: %s\n", progname); if (virThreadInitialize() < 0 || - virErrorInitialize() < 0 || - virRandomInitialize(time(NULL) ^ getpid())) + virErrorInitialize() < 0) return 1; virLogSetFromEnv(); diff --git a/tests/viratomictest.c b/tests/viratomictest.c index 48f0d24..772fbfe 100644 --- a/tests/viratomictest.c +++ b/tests/viratomictest.c @@ -165,8 +165,6 @@ mymain(void) { int ret = 0; - if (virRandomInitialize(time(NULL)) < 0) - return -1; if (virThreadInitialize() < 0) return -1; -- 1.7.11.2

On Fri, Aug 03, 2012 at 05:26:58PM -0600, Eric Blake wrote:
All callers used the same initialization seed (well, the new viratomictest forgot to look at getpid()); so we might as well make this value automatic. And while it may feel like we are giving up functionality, I documented how to get it back in the unlikely case that you actually need to debug with a fixed pseudo-random sequence. I left that crippled by default, so that a stray environment variable doesn't cause a lack of randomness to become a security issue.
* src/util/virrandom.c (virRandomInitialize): Rename... (virRandomOnceInit): ...and make static, with one-shot call. Document how to do fixed-seed debugging. * src/util/virrandom.h (virRandomInitialize): Drop prototype. * src/libvirt_private.syms (virrandom.h): Don't export it. * src/libvirt.c (virInitialize): Adjust caller. * src/lxc/lxc_controller.c (main): Likewise. * src/security/virt-aa-helper.c (main): Likewise. * src/util/iohelper.c (main): Likewise. * tests/seclabeltest.c (main): Likewise. * tests/testutils.c (virtTestMain): Likewise. * tests/viratomictest.c (mymain): Likewise. --- src/libvirt.c | 3 +-- src/libvirt_private.syms | 1 - src/lxc/lxc_controller.c | 5 ++--- src/security/virt-aa-helper.c | 3 --- src/util/iohelper.c | 5 ++--- src/util/virrandom.c | 25 ++++++++++++++++++++++++- src/util/virrandom.h | 1 - tests/seclabeltest.c | 3 +-- tests/testutils.c | 3 +-- tests/viratomictest.c | 2 -- 10 files changed, 31 insertions(+), 20 deletions(-)
ACK 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 :|

On 08/06/2012 03:58 AM, Daniel P. Berrange wrote:
On Fri, Aug 03, 2012 at 05:26:58PM -0600, Eric Blake wrote:
All callers used the same initialization seed (well, the new viratomictest forgot to look at getpid()); so we might as well make this value automatic. And while it may feel like we are giving up functionality, I documented how to get it back in the unlikely case that you actually need to debug with a fixed pseudo-random sequence. I left that crippled by default, so that a stray environment variable doesn't cause a lack of randomness to become a security issue.
ACK
Thanks; pushed. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

From: "Daniel P. Berrange" <berrange@redhat.com> There are a few issues with the current virAtomic APIs - They require use of a virAtomicInt struct instead of a plain int type - Several of the methods do not implement memory barriers - The methods do not implement compiler re-ordering barriers - There is no Win32 native impl The GLib library has a nice LGPLv2+ licensed impl of atomic ops that works with GCC, Win32, or pthreads.h that addresses all these problems. The main downside to their code is that the pthreads impl uses a single global mutex, instead of a per-variable mutex. Given that it does have a Win32 impl though, we don't expect anyone to seriously use the pthread.h impl, so this downside is not significant. * .gitignore: Ignore test case * configure.ac: Check for which atomic ops impl to use * src/Makefile.am: Add viratomic.c * src/nwfilter/nwfilter_dhcpsnoop.c: Switch to new atomic ops APIs and plain int datatype * src/util/viratomic.h: inline impls of all atomic ops for GCC, Win32 and pthreads * src/util/viratomic.c: Global pthreads mutex for atomic ops * tests/viratomictest.c: Test validate to validate safety of atomic ops. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- .gitignore | 1 + configure.ac | 57 +++++ src/Makefile.am | 6 +- src/libvirt_atomic.syms | 3 + src/nwfilter/nwfilter_dhcpsnoop.c | 45 ++-- src/util/viratomic.c | 35 +++ src/util/viratomic.h | 435 +++++++++++++++++++++++++++++++------ src/util/virfile.c | 3 +- tests/Makefile.am | 5 + tests/viratomictest.c | 180 +++++++++++++++ 10 files changed, 671 insertions(+), 99 deletions(-) create mode 100644 src/libvirt_atomic.syms create mode 100644 src/util/viratomic.c create mode 100644 tests/viratomictest.c diff --git a/.gitignore b/.gitignore index e4b3932..3d534c5 100644 --- a/.gitignore +++ b/.gitignore @@ -152,6 +152,7 @@ /tests/statstest /tests/storagebackendsheepdogtest /tests/utiltest +/tests/viratomictest /tests/virauthconfigtest /tests/virbuftest /tests/virdrivermoduletest diff --git a/configure.ac b/configure.ac index 3cc7b3c..5724f9b 100644 --- a/configure.ac +++ b/configure.ac @@ -159,6 +159,63 @@ AC_CHECK_HEADERS([pwd.h paths.h regex.h sys/un.h \ sys/un.h sys/syscall.h netinet/tcp.h ifaddrs.h libtasn1.h \ net/if.h execinfo.h]) +dnl We need to decide at configure time if libvirt will use real atomic +dnl operations ("lock free") or emulated ones with a mutex. + +dnl Note that the atomic ops are only available with GCC on x86 when +dnl using -march=i486 or higher. If we detect that the atomic ops are +dnl not available but would be available given the right flags, we want +dnl to abort and advise the user to fix their CFLAGS. It's better to do +dnl that then to silently fall back on emulated atomic ops just because +dnl the user had the wrong build environment. + +atomic_ops= + +AC_MSG_CHECKING([for atomic ops implementation]) + +AC_TRY_COMPILE([], [__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;],[ + atomic_ops=gcc +],[]) + +if test "$atomic_ops" = "" ; then + SAVE_CFLAGS="${CFLAGS}" + CFLAGS="-march=i486" + AC_TRY_COMPILE([], + [__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;], + [AC_MSG_ERROR([Libvirt must be build with -march=i486 or later.])], + []) + CFLAGS="${SAVE_CFLAGS}" + + case "$host" in + *-*-mingw* | *-*-msvc* ) + atomic_ops=win32 + ;; + *) + if test "$ac_cv_header_pthread_h" = "yes" ; then + atomic_ops=pthread + else + AC_MSG_ERROR([Libvirt must be built with GCC or have pthread.h on non-Win32 platforms]) + fi + ;; + esac +fi + +case "$atomic_ops" in + gcc) + AC_DEFINE([VIR_ATOMIC_OPS_GCC],[1],[Use GCC atomic ops]) + ;; + win32) + AC_DEFINE([VIR_ATOMIC_OPS_WIN32],[1],[Use Win32 atomic ops]) + ;; + pthread) + AC_DEFINE([VIR_ATOMIC_OPS_PTHREAD],[1],[Use pthread atomic ops emulation]) + ;; +esac +AM_CONDITIONAL([WITH_ATOMIC_OPS_PTHREAD],[test "$atomic_ops" = "pthread"]) +AC_MSG_RESULT([$atomic_ops]) + + + AC_MSG_CHECKING([for struct ifreq in net/if.h]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [[ diff --git a/src/Makefile.am b/src/Makefile.am index 3f6c7f5..984a743 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -79,7 +79,7 @@ UTIL_SOURCES = \ util/threadpool.c util/threadpool.h \ util/uuid.c util/uuid.h \ util/util.c util/util.h \ - util/viratomic.h \ + util/viratomic.h util/viratomic.c \ util/viraudit.c util/viraudit.h \ util/virauth.c util/virauth.h \ util/virauthconfig.c util/virauthconfig.h \ @@ -1301,6 +1301,10 @@ if HAVE_SASL USED_SYM_FILES += libvirt_sasl.syms endif +if WITH_ATOMIC_OPS_PTHREAD +USED_SYM_FILES += libvirt_atomic.syms +endif + EXTRA_DIST += \ libvirt_public.syms \ libvirt_private.syms \ diff --git a/src/libvirt_atomic.syms b/src/libvirt_atomic.syms new file mode 100644 index 0000000..afaaf70 --- /dev/null +++ b/src/libvirt_atomic.syms @@ -0,0 +1,3 @@ + +# viratomic.h +virAtomicLock; diff --git a/src/nwfilter/nwfilter_dhcpsnoop.c b/src/nwfilter/nwfilter_dhcpsnoop.c index 1395bfe..23cbdde 100644 --- a/src/nwfilter/nwfilter_dhcpsnoop.c +++ b/src/nwfilter/nwfilter_dhcpsnoop.c @@ -78,9 +78,9 @@ struct virNWFilterSnoopState { /* lease file */ int leaseFD; - virAtomicInt nLeases; /* number of active leases */ - virAtomicInt wLeases; /* number of written leases */ - virAtomicInt nThreads; /* number of running threads */ + int nLeases; /* number of active leases */ + int wLeases; /* number of written leases */ + int nThreads; /* number of running threads */ /* thread management */ virHashTablePtr snoopReqs; virHashTablePtr ifnameToKey; @@ -126,7 +126,7 @@ struct _virNWFilterSnoopReq { * publicSnoopReqs hash, the refctr may only * be modified with the SnoopLock held */ - virAtomicInt refctr; + int refctr; virNWFilterTechDriverPtr techdriver; char *ifname; @@ -240,7 +240,7 @@ struct _virNWFilterDHCPDecodeJob { unsigned char packet[PCAP_PBUFSIZE]; int caplen; bool fromVM; - virAtomicIntPtr qCtr; + int *qCtr; }; # define DHCP_PKT_RATE 10 /* pkts/sec */ @@ -271,7 +271,7 @@ struct _virNWFilterSnoopPcapConf { const pcap_direction_t dir; const char *filter; virNWFilterSnoopRateLimitConf rateLimit; /* indep. rate limiters */ - virAtomicInt qCtr; /* number of jobs in the worker's queue */ + int qCtr; /* number of jobs in the worker's queue */ const unsigned int maxQSize; unsigned long long penaltyTimeoutAbs; }; @@ -588,8 +588,7 @@ virNWFilterSnoopReqNew(const char *ifkey) req->threadStatus = THREAD_STATUS_NONE; - if (virAtomicIntInit(&req->refctr) < 0 || - virStrcpyStatic(req->ifkey, ifkey) == NULL || + if (virStrcpyStatic(req->ifkey, ifkey) == NULL || virMutexInitRecursive(&req->lock) < 0) goto err_free_req; @@ -622,7 +621,7 @@ virNWFilterSnoopReqFree(virNWFilterSnoopReqPtr req) if (!req) return; - if (virAtomicIntRead(&req->refctr) != 0) + if (virAtomicIntGet(&req->refctr) != 0) return; /* free all leases */ @@ -715,7 +714,7 @@ virNWFilterSnoopReqPut(virNWFilterSnoopReqPtr req) virNWFilterSnoopLock(); - if (virAtomicIntDec(&req->refctr) == 0) { + if (virAtomicIntDecAndTest(&req->refctr)) { /* * delete the request: * - if we don't find req on the global list anymore @@ -897,7 +896,7 @@ virNWFilterSnoopReqLeaseDel(virNWFilterSnoopReqPtr req, skip_instantiate: VIR_FREE(ipl); - virAtomicIntDec(&virNWFilterSnoopState.nLeases); + virAtomicIntDecAndTest(&virNWFilterSnoopState.nLeases); lease_not_found: VIR_FREE(ipstr); @@ -1159,7 +1158,7 @@ static void virNWFilterDHCPDecodeWorker(void *jobdata, void *opaque) _("Instantiation of rules failed on " "interface '%s'"), req->ifname); } - virAtomicIntDec(job->qCtr); + virAtomicIntDecAndTest(job->qCtr); VIR_FREE(job); } @@ -1170,7 +1169,7 @@ static int virNWFilterSnoopDHCPDecodeJobSubmit(virThreadPoolPtr pool, virNWFilterSnoopEthHdrPtr pep, int len, pcap_direction_t dir, - virAtomicIntPtr qCtr) + int *qCtr) { virNWFilterDHCPDecodeJobPtr job; int ret; @@ -1376,8 +1375,7 @@ virNWFilterDHCPSnoopThread(void *req0) virNWFilterSnoopDHCPOpen(req->ifname, &req->macaddr, pcapConf[i].filter, pcapConf[i].dir); - if (!pcapConf[i].handle || - virAtomicIntInit(&pcapConf[i].qCtr) < 0) { + if (!pcapConf[i].handle) { error = true; break; } @@ -1488,7 +1486,7 @@ virNWFilterDHCPSnoopThread(void *req0) unsigned int diff; /* submit packet to worker thread */ - if (virAtomicIntRead(&pcapConf[i].qCtr) > + if (virAtomicIntGet(&pcapConf[i].qCtr) > pcapConf[i].maxQSize) { if (last_displayed_queue - time(0) > 10) { last_displayed_queue = time(0); @@ -1554,7 +1552,7 @@ exit: pcap_close(pcapConf[i].handle); } - virAtomicIntDec(&virNWFilterSnoopState.nThreads); + virAtomicIntDecAndTest(&virNWFilterSnoopState.nThreads); return; } @@ -1805,7 +1803,7 @@ virNWFilterSnoopLeaseFileSave(virNWFilterSnoopIPLeasePtr ipl) /* keep dead leases at < ~95% of file size */ if (virAtomicIntInc(&virNWFilterSnoopState.wLeases) >= - virAtomicIntRead(&virNWFilterSnoopState.nLeases) * 20) + virAtomicIntGet(&virNWFilterSnoopState.nLeases) * 20) virNWFilterSnoopLeaseFileLoad(); /* load & refresh lease file */ err_exit: @@ -1836,7 +1834,7 @@ virNWFilterSnoopPruneIter(const void *payload, /* * have the entry removed if it has no leases and no one holds a ref */ - del_req = ((req->start == NULL) && (virAtomicIntRead(&req->refctr) == 0)); + del_req = ((req->start == NULL) && (virAtomicIntGet(&req->refctr) == 0)); virNWFilterSnoopReqUnlock(req); @@ -1994,9 +1992,9 @@ virNWFilterSnoopLeaseFileLoad(void) static void virNWFilterSnoopJoinThreads(void) { - while (virAtomicIntRead(&virNWFilterSnoopState.nThreads) != 0) { + while (virAtomicIntGet(&virNWFilterSnoopState.nThreads) != 0) { VIR_WARN("Waiting for snooping threads to terminate: %u\n", - virAtomicIntRead(&virNWFilterSnoopState.nThreads)); + virAtomicIntGet(&virNWFilterSnoopState.nThreads)); usleep(1000 * 1000); } } @@ -2061,10 +2059,7 @@ virNWFilterDHCPSnoopInit(void) VIR_DEBUG("Initializing DHCP snooping"); if (virMutexInitRecursive(&virNWFilterSnoopState.snoopLock) < 0 || - virMutexInit(&virNWFilterSnoopState.activeLock) < 0 || - virAtomicIntInit(&virNWFilterSnoopState.nLeases) < 0 || - virAtomicIntInit(&virNWFilterSnoopState.wLeases) < 0 || - virAtomicIntInit(&virNWFilterSnoopState.nThreads) < 0) + virMutexInit(&virNWFilterSnoopState.activeLock) < 0) return -1; virNWFilterSnoopState.ifnameToKey = virHashCreate(0, NULL); diff --git a/src/util/viratomic.c b/src/util/viratomic.c new file mode 100644 index 0000000..af846ff --- /dev/null +++ b/src/util/viratomic.c @@ -0,0 +1,35 @@ +/* + * viratomic.h: atomic integer operations + * + * Copyright (C) 2012 Red Hat, Inc. + * + * Based on code taken from GLib 2.32, under the LGPLv2+ + * + * Copyright (C) 2011 Ryan Lortie + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "viratomic.h" + + +#ifdef VIR_ATOMIC_OPS_PTHREAD + +pthread_mutex_t virAtomicLock = PTHREAD_MUTEX_INITIALIZER; + +#endif diff --git a/src/util/viratomic.h b/src/util/viratomic.h index 246fe2b..fa0a89a 100644 --- a/src/util/viratomic.h +++ b/src/util/viratomic.h @@ -1,10 +1,11 @@ /* * viratomic.h: atomic integer operations * - * Copyright (C) 2012 IBM Corporation + * Copyright (C) 2012 Red Hat, Inc. * - * Authors: - * Stefan Berger <stefanb@linux.vnet.ibm.com> + * Based on code taken from GLib 2.32, under the LGPLv2+ + * + * Copyright (C) 2011 Ryan Lortie * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,130 +26,422 @@ #ifndef __VIR_ATOMIC_H__ # define __VIR_ATOMIC_H__ -# include "threads.h" +# include "internal.h" -typedef struct _virAtomicInt virAtomicInt; -typedef virAtomicInt *virAtomicIntPtr; +/** + * virAtomicIntGet: + * Gets the current value of atomic. + * + * This call acts as a full compiler and hardware memory barrier + * (before the get) + */ +int virAtomicIntGet(volatile int *atomic) + ATTRIBUTE_NONNULL(1); -# define __VIR_ATOMIC_USES_LOCK +/** + * virAtomicIntSet: + * Sets the value of atomic to newval. + * + * This call acts as a full compiler and hardware memory barrier + * (after the set) + */ +void virAtomicIntSet(volatile int *atomic, + int newval) + ATTRIBUTE_NONNULL(1); -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) -# undef __VIR_ATOMIC_USES_LOCK -# endif +/** + * virAtomicIntInc: + * Increments the value of atomic by 1. + * + * Think of this operation as an atomic version of + * { *atomic += 1; return *atomic; } + * + * This call acts as a full compiler and hardware memory barrier. + */ +int virAtomicIntInc(volatile int *atomic) + ATTRIBUTE_NONNULL(1); -static inline int virAtomicIntInit(virAtomicIntPtr vaip) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; -static inline int virAtomicIntRead(virAtomicIntPtr vaip) +/** + * virAtomicIntDecAndTest: + * Decrements the value of atomic by 1. + * + * Think of this operation as an atomic version of + * { *atomic -= 1; return *atomic == 0; } + * + * This call acts as a full compiler and hardware memory barrier. + */ +bool virAtomicIntDecAndTest(volatile int *atomic) ATTRIBUTE_NONNULL(1); -static inline void virAtomicIntSet(virAtomicIntPtr vaip, int val) + +/** + * virAtomicIntCompareExchange: + * Compares atomic to oldval and, if equal, sets it to newval. If + * atomic was not equal to oldval then no change occurs. + * + * This compare and exchange is done atomically. + * + * Think of this operation as an atomic version of + * { if (*atomic == oldval) { *atomic = newval; return true; } + * else return false; } + * + * This call acts as a full compiler and hardware memory barrier. + */ +bool virAtomicIntCompareExchange(volatile int *atomic, + int oldval, + int newval) ATTRIBUTE_NONNULL(1); -static inline int virAtomicIntAdd(virAtomicIntPtr vaip, int add) + +/** + * virAtomicIntAdd: + * Atomically adds val to the value of atomic. + * + * Think of this operation as an atomic version of + * { tmp = *atomic; *atomic += val; return tmp; } + * + * This call acts as a full compiler and hardware memory barrier. + */ +int virAtomicIntAdd(volatile int *atomic, + int val) ATTRIBUTE_NONNULL(1); -static inline int virAtomicIntSub(virAtomicIntPtr vaip, int add) + +/** + * virAtomicIntAnd: + * Performs an atomic bitwise 'and' of the value of atomic + * and val, storing the result back in atomic. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Think of this operation as an atomic version of + * { tmp = *atomic; *atomic &= val; return tmp; } + */ +unsigned int virAtomicIntAnd(volatile unsigned int *atomic, + unsigned int val) ATTRIBUTE_NONNULL(1); -static inline int virAtomicIntInc(virAtomicIntPtr vaip) + +/** + * virAtomicIntOr: + * Performs an atomic bitwise 'or' of the value of atomic + * and val, storing the result back in atomic. + * + * Think of this operation as an atomic version of + * { tmp = *atomic; *atomic |= val; return tmp; } + * + * This call acts as a full compiler and hardware memory barrier. + */ +unsigned int virAtomicIntOr(volatile unsigned int *atomic, + unsigned int val) ATTRIBUTE_NONNULL(1); -static inline int virAtomicIntDec(virAtomicIntPtr vaip) + +/** + * virAtomicIntXor: + * Performs an atomic bitwise 'xor' of the value of atomic + * and val, storing the result back in atomic. + * + * Think of this operation as an atomic version of + * { tmp = *atomic; *atomic ^= val; return tmp; } + * + * This call acts as a full compiler and hardware memory barrier. + */ +unsigned int virAtomicIntXor(volatile unsigned int *atomic, + unsigned int val) ATTRIBUTE_NONNULL(1); -# ifdef __VIR_ATOMIC_USES_LOCK -struct _virAtomicInt { - virMutex lock; - int value; -}; +# ifdef VIR_ATOMIC_OPS_GCC + +# define virAtomicIntGet(atomic) \ + (__extension__ ({ \ + (void)verify_true(sizeof(*(atomic)) == sizeof(int)); \ + (void)(0 ? *(atomic) ^ *(atomic) : 0); \ + __sync_synchronize(); \ + (int)*(atomic); \ + })) +# define virAtomicIntSet(atomic, newval) \ + (__extension__ ({ \ + (void)verify_true(sizeof(*(atomic)) == sizeof(int)); \ + (void)(0 ? *(atomic) ^ (newval) : 0); \ + *(atomic) = (newval); \ + __sync_synchronize(); \ + })) +# define virAtomicIntInc(atomic) \ + (__extension__ ({ \ + (void)verify_true(sizeof(*(atomic)) == sizeof(int)); \ + (void)(0 ? *(atomic) ^ *(atomic) : 0); \ + __sync_add_and_fetch((atomic), 1); \ + })) +# define virAtomicIntDecAndTest(atomic) \ + (__extension__ ({ \ + (void)verify_true(sizeof(*(atomic)) == sizeof(int)); \ + (void)(0 ? *(atomic) ^ *(atomic) : 0); \ + __sync_fetch_and_sub((atomic), 1) == 1; \ + })) +# define virAtomicIntCompareExchange(atomic, oldval, newval) \ + (__extension__ ({ \ + (void)verify_true(sizeof(*(atomic)) == sizeof(int)); \ + (void)(0 ? *(atomic) ^ (newval) ^ (oldval) : 0); \ + (bool)__sync_bool_compare_and_swap((atomic), \ + (oldval), (newval)); \ + })) +# define virAtomicIntAdd(atomic, val) \ + (__extension__ ({ \ + (void)verify_true(sizeof(*(atomic)) == sizeof(int)); \ + (void)(0 ? *(atomic) ^ (val) : 0); \ + (int) __sync_fetch_and_add((atomic), (val)); \ + })) +# define virAtomicIntAnd(atomic, val) \ + (__extension__ ({ \ + (void)verify_true(sizeof(*(atomic)) == sizeof(int)); \ + (void) (0 ? *(atomic) ^ (val) : 0); \ + (unsigned int) __sync_fetch_and_and((atomic), (val)); \ + })) +# define virAtomicIntOr(atomic, val) \ + (__extension__ ({ \ + (void)verify_true(sizeof(*(atomic)) == sizeof(int)); \ + (void) (0 ? *(atomic) ^ (val) : 0); \ + (unsigned int) __sync_fetch_and_or((atomic), (val)); \ + })) +# define virAtomicIntXor(atomic, val) \ + (__extension__ ({ \ + (void)verify_true(sizeof(*(atomic)) == sizeof(int)); \ + (void) (0 ? *(atomic) ^ (val) : 0); \ + (unsigned int) __sync_fetch_and_xor((atomic), (val)); \ + })) + + +# else + +# ifdef VIR_ATOMIC_OPS_WIN32 + +# include <winsock2.h> +# include <windows.h> +# include <intrin.h> +# if !defined(_M_AMD64) && !defined (_M_IA64) && !defined(_M_X64) +# define InterlockedAnd _InterlockedAnd +# define InterlockedOr _InterlockedOr +# define InterlockedXor _InterlockedXor +# endif -static inline int -virAtomicIntInit(virAtomicIntPtr vaip) +/* + * http://msdn.microsoft.com/en-us/library/ms684122(v=vs.85).aspx + */ +inline int +virAtomicIntGet(volatile int *atomic) { - vaip->value = 0; - return virMutexInit(&vaip->lock); + MemoryBarrier(); + return *atomic; } -static inline int -virAtomicIntAdd(virAtomicIntPtr vaip, int add) +inline void +virAtomicIntSet(volatile int *atomic, + int newval) { - int ret; + *atomic = newval; + MemoryBarrier(); +} - virMutexLock(&vaip->lock); +inline int +virAtomicIntInc(volatile int *atomic) +{ + return InterlockedIncrement((volatile LONG *)atomic); +} - vaip->value += add; - ret = vaip->value; +inline bool +virAtomicIntDecAndTest(volatile int *atomic) +{ + return InterlockedDecrement((volatile LONG *)atomic) == 0; +} - virMutexUnlock(&vaip->lock); +inline bool +virAtomicIntCompareExchange(volatile int *atomic, + int oldval, + int newval) +{ + return InterlockedCompareExchange((volatile LONG *)atomic, newval, oldval) == oldval; +} - return ret; +inline int +virAtomicIntAdd(volatile int *atomic, + int val) +{ + return InterlockedExchangeAdd((volatile LONG *)atomic, val); } -static inline int -virAtomicIntSub(virAtomicIntPtr vaip, int sub) +inline unsigned int +virAtomicIntAnd(volatile unsigned int *atomic, + unsigned int val) { - int ret; + return InterlockedAnd((volatile LONG *)atomic, val); +} - virMutexLock(&vaip->lock); +inline unsigned int +virAtomicIntOr(volatile unsigned int *atomic, + unsigned int val) +{ + return InterlockedOr((volatile LONG *)atomic, val); +} - vaip->value -= sub; - ret = vaip->value; +inline unsigned int +virAtomicIntXor(volatile unsigned int *atomic, + unsigned int val) +{ + return InterlockedXor((volatile LONG *)atomic, val); +} - virMutexUnlock(&vaip->lock); - return ret; -} +# else +# ifdef VIR_ATOMIC_OPS_PTHREAD +# include <pthread.h> -# else /* __VIR_ATOMIC_USES_LOCK */ +extern pthread_mutex_t virAtomicLock; -struct _virAtomicInt { +inline int +virAtomicIntGet(volatile int *atomic) +{ int value; -}; -static inline int -virAtomicIntInit(virAtomicIntPtr vaip) + pthread_mutex_lock(&virAtomicLock); + value = *atomic; + pthread_mutex_unlock(&virAtomicLock); + + return value; +} + +inline void +virAtomicIntSet(volatile int *atomic, + int value) { - vaip->value = 0; - return 0; + pthread_mutex_lock(&virAtomicLock); + *atomic = value; + pthread_mutex_unlock(&virAtomicLock); } -static inline int -virAtomicIntAdd(virAtomicIntPtr vaip, int add) +inline int +virAtomicIntInc(volatile int *atomic) { - return __sync_add_and_fetch(&vaip->value, add); + int value; + + pthread_mutex_lock(&virAtomicLock); + value = ++(*atomic); + pthread_mutex_unlock(&virAtomicLock); + + return value; } -static inline int -virAtomicIntSub(virAtomicIntPtr vaip, int sub) +inline bool +virAtomicIntDecAndTest(volatile int *atomic) { - return __sync_sub_and_fetch(&vaip->value, sub); + bool is_zero; + + pthread_mutex_lock(&virAtomicLock); + is_zero = --(*atomic) == 0; + pthread_mutex_unlock(&virAtomicLock); + + return is_zero; } -# endif /* __VIR_ATOMIC_USES_LOCK */ +inline bool +virAtomicIntCompareExchange(volatile int *atomic, + int oldval, + int newval) +{ + bool success; + pthread_mutex_lock(&virAtomicLock); + if ((success = (*atomic == oldval))) + *atomic = newval; -/* common operations that need no locking or build on others */ + pthread_mutex_unlock(&virAtomicLock); + return success; +} -static inline void -virAtomicIntSet(virAtomicIntPtr vaip, int value) +inline int +virAtomicIntAdd(volatile int *atomic, + int val) { - vaip->value = value; + int oldval; + + pthread_mutex_lock(&virAtomicLock); + oldval = *atomic; + *atomic = oldval + val; + pthread_mutex_unlock(&virAtomicLock); + + return oldval; } -static inline int -virAtomicIntRead(virAtomicIntPtr vaip) +inline unsigned int +virAtomicIntAnd(volatile unsigned int *atomic, + unsigned int val) { - return *(volatile int *)&vaip->value; + unsigned int oldval; + + pthread_mutex_lock(&virAtomicLock); + oldval = *atomic; + *atomic = oldval & val; + pthread_mutex_unlock(&virAtomicLock); + + return oldval; } -static inline int -virAtomicIntInc(virAtomicIntPtr vaip) +inline unsigned int +virAtomicIntOr(volatile unsigned int *atomic, + unsigned int val) { - return virAtomicIntAdd(vaip, 1); + unsigned int oldval; + + pthread_mutex_lock(&virAtomicLock); + oldval = *atomic; + *atomic = oldval | val; + pthread_mutex_unlock(&virAtomicLock); + + return oldval; } -static inline int -virAtomicIntDec(virAtomicIntPtr vaip) +inline unsigned int +virAtomicIntXor(volatile unsigned int *atomic, + unsigned int val) { - return virAtomicIntSub(vaip, 1); + unsigned int oldval; + + pthread_mutex_lock(&virAtomicLock); + oldval = *atomic; + *atomic = oldval ^ val; + pthread_mutex_unlock(&virAtomicLock); + + return oldval; } + +# else +# error "No atomic integer impl for this platform" +# endif +# endif + +/* The int/unsigned int casts here ensure that you can + * pass either an int or unsigned int to all atomic op + * functions, in the same way that we can with GCC + * atomic op helpers. + */ +# define virAtomicIntGet(atomic) \ + virAtomicIntGet((int *)atomic) +# define virAtomicIntSet(atomic, val) \ + virAtomicIntSet((int *)atomic, val) +# define virAtomicIntInc(atomic) \ + virAtomicIntInc((int *)atomic) +# define virAtomicIntDecAndTest(atomic) \ + virAtomicIntDecAndTest((int *)atomic) +# define virAtomicIntCompareExchange(atomic, oldval, newval) \ + virAtomicIntCompareExchange((int *)atomic, oldval, newval) +# define virAtomicIntAdd(atomic, val) \ + virAtomicIntAdd((int *)atomic, val) +# define virAtomicIntAnd(atomic, val) \ + virAtomicIntAnd((unsigned int *)atomic, val) +# define virAtomicIntOr(atomic, val) \ + virAtomicIntOr((unsigned int *)atomic, val) +# define virAtomicIntXor(atomic, val) \ + virAtomicIntXor((unsigned int *)atomic, val) + +# endif + #endif /* __VIR_ATOMIC_H */ diff --git a/src/util/virfile.c b/src/util/virfile.c index 5c99976..78626fa 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -618,12 +618,11 @@ cleanup: #else /* __linux__ */ int virFileLoopDeviceAssociate(const char *file, - char **dev) + char **dev ATTRIBUTE_UNUSED) { virReportSystemError(ENOSYS, _("Unable to associate file %s with loop device"), file); - *dev = NULL; return -1; } diff --git a/tests/Makefile.am b/tests/Makefile.am index b931cea..6a1b18b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -89,6 +89,7 @@ test_programs = virshtest sockettest \ nodeinfotest virbuftest \ commandtest seclabeltest \ virhashtest virnetmessagetest virnetsockettest \ + viratomictest \ utiltest virnettlscontexttest shunloadtest \ virtimetest viruritest virkeyfiletest \ virauthconfigtest @@ -530,6 +531,10 @@ virhashtest_SOURCES = \ virhashtest.c virhashdata.h testutils.h testutils.c virhashtest_LDADD = $(LDADDS) +viratomictest_SOURCES = \ + viratomictest.c viratomicdata.h testutils.h testutils.c +viratomictest_LDADD = $(LDADDS) + jsontest_SOURCES = \ jsontest.c testutils.h testutils.c jsontest_LDADD = $(LDADDS) diff --git a/tests/viratomictest.c b/tests/viratomictest.c new file mode 100644 index 0000000..43c532b --- /dev/null +++ b/tests/viratomictest.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2011-2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include <time.h> +#include <sched.h> + +#include "testutils.h" + +#include "viratomic.h" +#include "virrandom.h" +#include "threads.h" + +static int +testTypes(const void *data ATTRIBUTE_UNUSED) +{ + unsigned int u, u2; + int s, s2; + bool res; + +#define virAssertCmpInt(a, op, b) \ + if (!((a) op (b))) \ + return -1; + virAtomicIntSet(&u, 5); + u2 = virAtomicIntGet(&u); + virAssertCmpInt(u2, ==, 5); + + res = virAtomicIntCompareExchange(&u, 6, 7); + if (res) + return -1; + virAssertCmpInt(u, ==, 5); + + virAtomicIntAdd(&u, 1); + virAssertCmpInt(u, ==, 6); + + virAtomicIntInc(&u); + virAssertCmpInt(u, ==, 7); + + res = virAtomicIntDecAndTest(&u); + if (res) + return -1; + virAssertCmpInt(u, ==, 6); + + u2 = virAtomicIntAnd(&u, 5); + virAssertCmpInt(u2, ==, 6); + virAssertCmpInt(u, ==, 4); + + u2 = virAtomicIntOr(&u, 8); + virAssertCmpInt(u2, ==, 4); + virAssertCmpInt(u, ==, 12); + + u2 = virAtomicIntXor(&u, 4); + virAssertCmpInt(u2, ==, 12); + virAssertCmpInt(u, ==, 8); + + virAtomicIntSet(&s, 5); + s2 = virAtomicIntGet(&s); + virAssertCmpInt(s2, ==, 5); + + res = virAtomicIntCompareExchange(&s, 6, 7); + if (res) + return -1; + virAssertCmpInt(s, ==, 5); + + virAtomicIntAdd(&s, 1); + virAssertCmpInt(s, ==, 6); + + virAtomicIntInc(&s); + virAssertCmpInt(s, ==, 7); + + res = virAtomicIntDecAndTest(&s); + if (res) + return -1; + virAssertCmpInt(s, ==, 6); + + s2 = virAtomicIntAnd(&s, 5); + virAssertCmpInt(s2, ==, 6); + virAssertCmpInt(s, ==, 4); + + s2 = virAtomicIntOr(&s, 8); + virAssertCmpInt(s2, ==, 4); + virAssertCmpInt(s, ==, 12); + + s2 = virAtomicIntXor(&s, 4); + virAssertCmpInt(s2, ==, 12); + virAssertCmpInt(s, ==, 8); + + return 0; +} + +#define THREADS 10 +#define ROUNDS 10000 + +volatile int bucket[THREADS]; +volatile int atomic; + +static void +thread_func(void *data) +{ + int idx = (int)(long)data; + int i; + int d; + + for (i = 0; i < ROUNDS; i++) { + d = virRandomBits(7); + bucket[idx] += d; + virAtomicIntAdd(&atomic, d); +#ifdef WIN32 + SleepEx(0,0); +#else + sched_yield(); +#endif + } +} + +static int +testThreads(const void *data ATTRIBUTE_UNUSED) +{ + int sum; + int i; + virThread threads[THREADS]; + + atomic = 0; + for (i = 0; i < THREADS; i++) + bucket[i] = 0; + + for (i = 0; i < THREADS; i++) { + if (virThreadCreate(&(threads[i]), true, thread_func, (void*)(long)i) < 0) + return -1; + } + + for (i = 0; i < THREADS; i++) + virThreadJoin(&threads[i]); + + sum = 0; + for (i = 0; i < THREADS; i++) + sum += bucket[i]; + + if (sum != atomic) + return -1; + + return 0; +} + +static int +mymain(void) +{ + int ret = 0; + + if (virRandomInitialize(time(NULL)) < 0) + return -1; + if (virThreadInitialize() < 0) + return -1; + + if (virtTestRun("types", 1, testTypes, NULL) < 0) + ret = -1; + if (virtTestRun("threads", 1, testThreads, NULL) < 0) + ret = -1; + + return ret; +} + +VIRT_TEST_MAIN(mymain) -- 1.7.10.4

On 07/31/2012 10:58 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
There are a few issues with the current virAtomic APIs
- They require use of a virAtomicInt struct instead of a plain int type - Several of the methods do not implement memory barriers - The methods do not implement compiler re-ordering barriers - There is no Win32 native impl
The GLib library has a nice LGPLv2+ licensed impl of atomic ops that works with GCC, Win32, or pthreads.h that addresses all these problems. The main downside to their code is that the pthreads impl uses a single global mutex, instead of a per-variable mutex. Given that it does have a Win32 impl though, we don't expect anyone to seriously use the pthread.h impl, so this downside is not significant.
* .gitignore: Ignore test case * configure.ac: Check for which atomic ops impl to use * src/Makefile.am: Add viratomic.c * src/nwfilter/nwfilter_dhcpsnoop.c: Switch to new atomic ops APIs and plain int datatype * src/util/viratomic.h: inline impls of all atomic ops for GCC, Win32 and pthreads * src/util/viratomic.c: Global pthreads mutex for atomic ops * tests/viratomictest.c: Test validate to validate safety of atomic ops.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> ---
+dnl Note that the atomic ops are only available with GCC on x86 when +dnl using -march=i486 or higher. If we detect that the atomic ops are +dnl not available but would be available given the right flags, we want +dnl to abort and advise the user to fix their CFLAGS. It's better to do +dnl that then to silently fall back on emulated atomic ops just because +dnl the user had the wrong build environment. + +atomic_ops= + +AC_MSG_CHECKING([for atomic ops implementation]) + +AC_TRY_COMPILE([], [__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;],[
The autoconf manual prefers 'AC_COMPILE_IFELSE' over 'AC_TRY_COMPILE', but as you are copying code, I won't worry if you don't change it.
+ atomic_ops=gcc +],[]) + +if test "$atomic_ops" = "" ; then + SAVE_CFLAGS="${CFLAGS}" + CFLAGS="-march=i486"
Should this be: CFLAGS="$CFLAGS -march=i486" so as not to lose previous flags that might be important?
+ AC_TRY_COMPILE([], + [__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;], + [AC_MSG_ERROR([Libvirt must be build with -march=i486 or later.])],
s/build/built/ Okay - the intent here is that if we compiled and __GCC_HAVE_SYNC_COMPARE_AND_SWAP failed, then we add a new option, and the recompilation attempt succeeds, then we a) must be using gcc, b) gcc recognizes the option, so we must be x86 (all other scenarios either passed on the first compilation, or point to a different architecture and/or different compiler so both compile attempts failed). Since the test is so simple, discarding all existing CFLAGS to look for just -march=i486 probably does the job, and I guess my earlier comment is not strictly necessary. Do we need to worry about updating './autogen.sh' to add this CFLAGS value automatically, or is gcc typically spec'd to a new enough platform by default in x86 distros these days? Then again, I just tested the patch myself and didn't hit the warning, so at least Fedora 17 has gcc spec'd to implicitly assume that flag.
@@ -1301,6 +1301,10 @@ if HAVE_SASL USED_SYM_FILES += libvirt_sasl.syms endif
+if WITH_ATOMIC_OPS_PTHREAD +USED_SYM_FILES += libvirt_atomic.syms +endif + EXTRA_DIST += \ libvirt_public.syms \ libvirt_private.syms \
Incomplete. EXTRA_DIST also needs to list libvirt_atomic.syms. Reviewing the next part out of order, so as to hit implementation before client's use of the implementation.
diff --git a/src/util/viratomic.c b/src/util/viratomic.c new file mode 100644 index 0000000..af846ff --- /dev/null +++ b/src/util/viratomic.c @@ -0,0 +1,35 @@ +/*
+ +#ifdef VIR_ATOMIC_OPS_PTHREAD + +pthread_mutex_t virAtomicLock = PTHREAD_MUTEX_INITIALIZER;
I guess since we know we are using pthread, we can directly use pthread_mutex_t instead of our virThread wrappers in our thread.h.
+++ b/src/util/viratomic.h @@ -1,10 +1,11 @@ /* * viratomic.h: atomic integer operations * - * Copyright (C) 2012 IBM Corporation + * Copyright (C) 2012 Red Hat, Inc.
Normally, I question tossing out an old copyright. But this is such a massive rewrite that I think you're safe. By the way, the diff was horrible to read; I more or less ended up reviewing the final state of the code, rather than the diff.
+/** + * virAtomicIntSet: + * Sets the value of atomic to newval. + * + * This call acts as a full compiler and hardware memory barrier + * (after the set) + */ +void virAtomicIntSet(volatile int *atomic, + int newval) + ATTRIBUTE_NONNULL(1);
Is it worth having this function return 'int' instead of 'void' to pass back the just-set value, similar to C semantics of 'a = b = c' returning the just-set value of 'b' when assigning to 'a'? Then again, you were able to do the conversion without it, so probably not worth changing.
+/** + * virAtomicIntInc: + * Increments the value of atomic by 1. + * + * Think of this operation as an atomic version of + * { *atomic += 1; return *atomic; }
Here we add then fetch; but with virAtomicIntAdd, we fetch then add. Is the difference going to bite us? At least it is documented, so I can review based on the documentation.
+/** + * virAtomicIntDecAndTest: + * Decrements the value of atomic by 1. + * + * Think of this operation as an atomic version of + * { *atomic -= 1; return *atomic == 0; }
I guess this is another case of add then fetch, more like virAtomicIntInc.
+/** + * virAtomicIntAdd: + * Atomically adds val to the value of atomic. + * + * Think of this operation as an atomic version of + * { tmp = *atomic; *atomic += val; return tmp; } + * + * This call acts as a full compiler and hardware memory barrier. + */ +int virAtomicIntAdd(volatile int *atomic, + int val) ATTRIBUTE_NONNULL(1); -static inline int virAtomicIntSub(virAtomicIntPtr vaip, int add) + +/** + * virAtomicIntAnd: + * Performs an atomic bitwise 'and' of the value of atomic + * and val, storing the result back in atomic. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Think of this operation as an atomic version of + * { tmp = *atomic; *atomic &= val; return tmp; }
I guess the other thing to consider is that with virAtomicIntAnd, you have no way to reconstruct the original value based solely on what you and'ed in, but given the original value, you can reconstruct what must have been assigned. With virAtomicIntInc and virAtomicIntAdd, you can reconstruct either value; so it boils down to a question of which value will be more useful (the original or the modified), as well as a symmetry (virAtomicIntAdd is more like virAtomicIntAnd on doing arbitrary operations, while virAtomicIntInc is limited to a change of 1).
+# ifdef VIR_ATOMIC_OPS_GCC + +# define virAtomicIntGet(atomic) \ + (__extension__ ({ \ + (void)verify_true(sizeof(*(atomic)) == sizeof(int)); \ + (void)(0 ? *(atomic) ^ *(atomic) : 0); \
The gnulib documentation actually recommends using verify_expr() these days rather than verify_true, as in: (void)verify_true(sizeof(*(atomic)) == sizeof(int), \ 0 ? *(atomic) ^ *(atomic) : 0); \ since in some situations, verify_expr() can give better diagnostics.
+inline int +virAtomicIntInc(volatile int *atomic) +{ + return InterlockedIncrement((volatile LONG *)atomic); +}
I checked that this value does indeed return the new value...
+inline int +virAtomicIntAdd(volatile int *atomic, + int val) +{ + return InterlockedExchangeAdd((volatile LONG *)atomic, val);
...and this returns the old value, so at least you are consistent to your documentation on this implementation. Yay - this header looks sound. Now, back to the rest of the commit.
@@ -1994,9 +1992,9 @@ virNWFilterSnoopLeaseFileLoad(void) static void virNWFilterSnoopJoinThreads(void) { - while (virAtomicIntRead(&virNWFilterSnoopState.nThreads) != 0) { + while (virAtomicIntGet(&virNWFilterSnoopState.nThreads) != 0) { VIR_WARN("Waiting for snooping threads to terminate: %u\n", - virAtomicIntRead(&virNWFilterSnoopState.nThreads)); + virAtomicIntGet(&virNWFilterSnoopState.nThreads));
Pre-existing, but this loop could print the wrong value in the VIR_WARN statement. It would be better to assign the condition of the loop to a temporary, then print that temporary, so the output won't be confusing.
+++ b/src/util/virfile.c @@ -618,12 +618,11 @@ cleanup: #else /* __linux__ */
int virFileLoopDeviceAssociate(const char *file, - char **dev) + char **dev ATTRIBUTE_UNUSED) { virReportSystemError(ENOSYS, _("Unable to associate file %s with loop device"), file); - *dev = NULL; return -1; }
This is a bogus hunk (conflict resolution gone wrong)
+++ b/tests/viratomictest.c
+static int +testTypes(const void *data ATTRIBUTE_UNUSED) +{ + unsigned int u, u2; + int s, s2; + bool res; + +#define virAssertCmpInt(a, op, b) \ + if (!((a) op (b))) \ + return -1; + virAtomicIntSet(&u, 5); + u2 = virAtomicIntGet(&u); + virAssertCmpInt(u2, ==, 5); + + res = virAtomicIntCompareExchange(&u, 6, 7); + if (res) + return -1; + virAssertCmpInt(u, ==, 5); + + virAtomicIntAdd(&u, 1);
slightly stronger test as: virAssertCmpInt(virAtomicIntAdd(&u, 1), == 5);
+ virAssertCmpInt(u, ==, 6); + + virAtomicIntInc(&u);
slightly stronger test as: virAssertCmpInt(virAtomicIntInc(&u), ==, 7); ACK once you fix src/Makefile.am and the configure.ac typo, and omit the virfile.c hunk. The rest of my comments aren't show-stoppers, so feel free to fix or ignore as suits you. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 07/31/2012 06:09 PM, Eric Blake wrote:
On 07/31/2012 10:58 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
There are a few issues with the current virAtomic APIs
- They require use of a virAtomicInt struct instead of a plain int type - Several of the methods do not implement memory barriers - The methods do not implement compiler re-ordering barriers - There is no Win32 native impl
Reviewing the next part out of order, so as to hit implementation before client's use of the implementation.
diff --git a/src/util/viratomic.c b/src/util/viratomic.c new file mode 100644 index 0000000..af846ff --- /dev/null +++ b/src/util/viratomic.c @@ -0,0 +1,35 @@
Oh, one more thing - run 'make syntax-check before pushing, and fix these: copyright_address src/util/viratomic.c:22: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA tests/viratomictest.c:16: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA maint.mk: Point to <http://www.gnu.org/licenses/>, not an address -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Tue, Jul 31, 2012 at 06:09:13PM -0600, Eric Blake wrote:
On 07/31/2012 10:58 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
There are a few issues with the current virAtomic APIs
- They require use of a virAtomicInt struct instead of a plain int type - Several of the methods do not implement memory barriers - The methods do not implement compiler re-ordering barriers - There is no Win32 native impl
The GLib library has a nice LGPLv2+ licensed impl of atomic ops that works with GCC, Win32, or pthreads.h that addresses all these problems. The main downside to their code is that the pthreads impl uses a single global mutex, instead of a per-variable mutex. Given that it does have a Win32 impl though, we don't expect anyone to seriously use the pthread.h impl, so this downside is not significant.
* .gitignore: Ignore test case * configure.ac: Check for which atomic ops impl to use * src/Makefile.am: Add viratomic.c * src/nwfilter/nwfilter_dhcpsnoop.c: Switch to new atomic ops APIs and plain int datatype * src/util/viratomic.h: inline impls of all atomic ops for GCC, Win32 and pthreads * src/util/viratomic.c: Global pthreads mutex for atomic ops * tests/viratomictest.c: Test validate to validate safety of atomic ops.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> ---
+dnl Note that the atomic ops are only available with GCC on x86 when +dnl using -march=i486 or higher. If we detect that the atomic ops are +dnl not available but would be available given the right flags, we want +dnl to abort and advise the user to fix their CFLAGS. It's better to do +dnl that then to silently fall back on emulated atomic ops just because +dnl the user had the wrong build environment. + +atomic_ops= + +AC_MSG_CHECKING([for atomic ops implementation]) + +AC_TRY_COMPILE([], [__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;],[
The autoconf manual prefers 'AC_COMPILE_IFELSE' over 'AC_TRY_COMPILE', but as you are copying code, I won't worry if you don't change it.
+ atomic_ops=gcc +],[]) + +if test "$atomic_ops" = "" ; then + SAVE_CFLAGS="${CFLAGS}" + CFLAGS="-march=i486"
Should this be:
CFLAGS="$CFLAGS -march=i486"
so as not to lose previous flags that might be important?
I don't think it really matters in the context of this test
+ AC_TRY_COMPILE([], + [__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;], + [AC_MSG_ERROR([Libvirt must be build with -march=i486 or later.])],
s/build/built/
Okay - the intent here is that if we compiled and __GCC_HAVE_SYNC_COMPARE_AND_SWAP failed, then we add a new option, and the recompilation attempt succeeds, then we a) must be using gcc, b) gcc recognizes the option, so we must be x86 (all other scenarios either passed on the first compilation, or point to a different architecture and/or different compiler so both compile attempts failed). Since the test is so simple, discarding all existing CFLAGS to look for just -march=i486 probably does the job, and I guess my earlier comment is not strictly necessary.
Do we need to worry about updating './autogen.sh' to add this CFLAGS value automatically, or is gcc typically spec'd to a new enough platform by default in x86 distros these days? Then again, I just tested the patch myself and didn't hit the warning, so at least Fedora 17 has gcc spec'd to implicitly assume that flag.
I believe all common distros have GCC builds default to at least i486 these days, precisely to get atomic op support. So don't reckon we need todo anything here.
@@ -1301,6 +1301,10 @@ if HAVE_SASL USED_SYM_FILES += libvirt_sasl.syms endif
+if WITH_ATOMIC_OPS_PTHREAD +USED_SYM_FILES += libvirt_atomic.syms +endif + EXTRA_DIST += \ libvirt_public.syms \ libvirt_private.syms \
Incomplete. EXTRA_DIST also needs to list libvirt_atomic.syms.
Opps, yes, will add.
diff --git a/src/util/viratomic.c b/src/util/viratomic.c new file mode 100644 index 0000000..af846ff --- /dev/null +++ b/src/util/viratomic.c @@ -0,0 +1,35 @@ +/*
+ +#ifdef VIR_ATOMIC_OPS_PTHREAD + +pthread_mutex_t virAtomicLock = PTHREAD_MUTEX_INITIALIZER;
I guess since we know we are using pthread, we can directly use pthread_mutex_t instead of our virThread wrappers in our thread.h.
The main reason is to be able to get the static initializer, which we don't support, since there's no easy way to achieve it on Win32. (Mingw pthreads does some horrible hacks to try, which I didn't fancy doing)
+++ b/src/util/viratomic.h @@ -1,10 +1,11 @@ /* * viratomic.h: atomic integer operations * - * Copyright (C) 2012 IBM Corporation + * Copyright (C) 2012 Red Hat, Inc.
Normally, I question tossing out an old copyright. But this is such a massive rewrite that I think you're safe. By the way, the diff was horrible to read; I more or less ended up reviewing the final state of the code, rather than the diff.
My justification for this is that I deleted the existing file entirely, and copied in the new file from GLib. So any matching lines between old & new are just co-incidence
+/** + * virAtomicIntSet: + * Sets the value of atomic to newval. + * + * This call acts as a full compiler and hardware memory barrier + * (after the set) + */ +void virAtomicIntSet(volatile int *atomic, + int newval) + ATTRIBUTE_NONNULL(1);
Is it worth having this function return 'int' instead of 'void' to pass back the just-set value, similar to C semantics of 'a = b = c' returning the just-set value of 'b' when assigning to 'a'? Then again, you were able to do the conversion without it, so probably not worth changing.
I figure we can change this in the future if it proves to be needed.
+/** + * virAtomicIntInc: + * Increments the value of atomic by 1. + * + * Think of this operation as an atomic version of + * { *atomic += 1; return *atomic; }
Here we add then fetch; but with virAtomicIntAdd, we fetch then add. Is the difference going to bite us? At least it is documented, so I can review based on the documentation.
It is annoying, but this lets us get optimal performance on Win32. If I made them consistent, then we'd be stuck with one of the Win32 impls being relatively inefficient :-(
+++ b/src/util/virfile.c @@ -618,12 +618,11 @@ cleanup: #else /* __linux__ */
int virFileLoopDeviceAssociate(const char *file, - char **dev) + char **dev ATTRIBUTE_UNUSED) { virReportSystemError(ENOSYS, _("Unable to associate file %s with loop device"), file); - *dev = NULL; return -1; }
This is a bogus hunk (conflict resolution gone wrong)
Opps, yes.
+ virAssertCmpInt(u, ==, 5); + + virAtomicIntAdd(&u, 1);
slightly stronger test as:
virAssertCmpInt(virAtomicIntAdd(&u, 1), == 5);
+ virAssertCmpInt(u, ==, 6); + + virAtomicIntInc(&u);
slightly stronger test as:
virAssertCmpInt(virAtomicIntInc(&u), ==, 7);
Good suggestions
ACK once you fix src/Makefile.am and the configure.ac typo, and omit the virfile.c hunk. The rest of my comments aren't show-stoppers, so feel free to fix or ignore as suits you.
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 :|

From: "Daniel P. Berrange" <berrange@redhat.com> This introduces a fairly basic reference counted virObject type and an associated virClass type, that use atomic operations for ref counting. In a global initializer (recommended to be invoked using the virOnceInit API), a virClass type must be allocated for each object type. This requires a class name, a "dispose" callback which will be invoked to free memory associated with the object's fields, and the size in bytes of the object struct. eg, virClassPtr connclass = virClassNew("virConnect", sizeof(virConnect), virConnectDispose); The struct for the object, must include 'virObject' as its first member eg struct _virConnect { virObject object; virURIPtr uri; }; The 'dispose' callback is only responsible for freeing fields in the object, not the object itself. eg a suitable impl for the above struct would be void virConnectDispose(void *obj) { virConnectPtr conn = obj; virURIFree(conn->uri); } There is no need to reset fields to 'NULL' or '0' in the dispose callback, since the entire object will be memset to 0, and the klass pointer & magic integer fields will be poisoned with 0xDEADBEEF When creating an instance of an object, one needs simply pass the virClassPtr eg virConnectPtr conn = virObjectNew(connklass); if (!conn) return NULL; conn->uri = virURIParse("foo:///bar") Object references can be manipulated with virObjectRef(conn) virObjectUnref(conn) The latter returns a true value, if the object has been freed (ie its ref count hit zero) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/Makefile.am | 1 + src/libvirt_private.syms | 9 ++ src/libvirt_probes.d | 7 ++ src/util/virobject.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virobject.h | 60 ++++++++++++++ 5 files changed, 281 insertions(+) create mode 100644 src/util/virobject.c create mode 100644 src/util/virobject.h diff --git a/src/Makefile.am b/src/Makefile.am index 984a743..ec849b4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -84,6 +84,7 @@ UTIL_SOURCES = \ util/virauth.c util/virauth.h \ util/virauthconfig.c util/virauthconfig.h \ util/virfile.c util/virfile.h \ + util/virobject.c util/virobject.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virpidfile.c util/virpidfile.h \ util/virtypedparam.c util/virtypedparam.h \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8b9e2c0..1d91b70 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1609,6 +1609,15 @@ nodeSuspendForDuration; virNodeSuspendGetTargetMask; +# virobject.h +virClassName; +virClassNew; +virObjectIsClass; +virObjectNew; +virObjectRef; +virObjectUnref; + + # virpidfile.h virPidFileAcquire; virPidFileAcquirePath; diff --git a/src/libvirt_probes.d b/src/libvirt_probes.d index 0dac8f3..ceb3caa 100644 --- a/src/libvirt_probes.d +++ b/src/libvirt_probes.d @@ -16,6 +16,13 @@ provider libvirt { probe event_poll_run(int nfds, int timeout); + # file: src/util/virobject.c + # prefix: object + probe object_new(void *obj, const char *klassname); + probe object_ref(void *obj); + probe object_unref(void *obj); + probe object_dispose(void *obj); + # file: src/rpc/virnetsocket.c # prefix: rpc probe rpc_socket_new(void *sock, int refs, int fd, int errfd, pid_t pid, const char *localAddr, const char *remoteAddr); diff --git a/src/util/virobject.c b/src/util/virobject.c new file mode 100644 index 0000000..4e02fd0 --- /dev/null +++ b/src/util/virobject.c @@ -0,0 +1,204 @@ +/* + * virobject.c: libvirt reference counted object + * + * Copyright (C) 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "virobject.h" +#include "threads.h" +#include "memory.h" +#include "viratomic.h" +#include "virterror_internal.h" +#include "logging.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +#define virObjectError(code, ...) \ + virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +static unsigned int magicCounter = 0xCAFE0000; + +struct _virClass { + unsigned int magic; + const char *name; + size_t objectSize; + + virObjectDisposeCallback dispose; +}; + + +/** + * virClassNew: + * @name: the class name + * @objectSize: total size of the object struct + * @dispose: callback to run to free object fields + * + * Register a new object class with @name. The @objectSize + * should give the total size of the object struct, which + * is expected to have a 'virObject object;' field as its + * first member. When the last reference on the object is + * released, the @dispose callback will be invoked to free + * memory of the object fields + * + * Returns a new class instance + */ +virClassPtr virClassNew(const char *name, + size_t objectSize, + virObjectDisposeCallback dispose) +{ + virClassPtr klass; + + if (VIR_ALLOC(klass) < 0) + return NULL; + + if (!(klass->name = strdup(name))) + goto no_memory; + klass->magic = virAtomicIntAdd(&magicCounter, 1); + klass->objectSize = objectSize; + klass->dispose = dispose; + + return klass; + +no_memory: + VIR_FREE(klass); + virReportOOMError(); + return NULL; +} + + +/** + * virObjectNew: + * @klass: the klass of object to create + * + * Allocates a new object of type @klass. The returned + * object will be an instance of "virObjectPtr", which + * can be cast to the struct associated with @klass. + * + * The initial reference count of the object will be 1. + * + * Returns the new object + */ +void *virObjectNew(virClassPtr klass) +{ + virObjectPtr obj = NULL; + char *somebytes; + + if (VIR_ALLOC_N(somebytes, klass->objectSize) < 0) { + virReportOOMError(); + return NULL; + } + obj = (virObjectPtr)somebytes; + + obj->magic = klass->magic; + obj->klass = klass; + virAtomicIntSet(&obj->refs, 1); + + PROBE(OBJECT_NEW, "obj=%p classname=%s", obj, obj->klass->name); + + return obj; +} + + +/** + * virObjectUnref: + * @anyobj: any instance of virObjectPtr + * + * Decrement the reference count on @anyobj and if + * it hits zero, runs the "dispose" callback associated + * with the object class. + * + * Returns true if the remaining reference count is + * non-zero, false if the object was disposed of + */ +bool virObjectUnref(void *anyobj) +{ + virObjectPtr obj = anyobj; + + if (!obj) + return false; + + bool lastRef = virAtomicIntDecAndTest(&obj->refs); + PROBE(OBJECT_UNREF, "obj=%p", obj); + if (lastRef) { + PROBE(OBJECT_DISPOSE, "obj=%p", obj); + if (obj->klass->dispose) + obj->klass->dispose(obj); + + /* Clear & poison object */ + memset(obj, 0, obj->klass->objectSize); + obj->magic = 0xDEADBEEF; + obj->klass = (void*)0xDEADBEEF; + VIR_FREE(obj); + } + + return !lastRef; +} + + +/** + * virObjectRef: + * @anyobj: any instance of virObjectPtr + * + * Increment the reference count on @anyobj and return + * the same pointer + * + * Returns @anyobj + */ +void *virObjectRef(void *anyobj) +{ + virObjectPtr obj = anyobj; + + if (!obj) + return NULL; + virAtomicIntInc(&obj->refs); + PROBE(OBJECT_REF, "obj=%p", obj); + return anyobj; +} + + +/** + * virObjectIsClass: + * @anyobj: any instance of virObjectPtr + * @klass: the class to check + * + * Checks whether @anyobj is an instance of + * @klass + * + * Returns true if @anyobj is an instance of @klass + */ +bool virObjectIsClass(void *anyobj, + virClassPtr klass) +{ + virObjectPtr obj = anyobj; + return obj != NULL && (obj->magic == klass->magic) && (obj->klass == klass); +} + + +/** + * virClassName: + * @klass: the object class + * + * Returns the name of @klass + */ +const char *virClassName(virClassPtr klass) +{ + return klass->name; +} diff --git a/src/util/virobject.h b/src/util/virobject.h new file mode 100644 index 0000000..3eb551d --- /dev/null +++ b/src/util/virobject.h @@ -0,0 +1,60 @@ +/* + * virobject.h: libvirt reference counted object + * + * Copyright (C) 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __VIR_OBJECT_H__ +# define __VIR_OBJECT_H__ + +# include "internal.h" + +typedef struct _virClass virClass; +typedef virClass *virClassPtr; + +typedef struct _virObject virObject; +typedef virObject *virObjectPtr; + +typedef void (*virObjectDisposeCallback)(void *obj); + +struct _virObject { + unsigned int magic; + virClassPtr klass; + int refs; +}; + +virClassPtr virClassNew(const char *name, + size_t objectSize, + virObjectDisposeCallback dispose) + ATTRIBUTE_NONNULL(1); + +const char *virClassName(virClassPtr klass) + ATTRIBUTE_NONNULL(1); + +void *virObjectNew(virClassPtr klass) + ATTRIBUTE_NONNULL(1); +bool virObjectUnref(void *obj) + ATTRIBUTE_NONNULL(1); +void *virObjectRef(void *obj) + ATTRIBUTE_NONNULL(1); + +bool virObjectIsClass(void *obj, + virClassPtr klass) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +#endif /* __VIR_OBJECT_H */ -- 1.7.10.4

On 07/31/2012 10:58 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
This introduces a fairly basic reference counted virObject type and an associated virClass type, that use atomic operations for ref counting.
In a global initializer (recommended to be invoked using the virOnceInit API), a virClass type must be allocated for each object type. This requires a class name, a "dispose" callback which will be invoked to free memory associated with the object's fields, and the size in bytes of the object struct.
eg,
virClassPtr connclass = virClassNew("virConnect", sizeof(virConnect), virConnectDispose);
Should we macroize any of this common pattern, as in: #define VIR_CLASS_NEW(name) \ virClassNew(#name, sizeof(name), name##Dispose) virClassPtr connclass = VIR_CLASS_NEW(virConnect); then again, you allow for a NULL dispose function, so duplicating the common idiom isn't too bad if we don't want to force a dispose function to exist.
The struct for the object, must include 'virObject' as its first member
eg
struct _virConnect { virObject object;
virURIPtr uri; };
The 'dispose' callback is only responsible for freeing fields in the object, not the object itself. eg a suitable impl for the above struct would be
void virConnectDispose(void *obj) { virConnectPtr conn = obj; virURIFree(conn->uri); }
There is no need to reset fields to 'NULL' or '0' in the dispose callback, since the entire object will be memset to 0, and the klass pointer & magic integer fields will be poisoned with 0xDEADBEEF
Should you mention that the object is then freed after being poisoned? That is, the memset is merely precautionary to make use-after-free bugs easier to detect.
When creating an instance of an object, one needs simply pass the virClassPtr eg
virConnectPtr conn = virObjectNew(connklass);
s/connklass/connclass/ to match above
if (!conn) return NULL; conn->uri = virURIParse("foo:///bar")
Object references can be manipulated with
virObjectRef(conn) virObjectUnref(conn)
The latter returns a true value, if the object has been freed (ie its ref count hit zero)
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> ---
+++ b/src/Makefile.am @@ -84,6 +84,7 @@ UTIL_SOURCES = \ util/virauth.c util/virauth.h \ util/virauthconfig.c util/virauthconfig.h \ util/virfile.c util/virfile.h \ + util/virobject.c util/virobject.h \ util/virnodesuspend.c util/virnodesuspend.h \
Sorting is off by one line.
+#define VIR_FROM_THIS VIR_FROM_NONE + +#define virObjectError(code, ...) \ + virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__)
This is stale now.
+virClassPtr virClassNew(const char *name, + size_t objectSize, + virObjectDisposeCallback dispose) +{ + virClassPtr klass; + + if (VIR_ALLOC(klass) < 0) + return NULL;
Missing a virReportOOMError(), especially since:
+ + if (!(klass->name = strdup(name))) + goto no_memory;
the rest of your code has it.
+ klass->magic = virAtomicIntAdd(&magicCounter, 1);
virAtomicIntInc(), now that it returns a value?
+/** + * virObjectUnref: + * @anyobj: any instance of virObjectPtr + * + * Decrement the reference count on @anyobj and if + * it hits zero, runs the "dispose" callback associated + * with the object class.
and then free anyobj.
+/** + * virObjectIsClass: + * @anyobj: any instance of virObjectPtr + * @klass: the class to check + * + * Checks whether @anyobj is an instance of + * @klass + * + * Returns true if @anyobj is an instance of @klass + */ +bool virObjectIsClass(void *anyobj, + virClassPtr klass) +{ + virObjectPtr obj = anyobj; + return obj != NULL && (obj->magic == klass->magic) && (obj->klass == klass);
Theoretically redundant, but I'm not opposed to the extra checking here as one more line of defense at quickly debugging bad code with use-after-free problems.
+++ b/src/util/virobject.h @@ -0,0 +1,60 @@ +/*
+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Fails 'make syntax-check'.
+struct _virObject { + unsigned int magic; + virClassPtr klass; + int refs; +};
On a machine with 64-bit void*, this is 24 bytes, but you could make it 16 bytes by swapping refs to occur before klass. Not that we're strapped for space, but there are some speed benefits to smaller structs.
+bool virObjectUnref(void *obj) + ATTRIBUTE_NONNULL(1);
This attribute is wrong, since you implemented the function to handle a NULL input.
+void *virObjectRef(void *obj) + ATTRIBUTE_NONNULL(1);
Likewise.
+ +bool virObjectIsClass(void *obj, + virClassPtr klass) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
Likewise for the first argument (but the 2nd is indeed non-NULL). Overall I like the direction this is headed. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

From: "Daniel P. Berrange" <berrange@redhat.com> Several APIs in src/datatypes.c were formatting an UUID to a uuidstr variable and then not using it. --- src/datatypes.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/datatypes.c b/src/datatypes.c index f1f6e61..343ee0d 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -173,7 +173,6 @@ virUnrefConnect(virConnectPtr conn) { virDomainPtr virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { virDomainPtr ret = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN]; if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); @@ -184,8 +183,6 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { virMutexLock(&conn->lock); - virUUIDFormat(uuid, uuidstr); - if (VIR_ALLOC(ret) < 0) { virMutexUnlock(&conn->lock); virReportOOMError(); @@ -301,7 +298,6 @@ virUnrefDomain(virDomainPtr domain) { virNetworkPtr virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { virNetworkPtr ret = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN]; if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); @@ -312,8 +308,6 @@ virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { virMutexLock(&conn->lock); - virUUIDFormat(uuid, uuidstr); - if (VIR_ALLOC(ret) < 0) { virMutexUnlock(&conn->lock); virReportOOMError(); @@ -562,7 +556,6 @@ virStoragePoolPtr virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uuid) { virStoragePoolPtr ret = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN]; if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); @@ -573,8 +566,6 @@ virGetStoragePool(virConnectPtr conn, const char *name, virMutexLock(&conn->lock); - virUUIDFormat(uuid, uuidstr); - if (VIR_ALLOC(ret) < 0) { virMutexUnlock(&conn->lock); virReportOOMError(); @@ -946,7 +937,6 @@ virGetSecret(virConnectPtr conn, const unsigned char *uuid, int usageType, const char *usageID) { virSecretPtr ret = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN]; if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); @@ -957,8 +947,6 @@ virGetSecret(virConnectPtr conn, const unsigned char *uuid, virMutexLock(&conn->lock); - virUUIDFormat(uuid, uuidstr); - if (VIR_ALLOC(ret) < 0) { virMutexUnlock(&conn->lock); virReportOOMError(); @@ -1128,7 +1116,6 @@ int virUnrefStream(virStreamPtr st) { virNWFilterPtr virGetNWFilter(virConnectPtr conn, const char *name, const unsigned char *uuid) { virNWFilterPtr ret = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN]; if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); @@ -1139,8 +1126,6 @@ virGetNWFilter(virConnectPtr conn, const char *name, const unsigned char *uuid) virMutexLock(&conn->lock); - virUUIDFormat(uuid, uuidstr); - if (VIR_ALLOC(ret) < 0) { virMutexUnlock(&conn->lock); virReportOOMError(); -- 1.7.10.4

On Tue, Jul 31, 2012 at 05:58:24PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Several APIs in src/datatypes.c were formatting an UUID to a uuidstr variable and then not using it. --- src/datatypes.c | 15 --------------- 1 file changed, 15 deletions(-)
diff --git a/src/datatypes.c b/src/datatypes.c index f1f6e61..343ee0d 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -173,7 +173,6 @@ virUnrefConnect(virConnectPtr conn) { virDomainPtr virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { virDomainPtr ret = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN];
if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); @@ -184,8 +183,6 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) {
virMutexLock(&conn->lock);
- virUUIDFormat(uuid, uuidstr); - if (VIR_ALLOC(ret) < 0) { virMutexUnlock(&conn->lock); virReportOOMError(); @@ -301,7 +298,6 @@ virUnrefDomain(virDomainPtr domain) { virNetworkPtr virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { virNetworkPtr ret = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN];
if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); @@ -312,8 +308,6 @@ virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) {
virMutexLock(&conn->lock);
- virUUIDFormat(uuid, uuidstr); - if (VIR_ALLOC(ret) < 0) { virMutexUnlock(&conn->lock); virReportOOMError(); @@ -562,7 +556,6 @@ virStoragePoolPtr virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uuid) { virStoragePoolPtr ret = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN];
if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); @@ -573,8 +566,6 @@ virGetStoragePool(virConnectPtr conn, const char *name,
virMutexLock(&conn->lock);
- virUUIDFormat(uuid, uuidstr); - if (VIR_ALLOC(ret) < 0) { virMutexUnlock(&conn->lock); virReportOOMError(); @@ -946,7 +937,6 @@ virGetSecret(virConnectPtr conn, const unsigned char *uuid, int usageType, const char *usageID) { virSecretPtr ret = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN];
if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); @@ -957,8 +947,6 @@ virGetSecret(virConnectPtr conn, const unsigned char *uuid,
virMutexLock(&conn->lock);
- virUUIDFormat(uuid, uuidstr); - if (VIR_ALLOC(ret) < 0) { virMutexUnlock(&conn->lock); virReportOOMError(); @@ -1128,7 +1116,6 @@ int virUnrefStream(virStreamPtr st) { virNWFilterPtr virGetNWFilter(virConnectPtr conn, const char *name, const unsigned char *uuid) { virNWFilterPtr ret = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN];
if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); @@ -1139,8 +1126,6 @@ virGetNWFilter(virConnectPtr conn, const char *name, const unsigned char *uuid)
virMutexLock(&conn->lock);
- virUUIDFormat(uuid, uuidstr); - if (VIR_ALLOC(ret) < 0) { virMutexUnlock(&conn->lock); virReportOOMError();
ACK independentky of the other part of the patch set, let's fix this :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: "Daniel P. Berrange" <berrange@redhat.com> This converts the following public API datatypes to use the virObject infrastructure: virConnectPtr virDomainPtr virDomainSnapshotPtr virInterfacePtr virNetworkPtr virNodeDevicePtr virNWFilterPtr virSecretPtr virStreamPtr virStorageVolPtr virStoragePoolPtr The code is significantly simplified, since the mutex in the virConnectPtr object now only needs to be held when accessing the per-connection virError object instance. All other operations are completely lock free. * src/datatypes.c, src/datatypes.h, src/libvirt.c: Convert public datatypes to use virObject * src/conf/domain_event.c, src/phyp/phyp_driver.c, src/qemu/qemu_command.c, src/qemu/qemu_migration.c, src/qemu/qemu_process.c, src/storage/storage_driver.c, src/vbox/vbox_tmpl.c, src/xen/xend_internal.c, tests/qemuxml2argvtest.c, tests/qemuxmlnstest.c, tests/sexpr2xmltest.c, tests/xmconfigtest.c: Convert to use virObjectUnref/virObjectRef Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/conf/domain_event.c | 8 +- src/datatypes.c | 1035 +++++++++++------------------------------- src/datatypes.h | 264 ++++------- src/libvirt.c | 145 ++---- src/libvirt_private.syms | 17 +- src/phyp/phyp_driver.c | 14 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_migration.c | 8 +- src/qemu/qemu_process.c | 2 +- src/storage/storage_driver.c | 4 +- src/vbox/vbox_tmpl.c | 2 +- src/xen/xend_internal.c | 4 +- tests/qemuxml2argvtest.c | 21 +- tests/qemuxmlnstest.c | 2 +- tests/sexpr2xmltest.c | 2 +- tests/xmconfigtest.c | 4 +- 16 files changed, 448 insertions(+), 1086 deletions(-) diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index f72bc8c..43ecdcf 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -169,7 +169,7 @@ virDomainEventCallbackListRemove(virConnectPtr conn, virFreeCallback freecb = cbList->callbacks[i]->freecb; if (freecb) (*freecb)(cbList->callbacks[i]->opaque); - virUnrefConnect(cbList->callbacks[i]->conn); + virObjectUnref(cbList->callbacks[i]->conn); VIR_FREE(cbList->callbacks[i]); if (i < (cbList->count - 1)) @@ -219,7 +219,7 @@ virDomainEventCallbackListRemoveID(virConnectPtr conn, virFreeCallback freecb = cbList->callbacks[i]->freecb; if (freecb) (*freecb)(cbList->callbacks[i]->opaque); - virUnrefConnect(cbList->callbacks[i]->conn); + virObjectUnref(cbList->callbacks[i]->conn); VIR_FREE(cbList->callbacks[i]); if (i < (cbList->count - 1)) @@ -309,7 +309,7 @@ virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList) virFreeCallback freecb = cbList->callbacks[i]->freecb; if (freecb) (*freecb)(cbList->callbacks[i]->opaque); - virUnrefConnect(cbList->callbacks[i]->conn); + virObjectUnref(cbList->callbacks[i]->conn); VIR_FREE(cbList->callbacks[i]); if (i < (cbList->count - 1)) @@ -395,7 +395,7 @@ virDomainEventCallbackListAddID(virConnectPtr conn, if (VIR_REALLOC_N(cbList->callbacks, cbList->count + 1) < 0) goto no_memory; - event->conn->refs++; + virObjectRef(event->conn); cbList->callbacks[cbList->count] = event; cbList->count++; diff --git a/src/datatypes.c b/src/datatypes.c index 343ee0d..6790a71 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -35,12 +35,58 @@ virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__) -/************************************************************************ - * * - * Domain and Connections allocations * - * * - ************************************************************************/ +virClassPtr virConnectClass; +virClassPtr virDomainClass; +virClassPtr virDomainSnapshotClass; +virClassPtr virInterfaceClass; +virClassPtr virNetworkClass; +virClassPtr virNodeDeviceClass; +virClassPtr virNWFilterClass; +virClassPtr virSecretClass; +virClassPtr virStreamClass; +virClassPtr virStorageVolClass; +virClassPtr virStoragePoolClass; + +static void virConnectDispose(void *obj); +static void virDomainDispose(void *obj); +static void virDomainSnapshotDispose(void *obj); +static void virInterfaceDispose(void *obj); +static void virNetworkDispose(void *obj); +static void virNodeDeviceDispose(void *obj); +static void virNWFilterDispose(void *obj); +static void virSecretDispose(void *obj); +static void virStreamDispose(void *obj); +static void virStorageVolDispose(void *obj); +static void virStoragePoolDispose(void *obj); + +static int +virDataTypesOnceInit(void) +{ +#define DECLARE_CLASS(basename) \ + if (!(basename ## Class = virClassNew(#basename, \ + sizeof(basename), \ + basename ## Dispose))) \ + return -1; + + DECLARE_CLASS(virConnect); + DECLARE_CLASS(virDomain); + DECLARE_CLASS(virDomainSnapshot); + DECLARE_CLASS(virInterface); + DECLARE_CLASS(virNetwork); + DECLARE_CLASS(virNodeDevice); + DECLARE_CLASS(virNWFilter); + DECLARE_CLASS(virSecret); + DECLARE_CLASS(virStream); + DECLARE_CLASS(virStorageVol); + DECLARE_CLASS(virStoragePool); + +#undef DECLARE_CLASS + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virDataTypes) /** * virGetConnect: @@ -50,38 +96,26 @@ * Returns a new pointer or NULL in case of error. */ virConnectPtr -virGetConnect(void) { +virGetConnect(void) +{ virConnectPtr ret; - if (VIR_ALLOC(ret) < 0) { - virReportOOMError(); - goto failed; - } + if (virDataTypesInitialize() < 0) + return NULL; + + if (!(ret = virObjectNew(virConnectClass))) + return NULL; + if (virMutexInit(&ret->lock) < 0) { VIR_FREE(ret); - goto failed; + return NULL; } - ret->magic = VIR_CONNECT_MAGIC; - ret->driver = NULL; - ret->networkDriver = NULL; - ret->privateData = NULL; - ret->networkPrivateData = NULL; - ret->interfacePrivateData = NULL; - - ret->refs = 1; return ret; - -failed: - if (ret != NULL) { - virMutexDestroy(&ret->lock); - VIR_FREE(ret); - } - return NULL; } /** - * virReleaseConnect: + * virConnectDispose: * @conn: the hypervisor connection to release * * Unconditionally release all memory associated with a connection. @@ -90,13 +124,9 @@ failed: * be used once this method returns. */ static void -virReleaseConnect(virConnectPtr conn) { - VIR_DEBUG("release connection %p", conn); - - /* make sure to release the connection lock before we call the - * close callbacks, otherwise we will deadlock if an error - * is raised by any of the callbacks */ - virMutexUnlock(&conn->lock); +virConnectDispose(void *obj) +{ + virConnectPtr conn = obj; if (conn->networkDriver) conn->networkDriver->close(conn); @@ -127,35 +157,6 @@ virReleaseConnect(virConnectPtr conn) { VIR_FREE(conn); } -/** - * virUnrefConnect: - * @conn: the hypervisor connection to unreference - * - * Unreference the connection. If the use count drops to zero, the structure is - * actually freed. - * - * Returns the reference count or -1 in case of failure. - */ -int -virUnrefConnect(virConnectPtr conn) { - int refs; - - if ((!VIR_IS_CONNECT(conn))) { - virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); - return -1; - } - virMutexLock(&conn->lock); - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - refs = conn->refs; - if (refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return 0; - } - virMutexUnlock(&conn->lock); - return refs; -} /** * virGetDomain: @@ -166,14 +167,18 @@ virUnrefConnect(virConnectPtr conn) { * Lookup if the domain is already registered for that connection, * if yes return a new pointer to it, if no allocate a new structure, * and register it in the table. In any case a corresponding call to - * virUnrefDomain() is needed to not leak data. + * virObjectUnref() is needed to not leak data. * * Returns a pointer to the domain, or NULL in case of failure */ virDomainPtr -virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { +virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) +{ virDomainPtr ret = NULL; + if (virDataTypesInitialize() < 0) + return NULL; + if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); return NULL; @@ -181,39 +186,26 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { virCheckNonNullArgReturn(name, NULL); virCheckNonNullArgReturn(uuid, NULL); - virMutexLock(&conn->lock); + if (!(ret = virObjectNew(virDomainClass))) + return NULL; - if (VIR_ALLOC(ret) < 0) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->name = strdup(name); - if (ret->name == NULL) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->magic = VIR_DOMAIN_MAGIC; - ret->conn = conn; + if (!(ret->name = strdup(name))) + goto no_memory; + + ret->conn = virObjectRef(conn); ret->id = -1; memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); - conn->refs++; - ret->refs++; - virMutexUnlock(&conn->lock); return ret; - error: - if (ret != NULL) { - VIR_FREE(ret->name); - VIR_FREE(ret); - } +no_memory: + virReportOOMError(); + virObjectUnref(ret); return NULL; } /** - * virReleaseDomain: + * virDomainDispose: * @domain: the domain to release * * Unconditionally release all memory associated with a domain. @@ -225,64 +217,21 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { * which may also be released if its ref count hits zero. */ static void -virReleaseDomain(virDomainPtr domain) { - virConnectPtr conn = domain->conn; +virDomainDispose(void *obj) +{ + virDomainPtr domain = obj; char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(domain->uuid, uuidstr); VIR_DEBUG("release domain %p %s %s", domain, domain->name, uuidstr); - domain->magic = -1; - domain->id = -1; VIR_FREE(domain->name); - VIR_FREE(domain); - - if (conn) { - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - if (conn->refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return; - } - virMutexUnlock(&conn->lock); - } + if (domain->conn) + virObjectUnref(domain->conn); } /** - * virUnrefDomain: - * @domain: the domain to unreference - * - * Unreference the domain. If the use count drops to zero, the structure is - * actually freed. - * - * Returns the reference count or -1 in case of failure. - */ -int -virUnrefDomain(virDomainPtr domain) { - int refs; - - if (!VIR_IS_CONNECTED_DOMAIN(domain)) { - virLibConnError(VIR_ERR_INVALID_DOMAIN, "%s", - _("bad domain or no connection")); - return -1; - } - virMutexLock(&domain->conn->lock); - VIR_DEBUG("unref domain %p %s %d", domain, domain->name, domain->refs); - domain->refs--; - refs = domain->refs; - if (refs == 0) { - virReleaseDomain(domain); - /* Already unlocked mutex */ - return 0; - } - - virMutexUnlock(&domain->conn->lock); - return refs; -} - -/** * virGetNetwork: * @conn: the hypervisor connection * @name: pointer to the network name @@ -291,14 +240,18 @@ virUnrefDomain(virDomainPtr domain) { * Lookup if the network is already registered for that connection, * if yes return a new pointer to it, if no allocate a new structure, * and register it in the table. In any case a corresponding call to - * virUnrefNetwork() is needed to not leak data. + * virObjectUnref() is needed to not leak data. * * Returns a pointer to the network, or NULL in case of failure */ virNetworkPtr -virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { +virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) +{ virNetworkPtr ret = NULL; + if (virDataTypesInitialize() < 0) + return NULL; + if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); return NULL; @@ -306,38 +259,25 @@ virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { virCheckNonNullArgReturn(name, NULL); virCheckNonNullArgReturn(uuid, NULL); - virMutexLock(&conn->lock); + if (!(ret = virObjectNew(virNetworkClass))) + return NULL; - if (VIR_ALLOC(ret) < 0) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->name = strdup(name); - if (ret->name == NULL) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->magic = VIR_NETWORK_MAGIC; - ret->conn = conn; + if (!(ret->name = strdup(name))) + goto no_memory; + + ret->conn = virObjectRef(conn); memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); - conn->refs++; - ret->refs++; - virMutexUnlock(&conn->lock); return ret; - error: - if (ret != NULL) { - VIR_FREE(ret->name); - VIR_FREE(ret); - } +no_memory: + virReportOOMError(); + virObjectUnref(ret); return NULL; } /** - * virReleaseNetwork: + * virNetworkDispose: * @network: the network to release * * Unconditionally release all memory associated with a network. @@ -349,60 +289,17 @@ virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { * which may also be released if its ref count hits zero. */ static void -virReleaseNetwork(virNetworkPtr network) { - virConnectPtr conn = network->conn; +virNetworkDispose(void *obj) +{ + virNetworkPtr network = obj; char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(network->uuid, uuidstr); VIR_DEBUG("release network %p %s %s", network, network->name, uuidstr); - network->magic = -1; VIR_FREE(network->name); - VIR_FREE(network); - - if (conn) { - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - if (conn->refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return; - } - virMutexUnlock(&conn->lock); - } -} - - -/** - * virUnrefNetwork: - * @network: the network to unreference - * - * Unreference the network. If the use count drops to zero, the structure is - * actually freed. - * - * Returns the reference count or -1 in case of failure. - */ -int -virUnrefNetwork(virNetworkPtr network) { - int refs; - - if (!VIR_IS_CONNECTED_NETWORK(network)) { - virLibConnError(VIR_ERR_INVALID_NETWORK, "%s", - _("bad network or no connection")); - return -1; - } - virMutexLock(&network->conn->lock); - VIR_DEBUG("unref network %p %s %d", network, network->name, network->refs); - network->refs--; - refs = network->refs; - if (refs == 0) { - virReleaseNetwork(network); - /* Already unlocked mutex */ - return 0; - } - - virMutexUnlock(&network->conn->lock); - return refs; + if (network->conn) + virObjectUnref(network->conn); } @@ -415,15 +312,19 @@ virUnrefNetwork(virNetworkPtr network) { * Lookup if the interface is already registered for that connection, * if yes return a new pointer to it (possibly updating the MAC * address), if no allocate a new structure, and register it in the - * table. In any case a corresponding call to virUnrefInterface() is + * table. In any case a corresponding call to virObjectUnref() is * needed to not leak data. * * Returns a pointer to the interface, or NULL in case of failure */ virInterfacePtr -virGetInterface(virConnectPtr conn, const char *name, const char *mac) { +virGetInterface(virConnectPtr conn, const char *name, const char *mac) +{ virInterfacePtr ret = NULL; + if (virDataTypesInitialize() < 0) + return NULL; + if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); return NULL; @@ -434,45 +335,26 @@ virGetInterface(virConnectPtr conn, const char *name, const char *mac) { if (mac == NULL) mac = ""; - virMutexLock(&conn->lock); + if (!(ret = virObjectNew(virInterfaceClass))) + return NULL; - if (VIR_ALLOC(ret) < 0) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->name = strdup(name); - if (ret->name == NULL) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->mac = strdup(mac); - if (ret->mac == NULL) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } + if (!(ret->name = strdup(name))) + goto no_memory; + if (!(ret->mac = strdup(mac))) + goto no_memory; - ret->magic = VIR_INTERFACE_MAGIC; - ret->conn = conn; + ret->conn = virObjectRef(conn); - conn->refs++; - ret->refs++; - virMutexUnlock(&conn->lock); return ret; - error: - if (ret != NULL) { - VIR_FREE(ret->name); - VIR_FREE(ret->mac); - VIR_FREE(ret); - } +no_memory: + virReportOOMError(); + virObjectUnref(ret); return NULL; } /** - * virReleaseInterface: + * virInterfaceDispose: * @interface: the interface to release * * Unconditionally release all memory associated with an interface. @@ -484,58 +366,15 @@ virGetInterface(virConnectPtr conn, const char *name, const char *mac) { * which may also be released if its ref count hits zero. */ static void -virReleaseInterface(virInterfacePtr iface) { - virConnectPtr conn = iface->conn; +virInterfaceDispose(void *obj) +{ + virInterfacePtr iface = obj; VIR_DEBUG("release interface %p %s", iface, iface->name); - iface->magic = -1; VIR_FREE(iface->name); VIR_FREE(iface->mac); - VIR_FREE(iface); - - if (conn) { - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - if (conn->refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return; - } - virMutexUnlock(&conn->lock); - } -} - - -/** - * virUnrefInterface: - * @interface: the interface to unreference - * - * Unreference the interface. If the use count drops to zero, the structure is - * actually freed. - * - * Returns the reference count or -1 in case of failure. - */ -int -virUnrefInterface(virInterfacePtr iface) { - int refs; - - if (!VIR_IS_CONNECTED_INTERFACE(iface)) { - virLibConnError(VIR_ERR_INVALID_INTERFACE, "%s", - _("bad interface or no connection")); - return -1; - } - virMutexLock(&iface->conn->lock); - VIR_DEBUG("unref interface %p %s %d", iface, iface->name, iface->refs); - iface->refs--; - refs = iface->refs; - if (refs == 0) { - virReleaseInterface(iface); - /* Already unlocked mutex */ - return 0; - } - - virMutexUnlock(&iface->conn->lock); - return refs; + if (iface->conn) + virObjectUnref(iface->conn); } @@ -548,15 +387,19 @@ virUnrefInterface(virInterfacePtr iface) { * Lookup if the storage pool is already registered for that connection, * if yes return a new pointer to it, if no allocate a new structure, * and register it in the table. In any case a corresponding call to - * virUnrefStoragePool() is needed to not leak data. + * virObjectUnref() is needed to not leak data. * * Returns a pointer to the network, or NULL in case of failure */ virStoragePoolPtr virGetStoragePool(virConnectPtr conn, const char *name, - const unsigned char *uuid) { + const unsigned char *uuid) +{ virStoragePoolPtr ret = NULL; + if (virDataTypesInitialize() < 0) + return NULL; + if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); return NULL; @@ -564,39 +407,26 @@ virGetStoragePool(virConnectPtr conn, const char *name, virCheckNonNullArgReturn(name, NULL); virCheckNonNullArgReturn(uuid, NULL); - virMutexLock(&conn->lock); + if (!(ret = virObjectNew(virStoragePoolClass))) + return NULL; - if (VIR_ALLOC(ret) < 0) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->name = strdup(name); - if (ret->name == NULL) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->magic = VIR_STORAGE_POOL_MAGIC; - ret->conn = conn; + if (!(ret->name = strdup(name))) + goto no_memory; + + ret->conn = virObjectRef(conn); memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); - conn->refs++; - ret->refs++; - virMutexUnlock(&conn->lock); return ret; -error: - if (ret != NULL) { - VIR_FREE(ret->name); - VIR_FREE(ret); - } +no_memory: + virReportOOMError(); + virObjectUnref(ret); return NULL; } /** - * virReleaseStoragePool: + * virStoragePoolDispose: * @pool: the pool to release * * Unconditionally release all memory associated with a pool. @@ -608,60 +438,17 @@ error: * which may also be released if its ref count hits zero. */ static void -virReleaseStoragePool(virStoragePoolPtr pool) { - virConnectPtr conn = pool->conn; +virStoragePoolDispose(void *obj) +{ + virStoragePoolPtr pool = obj; char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(pool->uuid, uuidstr); VIR_DEBUG("release pool %p %s %s", pool, pool->name, uuidstr); - pool->magic = -1; VIR_FREE(pool->name); - VIR_FREE(pool); - - if (conn) { - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - if (conn->refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return; - } - virMutexUnlock(&conn->lock); - } -} - - -/** - * virUnrefStoragePool: - * @pool: the pool to unreference - * - * Unreference the pool. If the use count drops to zero, the structure is - * actually freed. - * - * Returns the reference count or -1 in case of failure. - */ -int -virUnrefStoragePool(virStoragePoolPtr pool) { - int refs; - - if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { - virLibConnError(VIR_ERR_INVALID_STORAGE_POOL, "%s", - _("bad storage pool or no connection")); - return -1; - } - virMutexLock(&pool->conn->lock); - VIR_DEBUG("unref pool %p %s %d", pool, pool->name, pool->refs); - pool->refs--; - refs = pool->refs; - if (refs == 0) { - virReleaseStoragePool(pool); - /* Already unlocked mutex */ - return 0; - } - - virMutexUnlock(&pool->conn->lock); - return refs; + if (pool->conn) + virObjectUnref(pool->conn); } @@ -675,15 +462,19 @@ virUnrefStoragePool(virStoragePoolPtr pool) { * Lookup if the storage vol is already registered for that connection, * if yes return a new pointer to it, if no allocate a new structure, * and register it in the table. In any case a corresponding call to - * virUnrefStorageVol() is needed to not leak data. + * virObjectUnref() is needed to not leak data. * * Returns a pointer to the storage vol, or NULL in case of failure */ virStorageVolPtr virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, - const char *key) { + const char *key) +{ virStorageVolPtr ret = NULL; + if (virDataTypesInitialize() < 0) + return NULL; + if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); return NULL; @@ -691,52 +482,29 @@ virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, virCheckNonNullArgReturn(name, NULL); virCheckNonNullArgReturn(key, NULL); - virMutexLock(&conn->lock); + if (!(ret = virObjectNew(virStorageVolClass))) + return NULL; - if (VIR_ALLOC(ret) < 0) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->pool = strdup(pool); - if (ret->pool == NULL) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->name = strdup(name); - if (ret->name == NULL) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->key = strdup(key); - if (ret->key == NULL) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->magic = VIR_STORAGE_VOL_MAGIC; - ret->conn = conn; + if (!(ret->pool = strdup(pool))) + goto no_memory; + if (!(ret->name = strdup(name))) + goto no_memory; + if (!(ret->key = strdup(key))) + goto no_memory; + + ret->conn = virObjectRef(conn); - conn->refs++; - ret->refs++; - virMutexUnlock(&conn->lock); return ret; -error: - if (ret != NULL) { - VIR_FREE(ret->key); - VIR_FREE(ret->name); - VIR_FREE(ret->pool); - VIR_FREE(ret); - } +no_memory: + virReportOOMError(); + virObjectUnref(ret); return NULL; } /** - * virReleaseStorageVol: + * virStorageVolDispose: * @vol: the vol to release * * Unconditionally release all memory associated with a vol. @@ -748,59 +516,16 @@ error: * which may also be released if its ref count hits zero. */ static void -virReleaseStorageVol(virStorageVolPtr vol) { - virConnectPtr conn = vol->conn; +virStorageVolDispose(void *obj) +{ + virStorageVolPtr vol = obj; VIR_DEBUG("release vol %p %s", vol, vol->name); - vol->magic = -1; VIR_FREE(vol->key); VIR_FREE(vol->name); VIR_FREE(vol->pool); - VIR_FREE(vol); - - if (conn) { - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - if (conn->refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return; - } - virMutexUnlock(&conn->lock); - } -} - - -/** - * virUnrefStorageVol: - * @vol: the vol to unreference - * - * Unreference the vol. If the use count drops to zero, the structure is - * actually freed. - * - * Returns the reference count or -1 in case of failure. - */ -int -virUnrefStorageVol(virStorageVolPtr vol) { - int refs; - - if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) { - virLibConnError(VIR_ERR_INVALID_STORAGE_VOL, "%s", - _("bad storage volume or no connection")); - return -1; - } - virMutexLock(&vol->conn->lock); - VIR_DEBUG("unref vol %p %s %d", vol, vol->name, vol->refs); - vol->refs--; - refs = vol->refs; - if (refs == 0) { - virReleaseStorageVol(vol); - /* Already unlocked mutex */ - return 0; - } - - virMutexUnlock(&vol->conn->lock); - return refs; + if (vol->conn) + virObjectUnref(vol->conn); } @@ -812,7 +537,7 @@ virUnrefStorageVol(virStorageVolPtr vol) { * Lookup if the device is already registered for that connection, * if yes return a new pointer to it, if no allocate a new structure, * and register it in the table. In any case a corresponding call to - * virUnrefNodeDevice() is needed to not leak data. + * virObjectUnref() is needed to not leak data. * * Returns a pointer to the node device, or NULL in case of failure */ @@ -821,44 +546,32 @@ virGetNodeDevice(virConnectPtr conn, const char *name) { virNodeDevicePtr ret = NULL; + if (virDataTypesInitialize() < 0) + return NULL; + if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); return NULL; } virCheckNonNullArgReturn(name, NULL); - virMutexLock(&conn->lock); + if (!(ret = virObjectNew(virNodeDeviceClass))) + return NULL; - if (VIR_ALLOC(ret) < 0) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->magic = VIR_NODE_DEVICE_MAGIC; - ret->conn = conn; - ret->name = strdup(name); - if (ret->name == NULL) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } + if (!(ret->name = strdup(name))) + goto no_memory; - conn->refs++; - ret->refs++; - virMutexUnlock(&conn->lock); + ret->conn = virObjectRef(conn); return ret; - -error: - if (ret != NULL) { - VIR_FREE(ret->name); - VIR_FREE(ret); - } +no_memory: + virReportOOMError(); + virObjectUnref(ret); return NULL; } /** - * virReleaseNodeDevice: + * virNodeDeviceDispose: * @dev: the dev to release * * Unconditionally release all memory associated with a dev. @@ -870,53 +583,16 @@ error: * which may also be released if its ref count hits zero. */ static void -virReleaseNodeDevice(virNodeDevicePtr dev) { - virConnectPtr conn = dev->conn; +virNodeDeviceDispose(void *obj) +{ + virNodeDevicePtr dev = obj; VIR_DEBUG("release dev %p %s", dev, dev->name); - dev->magic = -1; VIR_FREE(dev->name); VIR_FREE(dev->parent); - VIR_FREE(dev); - - if (conn) { - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - if (conn->refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return; - } - virMutexUnlock(&conn->lock); - } -} - -/** - * virUnrefNodeDevice: - * @dev: the dev to unreference - * - * Unreference the dev. If the use count drops to zero, the structure is - * actually freed. - * - * Returns the reference count or -1 in case of failure. - */ -int -virUnrefNodeDevice(virNodeDevicePtr dev) { - int refs; - - virMutexLock(&dev->conn->lock); - VIR_DEBUG("unref dev %p %s %d", dev, dev->name, dev->refs); - dev->refs--; - refs = dev->refs; - if (refs == 0) { - virReleaseNodeDevice(dev); - /* Already unlocked mutex */ - return 0; - } - - virMutexUnlock(&dev->conn->lock); - return refs; + if (dev->conn) + virObjectUnref(dev->conn); } @@ -927,7 +603,7 @@ virUnrefNodeDevice(virNodeDevicePtr dev) { * * Lookup if the secret is already registered for that connection, if so return * a pointer to it, otherwise allocate a new structure, and register it in the - * table. In any case a corresponding call to virUnrefSecret() is needed to not + * table. In any case a corresponding call to virObjectUnref() is needed to not * leak data. * * Returns a pointer to the secret, or NULL in case of failure @@ -938,6 +614,9 @@ virGetSecret(virConnectPtr conn, const unsigned char *uuid, { virSecretPtr ret = NULL; + if (virDataTypesInitialize() < 0) + return NULL; + if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); return NULL; @@ -945,37 +624,25 @@ virGetSecret(virConnectPtr conn, const unsigned char *uuid, virCheckNonNullArgReturn(uuid, NULL); virCheckNonNullArgReturn(usageID, NULL); - virMutexLock(&conn->lock); + if (!(ret = virObjectNew(virSecretClass))) + return NULL; - if (VIR_ALLOC(ret) < 0) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->magic = VIR_SECRET_MAGIC; - ret->conn = conn; memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); ret->usageType = usageType; - if (!(ret->usageID = strdup(usageID))) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - conn->refs++; - ret->refs++; - virMutexUnlock(&conn->lock); - return ret; + if (!(ret->usageID = strdup(usageID))) + goto no_memory; -error: - if (ret != NULL) { - VIR_FREE(ret->usageID); - VIR_FREE(ret); - } + ret->conn = virObjectRef(conn); + + return ret; +no_memory: + virReportOOMError(); + virObjectUnref(ret); return NULL; } /** - * virReleaseSecret: + * virSecretDispose: * @secret: the secret to release * * Unconditionally release all memory associated with a secret. The conn.lock @@ -986,117 +653,44 @@ error: * released if its ref count hits zero. */ static void -virReleaseSecret(virSecretPtr secret) { - virConnectPtr conn = secret->conn; +virSecretDispose(void *obj) +{ + virSecretPtr secret = obj; char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(secret->uuid, uuidstr); VIR_DEBUG("release secret %p %s", secret, uuidstr); VIR_FREE(secret->usageID); - secret->magic = -1; - VIR_FREE(secret); - - if (conn) { - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - if (conn->refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return; - } - virMutexUnlock(&conn->lock); - } + if (secret->conn) + virObjectUnref(secret->conn); } -/** - * virUnrefSecret: - * @secret: the secret to unreference - * - * Unreference the secret. If the use count drops to zero, the structure is - * actually freed. - * - * Returns the reference count or -1 in case of failure. - */ -int -virUnrefSecret(virSecretPtr secret) { - int refs; - if (!VIR_IS_CONNECTED_SECRET(secret)) { - virLibConnError(VIR_ERR_INVALID_SECRET, "%s", - _("bad secret or no connection")); - return -1; - } - virMutexLock(&secret->conn->lock); - VIR_DEBUG("unref secret %p %p %d", secret, secret->uuid, secret->refs); - secret->refs--; - refs = secret->refs; - if (refs == 0) { - virReleaseSecret(secret); - /* Already unlocked mutex */ - return 0; - } +virStreamPtr +virGetStream(virConnectPtr conn) +{ + virStreamPtr ret = NULL; - virMutexUnlock(&secret->conn->lock); - return refs; -} + if (virDataTypesInitialize() < 0) + return NULL; -virStreamPtr virGetStream(virConnectPtr conn) { - virStreamPtr ret = NULL; + if (!(ret = virObjectNew(virStreamClass))) + return NULL; - virMutexLock(&conn->lock); + ret->conn = virObjectRef(conn); - if (VIR_ALLOC(ret) < 0) { - virReportOOMError(); - goto error; - } - ret->magic = VIR_STREAM_MAGIC; - ret->conn = conn; - conn->refs++; - ret->refs++; - virMutexUnlock(&conn->lock); return ret; - -error: - virMutexUnlock(&conn->lock); - VIR_FREE(ret); - return NULL; } static void -virReleaseStream(virStreamPtr st) { - virConnectPtr conn = st->conn; +virStreamDispose(void *obj) +{ + virStreamPtr st = obj; VIR_DEBUG("release dev %p", st); - st->magic = -1; - VIR_FREE(st); - - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - if (conn->refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return; - } - - virMutexUnlock(&conn->lock); -} - -int virUnrefStream(virStreamPtr st) { - int refs; - - virMutexLock(&st->conn->lock); - VIR_DEBUG("unref stream %p %d", st, st->refs); - st->refs--; - refs = st->refs; - if (refs == 0) { - virReleaseStream(st); - /* Already unlocked mutex */ - return 0; - } - - virMutexUnlock(&st->conn->lock); - return refs; + if (st->conn) + virObjectUnref(st->conn); } @@ -1109,14 +703,19 @@ int virUnrefStream(virStreamPtr st) { * Lookup if the network filter is already registered for that connection, * if yes return a new pointer to it, if no allocate a new structure, * and register it in the table. In any case a corresponding call to - * virUnrefNWFilter() is needed to not leak data. + * virObjectUnref() is needed to not leak data. * * Returns a pointer to the network, or NULL in case of failure */ virNWFilterPtr -virGetNWFilter(virConnectPtr conn, const char *name, const unsigned char *uuid) { +virGetNWFilter(virConnectPtr conn, const char *name, + const unsigned char *uuid) +{ virNWFilterPtr ret = NULL; + if (virDataTypesInitialize() < 0) + return NULL; + if (!VIR_IS_CONNECT(conn)) { virLibConnError(VIR_ERR_INVALID_CONN, "%s", _("no connection")); return NULL; @@ -1124,39 +723,26 @@ virGetNWFilter(virConnectPtr conn, const char *name, const unsigned char *uuid) virCheckNonNullArgReturn(name, NULL); virCheckNonNullArgReturn(uuid, NULL); - virMutexLock(&conn->lock); + if (!(ret = virObjectNew(virNWFilterClass))) + return NULL; + + if (!(ret->name = strdup(name))) + goto no_memory; - if (VIR_ALLOC(ret) < 0) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->name = strdup(name); - if (ret->name == NULL) { - virMutexUnlock(&conn->lock); - virReportOOMError(); - goto error; - } - ret->magic = VIR_NWFILTER_MAGIC; - ret->conn = conn; memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); - conn->refs++; - ret->refs++; - virMutexUnlock(&conn->lock); - return ret; + ret->conn = virObjectRef(conn); -error: - if (ret != NULL) { - VIR_FREE(ret->name); - VIR_FREE(ret); - } + return ret; +no_memory: + virReportOOMError(); + virObjectUnref(ret); return NULL; } /** - * virReleaseNWFilter: + * virNWFilterDispose: * @nwfilter: the nwfilter to release * * Unconditionally release all memory associated with a nwfilter. @@ -1168,63 +754,17 @@ error: * which may also be released if its ref count hits zero. */ static void -virReleaseNWFilter(virNWFilterPtr nwfilter) +virNWFilterDispose(void *obj) { - virConnectPtr conn = nwfilter->conn; + virNWFilterPtr nwfilter = obj; char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(nwfilter->uuid, uuidstr); VIR_DEBUG("release nwfilter %p %s %s", nwfilter, nwfilter->name, uuidstr); - nwfilter->magic = -1; VIR_FREE(nwfilter->name); - VIR_FREE(nwfilter); - - if (conn) { - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - if (conn->refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return; - } - virMutexUnlock(&conn->lock); - } -} - - -/** - * virUnrefNWFilter: - * @nwfilter: the nwfilter to unreference - * - * Unreference the networkf itler. If the use count drops to zero, the - * structure is actually freed. - * - * Returns the reference count or -1 in case of failure. - */ -int -virUnrefNWFilter(virNWFilterPtr nwfilter) -{ - int refs; - - if (!VIR_IS_CONNECTED_NWFILTER(nwfilter)) { - virLibConnError(VIR_ERR_INVALID_NWFILTER, "%s", - _("bad nwfilter or no connection")); - return -1; - } - virMutexLock(&nwfilter->conn->lock); - VIR_DEBUG("unref nwfilter %p %s %d", nwfilter, nwfilter->name, - nwfilter->refs); - nwfilter->refs--; - refs = nwfilter->refs; - if (refs == 0) { - virReleaseNWFilter(nwfilter); - /* Already unlocked mutex */ - return 0; - } - - virMutexUnlock(&nwfilter->conn->lock); - return refs; + if (nwfilter->conn) + virObjectUnref(nwfilter->conn); } @@ -1233,85 +773,36 @@ virGetDomainSnapshot(virDomainPtr domain, const char *name) { virDomainSnapshotPtr ret = NULL; + if (virDataTypesInitialize() < 0) + return NULL; + if (!VIR_IS_DOMAIN(domain)) { virLibConnError(VIR_ERR_INVALID_DOMAIN, "%s", _("bad domain")); return NULL; } virCheckNonNullArgReturn(name, NULL); - virMutexLock(&domain->conn->lock); - - if (VIR_ALLOC(ret) < 0) { - virMutexUnlock(&domain->conn->lock); - virReportOOMError(); - goto error; - } - ret->name = strdup(name); - if (ret->name == NULL) { - virMutexUnlock(&domain->conn->lock); - virReportOOMError(); - goto error; - } - ret->magic = VIR_SNAPSHOT_MAGIC; - ret->domain = domain; + if (!(ret = virObjectNew(virDomainSnapshotClass))) + return NULL; + if (!(ret->name = strdup(name))) + goto no_memory; + ret->domain = virObjectRef(domain); - domain->refs++; - ret->refs++; - virMutexUnlock(&domain->conn->lock); return ret; - - error: - if (ret != NULL) { - VIR_FREE(ret->name); - VIR_FREE(ret); - } +no_memory: + virReportOOMError(); + virObjectUnref(ret); return NULL; } static void -virReleaseDomainSnapshot(virDomainSnapshotPtr snapshot) +virDomainSnapshotDispose(void *obj) { - virDomainPtr domain = snapshot->domain; + virDomainSnapshotPtr snapshot = obj; VIR_DEBUG("release snapshot %p %s", snapshot, snapshot->name); - snapshot->magic = -1; VIR_FREE(snapshot->name); - VIR_FREE(snapshot); - - if (domain) { - VIR_DEBUG("unref domain %p %d", domain, domain->refs); - domain->refs--; - if (domain->refs == 0) { - virReleaseDomain(domain); - /* Already unlocked mutex */ - return; - } - virMutexUnlock(&domain->conn->lock); - } -} - -int -virUnrefDomainSnapshot(virDomainSnapshotPtr snapshot) -{ - int refs; - - if (!VIR_IS_DOMAIN_SNAPSHOT(snapshot)) { - virLibConnError(VIR_ERR_INVALID_DOMAIN_SNAPSHOT, "%s", - _("not a snapshot")); - return -1; - } - - virMutexLock(&snapshot->domain->conn->lock); - VIR_DEBUG("unref snapshot %p %s %d", snapshot, snapshot->name, snapshot->refs); - snapshot->refs--; - refs = snapshot->refs; - if (refs == 0) { - virReleaseDomainSnapshot(snapshot); - /* Already unlocked mutex */ - return 0; - } - - virMutexUnlock(&snapshot->domain->conn->lock); - return refs; + if (snapshot->domain) + virObjectUnref(snapshot->domain); } diff --git a/src/datatypes.h b/src/datatypes.h index a303cdc..c7aa747 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -26,118 +26,72 @@ # include "driver.h" # include "threads.h" - -/** - * VIR_CONNECT_MAGIC: - * - * magic value used to protect the API when pointers to connection structures - * are passed down by the users. - */ -# define VIR_CONNECT_MAGIC 0x4F23DEAD -# define VIR_IS_CONNECT(obj) ((obj) && (obj)->magic==VIR_CONNECT_MAGIC) - - -/** - * VIR_DOMAIN_MAGIC: - * - * magic value used to protect the API when pointers to domain structures - * are passed down by the users. - */ -# define VIR_DOMAIN_MAGIC 0xDEAD4321 -# define VIR_IS_DOMAIN(obj) ((obj) && (obj)->magic==VIR_DOMAIN_MAGIC) -# define VIR_IS_CONNECTED_DOMAIN(obj) (VIR_IS_DOMAIN(obj) && VIR_IS_CONNECT((obj)->conn)) - -/** - * VIR_NETWORK_MAGIC: - * - * magic value used to protect the API when pointers to network structures - * are passed down by the users. - */ -# define VIR_NETWORK_MAGIC 0xDEAD1234 -# define VIR_IS_NETWORK(obj) ((obj) && (obj)->magic==VIR_NETWORK_MAGIC) -# define VIR_IS_CONNECTED_NETWORK(obj) (VIR_IS_NETWORK(obj) && VIR_IS_CONNECT((obj)->conn)) - -/** - * VIR_INTERFACE_MAGIC: - * - * magic value used to protect the API when pointers to interface structures - * are passed down by the users. - */ -# define VIR_INTERFACE_MAGIC 0xDEAD5309 -# define VIR_IS_INTERFACE(obj) ((obj) && (obj)->magic==VIR_INTERFACE_MAGIC) -# define VIR_IS_CONNECTED_INTERFACE(obj) (VIR_IS_INTERFACE(obj) && VIR_IS_CONNECT((obj)->conn)) - -/** - * VIR_STORAGE_POOL_MAGIC: - * - * magic value used to protect the API when pointers to storage pool structures - * are passed down by the users. - */ -# define VIR_STORAGE_POOL_MAGIC 0xDEAD5678 -# define VIR_IS_STORAGE_POOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_POOL_MAGIC) -# define VIR_IS_CONNECTED_STORAGE_POOL(obj) (VIR_IS_STORAGE_POOL(obj) && VIR_IS_CONNECT((obj)->conn)) - -/** - * VIR_STORAGE_VOL_MAGIC: - * - * magic value used to protect the API when pointers to storage vol structures - * are passed down by the users. - */ -# define VIR_STORAGE_VOL_MAGIC 0xDEAD8765 -# define VIR_IS_STORAGE_VOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_VOL_MAGIC) -# define VIR_IS_CONNECTED_STORAGE_VOL(obj) (VIR_IS_STORAGE_VOL(obj) && VIR_IS_CONNECT((obj)->conn)) - -/** - * VIR_NODE_DEVICE_MAGIC: - * - * magic value used to protect the API when pointers to storage vol structures - * are passed down by the users. - */ -# define VIR_NODE_DEVICE_MAGIC 0xDEAD5679 -# define VIR_IS_NODE_DEVICE(obj) ((obj) && (obj)->magic==VIR_NODE_DEVICE_MAGIC) -# define VIR_IS_CONNECTED_NODE_DEVICE(obj) (VIR_IS_NODE_DEVICE(obj) && VIR_IS_CONNECT((obj)->conn)) - -/** - * VIR_SECRET_MAGIC: - * - * magic value used to protect the API when pointers to secret structures are - * passed down by the users. - */ -# define VIR_SECRET_MAGIC 0x5678DEAD -# define VIR_IS_SECRET(obj) ((obj) && (obj)->magic==VIR_SECRET_MAGIC) -# define VIR_IS_CONNECTED_SECRET(obj) (VIR_IS_SECRET(obj) && VIR_IS_CONNECT((obj)->conn)) - - -/** - * VIR_STREAM_MAGIC: - * - * magic value used to protect the API when pointers to stream structures - * are passed down by the users. - */ -# define VIR_STREAM_MAGIC 0x1DEAD666 -# define VIR_IS_STREAM(obj) ((obj) && (obj)->magic==VIR_STREAM_MAGIC) -# define VIR_IS_CONNECTED_STREAM(obj) (VIR_IS_STREAM(obj) && VIR_IS_CONNECT((obj)->conn)) - - -/** - * VIR_NWFILTER_MAGIC: - * - * magic value used to protect the API when pointers to network filter - * pool structures are passed down by the users. - */ -# define VIR_NWFILTER_MAGIC 0xDEAD7777 -# define VIR_IS_NWFILTER(obj) ((obj) && (obj)->magic==VIR_NWFILTER_MAGIC) -# define VIR_IS_CONNECTED_NWFILTER(obj) (VIR_IS_NWFILTER(obj) && VIR_IS_CONNECT((obj)->conn)) - -/** - * VIR_SNAPSHOT_MAGIC: - * - * magic value used to protect the API when pointers to snapshot structures - * are passed down by the users. - */ -# define VIR_SNAPSHOT_MAGIC 0x6666DEAD -# define VIR_IS_SNAPSHOT(obj) ((obj) && (obj)->magic==VIR_SNAPSHOT_MAGIC) -# define VIR_IS_DOMAIN_SNAPSHOT(obj) (VIR_IS_SNAPSHOT(obj) && VIR_IS_DOMAIN((obj)->domain)) +# include "virobject.h" + +extern virClassPtr virConnectClass; +extern virClassPtr virDomainClass; +extern virClassPtr virDomainSnapshotClass; +extern virClassPtr virInterfaceClass; +extern virClassPtr virNetworkClass; +extern virClassPtr virNodeDeviceClass; +extern virClassPtr virNWFilterClass; +extern virClassPtr virSecretClass; +extern virClassPtr virStreamClass; +extern virClassPtr virStorageVolClass; +extern virClassPtr virStoragePoolClass; + +# define VIR_IS_CONNECT(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virConnectClass)) + +# define VIR_IS_DOMAIN(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virDomainClass)) +# define VIR_IS_CONNECTED_DOMAIN(obj) \ + (VIR_IS_DOMAIN(obj) && VIR_IS_CONNECT((obj)->conn)) + +# define VIR_IS_NETWORK(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virNetworkClass)) +# define VIR_IS_CONNECTED_NETWORK(obj) \ + (VIR_IS_NETWORK(obj) && VIR_IS_CONNECT((obj)->conn)) + +# define VIR_IS_INTERFACE(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virInterfaceClass)) +# define VIR_IS_CONNECTED_INTERFACE(obj) \ + (VIR_IS_INTERFACE(obj) && VIR_IS_CONNECT((obj)->conn)) + +# define VIR_IS_STORAGE_POOL(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virStoragePoolClass)) +# define VIR_IS_CONNECTED_STORAGE_POOL(obj) \ + (VIR_IS_STORAGE_POOL(obj) && VIR_IS_CONNECT((obj)->conn)) + +# define VIR_IS_STORAGE_VOL(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virStorageVolClass)) +# define VIR_IS_CONNECTED_STORAGE_VOL(obj) \ + (VIR_IS_STORAGE_VOL(obj) && VIR_IS_CONNECT((obj)->conn)) + +# define VIR_IS_NODE_DEVICE(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virNodeDeviceClass)) +# define VIR_IS_CONNECTED_NODE_DEVICE(obj) \ + (VIR_IS_NODE_DEVICE(obj) && VIR_IS_CONNECT((obj)->conn)) + +# define VIR_IS_SECRET(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virSecretClass)) +# define VIR_IS_CONNECTED_SECRET(obj) \ + (VIR_IS_SECRET(obj) && VIR_IS_CONNECT((obj)->conn)) + +# define VIR_IS_STREAM(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virStreamClass)) +# define VIR_IS_CONNECTED_STREAM(obj) \ + (VIR_IS_STREAM(obj) && VIR_IS_CONNECT((obj)->conn)) + +# define VIR_IS_NWFILTER(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virNWFilterClass)) +# define VIR_IS_CONNECTED_NWFILTER(obj) \ + (VIR_IS_NWFILTER(obj) && VIR_IS_CONNECT((obj)->conn)) + +# define VIR_IS_SNAPSHOT(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virDomainSnapshotClass)) +# define VIR_IS_DOMAIN_SNAPSHOT(obj) \ + (VIR_IS_SNAPSHOT(obj) && VIR_IS_DOMAIN((obj)->domain)) /** * _virConnect: @@ -145,11 +99,11 @@ * Internal structure associated to a connection */ struct _virConnect { + virObject object; /* All the variables from here, until the 'lock' declaration * are setup at time of connection open, and never changed * since. Thus no need to lock when accessing them */ - unsigned int magic; /* specific value to check */ unsigned int flags; /* a set of connection flags */ virURIPtr uri; /* connection URI */ @@ -193,8 +147,6 @@ struct _virConnect { virFreeCallback closeFreeCallback; bool closeDispatch; unsigned closeUnregisterCount; - - int refs; /* reference count */ }; /** @@ -203,8 +155,7 @@ struct _virConnect { * Internal structure associated to a domain */ struct _virDomain { - unsigned int magic; /* specific value to check */ - int refs; /* reference count */ + virObject object; virConnectPtr conn; /* pointer back to the connection */ char *name; /* the domain external name */ int id; /* the domain ID */ @@ -217,8 +168,7 @@ struct _virDomain { * Internal structure associated to a domain */ struct _virNetwork { - unsigned int magic; /* specific value to check */ - int refs; /* reference count */ + virObject object; virConnectPtr conn; /* pointer back to the connection */ char *name; /* the network external name */ unsigned char uuid[VIR_UUID_BUFLEN]; /* the network unique identifier */ @@ -230,8 +180,7 @@ struct _virNetwork { * Internal structure associated to a physical host interface */ struct _virInterface { - unsigned int magic; /* specific value to check */ - int refs; /* reference count */ + virObject object; virConnectPtr conn; /* pointer back to the connection */ char *name; /* the network external name */ char *mac; /* the interface MAC address */ @@ -243,8 +192,7 @@ struct _virInterface { * Internal structure associated to a storage pool */ struct _virStoragePool { - unsigned int magic; /* specific value to check */ - int refs; /* reference count */ + virObject object; virConnectPtr conn; /* pointer back to the connection */ char *name; /* the storage pool external name */ unsigned char uuid[VIR_UUID_BUFLEN]; /* the storage pool unique identifier */ @@ -256,8 +204,7 @@ struct _virStoragePool { * Internal structure associated to a storage volume */ struct _virStorageVol { - unsigned int magic; /* specific value to check */ - int refs; /* reference count */ + virObject object; virConnectPtr conn; /* pointer back to the connection */ char *pool; /* Pool name of owner */ char *name; /* the storage vol external name */ @@ -270,8 +217,7 @@ struct _virStorageVol { * Internal structure associated with a node device */ struct _virNodeDevice { - unsigned int magic; /* specific value to check */ - int refs; /* reference count */ + virObject object; virConnectPtr conn; /* pointer back to the connection */ char *name; /* device name (unique on node) */ char *parent; /* parent device name */ @@ -283,8 +229,7 @@ struct _virNodeDevice { * Internal structure associated with a secret */ struct _virSecret { - unsigned int magic; /* specific value to check */ - int refs; /* reference count */ + virObject object; virConnectPtr conn; /* pointer back to the connection */ unsigned char uuid[VIR_UUID_BUFLEN]; /* the domain unique identifier */ int usageType; /* the type of usage */ @@ -301,9 +246,8 @@ typedef int (*virStreamFinishFunc)(virStreamPtr, void *opaque); * Internal structure associated with an input stream */ struct _virStream { - unsigned int magic; + virObject object; virConnectPtr conn; - int refs; unsigned int flags; virStreamDriverPtr driver; @@ -316,77 +260,59 @@ struct _virStream { * Internal structure associated with a domain snapshot */ struct _virDomainSnapshot { - unsigned int magic; - int refs; + virObject object; char *name; virDomainPtr domain; }; -/************************************************************************ - * * - * API for domain/connections (de)allocations and lookups * - * * - ************************************************************************/ +/** +* _virNWFilter: +* +* Internal structure associated to a network filter +*/ +struct _virNWFilter { + virObject object; + virConnectPtr conn; /* pointer back to the connection */ + char *name; /* the network filter external name */ + unsigned char uuid[VIR_UUID_BUFLEN]; /* the network filter unique identifier */ +}; + + +/* + * Helper APIs for allocating new object instances + */ virConnectPtr virGetConnect(void); -int virUnrefConnect(virConnectPtr conn); virDomainPtr virGetDomain(virConnectPtr conn, + const char *name, + const unsigned char *uuid); +virNetworkPtr virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid); -int virUnrefDomain(virDomainPtr domain); -virNetworkPtr virGetNetwork(virConnectPtr conn, - const char *name, - const unsigned char *uuid); -int virUnrefNetwork(virNetworkPtr network); - virInterfacePtr virGetInterface(virConnectPtr conn, const char *name, const char *mac); -int virUnrefInterface(virInterfacePtr iface); - virStoragePoolPtr virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uuid); -int virUnrefStoragePool(virStoragePoolPtr pool); virStorageVolPtr virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, const char *key); -int virUnrefStorageVol(virStorageVolPtr vol); virNodeDevicePtr virGetNodeDevice(virConnectPtr conn, const char *name); -int virUnrefNodeDevice(virNodeDevicePtr dev); - virSecretPtr virGetSecret(virConnectPtr conn, const unsigned char *uuid, int usageType, const char *usageID); -int virUnrefSecret(virSecretPtr secret); - virStreamPtr virGetStream(virConnectPtr conn); -int virUnrefStream(virStreamPtr st); - -/** -* _virNWFilter: -* -* Internal structure associated to a network filter -*/ -struct _virNWFilter { - unsigned int magic; /* specific value to check */ - int refs; /* reference count */ - virConnectPtr conn; /* pointer back to the connection */ - char *name; /* the network filter external name */ - unsigned char uuid[VIR_UUID_BUFLEN]; /* the network filter unique identifier */ -}; virNWFilterPtr virGetNWFilter(virConnectPtr conn, const char *name, const unsigned char *uuid); -int virUnrefNWFilter(virNWFilterPtr nwfilter); virDomainSnapshotPtr virGetDomainSnapshot(virDomainPtr domain, const char *name); -int virUnrefDomainSnapshot(virDomainSnapshotPtr snapshot); #endif diff --git a/src/libvirt.c b/src/libvirt.c index 4368b99..45cb2ad 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -1285,7 +1285,7 @@ do_open (const char *name, failed: virConfFree(conf); - virUnrefConnect(ret); + virObjectUnref(ret); return NULL; } @@ -1420,14 +1420,16 @@ error: * matching virConnectClose, and all other references will be released * after the corresponding operation completes. * - * Returns the number of remaining references on success - * (positive implies that some other call still has a reference open, - * 0 implies that no references remain and the connection is closed), - * or -1 on failure. It is possible for the last virConnectClose to - * return a positive value if some other object still has a temporary - * reference to the connection, but the application should not try to - * further use a connection after the virConnectClose that matches the - * initial open. + * Returns the a positive number if at least 1 reference remains on + * success. The returned value should not be assumed to be the total + * reference count. A return of 0 implies no references remain and + * the connection is closed & memory has been freed. A return of -1 + * implies a failure. + * + * It is possible for the last virConnectClose to return a positive + * value if some other object still has a temporary reference to the + * connection, but the application should not try to further use a + * connection after the virConnectClose that matches the initial open. */ int virConnectClose(virConnectPtr conn) @@ -1442,10 +1444,9 @@ virConnectClose(virConnectPtr conn) goto error; } - ret = virUnrefConnect(conn); - if (ret < 0) - goto error; - return ret; + if (!virObjectUnref(conn)) + return 0; + return 1; error: virDispatchError(NULL); @@ -1477,10 +1478,8 @@ virConnectRef(virConnectPtr conn) virDispatchError(NULL); return -1; } - virMutexLock(&conn->lock); - VIR_DEBUG("conn=%p refs=%d", conn, conn->refs); - conn->refs++; - virMutexUnlock(&conn->lock); + VIR_DEBUG("conn=%p refs=%d", conn, conn->object.refs); + virObjectRef(conn); return 0; } @@ -2277,10 +2276,7 @@ virDomainFree(virDomainPtr domain) virDispatchError(NULL); return -1; } - if (virUnrefDomain(domain) < 0) { - virDispatchError(NULL); - return -1; - } + virObjectUnref(domain); return 0; } @@ -2309,10 +2305,9 @@ virDomainRef(virDomainPtr domain) virDispatchError(NULL); return -1; } - virMutexLock(&domain->conn->lock); - VIR_DOMAIN_DEBUG(domain, "refs=%d", domain->refs); - domain->refs++; - virMutexUnlock(&domain->conn->lock); + + VIR_DOMAIN_DEBUG(domain, "refs=%d", domain->object.refs); + virObjectRef(domain); return 0; } @@ -10109,10 +10104,7 @@ virNetworkFree(virNetworkPtr network) virDispatchError(NULL); return -1; } - if (virUnrefNetwork(network) < 0) { - virDispatchError(NULL); - return -1; - } + virObjectUnref(network); return 0; } @@ -10141,10 +10133,8 @@ virNetworkRef(virNetworkPtr network) virDispatchError(NULL); return -1; } - virMutexLock(&network->conn->lock); - VIR_DEBUG("network=%p refs=%d", network, network->refs); - network->refs++; - virMutexUnlock(&network->conn->lock); + VIR_DEBUG("network=%p refs=%d", network, network->object.refs); + virObjectRef(network); return 0; } @@ -11014,10 +11004,8 @@ virInterfaceRef(virInterfacePtr iface) virDispatchError(NULL); return -1; } - virMutexLock(&iface->conn->lock); - VIR_DEBUG("iface=%p refs=%d", iface, iface->refs); - iface->refs++; - virMutexUnlock(&iface->conn->lock); + VIR_DEBUG("iface=%p refs=%d", iface, iface->object.refs); + virObjectRef(iface); return 0; } @@ -11042,10 +11030,7 @@ virInterfaceFree(virInterfacePtr iface) virDispatchError(NULL); return -1; } - if (virUnrefInterface(iface) < 0) { - virDispatchError(NULL); - return -1; - } + virObjectUnref(iface); return 0; } @@ -11951,10 +11936,7 @@ virStoragePoolFree(virStoragePoolPtr pool) virDispatchError(NULL); return -1; } - if (virUnrefStoragePool(pool) < 0) { - virDispatchError(NULL); - return -1; - } + virObjectUnref(pool); return 0; } @@ -11985,10 +11967,8 @@ virStoragePoolRef(virStoragePoolPtr pool) virDispatchError(NULL); return -1; } - virMutexLock(&pool->conn->lock); - VIR_DEBUG("pool=%p refs=%d", pool, pool->refs); - pool->refs++; - virMutexUnlock(&pool->conn->lock); + VIR_DEBUG("pool=%p refs=%d", pool, pool->object.refs); + virObjectRef(pool); return 0; } @@ -13017,10 +12997,7 @@ virStorageVolFree(virStorageVolPtr vol) virDispatchError(NULL); return -1; } - if (virUnrefStorageVol(vol) < 0) { - virDispatchError(NULL); - return -1; - } + virObjectUnref(vol); return 0; } @@ -13050,10 +13027,8 @@ virStorageVolRef(virStorageVolPtr vol) virDispatchError(NULL); return -1; } - virMutexLock(&vol->conn->lock); - VIR_DEBUG("vol=%p refs=%d", vol, vol->refs); - vol->refs++; - virMutexUnlock(&vol->conn->lock); + VIR_DEBUG("vol=%p refs=%d", vol, vol->object.refs); + virObjectRef(vol); return 0; } @@ -13592,10 +13567,7 @@ int virNodeDeviceFree(virNodeDevicePtr dev) virDispatchError(NULL); return -1; } - if (virUnrefNodeDevice(dev) < 0) { - virDispatchError(NULL); - return -1; - } + virObjectUnref(dev); return 0; } @@ -13625,10 +13597,8 @@ virNodeDeviceRef(virNodeDevicePtr dev) virDispatchError(NULL); return -1; } - virMutexLock(&dev->conn->lock); - VIR_DEBUG("dev=%p refs=%d", dev, dev->refs); - dev->refs++; - virMutexUnlock(&dev->conn->lock); + VIR_DEBUG("dev=%p refs=%d", dev, dev->object.refs); + virObjectRef(dev); return 0; } @@ -14598,10 +14568,8 @@ virSecretRef(virSecretPtr secret) virDispatchError(NULL); return -1; } - virMutexLock(&secret->conn->lock); - VIR_DEBUG("secret=%p refs=%d", secret, secret->refs); - secret->refs++; - virMutexUnlock(&secret->conn->lock); + VIR_DEBUG("secret=%p refs=%d", secret, secret->object.refs); + virObjectRef(secret); return 0; } @@ -14625,10 +14593,7 @@ virSecretFree(virSecretPtr secret) virDispatchError(NULL); return -1; } - if (virUnrefSecret(secret) < 0) { - virDispatchError(NULL); - return -1; - } + virObjectUnref(secret); return 0; } @@ -14697,10 +14662,8 @@ virStreamRef(virStreamPtr stream) virDispatchError(NULL); return -1; } - virMutexLock(&stream->conn->lock); - VIR_DEBUG("stream=%p refs=%d", stream, stream->refs); - stream->refs++; - virMutexUnlock(&stream->conn->lock); + VIR_DEBUG("stream=%p refs=%d", stream, stream->object.refs); + virObjectRef(stream); return 0; } @@ -15341,10 +15304,7 @@ int virStreamFree(virStreamPtr stream) /* XXX Enforce shutdown before free'ing resources ? */ - if (virUnrefStream(stream) < 0) { - virDispatchError(NULL); - return -1; - } + virObjectUnref(stream); return 0; } @@ -15805,10 +15765,8 @@ virNWFilterFree(virNWFilterPtr nwfilter) virDispatchError(NULL); return -1; } - if (virUnrefNWFilter(nwfilter) < 0) { - virDispatchError(NULL); - return -1; - } + + virObjectUnref(nwfilter); return 0; } @@ -16064,10 +16022,8 @@ virNWFilterRef(virNWFilterPtr nwfilter) virDispatchError(NULL); return -1; } - virMutexLock(&nwfilter->conn->lock); - VIR_DEBUG("nwfilter=%p refs=%d", nwfilter, nwfilter->refs); - nwfilter->refs++; - virMutexUnlock(&nwfilter->conn->lock); + VIR_DEBUG("nwfilter=%p refs=%d", nwfilter, nwfilter->object.refs); + virObjectRef(nwfilter); return 0; } @@ -17951,10 +17907,8 @@ virDomainSnapshotRef(virDomainSnapshotPtr snapshot) virDispatchError(NULL); return -1; } - virMutexLock(&snapshot->domain->conn->lock); - VIR_DEBUG("snapshot=%p, refs=%d", snapshot, snapshot->refs); - snapshot->refs++; - virMutexUnlock(&snapshot->domain->conn->lock); + VIR_DEBUG("snapshot=%p, refs=%d", snapshot, snapshot->object.refs); + virObjectRef(snapshot); return 0; } @@ -17980,10 +17934,7 @@ virDomainSnapshotFree(virDomainSnapshotPtr snapshot) virDispatchError(NULL); return -1; } - if (virUnrefDomainSnapshot(snapshot) < 0) { - virDispatchError(NULL); - return -1; - } + virObjectUnref(snapshot); return 0; } diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1d91b70..2031701 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -194,6 +194,9 @@ virCPUModeTypeToString; # datatypes.h +virConnectClass; +virDomainClass; +virDomainSnapshotClass; virGetConnect; virGetDomain; virGetDomainSnapshot; @@ -205,12 +208,14 @@ virGetSecret; virGetStoragePool; virGetStorageVol; virGetStream; -virUnrefConnect; -virUnrefDomain; -virUnrefNWFilter; -virUnrefSecret; -virUnrefStorageVol; -virUnrefStream; +virInterfaceClass; +virNetworkClass; +virNodeDeviceClass; +virNWFilterClass; +virSecretClass; +virStorageVolClass; +virStoragePoolClass; +virStreamClass; # dnsmasq.h diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 0ebdfff..a4111c8 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -2085,7 +2085,7 @@ phypStorageVolCreateXML(virStoragePoolPtr pool, /* checking if this name already exists on this system */ if ((dup_vol = phypVolumeLookupByName(pool, voldef->name)) != NULL) { VIR_ERROR(_("StoragePool name already exists.")); - virUnrefStorageVol(dup_vol); + virObjectUnref(dup_vol); goto err; } @@ -2122,7 +2122,7 @@ err: virStorageVolDefFree(voldef); virStoragePoolDefFree(spdef); if (vol) - virUnrefStorageVol(vol); + virObjectUnref(vol); return NULL; } @@ -2322,7 +2322,7 @@ phypVolumeGetXMLDesc(virStorageVolPtr vol, unsigned int flags) cleanup: if (sp) - virUnrefStoragePool(sp); + virObjectUnref(sp); return xml; } @@ -2718,14 +2718,14 @@ phypStoragePoolCreateXML(virConnectPtr conn, /* checking if this name already exists on this system */ if ((dup_sp = phypStoragePoolLookupByName(conn, def->name)) != NULL) { VIR_WARN("StoragePool name already exists."); - virUnrefStoragePool(dup_sp); + virObjectUnref(dup_sp); goto err; } /* checking if ID or UUID already exists on this system */ if ((dup_sp = phypGetStoragePoolLookUpByUUID(conn, def->uuid)) != NULL) { VIR_WARN("StoragePool uuid already exists."); - virUnrefStoragePool(dup_sp); + virObjectUnref(dup_sp); goto err; } @@ -2740,7 +2740,7 @@ phypStoragePoolCreateXML(virConnectPtr conn, err: virStoragePoolDefFree(def); if (sp) - virUnrefStoragePool(sp); + virObjectUnref(sp); return NULL; } @@ -3686,7 +3686,7 @@ phypDomainCreateAndStart(virConnectPtr conn, err: virDomainDefFree(def); if (dom) - virUnrefDomain(dom); + virObjectUnref(dom); return NULL; } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 4033644..4bae674 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1896,7 +1896,7 @@ qemuBuildRBDString(virConnectPtr conn, cleanup: VIR_FREE(secret); if (sec) - virUnrefSecret(sec); + virObjectUnref(sec); return ret; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 7663e5e..362ef9b 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2285,14 +2285,14 @@ finish: cleanup: if (ddomain) { - virUnrefDomain(ddomain); + virObjectUnref(ddomain); ret = 0; } else { ret = -1; } if (st) - virUnrefStream(st); + virObjectUnref(st); if (orig_err) { virSetError(orig_err); @@ -2479,14 +2479,14 @@ finish: cleanup: if (ddomain) { - virUnrefDomain(ddomain); + virObjectUnref(ddomain); ret = 0; } else { ret = -1; } if (st) - virUnrefStream(st); + virObjectUnref(st); if (orig_err) { virSetError(orig_err); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 685ea7c..0d4f5ae 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -447,7 +447,7 @@ qemuProcessGetVolumeQcowPassphrase(virConnectPtr conn, goto cleanup; data = conn->secretDriver->getValue(secret, &size, 0, VIR_SECRET_GET_VALUE_INTERNAL_CALL); - virUnrefSecret(secret); + virObjectUnref(secret); if (data == NULL) goto cleanup; diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 6d7dd2b..825ed1d 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1399,7 +1399,7 @@ storageVolumeCreateXML(virStoragePoolPtr obj, cleanup: if (volobj) - virUnrefStorageVol(volobj); + virObjectUnref(volobj); virStorageVolDefFree(voldef); if (pool) virStoragePoolObjUnlock(pool); @@ -1561,7 +1561,7 @@ storageVolumeCreateXMLFrom(virStoragePoolPtr obj, cleanup: if (volobj) - virUnrefStorageVol(volobj); + virObjectUnref(volobj); virStorageVolDefFree(newvol); if (pool) virStoragePoolObjUnlock(pool); diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index b672b24..8185c3a 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -1204,7 +1204,7 @@ static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml, if (vboxDomainCreate(dom) < 0) { vboxDomainUndefineFlags(dom, 0); - virUnrefDomain(dom); + virObjectUnref(dom); return NULL; } diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 9c27933..9b728c5 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -1237,7 +1237,7 @@ error: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to parse Xend domain information")); if (ret != NULL) - virUnrefDomain(ret); + virObjectUnref(ret); return NULL; } @@ -2600,7 +2600,7 @@ xenDaemonCreateXML(virConnectPtr conn, const char *xmlDesc, /* Make sure we don't leave a still-born domain around */ if (dom != NULL) { xenDaemonDomainDestroyFlags(dom, 0); - virUnrefDomain(dom); + virObjectUnref(dom); } virDomainDefFree(def); return NULL; diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index c4aa7c4..2c2b599 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -40,23 +40,12 @@ fakeSecretLookupByUsage(virConnectPtr conn, int usageType ATTRIBUTE_UNUSED, const char *usageID) { - virSecretPtr ret = NULL; - int err; + unsigned char uuid[VIR_UUID_BUFLEN]; if (STRNEQ(usageID, "mycluster_myname")) return NULL; - err = VIR_ALLOC(ret); - if (err < 0) - return NULL; - ret->magic = VIR_SECRET_MAGIC; - ret->refs = 1; - ret->usageID = strdup(usageID); - if (!ret->usageID) { - VIR_FREE(ret); - return NULL; - } - ret->conn = conn; - conn->refs++; - return ret; + + virUUIDGenerate(uuid); + return virGetSecret(conn, uuid, usageType, usageID); } static int @@ -239,7 +228,7 @@ out: VIR_FREE(actualargv); virCommandFree(cmd); virDomainDefFree(vmdef); - virUnrefConnect(conn); + virObjectUnref(conn); return ret; } diff --git a/tests/qemuxmlnstest.c b/tests/qemuxmlnstest.c index 0bc821d..253c89e 100644 --- a/tests/qemuxmlnstest.c +++ b/tests/qemuxmlnstest.c @@ -157,7 +157,7 @@ static int testCompareXMLToArgvFiles(const char *xml, VIR_FREE(actualargv); virCommandFree(cmd); virDomainDefFree(vmdef); - virUnrefConnect(conn); + virObjectUnref(conn); return ret; } diff --git a/tests/sexpr2xmltest.c b/tests/sexpr2xmltest.c index 37e3749..93049dd 100644 --- a/tests/sexpr2xmltest.c +++ b/tests/sexpr2xmltest.c @@ -72,7 +72,7 @@ testCompareFiles(const char *xml, const char *sexpr, int xendConfigVersion) VIR_FREE(gotxml); virDomainDefFree(def); if (conn) - virUnrefConnect(conn); + virObjectUnref(conn); return ret; } diff --git a/tests/xmconfigtest.c b/tests/xmconfigtest.c index 3a0937e..826bed8 100644 --- a/tests/xmconfigtest.c +++ b/tests/xmconfigtest.c @@ -93,7 +93,7 @@ testCompareParseXML(const char *xmcfg, const char *xml, int xendConfigVersion) if (conf) virConfFree(conf); virDomainDefFree(def); - virUnrefConnect(conn); + virObjectUnref(conn); return ret; } @@ -147,7 +147,7 @@ testCompareFormatXML(const char *xmcfg, const char *xml, int xendConfigVersion) VIR_FREE(xmcfgData); VIR_FREE(gotxml); virDomainDefFree(def); - virUnrefConnect(conn); + virObjectUnref(conn); return ret; } -- 1.7.10.4

On 07/31/2012 10:58 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
This converts the following public API datatypes to use the virObject infrastructure:
virConnectPtr virDomainPtr virDomainSnapshotPtr virInterfacePtr virNetworkPtr virNodeDevicePtr virNWFilterPtr virSecretPtr virStreamPtr virStorageVolPtr virStoragePoolPtr
Given recent changes, this now fails to apply cleanly. Would you mind refreshing the series, to make it easier to review?
16 files changed, 448 insertions(+), 1086 deletions(-)
Love the diffstat! I still spotted some nits, even going solely by code inspection:
@@ -225,64 +217,21 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { * which may also be released if its ref count hits zero. */ static void -virReleaseDomain(virDomainPtr domain) { - virConnectPtr conn = domain->conn; +virDomainDispose(void *obj) +{
- - if (conn) { - VIR_DEBUG("unref connection %p %d", conn, conn->refs); - conn->refs--; - if (conn->refs == 0) { - virReleaseConnect(conn); - /* Already unlocked mutex */ - return; - } - virMutexUnlock(&conn->lock); - } + if (domain->conn) + virObjectUnref(domain->conn);
Technically, we have a bug if we ever have domain->conn==NULL when we get here. Besides, you coded virObjectUnref(NULL) to be a graceful no-op, so that means you should add virObjectUnref to cfg.mk's list of free-like functions and drop the conditional. Oh, that reminds me - we DO have a bug in our RPC code where we fail to check for NULL after strdup and such in the various make_nonnull_* functions, and therefore I suppose that is an instance where we really _could_ end up with domain->conn being NULL at the moment - I've been meaning to spend some time on fixing that.
@@ -349,60 +289,17 @@ virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { * which may also be released if its ref count hits zero. */ static void -virReleaseNetwork(virNetworkPtr network) { - virConnectPtr conn = network->conn; +virNetworkDispose(void *obj) +{ + virNetworkPtr network = obj; char uuidstr[VIR_UUID_STRING_BUFLEN];
+ if (network->conn) + virObjectUnref(network->conn);
Another place where you can drop the conditional.
@@ -484,58 +366,15 @@ virGetInterface(virConnectPtr conn, const char *name, const char *mac) { * which may also be released if its ref count hits zero. */ static void -virReleaseInterface(virInterfacePtr iface) { - virConnectPtr conn = iface->conn; +virInterfaceDispose(void *obj) +{ + virInterfacePtr iface = obj; + if (iface->conn) + virObjectUnref(iface->conn);
and again
@@ -608,60 +438,17 @@ error: * which may also be released if its ref count hits zero. */ static void -virReleaseStoragePool(virStoragePoolPtr pool) { - virConnectPtr conn = pool->conn; +virStoragePoolDispose(void *obj) +{ + virStoragePoolPtr pool = obj; char uuidstr[VIR_UUID_STRING_BUFLEN];
+ if (pool->conn) + virObjectUnref(pool->conn);
I'm turning into a broken record...
@@ -748,59 +516,16 @@ error: * which may also be released if its ref count hits zero. */ static void -virReleaseStorageVol(virStorageVolPtr vol) { - virConnectPtr conn = vol->conn; +virStorageVolDispose(void *obj) +{ + virStorageVolPtr vol = obj;
+ if (vol->conn) + virObjectUnref(vol->conn);
Need I say it? :) I'll quit mentioning it (again, a cfg.mk rule will make it easier to find all instances).
+++ b/src/datatypes.h
+# define VIR_IS_CONNECT(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virConnectClass))
Why the extra cast here? The compiler can convert obj to 'void*' without your help.
+ +# define VIR_IS_DOMAIN(obj) \ + (virObjectIsClass((virObjectPtr)(obj), virDomainClass))
Likewise throughout these macros.
+++ b/src/libvirt.c
@@ -1420,14 +1420,16 @@ error: * matching virConnectClose, and all other references will be released * after the corresponding operation completes. * - * Returns the number of remaining references on success - * (positive implies that some other call still has a reference open, - * 0 implies that no references remain and the connection is closed), - * or -1 on failure. It is possible for the last virConnectClose to - * return a positive value if some other object still has a temporary - * reference to the connection, but the application should not try to - * further use a connection after the virConnectClose that matches the - * initial open. + * Returns the a positive number if at least 1 reference remains on
s/the a/a/
--- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms +virSecretClass; +virStorageVolClass; +virStoragePoolClass;
Sorting.
+++ b/src/xen/xend_internal.c @@ -1237,7 +1237,7 @@ error: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to parse Xend domain information")); if (ret != NULL) - virUnrefDomain(ret); + virObjectUnref(ret);
Another useless if before free.
+++ b/tests/sexpr2xmltest.c @@ -72,7 +72,7 @@ testCompareFiles(const char *xml, const char *sexpr, int xendConfigVersion) VIR_FREE(gotxml); virDomainDefFree(def); if (conn) - virUnrefConnect(conn); + virObjectUnref(conn);
Oops, I promised not to point them out :) -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

From: "Daniel P. Berrange" <berrange@redhat.com> Switch virDomainObjPtr to use the virObject APIs for reference counting. The main change is that virObjectUnref does not return the reference count, merely a bool indicating whether the object still has any refs left. Checking the return value is also not mandatory. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/conf/domain_conf.c | 59 ++++++++++++++++++++------------------------- src/conf/domain_conf.h | 8 +++--- src/libvirt_private.syms | 3 +-- src/libxl/libxl_driver.c | 6 ++--- src/lxc/lxc_process.c | 6 ++--- src/openvz/openvz_conf.c | 19 +++------------ src/qemu/qemu_domain.c | 27 +++++++++------------ src/qemu/qemu_domain.h | 8 +++--- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_migration.c | 22 ++++++++--------- src/qemu/qemu_migration.h | 4 +-- src/qemu/qemu_process.c | 50 ++++++++++++++++++-------------------- src/vmware/vmware_conf.c | 4 +-- 13 files changed, 93 insertions(+), 125 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 143d92e..72d41f5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -658,6 +658,21 @@ VIR_ENUM_IMPL(virDomainNumatuneMemPlacementMode, #define VIR_DOMAIN_XML_WRITE_FLAGS VIR_DOMAIN_XML_SECURE #define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE +static virClassPtr virDomainObjClass; +static void virDomainObjDispose(void *obj); + +static int virDomainObjOnceInit(void) +{ + if (!(virDomainObjClass = virClassNew("virDomainObj", + sizeof(virDomainObj), + virDomainObjDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virDomainObj) + void virBlkioDeviceWeightArrayClear(virBlkioDeviceWeightPtr deviceWeights, int ndevices) @@ -723,7 +738,7 @@ virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED) { virDomainObjPtr obj = payload; virDomainObjLock(obj); - if (virDomainObjUnref(obj) > 0) + if (!virObjectUnref(obj)) virDomainObjUnlock(obj); } @@ -1637,10 +1652,10 @@ void virDomainDefFree(virDomainDefPtr def) } static void virDomainSnapshotObjListDeinit(virDomainSnapshotObjListPtr snapshots); -static void virDomainObjFree(virDomainObjPtr dom) + +static void virDomainObjDispose(void *obj) { - if (!dom) - return; + virDomainObjPtr dom = obj; VIR_DEBUG("obj=%p", dom); virDomainDefFree(dom->def); @@ -1652,37 +1667,18 @@ static void virDomainObjFree(virDomainObjPtr dom) virMutexDestroy(&dom->lock); virDomainSnapshotObjListDeinit(&dom->snapshots); - - VIR_FREE(dom); -} - -void virDomainObjRef(virDomainObjPtr dom) -{ - dom->refs++; - VIR_DEBUG("obj=%p refs=%d", dom, dom->refs); } -int virDomainObjUnref(virDomainObjPtr dom) -{ - dom->refs--; - VIR_DEBUG("obj=%p refs=%d", dom, dom->refs); - if (dom->refs == 0) { - virDomainObjUnlock(dom); - virDomainObjFree(dom); - return 0; - } - return dom->refs; -} - -static virDomainObjPtr virDomainObjNew(virCapsPtr caps) +virDomainObjPtr virDomainObjNew(virCapsPtr caps) { virDomainObjPtr domain; - if (VIR_ALLOC(domain) < 0) { - virReportOOMError(); + if (virDomainObjInitialize() < 0) + return NULL; + + if (!(domain = virObjectNew(virDomainObjClass))) return NULL; - } if (caps->privateDataAllocFunc && !(domain->privateData = (caps->privateDataAllocFunc)())) { @@ -1704,7 +1700,6 @@ static virDomainObjPtr virDomainObjNew(virCapsPtr caps) virDomainObjLock(domain); virDomainObjSetState(domain, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_UNKNOWN); - domain->refs = 1; virDomainSnapshotObjListInit(&domain->snapshots); @@ -9326,8 +9321,7 @@ static virDomainObjPtr virDomainObjParseXML(virCapsPtr caps, return obj; error: - /* obj was never shared, so unref should return 0 */ - ignore_value(virDomainObjUnref(obj)); + virObjectUnref(obj); VIR_FREE(nodes); return NULL; } @@ -13384,9 +13378,8 @@ static virDomainObjPtr virDomainLoadStatus(virCapsPtr caps, return obj; error: - /* obj was never shared, so unref should return 0 */ if (obj) - ignore_value(virDomainObjUnref(obj)); + virObjectUnref(obj); VIR_FREE(statusFile); return NULL; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bc02caf..1d831b5 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -43,6 +43,7 @@ # include "virnetdevvportprofile.h" # include "virnetdevopenvswitch.h" # include "virnetdevbandwidth.h" +# include "virobject.h" /* forward declarations of all device types, required by * virDomainDeviceDef @@ -1807,8 +1808,9 @@ struct _virDomainStateReason { typedef struct _virDomainObj virDomainObj; typedef virDomainObj *virDomainObjPtr; struct _virDomainObj { + virObject object; + virMutex lock; - int refs; pid_t pid; virDomainStateReason state; @@ -1845,6 +1847,7 @@ virDomainObjIsActive(virDomainObjPtr dom) return dom->def->id != -1; } +virDomainObjPtr virDomainObjNew(virCapsPtr caps); int virDomainObjListInit(virDomainObjListPtr objs); void virDomainObjListDeinit(virDomainObjListPtr objs); @@ -1907,9 +1910,6 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def, void *opaque); void virDomainDefFree(virDomainDefPtr vm); -void virDomainObjRef(virDomainObjPtr vm); -/* Returns 1 if the object was freed, 0 if more refs exist */ -int virDomainObjUnref(virDomainObjPtr vm) ATTRIBUTE_RETURN_CHECK; virDomainChrDefPtr virDomainChrDefNew(void); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 2031701..d1a4c65 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -425,12 +425,11 @@ virDomainObjListGetInactiveNames; virDomainObjListInit; virDomainObjListNumOfDomains; virDomainObjLock; -virDomainObjRef; +virDomainObjNew; virDomainObjSetDefTransient; virDomainObjSetState; virDomainObjTaint; virDomainObjUnlock; -virDomainObjUnref; virDomainPausedReasonTypeFromString; virDomainPausedReasonTypeToString; virDomainPciRombarModeTypeFromString; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 873f973..150900f 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -134,7 +134,7 @@ libxlDomainObjUnref(void *data) { virDomainObjPtr vm = data; - ignore_value(virDomainObjUnref(vm)); + virObjectUnref(vm); } static void @@ -484,13 +484,13 @@ libxlCreateDomEvents(virDomainObjPtr vm) /* Add a reference to the domain object while it is injected in * the event loop. */ - virDomainObjRef(vm); + virObjectRef(vm); if ((priv->eventHdl = virEventAddHandle( fd, VIR_EVENT_HANDLE_READABLE | VIR_EVENT_HANDLE_ERROR, libxlEventHandler, vm, libxlDomainObjUnref)) < 0) { - ignore_value(virDomainObjUnref(vm)); + virObjectUnref(vm); goto error; } diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 65b463f..046ed86 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -565,7 +565,7 @@ static void virLXCProcessMonitorDestroy(virLXCMonitorPtr mon, priv = vm->privateData; if (priv->monitor == mon) priv->monitor = NULL; - if (virDomainObjUnref(vm) > 0) + if (virObjectUnref(vm)) virDomainObjUnlock(vm); } @@ -666,12 +666,12 @@ static virLXCMonitorPtr virLXCProcessConnectMonitor(virLXCDriverPtr driver, /* Hold an extra reference because we can't allow 'vm' to be * deleted while the monitor is active */ - virDomainObjRef(vm); + virObjectRef(vm); monitor = virLXCMonitorNew(vm, driver->stateDir, &monitorCallbacks); if (monitor == NULL) - ignore_value(virDomainObjUnref(vm)); + virObjectUnref(vm); if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0) { if (monitor) { diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index 5dc071c..e62bf8c 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -598,17 +598,8 @@ int openvzLoadDomains(struct openvz_driver *driver) { } *line++ = '\0'; - if (VIR_ALLOC(dom) < 0) - goto no_memory; - - if (virMutexInit(&dom->lock) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot initialize mutex")); - VIR_FREE(dom); - goto cleanup; - } - - virDomainObjLock(dom); + if (!(dom = virDomainObjNew(driver->caps))) + goto cleanup; if (VIR_ALLOC(dom->def) < 0) goto no_memory; @@ -623,7 +614,6 @@ int openvzLoadDomains(struct openvz_driver *driver) { VIR_DOMAIN_RUNNING_UNKNOWN); } - dom->refs = 1; dom->pid = veid; if (virDomainObjGetState(dom, NULL) == VIR_DOMAIN_SHUTOFF) dom->def->id = -1; @@ -683,7 +673,6 @@ int openvzLoadDomains(struct openvz_driver *driver) { goto cleanup; } - virDomainObjUnlock(dom); dom = NULL; } @@ -700,9 +689,7 @@ int openvzLoadDomains(struct openvz_driver *driver) { virCommandFree(cmd); VIR_FREE(temp); VIR_FREE(outbuf); - /* dom hasn't been shared yet, so unref should return 0 */ - if (dom) - ignore_value(virDomainObjUnref(dom)); + virObjectUnref(dom); return -1; } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 86f0265..4acbb20 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -774,7 +774,7 @@ qemuDomainObjBeginJobInternal(struct qemud_driver *driver, return -1; then = now + QEMU_JOB_WAIT_TIME; - virDomainObjRef(obj); + virObjectRef(obj); if (driver_locked) qemuDriverUnlock(driver); @@ -854,8 +854,7 @@ error: qemuDriverLock(driver); virDomainObjLock(obj); } - /* Safe to ignore value since ref count was incremented above */ - ignore_value(virDomainObjUnref(obj)); + virObjectUnref(obj); return -1; } @@ -922,10 +921,10 @@ int qemuDomainObjBeginAsyncJobWithDriver(struct qemud_driver *driver, * To be called after completing the work associated with the * earlier qemuDomainBeginJob() call * - * Returns remaining refcount on 'obj', maybe 0 to indicated it - * was deleted + * Returns true if @obj was still referenced, false if it was + * disposed of. */ -int qemuDomainObjEndJob(struct qemud_driver *driver, virDomainObjPtr obj) +bool qemuDomainObjEndJob(struct qemud_driver *driver, virDomainObjPtr obj) { qemuDomainObjPrivatePtr priv = obj->privateData; enum qemuDomainJob job = priv->job.active; @@ -941,10 +940,10 @@ int qemuDomainObjEndJob(struct qemud_driver *driver, virDomainObjPtr obj) qemuDomainObjSaveJob(driver, obj); virCondSignal(&priv->job.cond); - return virDomainObjUnref(obj); + return virObjectUnref(obj); } -int +bool qemuDomainObjEndAsyncJob(struct qemud_driver *driver, virDomainObjPtr obj) { qemuDomainObjPrivatePtr priv = obj->privateData; @@ -958,7 +957,7 @@ qemuDomainObjEndAsyncJob(struct qemud_driver *driver, virDomainObjPtr obj) qemuDomainObjSaveJob(driver, obj); virCondBroadcast(&priv->job.asyncCond); - return virDomainObjUnref(obj); + return virObjectUnref(obj); } static int @@ -1031,9 +1030,7 @@ qemuDomainObjExitMonitorInternal(struct qemud_driver *driver, qemuDomainObjSaveJob(driver, obj); virCondSignal(&priv->job.cond); - /* safe to ignore since the surrounding async job increased - * the reference counter as well */ - ignore_value(virDomainObjUnref(obj)); + virObjectUnref(obj); } } @@ -1207,7 +1204,7 @@ void qemuDomainObjExitAgentWithDriver(struct qemud_driver *driver, void qemuDomainObjEnterRemoteWithDriver(struct qemud_driver *driver, virDomainObjPtr obj) { - virDomainObjRef(obj); + virObjectRef(obj); virDomainObjUnlock(obj); qemuDriverUnlock(driver); } @@ -1217,9 +1214,7 @@ void qemuDomainObjExitRemoteWithDriver(struct qemud_driver *driver, { qemuDriverLock(driver); virDomainObjLock(obj); - /* Safe to ignore value, since we incremented ref in - * qemuDomainObjEnterRemoteWithDriver */ - ignore_value(virDomainObjUnref(obj)); + virObjectUnref(obj); } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 9f9467d..d5ea33d 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -193,11 +193,11 @@ int qemuDomainObjBeginAsyncJobWithDriver(struct qemud_driver *driver, enum qemuDomainAsyncJob asyncJob) ATTRIBUTE_RETURN_CHECK; -int qemuDomainObjEndJob(struct qemud_driver *driver, - virDomainObjPtr obj) +bool qemuDomainObjEndJob(struct qemud_driver *driver, + virDomainObjPtr obj) ATTRIBUTE_RETURN_CHECK; -int qemuDomainObjEndAsyncJob(struct qemud_driver *driver, - virDomainObjPtr obj) +bool qemuDomainObjEndAsyncJob(struct qemud_driver *driver, + virDomainObjPtr obj) ATTRIBUTE_RETURN_CHECK; void qemuDomainObjSetJobPhase(struct qemud_driver *driver, virDomainObjPtr obj, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0da5c5a..0ef74e0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3402,7 +3402,7 @@ endjob: ignore_value(qemuDomainObjEndAsyncJob(driver, wdEvent->vm)); unlock: - if (virDomainObjUnref(wdEvent->vm) > 0) + if (virObjectUnref(wdEvent->vm)) virDomainObjUnlock(wdEvent->vm); qemuDriverUnlock(driver); VIR_FREE(wdEvent); diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 362ef9b..b7a417f 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1369,7 +1369,7 @@ qemuMigrationPrepareAny(struct qemud_driver *driver, * This prevents any other APIs being invoked while incoming * migration is taking place. */ - if (qemuMigrationJobContinue(vm) == 0) { + if (!qemuMigrationJobContinue(vm)) { vm = NULL; virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("domain disappeared")); @@ -1396,7 +1396,7 @@ cleanup: return ret; endjob: - if (qemuMigrationJobFinish(driver, vm) == 0) { + if (!qemuMigrationJobFinish(driver, vm)) { vm = NULL; } goto cleanup; @@ -2682,7 +2682,7 @@ endjob: VIR_DOMAIN_EVENT_RESUMED_MIGRATED); } - if (qemuMigrationJobFinish(driver, vm) == 0) { + if (!qemuMigrationJobFinish(driver, vm)) { vm = NULL; } else if (!virDomainObjIsActive(vm) && (!vm->persistent || @@ -2724,7 +2724,7 @@ qemuMigrationPerformPhase(struct qemud_driver *driver, virDomainEventPtr event = NULL; int ret = -1; bool resume; - int refs; + bool hasrefs; /* If we didn't start the job in the begin phase, start it now. */ if (!(flags & VIR_MIGRATE_CHANGE_PROTECTION)) { @@ -2772,10 +2772,10 @@ qemuMigrationPerformPhase(struct qemud_driver *driver, endjob: if (ret < 0) - refs = qemuMigrationJobFinish(driver, vm); + hasrefs = qemuMigrationJobFinish(driver, vm); else - refs = qemuMigrationJobContinue(vm); - if (refs == 0) { + hasrefs = qemuMigrationJobContinue(vm); + if (!hasrefs) { vm = NULL; } else if (!virDomainObjIsActive(vm) && !vm->persistent) { qemuDomainRemoveInactive(driver, vm); @@ -3376,15 +3376,15 @@ qemuMigrationJobStartPhase(struct qemud_driver *driver, virDomainObjPtr vm, enum qemuMigrationJobPhase phase) { - virDomainObjRef(vm); + virObjectRef(vm); qemuMigrationJobSetPhase(driver, vm, phase); } -int +bool qemuMigrationJobContinue(virDomainObjPtr vm) { qemuDomainObjReleaseAsyncJob(vm); - return virDomainObjUnref(vm); + return virObjectUnref(vm); } bool @@ -3407,7 +3407,7 @@ qemuMigrationJobIsActive(virDomainObjPtr vm, return true; } -int +bool qemuMigrationJobFinish(struct qemud_driver *driver, virDomainObjPtr vm) { return qemuDomainObjEndAsyncJob(driver, vm); diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index e6ca215..1740204 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -66,12 +66,12 @@ void qemuMigrationJobStartPhase(struct qemud_driver *driver, virDomainObjPtr vm, enum qemuMigrationJobPhase phase) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -int qemuMigrationJobContinue(virDomainObjPtr obj) +bool qemuMigrationJobContinue(virDomainObjPtr obj) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; bool qemuMigrationJobIsActive(virDomainObjPtr vm, enum qemuDomainAsyncJob job) ATTRIBUTE_NONNULL(1); -int qemuMigrationJobFinish(struct qemud_driver *driver, virDomainObjPtr obj) +bool qemuMigrationJobFinish(struct qemud_driver *driver, virDomainObjPtr obj) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; int qemuMigrationSetOffline(struct qemud_driver *driver, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 0d4f5ae..3a08c5b 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -173,7 +173,7 @@ static void qemuProcessHandleAgentDestroy(qemuAgentPtr agent, priv = vm->privateData; if (priv->agent == agent) priv->agent = NULL; - if (virDomainObjUnref(vm) > 0) + if (virObjectUnref(vm)) virDomainObjUnlock(vm); } @@ -225,7 +225,7 @@ qemuConnectAgent(struct qemud_driver *driver, virDomainObjPtr vm) /* Hold an extra reference because we can't allow 'vm' to be * deleted while the agent is active */ - virDomainObjRef(vm); + virObjectRef(vm); ignore_value(virTimeMillisNow(&priv->agentStart)); virDomainObjUnlock(vm); @@ -246,9 +246,8 @@ qemuConnectAgent(struct qemud_driver *driver, virDomainObjPtr vm) goto cleanup; } - /* Safe to ignore value since ref count was incremented above */ if (agent == NULL) - ignore_value(virDomainObjUnref(vm)); + virObjectUnref(vm); if (!virDomainObjIsActive(vm)) { qemuAgentClose(agent); @@ -584,7 +583,7 @@ qemuProcessFakeReboot(void *opaque) ret = 0; endjob: - if (qemuDomainObjEndJob(driver, vm) == 0) + if (!qemuDomainObjEndJob(driver, vm)) vm = NULL; cleanup: @@ -593,7 +592,7 @@ cleanup: ignore_value(qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE)); } - if (virDomainObjUnref(vm) > 0) + if (virObjectUnref(vm)) virDomainObjUnlock(vm); } if (event) @@ -610,7 +609,7 @@ qemuProcessShutdownOrReboot(struct qemud_driver *driver, if (priv->fakeReboot) { qemuDomainSetFakeReboot(driver, vm, false); - virDomainObjRef(vm); + virObjectRef(vm); virThread th; if (virThreadCreate(&th, false, @@ -619,8 +618,7 @@ qemuProcessShutdownOrReboot(struct qemud_driver *driver, VIR_ERROR(_("Failed to create reboot thread, killing domain")); ignore_value(qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_NOWAIT)); - /* Safe to ignore value since ref count was incremented above */ - ignore_value(virDomainObjUnref(vm)); + virObjectUnref(vm); } } else { ignore_value(qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_NOWAIT)); @@ -801,9 +799,9 @@ qemuProcessHandleWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED, /* Hold an extra reference because we can't allow 'vm' to be * deleted before handling watchdog event is finished. */ - virDomainObjRef(vm); + virObjectRef(vm); if (virThreadPoolSendJob(driver->workerPool, 0, wdEvent) < 0) { - if (virDomainObjUnref(vm) == 0) + if (!virObjectUnref(vm)) vm = NULL; VIR_FREE(wdEvent); } @@ -1022,7 +1020,7 @@ static void qemuProcessHandleMonitorDestroy(qemuMonitorPtr mon, priv = vm->privateData; if (priv->mon == mon) priv->mon = NULL; - if (virDomainObjUnref(vm) > 0) + if (virObjectUnref(vm)) virDomainObjUnlock(vm); } @@ -1213,7 +1211,7 @@ qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm) /* Hold an extra reference because we can't allow 'vm' to be * deleted while the monitor is active */ - virDomainObjRef(vm); + virObjectRef(vm); ignore_value(virTimeMillisNow(&priv->monStart)); virDomainObjUnlock(vm); @@ -1228,9 +1226,8 @@ qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm) virDomainObjLock(vm); priv->monStart = 0; - /* Safe to ignore value since ref count was incremented above */ if (mon == NULL) - ignore_value(virDomainObjUnref(vm)); + virObjectUnref(vm); if (!virDomainObjIsActive(vm)) { qemuMonitorClose(mon); @@ -3068,7 +3065,7 @@ qemuProcessReconnect(void *opaque) /* Hold an extra reference because we can't allow 'vm' to be * deleted if qemuConnectMonitor() failed */ - virDomainObjRef(obj); + virObjectRef(obj); /* XXX check PID liveliness & EXE path */ if (qemuConnectMonitor(driver, obj) < 0) @@ -3165,10 +3162,10 @@ qemuProcessReconnect(void *opaque) driver->nextvmid = obj->def->id + 1; endjob: - if (qemuDomainObjEndJob(driver, obj) == 0) + if (!qemuDomainObjEndJob(driver, obj)) obj = NULL; - if (obj && virDomainObjUnref(obj) > 0) + if (obj && virObjectUnref(obj)) virDomainObjUnlock(obj); qemuDriverUnlock(driver); @@ -3178,18 +3175,18 @@ endjob: return; error: - if (qemuDomainObjEndJob(driver, obj) == 0) + if (!qemuDomainObjEndJob(driver, obj)) obj = NULL; if (obj) { if (!virDomainObjIsActive(obj)) { - if (virDomainObjUnref(obj) > 0) + if (virObjectUnref(obj)) virDomainObjUnlock(obj); qemuDriverUnlock(driver); return; } - if (virDomainObjUnref(obj) > 0) { + if (virObjectUnref(obj)) { /* We can't get the monitor back, so must kill the VM * to remove danger of it ending up running twice if * user tries to start it again later @@ -3277,9 +3274,9 @@ qemuProcessReconnectHelper(void *payload, virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create thread. QEMU initialization " "might be incomplete")); - if (qemuDomainObjEndJob(src->driver, obj) == 0) { + if (!qemuDomainObjEndJob(src->driver, obj)) { obj = NULL; - } else if (virDomainObjUnref(obj) > 0) { + } else if (virObjectUnref(obj)) { /* We can't spawn a thread and thus connect to monitor. * Kill qemu */ qemuProcessStop(src->driver, obj, VIR_DOMAIN_SHUTOFF_FAILED, 0); @@ -3950,12 +3947,11 @@ cleanup: * a case, but there are too many to maintain certainty, so we * will do this as a precaution). */ - virDomainObjRef(vm); + virObjectRef(vm); virDomainObjUnlock(vm); qemuDriverLock(driver); virDomainObjLock(vm); - /* Safe to ignore value since ref count was incremented above */ - ignore_value(virDomainObjUnref(vm)); + virObjectUnref(vm); } return ret; } @@ -4407,7 +4403,7 @@ qemuProcessAutoDestroy(struct qemud_driver *driver, VIR_DOMAIN_EVENT_STOPPED, VIR_DOMAIN_EVENT_STOPPED_DESTROYED); - if (qemuDomainObjEndJob(driver, dom) == 0) + if (!qemuDomainObjEndJob(driver, dom)) dom = NULL; if (dom && !dom->persistent) qemuDomainRemoveInactive(driver, dom); diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c index 9fb95c4..b52c002 100644 --- a/src/vmware/vmware_conf.c +++ b/src/vmware/vmware_conf.c @@ -213,9 +213,7 @@ cleanup: VIR_FREE(directoryName); VIR_FREE(fileName); VIR_FREE(vmx); - /* any non-NULL vm here has not been shared, so unref will return 0 */ - if (vm) - ignore_value(virDomainObjUnref(vm)); + virObjectUnref(vm); return ret; } -- 1.7.10.4

void virBlkioDeviceWeightArrayClear(virBlkioDeviceWeightPtr deviceWeights, int ndevices) @@ -723,7 +738,7 @@ virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED) { virDomainObjPtr obj = payload; virDomainObjLock(obj); - if (virDomainObjUnref(obj) > 0) + if (!virObjectUnref(obj)) virDomainObjUnlock(obj); }
I suppose you mean if (virObjectUnref(obj)) here. But, I can't see any reason to lock then unref then unlock, just unref is enough. BTW, if containers, like virHashTable, support only virObject, then the free callback, say virHashDataFree, can be to simply unref the virObject. -- Thanks, Hu Tao

On Wed, Aug 01, 2012 at 04:39:24PM +0800, Hu Tao wrote:
void virBlkioDeviceWeightArrayClear(virBlkioDeviceWeightPtr deviceWeights, int ndevices) @@ -723,7 +738,7 @@ virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED) { virDomainObjPtr obj = payload; virDomainObjLock(obj); - if (virDomainObjUnref(obj) > 0) + if (!virObjectUnref(obj)) virDomainObjUnlock(obj); }
I suppose you mean
if (virObjectUnref(obj))
here.
But, I can't see any reason to lock then unref then unlock, just unref is enough.
I didn't want to change multiple things at the same time. Simplification of locking in various places can follow later. 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 :|

On Thu, Aug 02, 2012 at 11:13:20AM +0100, Daniel P. Berrange wrote:
On Wed, Aug 01, 2012 at 04:39:24PM +0800, Hu Tao wrote:
void virBlkioDeviceWeightArrayClear(virBlkioDeviceWeightPtr deviceWeights, int ndevices) @@ -723,7 +738,7 @@ virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED) { virDomainObjPtr obj = payload; virDomainObjLock(obj); - if (virDomainObjUnref(obj) > 0) + if (!virObjectUnref(obj)) virDomainObjUnlock(obj); }
I suppose you mean
if (virObjectUnref(obj))
here.
Oh, yes I do.
But, I can't see any reason to lock then unref then unlock, just unref is enough.
I didn't want to change multiple things at the same time. Simplification of locking in various places can follow later.
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 :|

From: "Daniel P. Berrange" <berrange@redhat.com> Make qemuAgentPtr and qemuMonitorPtr types use the virObject APIs for reference counting Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/qemu/qemu_agent.c | 86 ++++++++++++++++++----------------------- src/qemu/qemu_agent.h | 3 -- src/qemu/qemu_domain.c | 22 +++++------ src/qemu/qemu_monitor.c | 97 ++++++++++++++++++++--------------------------- src/qemu/qemu_monitor.h | 3 -- 5 files changed, 89 insertions(+), 122 deletions(-) diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 14bf11b..4bc8c0f 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -40,6 +40,7 @@ #include "json.h" #include "virfile.h" #include "virtime.h" +#include "virobject.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -80,11 +81,11 @@ struct _qemuAgentMessage { struct _qemuAgent { + virObject object; + virMutex lock; /* also used to protect fd */ virCond notify; - int refs; - int fd; int watch; @@ -114,6 +115,22 @@ struct _qemuAgent { qemuAgentEvent await_event; }; +static virClassPtr qemuAgentClass; +static void qemuAgentDispose(void *obj); + +static int qemuAgentOnceInit(void) +{ + if (!(qemuAgentClass = virClassNew("qemuAgent", + sizeof(qemuAgent), + qemuAgentDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(qemuAgent) + + #if DEBUG_RAW_IO # include <c-ctype.h> static char * @@ -146,45 +163,15 @@ void qemuAgentUnlock(qemuAgentPtr mon) } -static void qemuAgentFree(qemuAgentPtr mon) +static void qemuAgentDispose(void *obj) { + qemuAgentPtr mon = obj; VIR_DEBUG("mon=%p", mon); if (mon->cb && mon->cb->destroy) (mon->cb->destroy)(mon, mon->vm); ignore_value(virCondDestroy(&mon->notify)); virMutexDestroy(&mon->lock); VIR_FREE(mon->buffer); - VIR_FREE(mon); -} - -int qemuAgentRef(qemuAgentPtr mon) -{ - mon->refs++; - VIR_DEBUG("%d", mon->refs); - return mon->refs; -} - -int qemuAgentUnref(qemuAgentPtr mon) -{ - mon->refs--; - VIR_DEBUG("%d", mon->refs); - if (mon->refs == 0) { - qemuAgentUnlock(mon); - qemuAgentFree(mon); - return 0; - } - - return mon->refs; -} - -static void -qemuAgentUnwatch(void *monitor) -{ - qemuAgentPtr mon = monitor; - - qemuAgentLock(mon); - if (qemuAgentUnref(mon) > 0) - qemuAgentUnlock(mon); } static int @@ -599,9 +586,9 @@ qemuAgentIO(int watch, int fd, int events, void *opaque) { bool error = false; bool eof = false; + virObjectRef(mon); /* lock access to the monitor and protect fd */ qemuAgentLock(mon); - qemuAgentRef(mon); #if DEBUG_IO VIR_DEBUG("Agent %p I/O on watch %d fd %d events %d", mon, watch, fd, events); #endif @@ -704,8 +691,8 @@ qemuAgentIO(int watch, int fd, int events, void *opaque) { /* Make sure anyone waiting wakes up now */ virCondSignal(&mon->notify); - if (qemuAgentUnref(mon) > 0) - qemuAgentUnlock(mon); + qemuAgentUnlock(mon); + virObjectUnref(mon); VIR_DEBUG("Triggering EOF callback"); (eofNotify)(mon, vm); } else if (error) { @@ -715,13 +702,13 @@ qemuAgentIO(int watch, int fd, int events, void *opaque) { /* Make sure anyone waiting wakes up now */ virCondSignal(&mon->notify); - if (qemuAgentUnref(mon) > 0) - qemuAgentUnlock(mon); + qemuAgentUnlock(mon); + virObjectUnref(mon); VIR_DEBUG("Triggering error callback"); (errorNotify)(mon, vm); } else { - if (qemuAgentUnref(mon) > 0) - qemuAgentUnlock(mon); + qemuAgentUnlock(mon); + virObjectUnref(mon); } } @@ -739,10 +726,11 @@ qemuAgentOpen(virDomainObjPtr vm, return NULL; } - if (VIR_ALLOC(mon) < 0) { - virReportOOMError(); + if (qemuAgentInitialize() < 0) + return NULL; + + if (!(mon = virObjectNew(qemuAgentClass))) return NULL; - } if (virMutexInit(&mon->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -758,7 +746,6 @@ qemuAgentOpen(virDomainObjPtr vm, return NULL; } mon->fd = -1; - mon->refs = 1; mon->vm = vm; mon->cb = cb; qemuAgentLock(mon); @@ -791,12 +778,13 @@ qemuAgentOpen(virDomainObjPtr vm, VIR_EVENT_HANDLE_WRITABLE : 0), qemuAgentIO, - mon, qemuAgentUnwatch)) < 0) { + mon, + (virFreeCallback)virObjectUnref)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("unable to register monitor events")); goto cleanup; } - qemuAgentRef(mon); + virObjectRef(mon); VIR_DEBUG("New mon %p fd =%d watch=%d", mon, mon->fd, mon->watch); qemuAgentUnlock(mon); @@ -837,9 +825,9 @@ void qemuAgentClose(qemuAgentPtr mon) mon->msg->finished = 1; virCondSignal(&mon->notify); } + qemuAgentUnlock(mon); - if (qemuAgentUnref(mon) > 0) - qemuAgentUnlock(mon); + virObjectUnref(mon); } #define QEMU_AGENT_WAIT_TIME (1000ull * 5) diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h index 860e7e5..2fdebb2 100644 --- a/src/qemu/qemu_agent.h +++ b/src/qemu/qemu_agent.h @@ -50,9 +50,6 @@ qemuAgentPtr qemuAgentOpen(virDomainObjPtr vm, void qemuAgentLock(qemuAgentPtr mon); void qemuAgentUnlock(qemuAgentPtr mon); -int qemuAgentRef(qemuAgentPtr mon); -int qemuAgentUnref(qemuAgentPtr mon) ATTRIBUTE_RETURN_CHECK; - void qemuAgentClose(qemuAgentPtr mon); typedef enum { diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 4acbb20..f7cbe7f 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -994,7 +994,7 @@ qemuDomainObjEnterMonitorInternal(struct qemud_driver *driver, } qemuMonitorLock(priv->mon); - qemuMonitorRef(priv->mon); + virObjectRef(priv->mon); ignore_value(virTimeMillisNow(&priv->monStart)); virDomainObjUnlock(obj); if (driver_locked) @@ -1009,11 +1009,11 @@ qemuDomainObjExitMonitorInternal(struct qemud_driver *driver, virDomainObjPtr obj) { qemuDomainObjPrivatePtr priv = obj->privateData; - int refs; + bool hasRefs; - refs = qemuMonitorUnref(priv->mon); + hasRefs = virObjectUnref(priv->mon); - if (refs > 0) + if (hasRefs) qemuMonitorUnlock(priv->mon); if (driver_locked) @@ -1021,9 +1021,8 @@ qemuDomainObjExitMonitorInternal(struct qemud_driver *driver, virDomainObjLock(obj); priv->monStart = 0; - if (refs == 0) { + if (!hasRefs) priv->mon = NULL; - } if (priv->job.active == QEMU_JOB_ASYNC_NESTED) { qemuDomainObjResetJob(priv); @@ -1118,7 +1117,7 @@ qemuDomainObjEnterAgentInternal(struct qemud_driver *driver, qemuDomainObjPrivatePtr priv = obj->privateData; qemuAgentLock(priv->agent); - qemuAgentRef(priv->agent); + virObjectRef(priv->agent); ignore_value(virTimeMillisNow(&priv->agentStart)); virDomainObjUnlock(obj); if (driver_locked) @@ -1133,11 +1132,11 @@ qemuDomainObjExitAgentInternal(struct qemud_driver *driver, virDomainObjPtr obj) { qemuDomainObjPrivatePtr priv = obj->privateData; - int refs; + bool hasRefs; - refs = qemuAgentUnref(priv->agent); + hasRefs = virObjectUnref(priv->agent); - if (refs > 0) + if (hasRefs) qemuAgentUnlock(priv->agent); if (driver_locked) @@ -1145,9 +1144,8 @@ qemuDomainObjExitAgentInternal(struct qemud_driver *driver, virDomainObjLock(obj); priv->agentStart = 0; - if (refs == 0) { + if (!hasRefs) priv->agent = NULL; - } } /* diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 20395b0..f53746e 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -36,6 +36,7 @@ #include "memory.h" #include "logging.h" #include "virfile.h" +#include "virobject.h" #ifdef WITH_DTRACE_PROBES # include "libvirt_qemu_probes.h" @@ -47,11 +48,11 @@ #define DEBUG_RAW_IO 0 struct _qemuMonitor { + virObject object; + virMutex lock; /* also used to protect fd */ virCond notify; - int refs; - int fd; int watch; int hasSendFD; @@ -80,6 +81,21 @@ struct _qemuMonitor { unsigned json_hmp: 1; }; +static virClassPtr qemuMonitorClass; +static void qemuMonitorDispose(void *obj); + +static int qemuMonitorOnceInit(void) +{ + if (!(qemuMonitorClass = virClassNew("qemuMonitor", + sizeof(qemuMonitor), + qemuMonitorDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(qemuMonitor) + VIR_ENUM_IMPL(qemuMonitorMigrationStatus, QEMU_MONITOR_MIGRATION_STATUS_LAST, @@ -224,8 +240,10 @@ void qemuMonitorUnlock(qemuMonitorPtr mon) } -static void qemuMonitorFree(qemuMonitorPtr mon) +static void qemuMonitorDispose(void *obj) { + qemuMonitorPtr mon = obj; + VIR_DEBUG("mon=%p", mon); if (mon->cb && mon->cb->destroy) (mon->cb->destroy)(mon, mon->vm); @@ -233,41 +251,8 @@ static void qemuMonitorFree(qemuMonitorPtr mon) {} virMutexDestroy(&mon->lock); VIR_FREE(mon->buffer); - VIR_FREE(mon); -} - -int qemuMonitorRef(qemuMonitorPtr mon) -{ - mon->refs++; - PROBE(QEMU_MONITOR_REF, - "mon=%p refs=%d", mon, mon->refs); - return mon->refs; -} - -int qemuMonitorUnref(qemuMonitorPtr mon) -{ - mon->refs--; - - PROBE(QEMU_MONITOR_UNREF, - "mon=%p refs=%d", mon, mon->refs); - if (mon->refs == 0) { - qemuMonitorUnlock(mon); - qemuMonitorFree(mon); - return 0; - } - - return mon->refs; } -static void -qemuMonitorUnwatch(void *monitor) -{ - qemuMonitorPtr mon = monitor; - - qemuMonitorLock(mon); - if (qemuMonitorUnref(mon) > 0) - qemuMonitorUnlock(mon); -} static int qemuMonitorOpenUnix(const char *monitor, pid_t cpid) @@ -567,9 +552,10 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque) { bool error = false; bool eof = false; + virObjectRef(mon); + /* 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 @@ -667,8 +653,8 @@ 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); + virObjectUnref(mon); VIR_DEBUG("Triggering EOF callback"); (eofNotify)(mon, vm); } else if (error) { @@ -678,13 +664,13 @@ 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); + virObjectUnref(mon); VIR_DEBUG("Triggering error callback"); (errorNotify)(mon, vm); } else { - if (qemuMonitorUnref(mon) > 0) - qemuMonitorUnlock(mon); + qemuMonitorUnlock(mon); + virObjectUnref(mon); } } @@ -703,10 +689,11 @@ qemuMonitorOpen(virDomainObjPtr vm, return NULL; } - if (VIR_ALLOC(mon) < 0) { - virReportOOMError(); + if (qemuMonitorInitialize() < 0) + return NULL; + + if (!(mon = virObjectNew(qemuMonitorClass))) return NULL; - } if (virMutexInit(&mon->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -722,7 +709,6 @@ qemuMonitorOpen(virDomainObjPtr vm, return NULL; } mon->fd = -1; - mon->refs = 1; mon->vm = vm; mon->json = json; mon->cb = cb; @@ -764,16 +750,17 @@ qemuMonitorOpen(virDomainObjPtr vm, VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_READABLE, qemuMonitorIO, - mon, qemuMonitorUnwatch)) < 0) { + mon, + (virFreeCallback)virObjectUnref)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("unable to register monitor events")); goto cleanup; } - qemuMonitorRef(mon); + virObjectRef(mon); PROBE(QEMU_MONITOR_NEW, "mon=%p refs=%d fd=%d", - mon, mon->refs, mon->fd); + mon, mon->object.refs, mon->fd); qemuMonitorUnlock(mon); return mon; @@ -798,7 +785,7 @@ void qemuMonitorClose(qemuMonitorPtr mon) qemuMonitorLock(mon); PROBE(QEMU_MONITOR_CLOSE, - "mon=%p refs=%d", mon, mon->refs); + "mon=%p refs=%d", mon, mon->object.refs); if (mon->fd >= 0) { if (mon->watch) @@ -827,8 +814,8 @@ void qemuMonitorClose(qemuMonitorPtr mon) virCondSignal(&mon->notify); } - if (qemuMonitorUnref(mon) > 0) - qemuMonitorUnlock(mon); + qemuMonitorUnlock(mon); + virObjectUnref(mon); } @@ -919,12 +906,12 @@ cleanup: /* Ensure proper locking around callbacks. */ #define QEMU_MONITOR_CALLBACK(mon, ret, callback, ...) \ do { \ - qemuMonitorRef(mon); \ + virObjectRef(mon); \ qemuMonitorUnlock(mon); \ if ((mon)->cb && (mon)->cb->callback) \ (ret) = ((mon)->cb->callback)(mon, __VA_ARGS__); \ qemuMonitorLock(mon); \ - ignore_value(qemuMonitorUnref(mon)); \ + virObjectUnref(mon); \ } while (0) int qemuMonitorGetDiskSecret(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 995948b..42f33d1 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -156,9 +156,6 @@ 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; - int qemuMonitorSetLink(qemuMonitorPtr mon, const char *name, enum virDomainNetInterfaceLinkState state) ; -- 1.7.10.4

On 07/31/2012 10:58 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Make qemuAgentPtr and qemuMonitorPtr types use the virObject APIs for reference counting
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/qemu/qemu_agent.c | 86 ++++++++++++++++++----------------------- src/qemu/qemu_agent.h | 3 -- src/qemu/qemu_domain.c | 22 +++++------ src/qemu/qemu_monitor.c | 97 ++++++++++++++++++++--------------------------- src/qemu/qemu_monitor.h | 3 -- 5 files changed, 89 insertions(+), 122 deletions(-)
These diffstats are showing that this is a good move.
@@ -791,12 +778,13 @@ qemuAgentOpen(virDomainObjPtr vm, VIR_EVENT_HANDLE_WRITABLE : 0), qemuAgentIO, - mon, qemuAgentUnwatch)) < 0) { + mon, + (virFreeCallback)virObjectUnref)) < 0) {
Should virobject.h provide something like static inline void virObjectFreeCallback(void *opaque) { virObjectUnref(opaque); } just so that we don't have to cast virObjectUnref in so many places? ACK. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

From: "Daniel P. Berrange" <berrange@redhat.com> Make virNetTLSContext and virNetTLSSession use the virObject APIs for reference counting Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- daemon/libvirtd.c | 4 +- src/libvirt_private.syms | 2 - src/libvirt_probes.d | 8 +-- src/remote/remote_driver.c | 2 +- src/rpc/virnetclient.c | 6 +-- src/rpc/virnetserver.c | 3 +- src/rpc/virnetserverclient.c | 11 ++--- src/rpc/virnetserverservice.c | 10 ++-- src/rpc/virnetsocket.c | 7 ++- src/rpc/virnettlscontext.c | 110 +++++++++++++++-------------------------- src/rpc/virnettlscontext.h | 10 +--- tests/virnettlscontexttest.c | 10 ++-- 12 files changed, 66 insertions(+), 117 deletions(-) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index ba0cc1f..3ccd70a 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -541,7 +541,7 @@ static int daemonSetupNetworking(virNetServerPtr srv, false, config->max_client_requests, ctxt))) { - virNetTLSContextFree(ctxt); + virObjectUnref(ctxt); goto error; } if (virNetServerAddService(srv, svcTLS, @@ -549,7 +549,7 @@ static int daemonSetupNetworking(virNetServerPtr srv, !config->listen_tcp ? "_libvirt._tcp" : NULL) < 0) goto error; - virNetTLSContextFree(ctxt); + virObjectUnref(ctxt); } } diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d1a4c65..50ed572 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1590,14 +1590,12 @@ virNetSocketWrite; # virnettlscontext.h virNetTLSContextCheckCertificate; -virNetTLSContextFree; virNetTLSContextNewClient; virNetTLSContextNewClientPath; virNetTLSContextNewServer; virNetTLSContextNewServerPath; virNetTLSContextRef; virNetTLSInit; -virNetTLSSessionFree; virNetTLSSessionGetHandshakeStatus; virNetTLSSessionGetKeySize; virNetTLSSessionHandshake; diff --git a/src/libvirt_probes.d b/src/libvirt_probes.d index ceb3caa..3b138a9 100644 --- a/src/libvirt_probes.d +++ b/src/libvirt_probes.d @@ -61,19 +61,15 @@ provider libvirt { # file: src/rpc/virnettlscontext.c # prefix: rpc - probe rpc_tls_context_new(void *ctxt, int refs, const char *cacert, const char *cacrl, + probe rpc_tls_context_new(void *ctxt, const char *cacert, const char *cacrl, const char *cert, const char *key, int sanityCheckCert, int requireValidCert, int isServer); - probe rpc_tls_context_ref(void *ctxt, int refs); - probe rpc_tls_context_free(void *ctxt, int refs); probe rpc_tls_context_session_allow(void *ctxt, void *sess, const char *dname); probe rpc_tls_context_session_deny(void *ctxt, void *sess, const char *dname); probe rpc_tls_context_session_fail(void *ctxt, void *sess); - probe rpc_tls_session_new(void *sess, void *ctxt, int refs, const char *hostname, int isServer); - probe rpc_tls_session_ref(void *sess, int refs); - probe rpc_tls_session_free(void *sess, int refs); + probe rpc_tls_session_new(void *sess, void *ctxt, const char *hostname, int isServer); probe rpc_tls_session_handshake_pass(void *sess); probe rpc_tls_session_handshake_fail(void *sess); diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 9ac27b2..91d337f 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -943,7 +943,7 @@ doRemoteClose (virConnectPtr conn, struct private_data *priv) (xdrproc_t) xdr_void, (char *) NULL) == -1) ret = -1; - virNetTLSContextFree(priv->tls); + virObjectUnref(priv->tls); priv->tls = NULL; virNetClientClose(priv->client); virNetClientFree(priv->client); diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index b210a72..3a1b831 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -495,7 +495,7 @@ void virNetClientFree(virNetClientPtr client) if (client->sock) virNetSocketRemoveIOCallback(client->sock); virNetSocketFree(client->sock); - virNetTLSSessionFree(client->tls); + virObjectUnref(client->tls); #if HAVE_SASL virNetSASLSessionFree(client->sasl); #endif @@ -529,7 +529,7 @@ virNetClientCloseLocked(virNetClientPtr client) virNetSocketFree(client->sock); client->sock = NULL; - virNetTLSSessionFree(client->tls); + virObjectUnref(client->tls); client->tls = NULL; #if HAVE_SASL virNetSASLSessionFree(client->sasl); @@ -709,7 +709,7 @@ int virNetClientSetTLSSession(virNetClientPtr client, return 0; error: - virNetTLSSessionFree(client->tls); + virObjectUnref(client->tls); client->tls = NULL; virNetClientUnlock(client); return -1; diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 248ad9f..e9f500e 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -652,8 +652,7 @@ no_memory: int virNetServerSetTLSContext(virNetServerPtr srv, virNetTLSContextPtr tls) { - srv->tls = tls; - virNetTLSContextRef(tls); + srv->tls = virObjectRef(tls); return 0; } diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index d0a144c..c419e74 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -346,7 +346,7 @@ virNetServerClientPtr virNetServerClientNew(virNetSocketPtr sock, client->sock = sock; client->auth = auth; client->readonly = readonly; - client->tlsCtxt = tls; + client->tlsCtxt = virObjectRef(tls); client->nrequests_max = nrequests_max; client->sockTimer = virEventAddTimeout(-1, virNetServerClientSockTimerFunc, @@ -354,9 +354,6 @@ virNetServerClientPtr virNetServerClientNew(virNetSocketPtr sock, if (client->sockTimer < 0) goto error; - if (tls) - virNetTLSContextRef(tls); - /* Prepare one for packet receive */ if (!(client->rx = virNetMessageNew(true))) goto error; @@ -598,8 +595,8 @@ void virNetServerClientFree(virNetServerClientPtr client) #endif if (client->sockTimer > 0) virEventRemoveTimeout(client->sockTimer); - virNetTLSSessionFree(client->tls); - virNetTLSContextFree(client->tlsCtxt); + virObjectUnref(client->tls); + virObjectUnref(client->tlsCtxt); virNetSocketFree(client->sock); virNetServerClientUnlock(client); virMutexDestroy(&client->lock); @@ -654,7 +651,7 @@ void virNetServerClientClose(virNetServerClientPtr client) virNetSocketRemoveIOCallback(client->sock); if (client->tls) { - virNetTLSSessionFree(client->tls); + virObjectUnref(client->tls); client->tls = NULL; } client->wantClose = true; diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c index 2880df3..60fe89f 100644 --- a/src/rpc/virnetserverservice.c +++ b/src/rpc/virnetserverservice.c @@ -116,9 +116,7 @@ virNetServerServicePtr virNetServerServiceNewTCP(const char *nodename, svc->auth = auth; svc->readonly = readonly; svc->nrequests_client_max = nrequests_client_max; - svc->tls = tls; - if (tls) - virNetTLSContextRef(tls); + svc->tls = virObjectRef(tls); if (virNetSocketNewListenTCP(nodename, service, @@ -172,9 +170,7 @@ virNetServerServicePtr virNetServerServiceNewUNIX(const char *path, svc->auth = auth; svc->readonly = readonly; svc->nrequests_client_max = nrequests_client_max; - svc->tls = tls; - if (tls) - virNetTLSContextRef(tls); + svc->tls = virObjectRef(tls); svc->nsocks = 1; if (VIR_ALLOC_N(svc->socks, svc->nsocks) < 0) @@ -265,7 +261,7 @@ void virNetServerServiceFree(virNetServerServicePtr svc) virNetSocketFree(svc->socks[i]); VIR_FREE(svc->socks); - virNetTLSContextFree(svc->tls); + virObjectUnref(svc->tls); VIR_FREE(svc); } diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 88e5525..bca78b5 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -748,7 +748,7 @@ void virNetSocketFree(virNetSocketPtr sock) /* Make sure it can't send any more I/O during shutdown */ if (sock->tlsSession) virNetTLSSessionSetIOCallbacks(sock->tlsSession, NULL, NULL, NULL); - virNetTLSSessionFree(sock->tlsSession); + virObjectUnref(sock->tlsSession); #if HAVE_SASL virNetSASLSessionFree(sock->saslSession); #endif @@ -909,13 +909,12 @@ void virNetSocketSetTLSSession(virNetSocketPtr sock, virNetTLSSessionPtr sess) { virMutexLock(&sock->lock); - virNetTLSSessionFree(sock->tlsSession); - sock->tlsSession = sess; + virObjectUnref(sock->tlsSession); + sock->tlsSession = virObjectRef(sess); virNetTLSSessionSetIOCallbacks(sess, virNetSocketTLSSessionWrite, virNetSocketTLSSessionRead, sock); - virNetTLSSessionRef(sess); virMutexUnlock(&sock->lock); } diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index 5ae22f2..9fe6eb1 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -50,8 +50,9 @@ #define VIR_FROM_THIS VIR_FROM_RPC struct _virNetTLSContext { + virObject object; + virMutex lock; - int refs; gnutls_certificate_credentials_t x509cred; gnutls_dh_params_t dhParams; @@ -62,9 +63,9 @@ struct _virNetTLSContext { }; struct _virNetTLSSession { - virMutex lock; + virObject object; - int refs; + virMutex lock; bool handshakeComplete; @@ -76,6 +77,29 @@ struct _virNetTLSSession { void *opaque; }; +static virClassPtr virNetTLSContextClass; +static virClassPtr virNetTLSSessionClass; +static void virNetTLSContextDispose(void *obj); +static void virNetTLSSessionDispose(void *obj); + + +static int virNetTLSContextOnceInit(void) +{ + if (!(virNetTLSContextClass = virClassNew("virNetTLSContext", + sizeof(virNetTLSContext), + virNetTLSContextDispose))) + return -1; + + if (!(virNetTLSSessionClass = virClassNew("virNetTLSSession", + sizeof(virNetTLSSession), + virNetTLSSessionDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetTLSContext) + static int virNetTLSContextCheckCertFile(const char *type, const char *file, bool allowMissing) @@ -647,10 +671,11 @@ static virNetTLSContextPtr virNetTLSContextNew(const char *cacert, char *gnutlsdebug; int err; - if (VIR_ALLOC(ctxt) < 0) { - virReportOOMError(); + if (virNetTLSContextInitialize() < 0) + return NULL; + + if (!(ctxt = virObjectNew(virNetTLSContextClass))) return NULL; - } if (virMutexInit(&ctxt->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -659,8 +684,6 @@ static virNetTLSContextPtr virNetTLSContextNew(const char *cacert, return NULL; } - ctxt->refs = 1; - if ((gnutlsdebug = getenv("LIBVIRT_GNUTLS_DEBUG")) != NULL) { int val; if (virStrToLong_i(gnutlsdebug, NULL, 10, &val) < 0) @@ -716,8 +739,8 @@ static virNetTLSContextPtr virNetTLSContextNew(const char *cacert, ctxt->isServer = isServer; PROBE(RPC_TLS_CONTEXT_NEW, - "ctxt=%p refs=%d cacert=%s cacrl=%s cert=%s key=%s sanityCheckCert=%d requireValidCert=%d isServer=%d", - ctxt, ctxt->refs, cacert, NULLSTR(cacrl), cert, key, sanityCheckCert, requireValidCert, isServer); + "ctxt=%p cacert=%s cacrl=%s cert=%s key=%s sanityCheckCert=%d requireValidCert=%d isServer=%d", + ctxt, cacert, NULLSTR(cacrl), cert, key, sanityCheckCert, requireValidCert, isServer); return ctxt; @@ -927,17 +950,6 @@ virNetTLSContextPtr virNetTLSContextNewClient(const char *cacert, } -void virNetTLSContextRef(virNetTLSContextPtr ctxt) -{ - virMutexLock(&ctxt->lock); - ctxt->refs++; - PROBE(RPC_TLS_CONTEXT_REF, - "ctxt=%p refs=%d", - ctxt, ctxt->refs); - virMutexUnlock(&ctxt->lock); -} - - static int virNetTLSContextValidCertificate(virNetTLSContextPtr ctxt, virNetTLSSessionPtr sess) { @@ -1106,30 +1118,16 @@ cleanup: return ret; } -void virNetTLSContextFree(virNetTLSContextPtr ctxt) +void virNetTLSContextDispose(void *obj) { - if (!ctxt) - return; - - virMutexLock(&ctxt->lock); - PROBE(RPC_TLS_CONTEXT_FREE, - "ctxt=%p refs=%d", - ctxt, ctxt->refs); - ctxt->refs--; - if (ctxt->refs > 0) { - virMutexUnlock(&ctxt->lock); - return; - } + virNetTLSContextPtr ctxt = obj; gnutls_dh_params_deinit(ctxt->dhParams); gnutls_certificate_free_credentials(ctxt->x509cred); - virMutexUnlock(&ctxt->lock); virMutexDestroy(&ctxt->lock); - VIR_FREE(ctxt); } - static ssize_t virNetTLSSessionPush(void *opaque, const void *buf, size_t len) { @@ -1167,10 +1165,8 @@ virNetTLSSessionPtr virNetTLSSessionNew(virNetTLSContextPtr ctxt, VIR_DEBUG("ctxt=%p hostname=%s isServer=%d", ctxt, NULLSTR(hostname), ctxt->isServer); - if (VIR_ALLOC(sess) < 0) { - virReportOOMError(); + if (!(sess = virObjectNew(virNetTLSSessionClass))) return NULL; - } if (virMutexInit(&sess->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -1179,7 +1175,6 @@ virNetTLSSessionPtr virNetTLSSessionNew(virNetTLSContextPtr ctxt, return NULL; } - sess->refs = 1; if (hostname && !(sess->hostname = strdup(hostname))) { virReportOOMError(); @@ -1230,27 +1225,17 @@ virNetTLSSessionPtr virNetTLSSessionNew(virNetTLSContextPtr ctxt, sess->isServer = ctxt->isServer; PROBE(RPC_TLS_SESSION_NEW, - "sess=%p refs=%d ctxt=%p hostname=%s isServer=%d", - sess, sess->refs, ctxt, hostname, sess->isServer); + "sess=%p ctxt=%p hostname=%s isServer=%d", + sess, ctxt, hostname, sess->isServer); return sess; error: - virNetTLSSessionFree(sess); + virObjectUnref(sess); return NULL; } -void virNetTLSSessionRef(virNetTLSSessionPtr sess) -{ - virMutexLock(&sess->lock); - sess->refs++; - PROBE(RPC_TLS_SESSION_REF, - "sess=%p refs=%d", - sess, sess->refs); - virMutexUnlock(&sess->lock); -} - void virNetTLSSessionSetIOCallbacks(virNetTLSSessionPtr sess, virNetTLSSessionWriteFunc writeFunc, virNetTLSSessionReadFunc readFunc, @@ -1393,26 +1378,13 @@ cleanup: } -void virNetTLSSessionFree(virNetTLSSessionPtr sess) +void virNetTLSSessionDispose(void *obj) { - if (!sess) - return; - - virMutexLock(&sess->lock); - PROBE(RPC_TLS_SESSION_FREE, - "sess=%p refs=%d", - sess, sess->refs); - sess->refs--; - if (sess->refs > 0) { - virMutexUnlock(&sess->lock); - return; - } + virNetTLSSessionPtr sess = obj; VIR_FREE(sess->hostname); gnutls_deinit(sess->session); - virMutexUnlock(&sess->lock); virMutexDestroy(&sess->lock); - VIR_FREE(sess); } /* diff --git a/src/rpc/virnettlscontext.h b/src/rpc/virnettlscontext.h index 8893da9..e47c3c0 100644 --- a/src/rpc/virnettlscontext.h +++ b/src/rpc/virnettlscontext.h @@ -22,6 +22,7 @@ # define __VIR_NET_TLS_CONTEXT_H__ # include "internal.h" +# include "virobject.h" typedef struct _virNetTLSContext virNetTLSContext; typedef virNetTLSContext *virNetTLSContextPtr; @@ -58,13 +59,9 @@ virNetTLSContextPtr virNetTLSContextNewClient(const char *cacert, bool sanityCheckCert, bool requireValidCert); -void virNetTLSContextRef(virNetTLSContextPtr ctxt); - int virNetTLSContextCheckCertificate(virNetTLSContextPtr ctxt, virNetTLSSessionPtr sess); -void virNetTLSContextFree(virNetTLSContextPtr ctxt); - typedef ssize_t (*virNetTLSSessionWriteFunc)(const char *buf, size_t len, void *opaque); @@ -79,8 +76,6 @@ void virNetTLSSessionSetIOCallbacks(virNetTLSSessionPtr sess, virNetTLSSessionReadFunc readFunc, void *opaque); -void virNetTLSSessionRef(virNetTLSSessionPtr sess); - ssize_t virNetTLSSessionWrite(virNetTLSSessionPtr sess, const char *buf, size_t len); ssize_t virNetTLSSessionRead(virNetTLSSessionPtr sess, @@ -99,7 +94,4 @@ virNetTLSSessionGetHandshakeStatus(virNetTLSSessionPtr sess); int virNetTLSSessionGetKeySize(virNetTLSSessionPtr sess); -void virNetTLSSessionFree(virNetTLSSessionPtr sess); - - #endif diff --git a/tests/virnettlscontexttest.c b/tests/virnettlscontexttest.c index 0dfaa23..397c967 100644 --- a/tests/virnettlscontexttest.c +++ b/tests/virnettlscontexttest.c @@ -496,7 +496,7 @@ static int testTLSContextInit(const void *opaque) ret = 0; cleanup: - virNetTLSContextFree(ctxt); + virObjectUnref(ctxt); gnutls_x509_crt_deinit(data->careq.crt); gnutls_x509_crt_deinit(data->certreq.crt); data->careq.crt = data->certreq.crt = NULL; @@ -710,10 +710,10 @@ static int testTLSSessionInit(const void *opaque) ret = 0; cleanup: - virNetTLSContextFree(serverCtxt); - virNetTLSContextFree(clientCtxt); - virNetTLSSessionFree(serverSess); - virNetTLSSessionFree(clientSess); + virObjectUnref(serverCtxt); + virObjectUnref(clientCtxt); + virObjectUnref(serverSess); + virObjectUnref(clientSess); gnutls_x509_crt_deinit(data->careq.crt); if (data->othercareq.filename) gnutls_x509_crt_deinit(data->othercareq.crt); -- 1.7.10.4

From: "Daniel P. Berrange" <berrange@redhat.com> Make virNetSASLContext and virNetSASLSession use virObject APIs for reference counting Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- daemon/remote.c | 8 ++-- src/remote/remote_driver.c | 4 +- src/rpc/virnetclient.c | 7 ++- src/rpc/virnetsaslcontext.c | 106 ++++++++++++++++++------------------------ src/rpc/virnetsaslcontext.h | 8 +--- src/rpc/virnetserverclient.c | 7 ++- src/rpc/virnetsocket.c | 7 ++- 7 files changed, 61 insertions(+), 86 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index d25717c..832307e 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2325,7 +2325,7 @@ authfail: PROBE(RPC_SERVER_CLIENT_AUTH_FAIL, "client=%p auth=%d", client, REMOTE_AUTH_SASL); - virNetSASLSessionFree(sasl); + virObjectUnref(sasl); virMutexUnlock(&priv->lock); return -1; } @@ -2369,7 +2369,7 @@ remoteSASLFinish(virNetServerClientPtr client) "client=%p auth=%d identity=%s", client, REMOTE_AUTH_SASL, identity); - virNetSASLSessionFree(priv->sasl); + virObjectUnref(priv->sasl); priv->sasl = NULL; return 0; @@ -2467,7 +2467,7 @@ authdeny: goto error; error: - virNetSASLSessionFree(priv->sasl); + virObjectUnref(priv->sasl); priv->sasl = NULL; virResetLastError(); virReportError(VIR_ERR_AUTH_FAILED, "%s", @@ -2565,7 +2565,7 @@ authdeny: goto error; error: - virNetSASLSessionFree(priv->sasl); + virObjectUnref(priv->sasl); priv->sasl = NULL; virResetLastError(); virReportError(VIR_ERR_AUTH_FAILED, "%s", diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 91d337f..bfea919 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -3409,8 +3409,8 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, remoteAuthInteractStateClear(&state, true); VIR_FREE(saslcb); - virNetSASLSessionFree(sasl); - virNetSASLContextFree(saslCtxt); + virObjectUnref(sasl); + virObjectUnref(saslCtxt); return ret; } diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index 3a1b831..e611370 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -497,7 +497,7 @@ void virNetClientFree(virNetClientPtr client) virNetSocketFree(client->sock); virObjectUnref(client->tls); #if HAVE_SASL - virNetSASLSessionFree(client->sasl); + virObjectUnref(client->sasl); #endif virNetClientUnlock(client); virMutexDestroy(&client->lock); @@ -532,7 +532,7 @@ virNetClientCloseLocked(virNetClientPtr client) virObjectUnref(client->tls); client->tls = NULL; #if HAVE_SASL - virNetSASLSessionFree(client->sasl); + virObjectUnref(client->sasl); client->sasl = NULL; #endif ka = client->keepalive; @@ -604,8 +604,7 @@ void virNetClientSetSASLSession(virNetClientPtr client, virNetSASLSessionPtr sasl) { virNetClientLock(client); - client->sasl = sasl; - virNetSASLSessionRef(sasl); + client->sasl = virObjectRef(sasl); virNetSocketSetSASLSession(client->sock, client->sasl); virNetClientUnlock(client); } diff --git a/src/rpc/virnetsaslcontext.c b/src/rpc/virnetsaslcontext.c index af6e237..2feb9a9 100644 --- a/src/rpc/virnetsaslcontext.c +++ b/src/rpc/virnetsaslcontext.c @@ -33,24 +33,52 @@ #define VIR_FROM_THIS VIR_FROM_RPC struct _virNetSASLContext { + virObject object; + virMutex lock; const char *const*usernameWhitelist; - int refs; }; struct _virNetSASLSession { + virObject object; + virMutex lock; sasl_conn_t *conn; - int refs; size_t maxbufsize; }; +static virClassPtr virNetSASLContextClass; +static virClassPtr virNetSASLSessionClass; +static void virNetSASLContextDispose(void *obj); +static void virNetSASLSessionDispose(void *obj); + +static int virNetSASLContextOnceInit(void) +{ + if (!(virNetSASLContextClass = virClassNew("virNetSASLContext", + sizeof(virNetSASLContext), + virNetSASLContextDispose))) + return -1; + + if (!(virNetSASLSessionClass = virClassNew("virNetSASLSession", + sizeof(virNetSASLSession), + virNetSASLSessionDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetSASLContext) + + virNetSASLContextPtr virNetSASLContextNewClient(void) { virNetSASLContextPtr ctxt; int err; + if (virNetSASLContextInitialize() < 0) + return NULL; + err = sasl_client_init(NULL); if (err != SASL_OK) { virReportError(VIR_ERR_AUTH_FAILED, @@ -59,10 +87,8 @@ virNetSASLContextPtr virNetSASLContextNewClient(void) return NULL; } - if (VIR_ALLOC(ctxt) < 0) { - virReportOOMError(); + if (!(ctxt = virObjectNew(virNetSASLContextClass))) return NULL; - } if (virMutexInit(&ctxt->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -71,8 +97,6 @@ virNetSASLContextPtr virNetSASLContextNewClient(void) return NULL; } - ctxt->refs = 1; - return ctxt; } @@ -81,6 +105,9 @@ virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitel virNetSASLContextPtr ctxt; int err; + if (virNetSASLContextInitialize() < 0) + return NULL; + err = sasl_server_init(NULL, "libvirt"); if (err != SASL_OK) { virReportError(VIR_ERR_AUTH_FAILED, @@ -89,10 +116,8 @@ virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitel return NULL; } - if (VIR_ALLOC(ctxt) < 0) { - virReportOOMError(); + if (!(ctxt = virObjectNew(virNetSASLContextClass))) return NULL; - } if (virMutexInit(&ctxt->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -102,7 +127,6 @@ virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitel } ctxt->usernameWhitelist = usernameWhitelist; - ctxt->refs = 1; return ctxt; } @@ -152,28 +176,11 @@ cleanup: } -void virNetSASLContextRef(virNetSASLContextPtr ctxt) -{ - virMutexLock(&ctxt->lock); - ctxt->refs++; - virMutexUnlock(&ctxt->lock); -} - -void virNetSASLContextFree(virNetSASLContextPtr ctxt) +void virNetSASLContextDispose(void *obj) { - if (!ctxt) - return; - - virMutexLock(&ctxt->lock); - ctxt->refs--; - if (ctxt->refs > 0) { - virMutexUnlock(&ctxt->lock); - return; - } + virNetSASLContextPtr ctxt = obj; - virMutexUnlock(&ctxt->lock); virMutexDestroy(&ctxt->lock); - VIR_FREE(ctxt); } virNetSASLSessionPtr virNetSASLSessionNewClient(virNetSASLContextPtr ctxt ATTRIBUTE_UNUSED, @@ -186,10 +193,8 @@ virNetSASLSessionPtr virNetSASLSessionNewClient(virNetSASLContextPtr ctxt ATTRIB virNetSASLSessionPtr sasl = NULL; int err; - if (VIR_ALLOC(sasl) < 0) { - virReportOOMError(); - goto cleanup; - } + if (!(sasl = virObjectNew(virNetSASLSessionClass))) + return NULL; if (virMutexInit(&sasl->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -198,7 +203,6 @@ virNetSASLSessionPtr virNetSASLSessionNewClient(virNetSASLContextPtr ctxt ATTRIB return NULL; } - sasl->refs = 1; /* Arbitrary size for amount of data we can encode in a single block */ sasl->maxbufsize = 1 << 16; @@ -219,7 +223,7 @@ virNetSASLSessionPtr virNetSASLSessionNewClient(virNetSASLContextPtr ctxt ATTRIB return sasl; cleanup: - virNetSASLSessionFree(sasl); + virObjectUnref(sasl); return NULL; } @@ -231,10 +235,8 @@ virNetSASLSessionPtr virNetSASLSessionNewServer(virNetSASLContextPtr ctxt ATTRIB virNetSASLSessionPtr sasl = NULL; int err; - if (VIR_ALLOC(sasl) < 0) { - virReportOOMError(); - goto cleanup; - } + if (!(sasl = virObjectNew(virNetSASLSessionClass))) + return NULL; if (virMutexInit(&sasl->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -243,7 +245,6 @@ virNetSASLSessionPtr virNetSASLSessionNewServer(virNetSASLContextPtr ctxt ATTRIB return NULL; } - sasl->refs = 1; /* Arbitrary size for amount of data we can encode in a single block */ sasl->maxbufsize = 1 << 16; @@ -265,17 +266,10 @@ virNetSASLSessionPtr virNetSASLSessionNewServer(virNetSASLContextPtr ctxt ATTRIB return sasl; cleanup: - virNetSASLSessionFree(sasl); + virObjectUnref(sasl); return NULL; } -void virNetSASLSessionRef(virNetSASLSessionPtr sasl) -{ - virMutexLock(&sasl->lock); - sasl->refs++; - virMutexUnlock(&sasl->lock); -} - int virNetSASLSessionExtKeySize(virNetSASLSessionPtr sasl, int ssf) { @@ -712,22 +706,12 @@ cleanup: return ret; } -void virNetSASLSessionFree(virNetSASLSessionPtr sasl) +void virNetSASLSessionDispose(void *obj) { - if (!sasl) - return; - - virMutexLock(&sasl->lock); - sasl->refs--; - if (sasl->refs > 0) { - virMutexUnlock(&sasl->lock); - return; - } + virNetSASLSessionPtr sasl = obj; if (sasl->conn) sasl_dispose(&sasl->conn); - virMutexUnlock(&sasl->lock); virMutexDestroy(&sasl->lock); - VIR_FREE(sasl); } diff --git a/src/rpc/virnetsaslcontext.h b/src/rpc/virnetsaslcontext.h index 914c45c..8e322d8 100644 --- a/src/rpc/virnetsaslcontext.h +++ b/src/rpc/virnetsaslcontext.h @@ -24,6 +24,7 @@ # include <sasl/sasl.h> # include "internal.h" +# include "virobject.h" typedef struct _virNetSASLContext virNetSASLContext; typedef virNetSASLContext *virNetSASLContextPtr; @@ -43,9 +44,6 @@ virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitel int virNetSASLContextCheckIdentity(virNetSASLContextPtr ctxt, const char *identity); -void virNetSASLContextRef(virNetSASLContextPtr sasl); -void virNetSASLContextFree(virNetSASLContextPtr sasl); - virNetSASLSessionPtr virNetSASLSessionNewClient(virNetSASLContextPtr ctxt, const char *service, const char *hostname, @@ -59,8 +57,6 @@ virNetSASLSessionPtr virNetSASLSessionNewServer(virNetSASLContextPtr ctxt, char *virNetSASLSessionListMechanisms(virNetSASLSessionPtr sasl); -void virNetSASLSessionRef(virNetSASLSessionPtr sasl); - int virNetSASLSessionExtKeySize(virNetSASLSessionPtr sasl, int ssf); @@ -114,6 +110,4 @@ ssize_t virNetSASLSessionDecode(virNetSASLSessionPtr sasl, const char **output, size_t *outputlen); -void virNetSASLSessionFree(virNetSASLSessionPtr sasl); - #endif /* __VIR_NET_CLIENT_SASL_CONTEXT_H__ */ diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index c419e74..471cca0 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -474,8 +474,7 @@ void virNetServerClientSetSASLSession(virNetServerClientPtr client, * operation do we switch to SASL mode */ virNetServerClientLock(client); - client->sasl = sasl; - virNetSASLSessionRef(sasl); + client->sasl = virObjectRef(sasl); virNetServerClientUnlock(client); } #endif @@ -591,7 +590,7 @@ void virNetServerClientFree(virNetServerClientPtr client) VIR_FREE(client->identity); #if HAVE_SASL - virNetSASLSessionFree(client->sasl); + virObjectUnref(client->sasl); #endif if (client->sockTimer > 0) virEventRemoveTimeout(client->sockTimer); @@ -1009,7 +1008,7 @@ virNetServerClientDispatchWrite(virNetServerClientPtr client) */ if (client->sasl) { virNetSocketSetSASLSession(client->sock, client->sasl); - virNetSASLSessionFree(client->sasl); + virObjectUnref(client->sasl); client->sasl = NULL; } #endif diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index bca78b5..b6bb211 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -750,7 +750,7 @@ void virNetSocketFree(virNetSocketPtr sock) virNetTLSSessionSetIOCallbacks(sock->tlsSession, NULL, NULL, NULL); virObjectUnref(sock->tlsSession); #if HAVE_SASL - virNetSASLSessionFree(sock->saslSession); + virObjectUnref(sock->saslSession); #endif VIR_FORCE_CLOSE(sock->fd); @@ -924,9 +924,8 @@ void virNetSocketSetSASLSession(virNetSocketPtr sock, virNetSASLSessionPtr sess) { virMutexLock(&sock->lock); - virNetSASLSessionFree(sock->saslSession); - sock->saslSession = sess; - virNetSASLSessionRef(sess); + virObjectUnref(sock->saslSession); + sock->saslSession = virObjectRef(sess); virMutexUnlock(&sock->lock); } #endif -- 1.7.10.4

From: "Daniel P. Berrange" <berrange@redhat.com> Make virKeepAlive use the virObject APIs for reference counting Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/libvirt_probes.d | 4 +-- src/rpc/virkeepalive.c | 73 +++++++++++++++++------------------------- src/rpc/virkeepalive.h | 4 +-- src/rpc/virnetclient.c | 4 +-- src/rpc/virnetserverclient.c | 4 +-- 5 files changed, 35 insertions(+), 54 deletions(-) diff --git a/src/libvirt_probes.d b/src/libvirt_probes.d index 3b138a9..807239f 100644 --- a/src/libvirt_probes.d +++ b/src/libvirt_probes.d @@ -77,9 +77,7 @@ provider libvirt { # file: src/rpc/virkeepalive.c # prefix: rpc - probe rpc_keepalive_new(void *ka, void *client, int refs); - probe rpc_keepalive_ref(void *ka, void *client, int refs); - probe rpc_keepalive_free(void *ka, void *client, int refs); + probe rpc_keepalive_new(void *ka, void *client); probe rpc_keepalive_start(void *ka, void *client, int interval, int count); probe rpc_keepalive_stop(void *ka, void *client); probe rpc_keepalive_send(void *ka, void *client, int prog, int vers, int proc); diff --git a/src/rpc/virkeepalive.c b/src/rpc/virkeepalive.c index ffb059e..8606a2d 100644 --- a/src/rpc/virkeepalive.c +++ b/src/rpc/virkeepalive.c @@ -35,7 +35,8 @@ #define VIR_FROM_THIS VIR_FROM_RPC struct _virKeepAlive { - int refs; + virObject object; + virMutex lock; int interval; @@ -52,6 +53,21 @@ struct _virKeepAlive { }; +static virClassPtr virKeepAliveClass; +static void virKeepAliveDispose(void *obj); + +static int virKeepAliveOnceInit(void) +{ + if (!(virKeepAliveClass = virClassNew("virKeepAlive", + sizeof(virKeepAlive), + virKeepAliveDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virKeepAlive) + static void virKeepAliveLock(virKeepAlivePtr ka) { @@ -165,7 +181,7 @@ virKeepAliveTimer(int timer ATTRIBUTE_UNUSED, void *opaque) if (!dead && !msg) goto cleanup; - ka->refs++; + virObjectRef(ka); virKeepAliveUnlock(ka); if (dead) { @@ -176,20 +192,13 @@ virKeepAliveTimer(int timer ATTRIBUTE_UNUSED, void *opaque) } virKeepAliveLock(ka); - ka->refs--; + virObjectUnref(ka); cleanup: virKeepAliveUnlock(ka); } -static void -virKeepAliveTimerFree(void *opaque) -{ - virKeepAliveFree(opaque); -} - - virKeepAlivePtr virKeepAliveNew(int interval, unsigned int count, @@ -202,17 +211,17 @@ virKeepAliveNew(int interval, VIR_DEBUG("client=%p, interval=%d, count=%u", client, interval, count); - if (VIR_ALLOC(ka) < 0) { - virReportOOMError(); + if (virKeepAliveInitialize() < 0) + return NULL; + + if (!(ka = virObjectNew(virKeepAliveClass))) return NULL; - } if (virMutexInit(&ka->lock) < 0) { VIR_FREE(ka); return NULL; } - ka->refs = 1; ka->interval = interval; ka->count = count; ka->countToDeath = count; @@ -223,44 +232,20 @@ virKeepAliveNew(int interval, ka->freeCB = freeCB; PROBE(RPC_KEEPALIVE_NEW, - "ka=%p client=%p refs=%d", - ka, ka->client, ka->refs); + "ka=%p client=%p", + ka, ka->client); return ka; } void -virKeepAliveRef(virKeepAlivePtr ka) +virKeepAliveDispose(void *obj) { - virKeepAliveLock(ka); - ka->refs++; - PROBE(RPC_KEEPALIVE_REF, - "ka=%p client=%p refs=%d", - ka, ka->client, ka->refs); - virKeepAliveUnlock(ka); -} - - -void -virKeepAliveFree(virKeepAlivePtr ka) -{ - if (!ka) - return; - - virKeepAliveLock(ka); - PROBE(RPC_KEEPALIVE_FREE, - "ka=%p client=%p refs=%d", - ka, ka->client, ka->refs); - - if (--ka->refs > 0) { - virKeepAliveUnlock(ka); - return; - } + virKeepAlivePtr ka = obj; virMutexDestroy(&ka->lock); ka->freeCB(ka->client); - VIR_FREE(ka); } @@ -311,12 +296,12 @@ virKeepAliveStart(virKeepAlivePtr ka, timeout = ka->interval - delay; ka->intervalStart = now - (ka->interval - timeout); ka->timer = virEventAddTimeout(timeout * 1000, virKeepAliveTimer, - ka, virKeepAliveTimerFree); + ka, (virFreeCallback)virObjectUnref); if (ka->timer < 0) goto cleanup; /* the timer now has another reference to this object */ - ka->refs++; + virObjectRef(ka); ret = 0; cleanup: diff --git a/src/rpc/virkeepalive.h b/src/rpc/virkeepalive.h index 52e1d04..0f77f34 100644 --- a/src/rpc/virkeepalive.h +++ b/src/rpc/virkeepalive.h @@ -24,6 +24,7 @@ # define __VIR_KEEPALIVE_H__ # include "virnetmessage.h" +# include "virobject.h" typedef int (*virKeepAliveSendFunc)(void *client, virNetMessagePtr msg); typedef void (*virKeepAliveDeadFunc)(void *client); @@ -42,9 +43,6 @@ virKeepAlivePtr virKeepAliveNew(int interval, ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6); -void virKeepAliveRef(virKeepAlivePtr ka); -void virKeepAliveFree(virKeepAlivePtr ka); - int virKeepAliveStart(virKeepAlivePtr ka, int interval, unsigned int count); diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index e611370..dc685fb 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -361,7 +361,7 @@ error: VIR_FORCE_CLOSE(wakeupFD[1]); if (ka) { virKeepAliveStop(ka); - virKeepAliveFree(ka); + virObjectUnref(ka); } virNetClientFree(client); return NULL; @@ -548,7 +548,7 @@ virNetClientCloseLocked(virNetClientPtr client) if (ka) { virKeepAliveStop(ka); - virKeepAliveFree(ka); + virObjectUnref(ka); } if (closeCb) closeCb(client, closeReason, closeOpaque); diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 471cca0..3a6439d 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -629,7 +629,7 @@ void virNetServerClientClose(virNetServerClientPtr client) client->keepalive = NULL; client->refs++; virNetServerClientUnlock(client); - virKeepAliveFree(ka); + virObjectUnref(ka); virNetServerClientLock(client); client->refs--; } @@ -1199,7 +1199,7 @@ cleanup: virNetServerClientUnlock(client); if (ka) virKeepAliveStop(ka); - virKeepAliveFree(ka); + virObjectUnref(ka); return ret; } -- 1.7.10.4

From: "Daniel P. Berrange" <berrange@redhat.com> Make virSocket use the virObject APIs for reference counting Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/libvirt_private.syms | 1 - src/libvirt_probes.d | 4 +-- src/qemu/qemu_migration.c | 4 +-- src/rpc/virnetclient.c | 4 +-- src/rpc/virnetserverclient.c | 4 +-- src/rpc/virnetserverservice.c | 4 +-- src/rpc/virnetsocket.c | 71 ++++++++++++++++++----------------------- src/rpc/virnetsocket.h | 3 +- tests/virnetsockettest.c | 26 +++++++-------- 9 files changed, 54 insertions(+), 67 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 50ed572..1bbbe49 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1558,7 +1558,6 @@ virNetSocketAccept; virNetSocketAddIOCallback; virNetSocketClose; virNetSocketDupFD; -virNetSocketFree; virNetSocketGetFD; virNetSocketGetPort; virNetSocketGetUNIXIdentity; diff --git a/src/libvirt_probes.d b/src/libvirt_probes.d index 807239f..be1d938 100644 --- a/src/libvirt_probes.d +++ b/src/libvirt_probes.d @@ -25,11 +25,9 @@ provider libvirt { # file: src/rpc/virnetsocket.c # prefix: rpc - probe rpc_socket_new(void *sock, int refs, int fd, int errfd, pid_t pid, const char *localAddr, const char *remoteAddr); + probe rpc_socket_new(void *sock, int fd, int errfd, pid_t pid, const char *localAddr, const char *remoteAddr); probe rpc_socket_send_fd(void *sock, int fd); probe rpc_socket_recv_fd(void *sock, int fd); - probe rpc_socket_ref(void *sock, int refs); - probe rpc_socket_free(void *sock, int refs); # file: src/rpc/virnetserverclient.c diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index b7a417f..4216e4e 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1805,7 +1805,7 @@ qemuMigrationConnect(struct qemud_driver *driver, goto cleanup; if (virNetSocketNewConnectTCP(host, port, &sock) == 0) { spec->dest.fd.qemu = virNetSocketDupFD(sock, true); - virNetSocketFree(sock); + virObjectUnref(sock); } if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0 || spec->dest.fd.qemu == -1) @@ -2157,7 +2157,7 @@ cleanup: VIR_FORCE_CLOSE(spec.dest.fd.qemu); VIR_FORCE_CLOSE(spec.dest.fd.local); } else { - virNetSocketFree(sock); + virObjectUnref(sock); VIR_FREE(spec.dest.unix_socket.file); } diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index dc685fb..808c502 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -494,7 +494,7 @@ void virNetClientFree(virNetClientPtr client) if (client->sock) virNetSocketRemoveIOCallback(client->sock); - virNetSocketFree(client->sock); + virObjectUnref(client->sock); virObjectUnref(client->tls); #if HAVE_SASL virObjectUnref(client->sasl); @@ -527,7 +527,7 @@ virNetClientCloseLocked(virNetClientPtr client) if (!client->sock) return; - virNetSocketFree(client->sock); + virObjectUnref(client->sock); client->sock = NULL; virObjectUnref(client->tls); client->tls = NULL; diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 3a6439d..85f7c88 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -596,7 +596,7 @@ void virNetServerClientFree(virNetServerClientPtr client) virEventRemoveTimeout(client->sockTimer); virObjectUnref(client->tls); virObjectUnref(client->tlsCtxt); - virNetSocketFree(client->sock); + virObjectUnref(client->sock); virNetServerClientUnlock(client); virMutexDestroy(&client->lock); VIR_FREE(client); @@ -667,7 +667,7 @@ void virNetServerClientClose(virNetServerClientPtr client) } if (client->sock) { - virNetSocketFree(client->sock); + virObjectUnref(client->sock); client->sock = NULL; } diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c index 60fe89f..93c0574 100644 --- a/src/rpc/virnetserverservice.c +++ b/src/rpc/virnetserverservice.c @@ -86,7 +86,7 @@ error: virNetServerClientClose(client); virNetServerClientFree(client); } else { - virNetSocketFree(clientsock); + virObjectUnref(clientsock); } } @@ -258,7 +258,7 @@ void virNetServerServiceFree(virNetServerServicePtr svc) return; for (i = 0 ; i < svc->nsocks ; i++) - virNetSocketFree(svc->socks[i]); + virObjectUnref(svc->socks[i]); VIR_FREE(svc->socks); virObjectUnref(svc->tls); diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index b6bb211..b6f156b 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -51,8 +51,9 @@ struct _virNetSocket { + virObject object; + virMutex lock; - int refs; int fd; int watch; @@ -85,6 +86,22 @@ struct _virNetSocket { }; +static virClassPtr virNetSocketClass; +static void virNetSocketDispose(void *obj); + +static int virNetSocketOnceInit(void) +{ + if (!(virNetSocketClass = virClassNew("virNetSocket", + sizeof(virNetSocket), + virNetSocketDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetSocket) + + #ifndef WIN32 static int virNetSocketForkDaemon(const char *binary) { @@ -114,6 +131,9 @@ static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, virNetSocketPtr sock; int no_slow_start = 1; + if (virNetSocketInitialize() < 0) + return NULL; + VIR_DEBUG("localAddr=%p remoteAddr=%p fd=%d errfd=%d pid=%lld", localAddr, remoteAddr, fd, errfd, (long long) pid); @@ -129,10 +149,8 @@ static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, return NULL; } - if (VIR_ALLOC(sock) < 0) { - virReportOOMError(); + if (!(sock = virObjectNew(virNetSocketClass))) return NULL; - } if (virMutexInit(&sock->lock) < 0) { virReportSystemError(errno, "%s", @@ -140,7 +158,6 @@ static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, VIR_FREE(sock); return NULL; } - sock->refs = 1; if (localAddr) sock->localAddr = *localAddr; @@ -174,15 +191,15 @@ static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, sock->client = isClient; PROBE(RPC_SOCKET_NEW, - "sock=%p refs=%d fd=%d errfd=%d pid=%lld localAddr=%s, remoteAddr=%s", - sock, sock->refs, fd, errfd, (long long) pid, + "sock=%p fd=%d errfd=%d pid=%lld localAddr=%s, remoteAddr=%s", + sock, fd, errfd, (long long) pid, NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr)); return sock; error: sock->fd = sock->errfd = -1; /* Caller owns fd/errfd on failure */ - virNetSocketFree(sock); + virObjectUnref(sock); return NULL; } @@ -296,7 +313,7 @@ int virNetSocketNewListenTCP(const char *nodename, error: for (i = 0 ; i < nsocks ; i++) - virNetSocketFree(socks[i]); + virObjectUnref(socks[i]); VIR_FREE(socks); freeaddrinfo(ai); VIR_FORCE_CLOSE(fd); @@ -704,32 +721,9 @@ int virNetSocketNewConnectExternal(const char **cmdargv, } -void virNetSocketRef(virNetSocketPtr sock) -{ - virMutexLock(&sock->lock); - sock->refs++; - PROBE(RPC_SOCKET_REF, - "sock=%p refs=%d", - sock, sock->refs); - virMutexUnlock(&sock->lock); -} - - -void virNetSocketFree(virNetSocketPtr sock) +void virNetSocketDispose(void *obj) { - if (!sock) - return; - - virMutexLock(&sock->lock); - PROBE(RPC_SOCKET_FREE, - "sock=%p refs=%d", - sock, sock->refs); - - sock->refs--; - if (sock->refs > 0) { - virMutexUnlock(&sock->lock); - return; - } + virNetSocketPtr sock = obj; VIR_DEBUG("sock=%p fd=%d", sock, sock->fd); if (sock->watch > 0) { @@ -761,10 +755,7 @@ void virNetSocketFree(virNetSocketPtr sock) VIR_FREE(sock->localAddrStr); VIR_FREE(sock->remoteAddrStr); - virMutexUnlock(&sock->lock); virMutexDestroy(&sock->lock); - - VIR_FREE(sock); } @@ -1331,7 +1322,7 @@ static void virNetSocketEventFree(void *opaque) if (ff) ff(eopaque); - virNetSocketFree(sock); + virObjectUnref(sock); } int virNetSocketAddIOCallback(virNetSocketPtr sock, @@ -1342,7 +1333,7 @@ int virNetSocketAddIOCallback(virNetSocketPtr sock, { int ret = -1; - virNetSocketRef(sock); + virObjectRef(sock); virMutexLock(&sock->lock); if (sock->watch > 0) { VIR_DEBUG("Watch already registered on socket %p", sock); @@ -1366,7 +1357,7 @@ int virNetSocketAddIOCallback(virNetSocketPtr sock, cleanup: virMutexUnlock(&sock->lock); if (ret != 0) - virNetSocketFree(sock); + virObjectUnref(sock); return ret; } diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h index 6c8e77c..cc3f912 100644 --- a/src/rpc/virnetsocket.h +++ b/src/rpc/virnetsocket.h @@ -27,6 +27,7 @@ # include "virsocketaddr.h" # include "command.h" # include "virnettlscontext.h" +# include "virobject.h" # ifdef HAVE_SASL # include "virnetsaslcontext.h" # endif @@ -108,8 +109,6 @@ void virNetSocketSetSASLSession(virNetSocketPtr sock, # endif bool virNetSocketHasCachedData(virNetSocketPtr sock); bool virNetSocketHasPendingData(virNetSocketPtr sock); -void virNetSocketRef(virNetSocketPtr sock); -void virNetSocketFree(virNetSocketPtr sock); const char *virNetSocketLocalAddrString(virNetSocketPtr sock); const char *virNetSocketRemoteAddrString(virNetSocketPtr sock); diff --git a/tests/virnetsockettest.c b/tests/virnetsockettest.c index 0f7bbad..0395601 100644 --- a/tests/virnetsockettest.c +++ b/tests/virnetsockettest.c @@ -172,7 +172,7 @@ static int testSocketTCPAccept(const void *opaque) if (virNetSocketNewConnectTCP(data->cnode, portstr, &csock) < 0) goto cleanup; - virNetSocketFree(csock); + virObjectUnref(csock); for (i = 0 ; i < nlsock ; i++) { if (virNetSocketAccept(lsock[i], &ssock) != -1 && ssock) { @@ -183,16 +183,16 @@ static int testSocketTCPAccept(const void *opaque) goto cleanup; } } - virNetSocketFree(ssock); + virObjectUnref(ssock); ssock = NULL; } ret = 0; cleanup: - virNetSocketFree(ssock); + virObjectUnref(ssock); for (i = 0 ; i < nlsock ; i++) - virNetSocketFree(lsock[i]); + virObjectUnref(lsock[i]); VIR_FREE(lsock); return ret; } @@ -228,7 +228,7 @@ static int testSocketUNIXAccept(const void *data ATTRIBUTE_UNUSED) if (virNetSocketNewConnectUNIX(path, false, NULL, &csock) < 0) goto cleanup; - virNetSocketFree(csock); + virObjectUnref(csock); if (virNetSocketAccept(lsock, &ssock) != -1) { char c = 'a'; @@ -242,8 +242,8 @@ static int testSocketUNIXAccept(const void *data ATTRIBUTE_UNUSED) cleanup: VIR_FREE(path); - virNetSocketFree(lsock); - virNetSocketFree(ssock); + virObjectUnref(lsock); + virObjectUnref(ssock); if (tmpdir) rmdir(tmpdir); return ret; @@ -320,9 +320,9 @@ static int testSocketUNIXAddrs(const void *data ATTRIBUTE_UNUSED) cleanup: VIR_FREE(path); - virNetSocketFree(lsock); - virNetSocketFree(ssock); - virNetSocketFree(csock); + virObjectUnref(lsock); + virObjectUnref(ssock); + virObjectUnref(csock); if (tmpdir) rmdir(tmpdir); return ret; @@ -352,7 +352,7 @@ static int testSocketCommandNormal(const void *data ATTRIBUTE_UNUSED) ret = 0; cleanup: - virNetSocketFree(csock); + virObjectUnref(csock); return ret; } @@ -375,7 +375,7 @@ static int testSocketCommandFail(const void *data ATTRIBUTE_UNUSED) ret = 0; cleanup: - virNetSocketFree(csock); + virObjectUnref(csock); return ret; } @@ -444,7 +444,7 @@ static int testSocketSSH(const void *opaque) ret = 0; cleanup: - virNetSocketFree(csock); + virObjectUnref(csock); return ret; } -- 1.7.10.4

From: "Daniel P. Berrange" <berrange@redhat.com> Make all the virNetServer* objects use the virObject APIs for reference counting Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- daemon/libvirtd.c | 22 ++++----- daemon/stream.c | 19 ++------ src/libvirt_private.syms | 7 --- src/libvirt_probes.d | 4 +- src/lxc/lxc_controller.c | 8 +-- src/rpc/virnetserver.c | 79 ++++++++++++++---------------- src/rpc/virnetserver.h | 5 +- src/rpc/virnetserverclient.c | 108 ++++++++++++++++++----------------------- src/rpc/virnetserverclient.h | 5 +- src/rpc/virnetserverprogram.c | 49 ++++++++++--------- src/rpc/virnetserverprogram.h | 8 +-- src/rpc/virnetserverservice.c | 83 +++++++++++++++---------------- src/rpc/virnetserverservice.h | 5 +- 13 files changed, 172 insertions(+), 230 deletions(-) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 3ccd70a..55af7bf 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -568,10 +568,10 @@ static int daemonSetupNetworking(virNetServerPtr srv, return 0; error: - virNetServerServiceFree(svcTLS); - virNetServerServiceFree(svcTCP); - virNetServerServiceFree(svc); - virNetServerServiceFree(svcRO); + virObjectUnref(svcTLS); + virObjectUnref(svcTCP); + virObjectUnref(svc); + virObjectUnref(svcRO); return -1; } @@ -759,21 +759,21 @@ static void daemonRunStateInit(void *opaque) VIR_ERROR(_("Driver state initialization failed")); /* Ensure the main event loop quits */ kill(getpid(), SIGTERM); - virNetServerFree(srv); + virObjectUnref(srv); return; } /* Only now accept clients from network */ virNetServerUpdateServices(srv, true); - virNetServerFree(srv); + virObjectUnref(srv); } static int daemonStateInit(virNetServerPtr srv) { virThread thr; - virNetServerRef(srv); + virObjectRef(srv); if (virThreadCreate(&thr, false, daemonRunStateInit, srv) < 0) { - virNetServerFree(srv); + virObjectUnref(srv); return -1; } return 0; @@ -1324,10 +1324,10 @@ int main(int argc, char **argv) { cleanup: virNetlinkEventServiceStop(); - virNetServerProgramFree(remoteProgram); - virNetServerProgramFree(qemuProgram); + virObjectUnref(remoteProgram); + virObjectUnref(qemuProgram); virNetServerClose(srv); - virNetServerFree(srv); + virObjectUnref(srv); virNetlinkShutdown(); if (statuswrite != -1) { if (ret != 0) { diff --git a/daemon/stream.c b/daemon/stream.c index 6f26ee5..32d33c0 100644 --- a/daemon/stream.c +++ b/daemon/stream.c @@ -104,14 +104,6 @@ daemonStreamMessageFinished(virNetMessagePtr msg ATTRIBUTE_UNUSED, } -static void -daemonStreamEventFreeFunc(void *opaque) -{ - virNetServerClientPtr client = opaque; - - virNetServerClientFree(client); -} - /* * Callback that gets invoked when a stream becomes writable/readable */ @@ -332,14 +324,12 @@ daemonCreateClientStream(virNetServerClientPtr client, stream->refs = 1; stream->priv = priv; - stream->prog = prog; + stream->prog = virObjectRef(prog); stream->procedure = header->proc; stream->serial = header->serial; stream->filterID = -1; stream->st = st; - virNetServerProgramRef(prog); - return stream; } @@ -365,7 +355,7 @@ int daemonFreeClientStream(virNetServerClientPtr client, VIR_DEBUG("client=%p, proc=%d, serial=%d", client, stream->procedure, stream->serial); - virNetServerProgramFree(stream->prog); + virObjectUnref(stream->prog); msg = stream->rx; while (msg) { @@ -411,10 +401,11 @@ int daemonAddClientStream(virNetServerClientPtr client, if (virStreamEventAddCallback(stream->st, 0, daemonStreamEvent, client, - daemonStreamEventFreeFunc) < 0) + (virFreeCallback)virObjectUnref) < 0) return -1; - virNetServerClientRef(client); + virObjectRef(client); + if ((stream->filterID = virNetServerClientAddFilter(client, daemonStreamFilter, stream)) < 0) { diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1bbbe49..71bd4f2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1464,14 +1464,11 @@ virNetServerAddService; virNetServerAddSignalHandler; virNetServerAutoShutdown; virNetServerClose; -virNetServerFree; virNetServerIsPrivileged; virNetServerKeepAliveRequired; virNetServerNew; virNetServerQuit; -virNetServerRef; virNetServerRun; -virNetServerServiceFree; virNetServerServiceNewTCP; virNetServerServiceNewUNIX; virNetServerSetTLSContext; @@ -1482,7 +1479,6 @@ virNetServerUpdateServices; virNetServerClientAddFilter; virNetServerClientClose; virNetServerClientDelayedClose; -virNetServerClientFree; virNetServerClientGetAuth; virNetServerClientGetFD; virNetServerClientGetIdentity; @@ -1499,7 +1495,6 @@ virNetServerClientIsSecure; virNetServerClientLocalAddrString; virNetServerClientNeedAuth; virNetServerClientNew; -virNetServerClientRef; virNetServerClientRemoteAddrString; virNetServerClientRemoveFilter; virNetServerClientSendMessage; @@ -1527,13 +1522,11 @@ virNetServerMDNSStop; # virnetserverprogram.h virNetServerProgramDispatch; -virNetServerProgramFree; virNetServerProgramGetID; virNetServerProgramGetPriority; virNetServerProgramGetVersion; virNetServerProgramMatches; virNetServerProgramNew; -virNetServerProgramRef; virNetServerProgramSendReplyError; virNetServerProgramSendStreamData; virNetServerProgramSendStreamError; diff --git a/src/libvirt_probes.d b/src/libvirt_probes.d index be1d938..27f4e9a 100644 --- a/src/libvirt_probes.d +++ b/src/libvirt_probes.d @@ -32,9 +32,7 @@ provider libvirt { # file: src/rpc/virnetserverclient.c # prefix: rpc - probe rpc_server_client_new(void *client, int refs, void *sock); - probe rpc_server_client_ref(void *client, int refs); - probe rpc_server_client_free(void *client, int refs); + probe rpc_server_client_new(void *client, void *sock); probe rpc_server_client_msg_tx_queue(void *client, int len, int prog, int vers, int proc, int type, int status, int serial); probe rpc_server_client_msg_rx(void *client, int len, int prog, int vers, int proc, int type, int status, int serial); diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 56ed7d3..9bc8603 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -264,7 +264,7 @@ static void virLXCControllerFree(virLXCControllerPtr ctrl) if (ctrl->timerShutdown != -1) virEventRemoveTimeout(ctrl->timerShutdown); - virNetServerFree(ctrl->server); + virObjectUnref(ctrl->server); VIR_FREE(ctrl); } @@ -620,7 +620,7 @@ static int virLXCControllerSetupServer(virLXCControllerPtr ctrl) if (virNetServerAddService(ctrl->server, svc, NULL) < 0) goto error; - virNetServerServiceFree(svc); + virObjectUnref(svc); svc = NULL; if (!(ctrl->prog = virNetServerProgramNew(VIR_LXC_PROTOCOL_PROGRAM, @@ -635,9 +635,9 @@ static int virLXCControllerSetupServer(virLXCControllerPtr ctrl) error: VIR_FREE(sockpath); - virNetServerFree(ctrl->server); + virObjectUnref(ctrl->server); ctrl->server = NULL; - virNetServerServiceFree(svc); + virObjectUnref(svc); return -1; } diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index e9f500e..ecab0e0 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -66,7 +66,7 @@ struct _virNetServerJob { }; struct _virNetServer { - int refs; + virObjectPtr object; virMutex lock; @@ -113,6 +113,22 @@ struct _virNetServer { }; +static virClassPtr virNetServerClass; +static void virNetServerDispose(void *obj); + +static int virNetServerOnceInit(void) +{ + if (!(virNetServerClass = virClassNew("virNetServer", + sizeof(virNetServer), + virNetServerDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetServer) + + static void virNetServerLock(virNetServerPtr srv) { virMutexLock(&srv->lock); @@ -179,18 +195,18 @@ static void virNetServerHandleJob(void *jobOpaque, void *opaque) goto error; virNetServerLock(srv); - virNetServerProgramFree(job->prog); + virObjectUnref(job->prog); virNetServerUnlock(srv); - virNetServerClientFree(job->client); + virObjectUnref(job->client); VIR_FREE(job); return; error: - virNetServerProgramFree(job->prog); + virObjectUnref(job->prog); virNetMessageFree(job->msg); virNetServerClientClose(job->client); - virNetServerClientFree(job->client); + virObjectUnref(job->client); VIR_FREE(job); } @@ -227,7 +243,7 @@ static int virNetServerDispatchNewMessage(virNetServerClientPtr client, job->msg = msg; if (prog) { - virNetServerProgramRef(prog); + virObjectRef(prog); job->prog = prog; priority = virNetServerProgramGetPriority(prog, msg->header.proc); } @@ -236,7 +252,7 @@ static int virNetServerDispatchNewMessage(virNetServerClientPtr client, if (ret < 0) { VIR_FREE(job); - virNetServerProgramFree(prog); + virObjectUnref(prog); } } else { ret = virNetServerProcessMsg(srv, client, prog, msg); @@ -276,7 +292,7 @@ static int virNetServerDispatchNewClient(virNetServerServicePtr svc ATTRIBUTE_UN goto error; } srv->clients[srv->nclients-1] = client; - virNetServerClientRef(client); + virObjectRef(client); virNetServerClientSetDispatcher(client, virNetServerDispatchNewMessage, @@ -336,12 +352,11 @@ virNetServerPtr virNetServerNew(size_t min_workers, virNetServerPtr srv; struct sigaction sig_action; - if (VIR_ALLOC(srv) < 0) { - virReportOOMError(); + if (virNetServerInitialize() < 0) return NULL; - } - srv->refs = 1; + if (!(srv = virObjectNew(virNetServerClass))) + return NULL; if (max_workers && !(srv->workers = virThreadPoolNew(min_workers, max_workers, @@ -404,24 +419,14 @@ virNetServerPtr virNetServerNew(size_t min_workers, sigaction(SIGUSR2, &sig_action, NULL); #endif - VIR_DEBUG("srv=%p refs=%d", srv, srv->refs); return srv; error: - virNetServerFree(srv); + virObjectUnref(srv); return NULL; } -void virNetServerRef(virNetServerPtr srv) -{ - virNetServerLock(srv); - srv->refs++; - VIR_DEBUG("srv=%p refs=%d", srv, srv->refs); - virNetServerUnlock(srv); -} - - bool virNetServerIsPrivileged(virNetServerPtr srv) { bool priv; @@ -611,7 +616,7 @@ int virNetServerAddService(virNetServerPtr srv, #endif srv->services[srv->nservices-1] = svc; - virNetServerServiceRef(svc); + virObjectRef(svc); virNetServerServiceSetDispatcher(svc, virNetServerDispatchNewClient, @@ -637,8 +642,7 @@ int virNetServerAddProgram(virNetServerPtr srv, if (VIR_EXPAND_N(srv->programs, srv->nprograms, 1) < 0) goto no_memory; - srv->programs[srv->nprograms-1] = prog; - virNetServerProgramRef(prog); + srv->programs[srv->nprograms-1] = virObjectRef(prog); virNetServerUnlock(srv); return 0; @@ -749,7 +753,7 @@ void virNetServerRun(virNetServerPtr srv) if (virNetServerClientWantClose(srv->clients[i])) virNetServerClientClose(srv->clients[i]); if (virNetServerClientIsClosed(srv->clients[i])) { - virNetServerClientFree(srv->clients[i]); + virObjectUnref(srv->clients[i]); if (srv->nclients > 1) { memmove(srv->clients + i, srv->clients + i + 1, @@ -780,20 +784,10 @@ void virNetServerQuit(virNetServerPtr srv) virNetServerUnlock(srv); } -void virNetServerFree(virNetServerPtr srv) +void virNetServerDispose(void *obj) { + virNetServerPtr srv = obj; int i; - int refs; - - if (!srv) - return; - - virNetServerLock(srv); - VIR_DEBUG("srv=%p refs=%d", srv, srv->refs); - refs = --srv->refs; - virNetServerUnlock(srv); - if (refs > 0) - return; for (i = 0 ; i < srv->nservices ; i++) virNetServerServiceToggle(srv->services[i], false); @@ -811,16 +805,16 @@ void virNetServerFree(virNetServerPtr srv) virEventRemoveHandle(srv->sigwatch); for (i = 0 ; i < srv->nservices ; i++) - virNetServerServiceFree(srv->services[i]); + virObjectUnref(srv->services[i]); VIR_FREE(srv->services); for (i = 0 ; i < srv->nprograms ; i++) - virNetServerProgramFree(srv->programs[i]); + virObjectUnref(srv->programs[i]); VIR_FREE(srv->programs); for (i = 0 ; i < srv->nclients ; i++) { virNetServerClientClose(srv->clients[i]); - virNetServerClientFree(srv->clients[i]); + virObjectUnref(srv->clients[i]); } VIR_FREE(srv->clients); @@ -830,7 +824,6 @@ void virNetServerFree(virNetServerPtr srv) #endif virMutexDestroy(&srv->lock); - VIR_FREE(srv); } void virNetServerClose(virNetServerPtr srv) diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h index 92f741a..7dc52ca 100644 --- a/src/rpc/virnetserver.h +++ b/src/rpc/virnetserver.h @@ -30,6 +30,7 @@ # include "virnetserverprogram.h" # include "virnetserverclient.h" # include "virnetserverservice.h" +# include "virobject.h" typedef int (*virNetServerClientInitHook)(virNetServerPtr srv, virNetServerClientPtr client, @@ -48,8 +49,6 @@ virNetServerPtr virNetServerNew(size_t min_workers, typedef int (*virNetServerAutoShutdownFunc)(virNetServerPtr srv, void *opaque); -void virNetServerRef(virNetServerPtr srv); - bool virNetServerIsPrivileged(virNetServerPtr srv); void virNetServerAutoShutdown(virNetServerPtr srv, @@ -81,8 +80,6 @@ void virNetServerRun(virNetServerPtr srv); void virNetServerQuit(virNetServerPtr srv); -void virNetServerFree(virNetServerPtr srv); - void virNetServerClose(virNetServerPtr srv); bool virNetServerKeepAliveRequired(virNetServerPtr srv); diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 85f7c88..d06d90e 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -57,7 +57,8 @@ struct _virNetServerClientFilter { struct _virNetServerClient { - int refs; + virObject object; + bool wantClose; bool delayedClose; virMutex lock; @@ -103,6 +104,22 @@ struct _virNetServerClient }; +static virClassPtr virNetServerClientClass; +static void virNetServerClientDispose(void *obj); + +static int virNetServerClientOnceInit(void) +{ + if (!(virNetServerClientClass = virClassNew("virNetServerClient", + sizeof(virNetServerClient), + virNetServerClientDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetServerClient) + + static void virNetServerClientDispatchEvent(virNetSocketPtr sock, int events, void *opaque); static void virNetServerClientUpdateEvent(virNetServerClientPtr client); static void virNetServerClientDispatchRead(virNetServerClientPtr client); @@ -167,13 +184,6 @@ virNetServerClientCalculateHandleMode(virNetServerClientPtr client) { return mode; } -static void virNetServerClientEventFree(void *opaque) -{ - virNetServerClientPtr client = opaque; - - virNetServerClientFree(client); -} - /* * @server: a locked or unlocked server object * @client: a locked client object @@ -182,15 +192,17 @@ static int virNetServerClientRegisterEvent(virNetServerClientPtr client) { int mode = virNetServerClientCalculateHandleMode(client); - client->refs++; + if (!client->sock) + return -1; + + virObjectRef(client); VIR_DEBUG("Registering client event callback %d", mode); - if (!client->sock || - virNetSocketAddIOCallback(client->sock, + if (virNetSocketAddIOCallback(client->sock, mode, virNetServerClientDispatchEvent, client, - virNetServerClientEventFree) < 0) { - client->refs--; + (virFreeCallback)virObjectUnref) < 0) { + virObjectUnref(client); return -1; } @@ -334,15 +346,17 @@ virNetServerClientPtr virNetServerClientNew(virNetSocketPtr sock, VIR_DEBUG("sock=%p auth=%d tls=%p", sock, auth, tls); - if (VIR_ALLOC(client) < 0) { - virReportOOMError(); + if (virNetServerClientInitialize() < 0) return NULL; - } - if (virMutexInit(&client->lock) < 0) - goto error; + if (!(client = virObjectNew(virNetServerClientClass))) + return NULL; + + if (virMutexInit(&client->lock) < 0) { + VIR_FREE(client); + return NULL; + } - client->refs = 1; client->sock = sock; client->auth = auth; client->readonly = readonly; @@ -365,28 +379,18 @@ virNetServerClientPtr virNetServerClientNew(virNetSocketPtr sock, client->nrequests = 1; PROBE(RPC_SERVER_CLIENT_NEW, - "client=%p refs=%d sock=%p", - client, client->refs, client->sock); + "client=%p sock=%p", + client, client->sock); return client; error: /* XXX ref counting is better than this */ client->sock = NULL; /* Caller owns 'sock' upon failure */ - virNetServerClientFree(client); + virObjectUnref(client); return NULL; } -void virNetServerClientRef(virNetServerClientPtr client) -{ - virNetServerClientLock(client); - client->refs++; - PROBE(RPC_SERVER_CLIENT_REF, - "client=%p refs=%d", - client, client->refs); - virNetServerClientUnlock(client); -} - int virNetServerClientGetAuth(virNetServerClientPtr client) { @@ -568,21 +572,9 @@ const char *virNetServerClientRemoteAddrString(virNetServerClientPtr client) } -void virNetServerClientFree(virNetServerClientPtr client) +void virNetServerClientDispose(void *obj) { - if (!client) - return; - - virNetServerClientLock(client); - PROBE(RPC_SERVER_CLIENT_FREE, - "client=%p refs=%d", - client, client->refs); - - client->refs--; - if (client->refs > 0) { - virNetServerClientUnlock(client); - return; - } + virNetServerClientPtr client = obj; if (client->privateData && client->privateDataFreeFunc) @@ -599,7 +591,6 @@ void virNetServerClientFree(virNetServerClientPtr client) virObjectUnref(client->sock); virNetServerClientUnlock(client); virMutexDestroy(&client->lock); - VIR_FREE(client); } @@ -617,7 +608,7 @@ void virNetServerClientClose(virNetServerClientPtr client) virKeepAlivePtr ka; virNetServerClientLock(client); - VIR_DEBUG("client=%p refs=%d", client, client->refs); + VIR_DEBUG("client=%p", client); if (!client->sock) { virNetServerClientUnlock(client); return; @@ -627,20 +618,20 @@ void virNetServerClientClose(virNetServerClientPtr client) virKeepAliveStop(client->keepalive); ka = client->keepalive; client->keepalive = NULL; - client->refs++; + virObjectRef(client); virNetServerClientUnlock(client); virObjectUnref(ka); virNetServerClientLock(client); - client->refs--; + virObjectUnref(client); } if (client->privateDataCloseFunc) { cf = client->privateDataCloseFunc; - client->refs++; + virObjectRef(client); virNetServerClientUnlock(client); (cf)(client); virNetServerClientLock(client); - client->refs--; + virObjectUnref(client); } /* Do now, even though we don't close the socket @@ -904,12 +895,12 @@ readmore: /* Send off to for normal dispatch to workers */ if (msg) { - client->refs++; + virObjectRef(client); if (!client->dispatchFunc || client->dispatchFunc(client, msg, client->dispatchOpaque) < 0) { virNetMessageFree(msg); client->wantClose = true; - client->refs--; + virObjectUnref(client); return; } } @@ -1168,11 +1159,6 @@ virNetServerClientKeepAliveSendCB(void *opaque, return virNetServerClientSendMessage(opaque, msg); } -static void -virNetServerClientFreeCB(void *opaque) -{ - virNetServerClientFree(opaque); -} int virNetServerClientInitKeepAlive(virNetServerClientPtr client, @@ -1187,10 +1173,10 @@ virNetServerClientInitKeepAlive(virNetServerClientPtr client, if (!(ka = virKeepAliveNew(interval, count, client, virNetServerClientKeepAliveSendCB, virNetServerClientKeepAliveDeadCB, - virNetServerClientFreeCB))) + (virFreeCallback)virObjectUnref))) goto cleanup; /* keepalive object has a reference to client */ - client->refs++; + virObjectRef(client); client->keepalive = ka; ka = NULL; diff --git a/src/rpc/virnetserverclient.h b/src/rpc/virnetserverclient.h index 606c428..a1ff19b 100644 --- a/src/rpc/virnetserverclient.h +++ b/src/rpc/virnetserverclient.h @@ -26,6 +26,7 @@ # include "virnetsocket.h" # include "virnetmessage.h" +# include "virobject.h" typedef struct _virNetServerClient virNetServerClient; typedef virNetServerClient *virNetServerClientPtr; @@ -73,8 +74,6 @@ const char *virNetServerClientGetIdentity(virNetServerClientPtr client); int virNetServerClientGetUNIXIdentity(virNetServerClientPtr client, uid_t *uid, gid_t *gid, pid_t *pid); -void virNetServerClientRef(virNetServerClientPtr client); - typedef void (*virNetServerClientFreeFunc)(void *data); void virNetServerClientSetPrivateData(virNetServerClientPtr client, @@ -114,7 +113,5 @@ int virNetServerClientSendMessage(virNetServerClientPtr client, bool virNetServerClientNeedAuth(virNetServerClientPtr client); -void virNetServerClientFree(virNetServerClientPtr client); - #endif /* __VIR_NET_SERVER_CLIENT_H__ */ diff --git a/src/rpc/virnetserverprogram.c b/src/rpc/virnetserverprogram.c index c083fb3..d13b621 100644 --- a/src/rpc/virnetserverprogram.c +++ b/src/rpc/virnetserverprogram.c @@ -30,11 +30,12 @@ #include "virterror_internal.h" #include "logging.h" #include "virfile.h" +#include "threads.h" #define VIR_FROM_THIS VIR_FROM_RPC struct _virNetServerProgram { - int refs; + virObject object; unsigned program; unsigned version; @@ -42,6 +43,23 @@ struct _virNetServerProgram { size_t nprocs; }; + +static virClassPtr virNetServerProgramClass; +static void virNetServerProgramDispose(void *obj); + +static int virNetServerProgramOnceInit(void) +{ + if (!(virNetServerProgramClass = virClassNew("virNetServerProgram", + sizeof(virNetServerProgram), + virNetServerProgramDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetServerProgram) + + virNetServerProgramPtr virNetServerProgramNew(unsigned program, unsigned version, virNetServerProgramProcPtr procs, @@ -49,18 +67,18 @@ virNetServerProgramPtr virNetServerProgramNew(unsigned program, { virNetServerProgramPtr prog; - if (VIR_ALLOC(prog) < 0) { - virReportOOMError(); + if (virNetServerProgramInitialize() < 0) + return NULL; + + if (!(prog = virObjectNew(virNetServerProgramClass))) return NULL; - } - prog->refs = 1; prog->program = program; prog->version = version; prog->procs = procs; prog->nprocs = nprocs; - VIR_DEBUG("prog=%p refs=%d", prog, prog->refs); + VIR_DEBUG("prog=%p", prog); return prog; } @@ -78,13 +96,6 @@ int virNetServerProgramGetVersion(virNetServerProgramPtr prog) } -void virNetServerProgramRef(virNetServerProgramPtr prog) -{ - prog->refs++; - VIR_DEBUG("prog=%p refs=%d", prog, prog->refs); -} - - int virNetServerProgramMatches(virNetServerProgramPtr prog, virNetMessagePtr msg) { @@ -516,16 +527,6 @@ int virNetServerProgramSendStreamData(virNetServerProgramPtr prog, } -void virNetServerProgramFree(virNetServerProgramPtr prog) +void virNetServerProgramDispose(void *obj ATTRIBUTE_UNUSED) { - if (!prog) - return; - - VIR_DEBUG("prog=%p refs=%d", prog, prog->refs); - - prog->refs--; - if (prog->refs > 0) - return; - - VIR_FREE(prog); } diff --git a/src/rpc/virnetserverprogram.h b/src/rpc/virnetserverprogram.h index 015ecef..99e1661 100644 --- a/src/rpc/virnetserverprogram.h +++ b/src/rpc/virnetserverprogram.h @@ -26,6 +26,7 @@ # include "virnetmessage.h" # include "virnetserverclient.h" +# include "virobject.h" typedef struct _virNetServer virNetServer; typedef virNetServer *virNetServerPtr; @@ -67,8 +68,6 @@ int virNetServerProgramGetVersion(virNetServerProgramPtr prog); unsigned int virNetServerProgramGetPriority(virNetServerProgramPtr prog, int procedure); -void virNetServerProgramRef(virNetServerProgramPtr prog); - int virNetServerProgramMatches(virNetServerProgramPtr prog, virNetMessagePtr msg); @@ -102,9 +101,4 @@ int virNetServerProgramSendStreamData(virNetServerProgramPtr prog, const char *data, size_t len); -void virNetServerProgramFree(virNetServerProgramPtr prog); - - - - #endif /* __VIR_NET_SERVER_PROGRAM_H__ */ diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c index 93c0574..c464127 100644 --- a/src/rpc/virnetserverservice.c +++ b/src/rpc/virnetserverservice.c @@ -27,12 +27,12 @@ #include "memory.h" #include "virterror_internal.h" - +#include "threads.h" #define VIR_FROM_THIS VIR_FROM_RPC struct _virNetServerService { - int refs; + virObject object; size_t nsocks; virNetSocketPtr *socks; @@ -48,6 +48,21 @@ struct _virNetServerService { }; +static virClassPtr virNetServerServiceClass; +static void virNetServerServiceDispose(void *obj); + +static int virNetServerServiceOnceInit(void) +{ + if (!(virNetServerServiceClass = virClassNew("virNetServerService", + sizeof(virNetServerService), + virNetServerServiceDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetServerService) + static void virNetServerServiceAccept(virNetSocketPtr sock, int events ATTRIBUTE_UNUSED, @@ -76,7 +91,7 @@ static void virNetServerServiceAccept(virNetSocketPtr sock, if (svc->dispatchFunc(svc, client, svc->dispatchOpaque) < 0) virNetServerClientClose(client); - virNetServerClientFree(client); + virObjectUnref(client); cleanup: return; @@ -84,21 +99,13 @@ cleanup: error: if (client) { virNetServerClientClose(client); - virNetServerClientFree(client); + virObjectUnref(client); } else { virObjectUnref(clientsock); } } -static void virNetServerServiceEventFree(void *opaque) -{ - virNetServerServicePtr svc = opaque; - - virNetServerServiceFree(svc); -} - - virNetServerServicePtr virNetServerServiceNewTCP(const char *nodename, const char *service, int auth, @@ -109,10 +116,12 @@ virNetServerServicePtr virNetServerServiceNewTCP(const char *nodename, virNetServerServicePtr svc; size_t i; - if (VIR_ALLOC(svc) < 0) - goto no_memory; + if (virNetServerServiceInitialize() < 0) + return NULL; + + if (!(svc = virObjectNew(virNetServerServiceClass))) + return NULL; - svc->refs = 1; svc->auth = auth; svc->readonly = readonly; svc->nrequests_client_max = nrequests_client_max; @@ -130,13 +139,13 @@ virNetServerServicePtr virNetServerServiceNewTCP(const char *nodename, /* IO callback is initially disabled, until we're ready * to deal with incoming clients */ - virNetServerServiceRef(svc); + virObjectRef(svc); if (virNetSocketAddIOCallback(svc->socks[i], 0, virNetServerServiceAccept, svc, - virNetServerServiceEventFree) < 0) { - virNetServerServiceFree(svc); + (virFreeCallback)virObjectUnref) < 0) { + virObjectUnref(svc); goto error; } } @@ -144,10 +153,8 @@ virNetServerServicePtr virNetServerServiceNewTCP(const char *nodename, return svc; -no_memory: - virReportOOMError(); error: - virNetServerServiceFree(svc); + virObjectUnref(svc); return NULL; } @@ -163,10 +170,12 @@ virNetServerServicePtr virNetServerServiceNewUNIX(const char *path, virNetServerServicePtr svc; int i; - if (VIR_ALLOC(svc) < 0) - goto no_memory; + if (virNetServerServiceInitialize() < 0) + return NULL; + + if (!(svc = virObjectNew(virNetServerServiceClass))) + return NULL; - svc->refs = 1; svc->auth = auth; svc->readonly = readonly; svc->nrequests_client_max = nrequests_client_max; @@ -189,13 +198,13 @@ virNetServerServicePtr virNetServerServiceNewUNIX(const char *path, /* IO callback is initially disabled, until we're ready * to deal with incoming clients */ - virNetServerServiceRef(svc); + virObjectRef(svc); if (virNetSocketAddIOCallback(svc->socks[i], 0, virNetServerServiceAccept, svc, - virNetServerServiceEventFree) < 0) { - virNetServerServiceFree(svc); + (virFreeCallback)virObjectUnref) < 0) { + virObjectUnref(svc); goto error; } } @@ -206,7 +215,7 @@ virNetServerServicePtr virNetServerServiceNewUNIX(const char *path, no_memory: virReportOOMError(); error: - virNetServerServiceFree(svc); + virObjectUnref(svc); return NULL; } @@ -231,12 +240,6 @@ bool virNetServerServiceIsReadonly(virNetServerServicePtr svc) } -void virNetServerServiceRef(virNetServerServicePtr svc) -{ - svc->refs++; -} - - void virNetServerServiceSetDispatcher(virNetServerServicePtr svc, virNetServerServiceDispatchFunc func, void *opaque) @@ -246,24 +249,16 @@ void virNetServerServiceSetDispatcher(virNetServerServicePtr svc, } -void virNetServerServiceFree(virNetServerServicePtr svc) +void virNetServerServiceDispose(void *obj) { + virNetServerServicePtr svc = obj; int i; - if (!svc) - return; - - svc->refs--; - if (svc->refs > 0) - return; - for (i = 0 ; i < svc->nsocks ; i++) virObjectUnref(svc->socks[i]); VIR_FREE(svc->socks); virObjectUnref(svc->tls); - - VIR_FREE(svc); } void virNetServerServiceToggle(virNetServerServicePtr svc, diff --git a/src/rpc/virnetserverservice.h b/src/rpc/virnetserverservice.h index d6bf98b..98fd396 100644 --- a/src/rpc/virnetserverservice.h +++ b/src/rpc/virnetserverservice.h @@ -25,6 +25,7 @@ # define __VIR_NET_SERVER_SERVICE_H__ # include "virnetserverprogram.h" +# include "virobject.h" enum { VIR_NET_SERVER_SERVICE_AUTH_NONE = 0, @@ -55,14 +56,10 @@ int virNetServerServiceGetPort(virNetServerServicePtr svc); int virNetServerServiceGetAuth(virNetServerServicePtr svc); bool virNetServerServiceIsReadonly(virNetServerServicePtr svc); -void virNetServerServiceRef(virNetServerServicePtr svc); - void virNetServerServiceSetDispatcher(virNetServerServicePtr svc, virNetServerServiceDispatchFunc func, void *opaque); -void virNetServerServiceFree(virNetServerServicePtr svc); - void virNetServerServiceToggle(virNetServerServicePtr svc, bool enabled); -- 1.7.10.4

From: "Daniel P. Berrange" <berrange@redhat.com> Make all the virNetClient* objects use virObject APIs for reference counting Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/libvirt_probes.d | 4 +- src/lxc/lxc_monitor.c | 4 +- src/remote/remote_driver.c | 20 ++++----- src/rpc/gendispatch.pl | 4 +- src/rpc/virnetclient.c | 96 +++++++++++++++++------------------------ src/rpc/virnetclient.h | 4 +- src/rpc/virnetclientprogram.c | 43 +++++++++--------- src/rpc/virnetclientprogram.h | 5 +-- src/rpc/virnetclientstream.c | 65 +++++++++++++--------------- src/rpc/virnetclientstream.h | 5 +-- 10 files changed, 110 insertions(+), 140 deletions(-) diff --git a/src/libvirt_probes.d b/src/libvirt_probes.d index 27f4e9a..9343fa4 100644 --- a/src/libvirt_probes.d +++ b/src/libvirt_probes.d @@ -40,9 +40,7 @@ provider libvirt { # file: src/rpc/virnetclient.c # prefix: rpc - probe rpc_client_new(void *client, int refs, void *sock); - probe rpc_client_ref(void *client, int refs); - probe rpc_client_free(void *client, int refs); + probe rpc_client_new(void *client, void *sock); probe rpc_client_msg_tx_queue(void *client, int len, int prog, int vers, int proc, int type, int status, int serial); probe rpc_client_msg_rx(void *client, int len, int prog, int vers, int proc, int type, int status, int serial); diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c index a2a2599..a81d0f7 100644 --- a/src/lxc/lxc_monitor.c +++ b/src/lxc/lxc_monitor.c @@ -170,7 +170,7 @@ static void virLXCMonitorFree(virLXCMonitorPtr mon) if (mon->cb && mon->cb->destroy) (mon->cb->destroy)(mon, mon->vm); virMutexDestroy(&mon->lock); - virNetClientProgramFree(mon->program); + virObjectUnref(mon->program); VIR_FREE(mon); } @@ -199,7 +199,7 @@ void virLXCMonitorClose(virLXCMonitorPtr mon) { if (mon->client) { virNetClientClose(mon->client); - virNetClientFree(mon->client); + virObjectUnref(mon->client); mon->client = NULL; } } diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index bfea919..88a1573 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -792,10 +792,10 @@ doRemoteOpen (virConnectPtr conn, virReportOOMError(); failed: - virNetClientProgramFree(priv->remoteProgram); - virNetClientProgramFree(priv->qemuProgram); + virObjectUnref(priv->remoteProgram); + virObjectUnref(priv->qemuProgram); virNetClientClose(priv->client); - virNetClientFree(priv->client); + virObjectUnref(priv->client); priv->client = NULL; VIR_FREE(priv->hostname); @@ -946,10 +946,10 @@ doRemoteClose (virConnectPtr conn, struct private_data *priv) virObjectUnref(priv->tls); priv->tls = NULL; virNetClientClose(priv->client); - virNetClientFree(priv->client); + virObjectUnref(priv->client); priv->client = NULL; - virNetClientProgramFree(priv->remoteProgram); - virNetClientProgramFree(priv->qemuProgram); + virObjectUnref(priv->remoteProgram); + virObjectUnref(priv->qemuProgram); priv->remoteProgram = priv->qemuProgram = NULL; /* Free hostname copy */ @@ -4183,7 +4183,7 @@ remoteStreamFinish(virStreamPtr st) cleanup: virNetClientRemoveStream(priv->client, privst); - virNetClientStreamFree(privst); + virObjectUnref(privst); st->privateData = NULL; st->driver = NULL; @@ -4218,7 +4218,7 @@ remoteStreamAbort(virStreamPtr st) cleanup: virNetClientRemoveStream(priv->client, privst); - virNetClientStreamFree(privst); + virObjectUnref(privst); st->privateData = NULL; st->driver = NULL; @@ -4519,7 +4519,7 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn, goto done; if (virNetClientAddStream(priv->client, netst) < 0) { - virNetClientStreamFree(netst); + virObjectUnref(netst); goto done; } @@ -4537,7 +4537,7 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn, (xdrproc_t) xdr_remote_domain_migrate_prepare_tunnel3_args, (char *) &args, (xdrproc_t) xdr_remote_domain_migrate_prepare_tunnel3_ret, (char *) &ret) == -1) { virNetClientRemoveStream(priv->client, netst); - virNetClientStreamFree(netst); + virObjectUnref(netst); goto done; } diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 3a66445..12023e9 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -1450,7 +1450,7 @@ elsif ($opt_k) { print " goto done;\n"; print "\n"; print " if (virNetClientAddStream(priv->client, netst) < 0) {\n"; - print " virNetClientStreamFree(netst);\n"; + print " virObjectUnref(netst);\n"; print " goto done;\n"; print " }"; print "\n"; @@ -1526,7 +1526,7 @@ elsif ($opt_k) { if ($call->{streamflag} ne "none") { print " virNetClientRemoveStream(priv->client, netst);\n"; - print " virNetClientStreamFree(netst);\n"; + print " virObjectUnref(netst);\n"; print " st->driver = NULL;\n"; print " st->privateData = NULL;\n"; } diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index 808c502..27278a2 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -63,7 +63,7 @@ struct _virNetClientCall { struct _virNetClient { - int refs; + virObject object; virMutex lock; @@ -109,6 +109,21 @@ struct _virNetClient { }; +static virClassPtr virNetClientClass; +static void virNetClientDispose(void *obj); + +static int virNetClientOnceInit(void) +{ + if (!(virNetClientClass = virClassNew("virNetClient", + sizeof(virNetClient), + virNetClientDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetClient) + static void virNetClientIOEventLoopPassTheBuck(virNetClientPtr client, virNetClientCallPtr thiscall); static int virNetClientQueueNonBlocking(virNetClientPtr client, @@ -237,13 +252,6 @@ static bool virNetClientCallMatchPredicate(virNetClientCallPtr head, } -static void virNetClientEventFree(void *opaque) -{ - virNetClientPtr client = opaque; - - virNetClientFree(client); -} - bool virNetClientKeepAliveIsSupported(virNetClientPtr client) { @@ -303,19 +311,22 @@ static virNetClientPtr virNetClientNew(virNetSocketPtr sock, int wakeupFD[2] = { -1, -1 }; virKeepAlivePtr ka = NULL; + if (virNetClientInitialize() < 0) + return NULL; + if (pipe2(wakeupFD, O_CLOEXEC) < 0) { virReportSystemError(errno, "%s", _("unable to make pipe")); goto error; } - if (VIR_ALLOC(client) < 0) - goto no_memory; - - client->refs = 1; + if (!(client = virObjectNew(virNetClientClass))) + goto error; - if (virMutexInit(&client->lock) < 0) + if (virMutexInit(&client->lock) < 0) { + VIR_FREE(client); goto error; + } client->sock = sock; client->wakeupReadFD = wakeupFD[0]; @@ -327,13 +338,13 @@ static virNetClientPtr virNetClientNew(virNetSocketPtr sock, goto no_memory; /* Set up a callback to listen on the socket data */ - client->refs++; + virObjectRef(client); if (virNetSocketAddIOCallback(client->sock, VIR_EVENT_HANDLE_READABLE, virNetClientIncomingEvent, client, - virNetClientEventFree) < 0) { - client->refs--; + (virFreeCallback)virObjectUnref) < 0) { + virObjectUnref(client); VIR_DEBUG("Failed to add event watch, disabling events and support for" " keepalive messages"); } else { @@ -342,16 +353,16 @@ static virNetClientPtr virNetClientNew(virNetSocketPtr sock, if (!(ka = virKeepAliveNew(-1, 0, client, virNetClientKeepAliveSendCB, virNetClientKeepAliveDeadCB, - virNetClientEventFree))) + (virFreeCallback)virObjectUnref))) goto error; /* keepalive object has a reference to client */ - client->refs++; + virObjectRef(client); } client->keepalive = ka; PROBE(RPC_CLIENT_NEW, - "client=%p refs=%d sock=%p", - client, client->refs, client->sock); + "client=%p sock=%p", + client, client->sock); return client; no_memory: @@ -363,7 +374,7 @@ error: virKeepAliveStop(ka); virObjectUnref(ka); } - virNetClientFree(client); + virObjectUnref(client); return NULL; } @@ -422,17 +433,6 @@ virNetClientPtr virNetClientNewExternal(const char **cmdargv) } -void virNetClientRef(virNetClientPtr client) -{ - virNetClientLock(client); - client->refs++; - PROBE(RPC_CLIENT_REF, - "client=%p refs=%d", - client, client->refs); - virNetClientUnlock(client); -} - - int virNetClientGetFD(virNetClientPtr client) { int fd; @@ -463,28 +463,16 @@ bool virNetClientHasPassFD(virNetClientPtr client) } -void virNetClientFree(virNetClientPtr client) +void virNetClientDispose(void *obj) { + virNetClientPtr client = obj; int i; - if (!client) - return; - - virNetClientLock(client); - PROBE(RPC_CLIENT_FREE, - "client=%p refs=%d", - client, client->refs); - client->refs--; - if (client->refs > 0) { - virNetClientUnlock(client); - return; - } - if (client->closeFf) client->closeFf(client->closeOpaque); for (i = 0 ; i < client->nprograms ; i++) - virNetClientProgramFree(client->programs[i]); + virObjectUnref(client->programs[i]); VIR_FREE(client->programs); VIR_FORCE_CLOSE(client->wakeupSendFD); @@ -501,8 +489,6 @@ void virNetClientFree(virNetClientPtr client) #endif virNetClientUnlock(client); virMutexDestroy(&client->lock); - - VIR_FREE(client); } @@ -543,7 +529,7 @@ virNetClientCloseLocked(virNetClientPtr client) virNetClientCloseFunc closeCb = client->closeCb; void *closeOpaque = client->closeOpaque; int closeReason = client->closeReason; - client->refs++; + virObjectRef(client); virNetClientUnlock(client); if (ka) { @@ -554,7 +540,7 @@ virNetClientCloseLocked(virNetClientPtr client) closeCb(client, closeReason, closeOpaque); virNetClientLock(client); - client->refs--; + virObjectUnref(client); } } @@ -751,8 +737,7 @@ int virNetClientAddProgram(virNetClientPtr client, if (VIR_EXPAND_N(client->programs, client->nprograms, 1) < 0) goto no_memory; - client->programs[client->nprograms-1] = prog; - virNetClientProgramRef(prog); + client->programs[client->nprograms-1] = virObjectRef(prog); virNetClientUnlock(client); return 0; @@ -772,8 +757,7 @@ int virNetClientAddStream(virNetClientPtr client, if (VIR_EXPAND_N(client->streams, client->nstreams, 1) < 0) goto no_memory; - client->streams[client->nstreams-1] = st; - virNetClientStreamRef(st); + client->streams[client->nstreams-1] = virObjectRef(st); virNetClientUnlock(client); return 0; @@ -807,7 +791,7 @@ void virNetClientRemoveStream(virNetClientPtr client, VIR_FREE(client->streams); client->nstreams = 0; } - virNetClientStreamFree(st); + virObjectUnref(st); cleanup: virNetClientUnlock(client); diff --git a/src/rpc/virnetclient.h b/src/rpc/virnetclient.h index c939475..d6b9b3c 100644 --- a/src/rpc/virnetclient.h +++ b/src/rpc/virnetclient.h @@ -30,6 +30,7 @@ # endif # include "virnetclientprogram.h" # include "virnetclientstream.h" +# include "virobject.h" virNetClientPtr virNetClientNewUNIX(const char *path, @@ -60,8 +61,6 @@ void virNetClientSetCloseCallback(virNetClientPtr client, void *opaque, virFreeCallback ff); -void virNetClientRef(virNetClientPtr client); - int virNetClientGetFD(virNetClientPtr client); int virNetClientDupFD(virNetClientPtr client, bool cloexec); @@ -105,7 +104,6 @@ const char *virNetClientRemoteAddrString(virNetClientPtr client); int virNetClientGetTLSKeySize(virNetClientPtr client); -void virNetClientFree(virNetClientPtr client); void virNetClientClose(virNetClientPtr client); bool virNetClientKeepAliveIsSupported(virNetClientPtr client); diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c index c7d2409..320b7d4 100644 --- a/src/rpc/virnetclientprogram.c +++ b/src/rpc/virnetclientprogram.c @@ -33,11 +33,12 @@ #include "logging.h" #include "util.h" #include "virfile.h" +#include "threads.h" #define VIR_FROM_THIS VIR_FROM_RPC struct _virNetClientProgram { - int refs; + virObject object; unsigned program; unsigned version; @@ -46,6 +47,22 @@ struct _virNetClientProgram { void *eventOpaque; }; +static virClassPtr virNetClientProgramClass; +static void virNetClientProgramDispose(void *obj); + +static int virNetClientProgramOnceInit(void) +{ + if (!(virNetClientProgramClass = virClassNew("virNetClientProgram", + sizeof(virNetClientProgram), + virNetClientProgramDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetClientProgram) + + virNetClientProgramPtr virNetClientProgramNew(unsigned program, unsigned version, virNetClientProgramEventPtr events, @@ -54,12 +71,12 @@ virNetClientProgramPtr virNetClientProgramNew(unsigned program, { virNetClientProgramPtr prog; - if (VIR_ALLOC(prog) < 0) { - virReportOOMError(); + if (virNetClientProgramInitialize() < 0) + return NULL; + + if (!(prog = virObjectNew(virNetClientProgramClass))) return NULL; - } - prog->refs = 1; prog->program = program; prog->version = version; prog->events = events; @@ -70,22 +87,8 @@ virNetClientProgramPtr virNetClientProgramNew(unsigned program, } -void virNetClientProgramRef(virNetClientProgramPtr prog) +void virNetClientProgramDispose(void *obj ATTRIBUTE_UNUSED) { - prog->refs++; -} - - -void virNetClientProgramFree(virNetClientProgramPtr prog) -{ - if (!prog) - return; - - prog->refs--; - if (prog->refs > 0) - return; - - VIR_FREE(prog); } diff --git a/src/rpc/virnetclientprogram.h b/src/rpc/virnetclientprogram.h index f799f2e..9e92a3c 100644 --- a/src/rpc/virnetclientprogram.h +++ b/src/rpc/virnetclientprogram.h @@ -27,6 +27,7 @@ # include <rpc/xdr.h> # include "virnetmessage.h" +# include "virobject.h" typedef struct _virNetClient virNetClient; typedef virNetClient *virNetClientPtr; @@ -62,10 +63,6 @@ virNetClientProgramPtr virNetClientProgramNew(unsigned program, unsigned virNetClientProgramGetProgram(virNetClientProgramPtr prog); unsigned virNetClientProgramGetVersion(virNetClientProgramPtr prog); -void virNetClientProgramRef(virNetClientProgramPtr prog); - -void virNetClientProgramFree(virNetClientProgramPtr prog); - int virNetClientProgramMatches(virNetClientProgramPtr prog, virNetMessagePtr msg); diff --git a/src/rpc/virnetclientstream.c b/src/rpc/virnetclientstream.c index 8580e39..0714cfc 100644 --- a/src/rpc/virnetclientstream.c +++ b/src/rpc/virnetclientstream.c @@ -33,12 +33,13 @@ #define VIR_FROM_THIS VIR_FROM_RPC struct _virNetClientStream { + virObject object; + virMutex lock; virNetClientProgramPtr prog; int proc; unsigned serial; - int refs; virError err; @@ -63,6 +64,22 @@ struct _virNetClientStream { }; +static virClassPtr virNetClientStreamClass; +static void virNetClientStreamDispose(void *obj); + +static int virNetClientStreamOnceInit(void) +{ + if (!(virNetClientStreamClass = virClassNew("virNetClientStream", + sizeof(virNetClientStream), + virNetClientStreamDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetClientStream) + + static void virNetClientStreamEventTimerUpdate(virNetClientStreamPtr st) { @@ -119,26 +136,18 @@ virNetClientStreamEventTimer(int timer ATTRIBUTE_UNUSED, void *opaque) } -static void -virNetClientStreamEventTimerFree(void *opaque) -{ - virNetClientStreamPtr st = opaque; - virNetClientStreamFree(st); -} - - virNetClientStreamPtr virNetClientStreamNew(virNetClientProgramPtr prog, int proc, unsigned serial) { virNetClientStreamPtr st; - if (VIR_ALLOC(st) < 0) { - virReportOOMError(); + if (virNetClientStreamInitialize() < 0) + return NULL; + + if (!(st = virObjectNew(virNetClientStreamClass))) return NULL; - } - st->refs = 1; st->prog = prog; st->proc = proc; st->serial = serial; @@ -150,35 +159,19 @@ virNetClientStreamPtr virNetClientStreamNew(virNetClientProgramPtr prog, return NULL; } - virNetClientProgramRef(prog); + virObjectRef(prog); return st; } - -void virNetClientStreamRef(virNetClientStreamPtr st) +void virNetClientStreamDispose(void *obj) { - virMutexLock(&st->lock); - st->refs++; - virMutexUnlock(&st->lock); -} - -void virNetClientStreamFree(virNetClientStreamPtr st) -{ - virMutexLock(&st->lock); - st->refs--; - if (st->refs > 0) { - virMutexUnlock(&st->lock); - return; - } - - virMutexUnlock(&st->lock); + virNetClientStreamPtr st = obj; virResetError(&st->err); VIR_FREE(st->incoming); virMutexDestroy(&st->lock); - virNetClientProgramFree(st->prog); - VIR_FREE(st); + virObjectUnref(st->prog); } bool virNetClientStreamMatches(virNetClientStreamPtr st, @@ -454,13 +447,13 @@ int virNetClientStreamEventAddCallback(virNetClientStreamPtr st, goto cleanup; } - st->refs++; + virObjectRef(st); if ((st->cbTimer = virEventAddTimeout(-1, virNetClientStreamEventTimer, st, - virNetClientStreamEventTimerFree)) < 0) { - st->refs--; + (virFreeCallback)virObjectUnref)) < 0) { + virObjectUnref(st); goto cleanup; } diff --git a/src/rpc/virnetclientstream.h b/src/rpc/virnetclientstream.h index 00d598a..68a9e99 100644 --- a/src/rpc/virnetclientstream.h +++ b/src/rpc/virnetclientstream.h @@ -24,6 +24,7 @@ # define __VIR_NET_CLIENT_STREAM_H__ # include "virnetclientprogram.h" +# include "virobject.h" typedef struct _virNetClientStream virNetClientStream; typedef virNetClientStream *virNetClientStreamPtr; @@ -35,10 +36,6 @@ virNetClientStreamPtr virNetClientStreamNew(virNetClientProgramPtr prog, int proc, unsigned serial); -void virNetClientStreamRef(virNetClientStreamPtr st); - -void virNetClientStreamFree(virNetClientStreamPtr st); - bool virNetClientStreamRaiseError(virNetClientStreamPtr st); int virNetClientStreamSetError(virNetClientStreamPtr st, -- 1.7.10.4
participants (4)
-
Daniel P. Berrange
-
Daniel Veillard
-
Eric Blake
-
Hu Tao