Libvirt's original atomic ops impls were largely copied from GLib's code at the time. The only API difference was that libvirt's virAtomicIntInc() would return a value, but g_atomic_int_inc was void. We thus use g_atomic_int_add(v, 1) instead, though this means virAtomicIntInc() now returns the original value, instead of the new value. This rewrites libvirt's impl in terms of g_atomic_int* as a short term conversion. The key motivation was to quickly eliminate use of GNULIB's verify_expr() macro which is not a direct match for G_STATIC_ASSERT_EXPR. Long term all the callers should be updated to use g_atomic_int* directly. Reviewed-by: Pavel Hrdina <phrdina@xxxxxxxxxx> Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> --- src/libxl/libxl_domain.c | 2 +- src/libxl/libxl_driver.c | 2 +- src/lxc/lxc_process.c | 4 +- src/nwfilter/nwfilter_dhcpsnoop.c | 6 +- src/qemu/qemu_process.c | 4 +- src/util/viratomic.h | 351 ++---------------------------- src/util/virprocess.c | 2 +- tests/viratomictest.c | 2 +- 8 files changed, 26 insertions(+), 347 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 915aaeb8b0..f9be4ad583 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -1473,7 +1473,7 @@ libxlDomainStart(libxlDriverPrivatePtr driver, if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0) goto destroy_dom; - if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) + if (virAtomicIntInc(&driver->nactive) == 0 && driver->inhibitCallback) driver->inhibitCallback(true, driver->inhibitOpaque); /* finally we can call the 'started' hook script if any */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index f021ec9c5d..ef02a066d9 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -446,7 +446,7 @@ libxlReconnectDomain(virDomainObjPtr vm, virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNKNOWN); - if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) + if (virAtomicIntInc(&driver->nactive) == 0 && driver->inhibitCallback) driver->inhibitCallback(true, driver->inhibitOpaque); /* Enable domain death events */ diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 0a9ccdf9ec..af8593d6a5 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -1468,7 +1468,7 @@ int virLXCProcessStart(virConnectPtr conn, if (virCommandHandshakeNotify(cmd) < 0) goto cleanup; - if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) + if (virAtomicIntInc(&driver->nactive) == 0 && driver->inhibitCallback) driver->inhibitCallback(true, driver->inhibitOpaque); if (lxcContainerWaitForContinue(handshakefds[0]) < 0) { @@ -1670,7 +1670,7 @@ virLXCProcessReconnectDomain(virDomainObjPtr vm, virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNKNOWN); - if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) + if (virAtomicIntInc(&driver->nactive) == 0 && driver->inhibitCallback) driver->inhibitCallback(true, driver->inhibitOpaque); if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) diff --git a/src/nwfilter/nwfilter_dhcpsnoop.c b/src/nwfilter/nwfilter_dhcpsnoop.c index 9a71d13d57..f3acaf00dd 100644 --- a/src/nwfilter/nwfilter_dhcpsnoop.c +++ b/src/nwfilter/nwfilter_dhcpsnoop.c @@ -888,7 +888,7 @@ virNWFilterSnoopReqLeaseDel(virNWFilterSnoopReqPtr req, skip_instantiate: VIR_FREE(ipl); - virAtomicIntDecAndTest(&virNWFilterSnoopState.nLeases); + ignore_value(virAtomicIntDecAndTest(&virNWFilterSnoopState.nLeases)); lease_not_found: VIR_FREE(ipstr); @@ -1167,7 +1167,7 @@ static void virNWFilterDHCPDecodeWorker(void *jobdata, void *opaque) _("Instantiation of rules failed on " "interface '%s'"), req->binding->portdevname); } - virAtomicIntDecAndTest(job->qCtr); + ignore_value(virAtomicIntDecAndTest(job->qCtr)); VIR_FREE(job); } @@ -1568,7 +1568,7 @@ virNWFilterDHCPSnoopThread(void *req0) pcap_close(pcapConf[i].handle); } - virAtomicIntDecAndTest(&virNWFilterSnoopState.nThreads); + ignore_value(virAtomicIntDecAndTest(&virNWFilterSnoopState.nThreads)); return; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index a7bbab9e56..420d1c9c93 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5571,7 +5571,7 @@ qemuProcessInit(virQEMUDriverPtr driver, qemuDomainSetFakeReboot(driver, vm, false); virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_STARTING_UP); - if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) + if (virAtomicIntInc(&driver->nactive) == 0 && driver->inhibitCallback) driver->inhibitCallback(true, driver->inhibitOpaque); /* Run an early hook to set-up missing devices */ @@ -8139,7 +8139,7 @@ qemuProcessReconnect(void *opaque) goto error; } - if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) + if (virAtomicIntInc(&driver->nactive) == 0 && driver->inhibitCallback) driver->inhibitCallback(true, driver->inhibitOpaque); cleanup: diff --git a/src/util/viratomic.h b/src/util/viratomic.h index 9dfb77b992..12b116a6cd 100644 --- a/src/util/viratomic.h +++ b/src/util/viratomic.h @@ -1,11 +1,7 @@ /* * 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 + * Copyright (C) 2012-2020 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 @@ -21,18 +17,15 @@ * License along with this library. If not, see * <http://www.gnu.org/licenses/>. * + * APIs in this header should no longer be used. Direct + * use of the g_atomic APIs is preferred & existing code + * should be converted as needed. */ #pragma once #include "internal.h" -#ifdef VIR_ATOMIC_OPS_GCC -# define VIR_STATIC /* Nothing; we just never define the functions */ -#else -# define VIR_STATIC static -#endif - /** * virAtomicIntGet: * Gets the current value of atomic. @@ -40,8 +33,7 @@ * This call acts as a full compiler and hardware memory barrier * (before the get) */ -VIR_STATIC int virAtomicIntGet(volatile int *atomic) - ATTRIBUTE_NONNULL(1); +#define virAtomicIntGet(v) g_atomic_int_get(v) /** * virAtomicIntSet: @@ -50,21 +42,18 @@ VIR_STATIC int virAtomicIntGet(volatile int *atomic) * This call acts as a full compiler and hardware memory barrier * (after the set) */ -VIR_STATIC void virAtomicIntSet(volatile int *atomic, - int newval) - ATTRIBUTE_NONNULL(1); +#define virAtomicIntSet(i, newv) g_atomic_int_set(i, newv) /** * virAtomicIntInc: * Increments the value of atomic by 1. * * Think of this operation as an atomic version of - * { *atomic += 1; return *atomic; } + * { tmp = *atomic; *atomic += 1; return tmp; } * * This call acts as a full compiler and hardware memory barrier. */ -VIR_STATIC int virAtomicIntInc(volatile int *atomic) - ATTRIBUTE_NONNULL(1); +#define virAtomicIntInc(i) g_atomic_int_add(i, 1) /** * virAtomicIntDecAndTest: @@ -75,8 +64,7 @@ VIR_STATIC int virAtomicIntInc(volatile int *atomic) * * This call acts as a full compiler and hardware memory barrier. */ -VIR_STATIC bool virAtomicIntDecAndTest(volatile int *atomic) - ATTRIBUTE_NONNULL(1); +#define virAtomicIntDecAndTest(i) (!!g_atomic_int_dec_and_test(i)) /** * virAtomicIntCompareExchange: @@ -91,10 +79,8 @@ VIR_STATIC bool virAtomicIntDecAndTest(volatile int *atomic) * * This call acts as a full compiler and hardware memory barrier. */ -VIR_STATIC bool virAtomicIntCompareExchange(volatile int *atomic, - int oldval, - int newval) - ATTRIBUTE_NONNULL(1); +#define virAtomicIntCompareExchange(i, oldi, newi) \ + (!!g_atomic_int_compare_and_exchange(i, oldi, newi)) /** * virAtomicIntAdd: @@ -105,9 +91,7 @@ VIR_STATIC bool virAtomicIntCompareExchange(volatile int *atomic, * * This call acts as a full compiler and hardware memory barrier. */ -VIR_STATIC int virAtomicIntAdd(volatile int *atomic, - int val) - ATTRIBUTE_NONNULL(1); +#define virAtomicIntAdd(i, v) g_atomic_int_add(i, v) /** * virAtomicIntAnd: @@ -119,9 +103,7 @@ VIR_STATIC int virAtomicIntAdd(volatile int *atomic, * Think of this operation as an atomic version of * { tmp = *atomic; *atomic &= val; return tmp; } */ -VIR_STATIC unsigned int virAtomicIntAnd(volatile unsigned int *atomic, - unsigned int val) - ATTRIBUTE_NONNULL(1); +#define virAtomicIntAnd(i, v) g_atomic_int_and(i, v) /** * virAtomicIntOr: @@ -133,9 +115,7 @@ VIR_STATIC unsigned int virAtomicIntAnd(volatile unsigned int *atomic, * * This call acts as a full compiler and hardware memory barrier. */ -VIR_STATIC unsigned int virAtomicIntOr(volatile unsigned int *atomic, - unsigned int val) - ATTRIBUTE_NONNULL(1); +#define virAtomicIntOr(i, v) g_atomic_int_or(i, v) /** * virAtomicIntXor: @@ -147,305 +127,4 @@ VIR_STATIC unsigned int virAtomicIntOr(volatile unsigned int *atomic, * * This call acts as a full compiler and hardware memory barrier. */ -VIR_STATIC unsigned int virAtomicIntXor(volatile unsigned int *atomic, - unsigned int val) - ATTRIBUTE_NONNULL(1); - -#undef VIR_STATIC - -#ifdef VIR_ATOMIC_OPS_GCC - -# define virAtomicIntGet(atomic) \ - (__extension__ ({ \ - (void)verify_expr(sizeof(*(atomic)) == sizeof(int), 0); \ - (void)(0 ? *(atomic) ^ *(atomic) : 0); \ - __sync_synchronize(); \ - (int)*(atomic); \ - })) -# define virAtomicIntSet(atomic, newval) \ - (__extension__ ({ \ - (void)verify_expr(sizeof(*(atomic)) == sizeof(int), 0); \ - (void)(0 ? *(atomic) ^ (newval) : 0); \ - *(atomic) = (newval); \ - __sync_synchronize(); \ - })) -# define virAtomicIntInc(atomic) \ - (__extension__ ({ \ - (void)verify_expr(sizeof(*(atomic)) == sizeof(int), 0); \ - (void)(0 ? *(atomic) ^ *(atomic) : 0); \ - __sync_add_and_fetch((atomic), 1); \ - })) -# define virAtomicIntDecAndTest(atomic) \ - (__extension__ ({ \ - (void)verify_expr(sizeof(*(atomic)) == sizeof(int), 0); \ - (void)(0 ? *(atomic) ^ *(atomic) : 0); \ - __sync_fetch_and_sub((atomic), 1) == 1; \ - })) -# define virAtomicIntCompareExchange(atomic, oldval, newval) \ - (__extension__ ({ \ - (void)verify_expr(sizeof(*(atomic)) == sizeof(int), 0); \ - (void)(0 ? *(atomic) ^ (newval) ^ (oldval) : 0); \ - (bool)__sync_bool_compare_and_swap((atomic), \ - (oldval), (newval)); \ - })) -# define virAtomicIntAdd(atomic, val) \ - (__extension__ ({ \ - (void)verify_expr(sizeof(*(atomic)) == sizeof(int), 0); \ - (void)(0 ? *(atomic) ^ (val) : 0); \ - (int) __sync_fetch_and_add((atomic), (val)); \ - })) -# define virAtomicIntAnd(atomic, val) \ - (__extension__ ({ \ - (void)verify_expr(sizeof(*(atomic)) == sizeof(int), 0); \ - (void) (0 ? *(atomic) ^ (val) : 0); \ - (unsigned int) __sync_fetch_and_and((atomic), (val)); \ - })) -# define virAtomicIntOr(atomic, val) \ - (__extension__ ({ \ - (void)verify_expr(sizeof(*(atomic)) == sizeof(int), 0); \ - (void) (0 ? *(atomic) ^ (val) : 0); \ - (unsigned int) __sync_fetch_and_or((atomic), (val)); \ - })) -# define virAtomicIntXor(atomic, val) \ - (__extension__ ({ \ - (void)verify_expr(sizeof(*(atomic)) == sizeof(int), 0); \ - (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 - -/* - * http://msdn.microsoft.com/en-us/library/ms684122(v=vs.85).aspx - */ -static inline int -virAtomicIntGet(volatile int *atomic) -{ - MemoryBarrier(); - return *atomic; -} - -static inline void -virAtomicIntSet(volatile int *atomic, - int newval) -{ - *atomic = newval; - MemoryBarrier(); -} - -static inline int -virAtomicIntInc(volatile int *atomic) -{ - return InterlockedIncrement((volatile LONG *)atomic); -} - -static inline bool -virAtomicIntDecAndTest(volatile int *atomic) -{ - return InterlockedDecrement((volatile LONG *)atomic) == 0; -} - -static inline bool -virAtomicIntCompareExchange(volatile int *atomic, - int oldval, - int newval) -{ - return InterlockedCompareExchange((volatile LONG *)atomic, newval, oldval) == oldval; -} - -static inline int -virAtomicIntAdd(volatile int *atomic, - int val) -{ - return InterlockedExchangeAdd((volatile LONG *)atomic, val); -} - -static inline unsigned int -virAtomicIntAnd(volatile unsigned int *atomic, - unsigned int val) -{ - return InterlockedAnd((volatile LONG *)atomic, val); -} - -static inline unsigned int -virAtomicIntOr(volatile unsigned int *atomic, - unsigned int val) -{ - return InterlockedOr((volatile LONG *)atomic, val); -} - -static inline unsigned int -virAtomicIntXor(volatile unsigned int *atomic, - unsigned int val) -{ - return InterlockedXor((volatile LONG *)atomic, val); -} - - -# else -# ifdef VIR_ATOMIC_OPS_PTHREAD -# include <pthread.h> - -extern pthread_mutex_t virAtomicLock; - -static inline int -virAtomicIntGet(volatile int *atomic) -{ - int value; - - pthread_mutex_lock(&virAtomicLock); - value = *atomic; - pthread_mutex_unlock(&virAtomicLock); - - return value; -} - -static inline void -virAtomicIntSet(volatile int *atomic, - int value) -{ - pthread_mutex_lock(&virAtomicLock); - *atomic = value; - pthread_mutex_unlock(&virAtomicLock); -} - -static inline int -virAtomicIntInc(volatile int *atomic) -{ - int value; - - pthread_mutex_lock(&virAtomicLock); - value = ++(*atomic); - pthread_mutex_unlock(&virAtomicLock); - - return value; -} - -static inline bool -virAtomicIntDecAndTest(volatile int *atomic) -{ - bool is_zero; - - pthread_mutex_lock(&virAtomicLock); - is_zero = --(*atomic) == 0; - pthread_mutex_unlock(&virAtomicLock); - - return is_zero; -} - -static inline bool -virAtomicIntCompareExchange(volatile int *atomic, - int oldval, - int newval) -{ - bool success; - - pthread_mutex_lock(&virAtomicLock); - - if ((success = (*atomic == oldval))) - *atomic = newval; - - pthread_mutex_unlock(&virAtomicLock); - - return success; -} - -static inline int -virAtomicIntAdd(volatile int *atomic, - int val) -{ - int oldval; - - pthread_mutex_lock(&virAtomicLock); - oldval = *atomic; - *atomic = oldval + val; - pthread_mutex_unlock(&virAtomicLock); - - return oldval; -} - -static inline unsigned int -virAtomicIntAnd(volatile unsigned int *atomic, - unsigned int val) -{ - unsigned int oldval; - - pthread_mutex_lock(&virAtomicLock); - oldval = *atomic; - *atomic = oldval & val; - pthread_mutex_unlock(&virAtomicLock); - - return oldval; -} - -static inline unsigned int -virAtomicIntOr(volatile unsigned int *atomic, - unsigned int val) -{ - unsigned int oldval; - - pthread_mutex_lock(&virAtomicLock); - oldval = *atomic; - *atomic = oldval | val; - pthread_mutex_unlock(&virAtomicLock); - - return oldval; -} - -static inline unsigned int -virAtomicIntXor(volatile unsigned int *atomic, - unsigned int val) -{ - 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 +#define virAtomicIntXor(i, v) g_atomic_int_xor(i, v) diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 32f19e6b63..d5589daf6a 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -1021,7 +1021,7 @@ int virProcessGetStartTime(pid_t pid, unsigned long long *timestamp) { static int warned; - if (virAtomicIntInc(&warned) == 1) { + if (virAtomicIntInc(&warned) == 0) { VIR_WARN("Process start time of pid %lld not available on this platform", (long long) pid); } diff --git a/tests/viratomictest.c b/tests/viratomictest.c index 8c885a5b96..e30df66cd7 100644 --- a/tests/viratomictest.c +++ b/tests/viratomictest.c @@ -50,7 +50,7 @@ testTypes(const void *data G_GNUC_UNUSED) testAssertEq(virAtomicIntAdd(&u, 1), 5); testAssertEq(u, 6); - testAssertEq(virAtomicIntInc(&u), 7); + testAssertEq(virAtomicIntInc(&u), 6); testAssertEq(u, 7); res = virAtomicIntDecAndTest(&u); -- 2.24.1