From 83821352657a9481dbff6ab04e8ae60566c17d5e Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Sat, 28 May 2011 15:59:18 -0400 Subject: [PATCH] glib: Rewrite gatomic.[ch] - remove all inline assembly versions - implement the atomic operations using either GCC intrinsics, the Windows interlocked API or a mutex-based fallback - drop gatomic-gcc.c since these are now defined in the header file. Adjust Makefile.am accordingly. - expand the set of operations: support 'get', 'set', 'compare and exchange', 'add', 'or', and 'xor' for both integers and pointers - deprecate g_atomic_int_exchange_and_add since g_atomic_int_add (as with all the new arithmetic operations) now returns the prior value - unify the use of macros: all functions are now wrapped in macros that perform the proper casts and checks - remove G_GNUC_MAY_ALIAS use; it was never required for the integer operations (since casting between pointers that only vary in signedness of the target is explicitly permitted) and we avoid the need for the pointer operations by using simple 'void *' instead of 'gpointer *' (which caused the 'type-punned pointer' warning) - provide function implementations of g_atomic_int_inc and g_atomic_int_dec_and_test: these were strictly macros before - improve the documentation to make it very clear exactly which types of pointers these operations may be used with - remove a few uses of the now-deprecated g_atomic_int_exchange_and_add - drop initialisation of gatomic from gthread (by using a GStaticMutex instead of a GMutex) - update glib.symbols and documentation sections files Closes #650823 and #650935 --- docs/reference/glib/glib-sections.txt | 21 +- glib/Makefile.am | 8 +- glib/gatomic-gcc.c | 104 -- glib/gatomic.c | 1892 ++++++++++--------------- glib/gatomic.h | 324 +++-- glib/glib.symbols | 13 +- glib/gthread.c | 1 - glib/gthreadpool.c | 2 +- glib/tests/atomic.c | 2 - gobject/gobject.c | 4 +- 10 files changed, 978 insertions(+), 1393 deletions(-) delete mode 100644 glib/gatomic-gcc.c diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index f1a8c4f59..a290ac1e6 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -759,17 +759,28 @@ g_async_queue_sort_unlocked
Atomic Operations -atomic_operationsg +atomic_operations g_atomic_int_get g_atomic_int_set -g_atomic_int_add -g_atomic_int_exchange_and_add +g_atomic_int_inc +g_atomic_int_dec_and_test g_atomic_int_compare_and_exchange +g_atomic_int_add +g_atomic_int_and +g_atomic_int_or +g_atomic_int_xor + + g_atomic_pointer_get g_atomic_pointer_set g_atomic_pointer_compare_and_exchange -g_atomic_int_inc -g_atomic_int_dec_and_test +g_atomic_pointer_add +g_atomic_pointer_and +g_atomic_pointer_or +g_atomic_pointer_xor + + +g_atomic_int_exchange_and_add G_ATOMIC_OP_MEMORY_BARRIER_NEEDED diff --git a/glib/Makefile.am b/glib/Makefile.am index d0da7b21a..7d333a812 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -42,12 +42,6 @@ gregex_c = gregex_h = endif -if HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS -gatomic_c = gatomic-gcc.c -else -gatomic_c = gatomic.c -endif - SUBDIRS = libcharset $(PRINTF_SUBDIR) $(MAYBE_PCRE) update-pcre . tests DIST_SUBDIRS = libcharset gnulib pcre update-pcre tests @@ -121,7 +115,7 @@ libglib_2_0_la_SOURCES = \ glib_probes.d \ garray.c \ gasyncqueue.c \ - $(gatomic_c) \ + gatomic.c \ gbacktrace.c \ gbase64.c \ gbitlock.c \ diff --git a/glib/gatomic-gcc.c b/glib/gatomic-gcc.c deleted file mode 100644 index 09cd3aafa..000000000 --- a/glib/gatomic-gcc.c +++ /dev/null @@ -1,104 +0,0 @@ -/* GLIB - Library of useful routines for C programming - * gatomic-gcc.c: atomic operations using GCC builtins. - * Copyright (C) 2009 Hiroyuki Ikezoe - * - * 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 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 "gatomic.h" - -/* All atomic operations are available as macros evaluating - * to gcc builtins (when using gcc builtins for atomic operations). - * For ABI stability, we provide functions for them too. - * - * To avoid interference, undefine the macros first. - */ - -#undef g_atomic_int_exchange_and_add -#undef g_atomic_int_compare_and_exchange -#undef g_atomic_int_add -#undef g_atomic_int_get -#undef g_atomic_int_set -#undef g_atomic_pointer_compare_and_exchange -#undef g_atomic_pointer_get -#undef g_atomic_pointer_set - -gint -g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - return __sync_fetch_and_add (atomic, val); -} - -void -g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - __sync_fetch_and_add (atomic, val); -} - -gboolean -g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval) -{ - return __sync_bool_compare_and_swap (atomic, oldval, newval); -} - -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - return __sync_bool_compare_and_swap (atomic, oldval, newval); -} - -void -_g_atomic_thread_init (void) -{ -} - -gint -g_atomic_int_get (volatile gint G_GNUC_MAY_ALIAS *atomic) -{ - __sync_synchronize (); - return *atomic; -} - -void -g_atomic_int_set (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint newval) -{ - *atomic = newval; - __sync_synchronize (); -} - -gpointer -g_atomic_pointer_get (volatile gpointer G_GNUC_MAY_ALIAS *atomic) -{ - __sync_synchronize (); - return *atomic; -} - -void -g_atomic_pointer_set (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer newval) -{ - *atomic = newval; - __sync_synchronize (); -} diff --git a/glib/gatomic.c b/glib/gatomic.c index f90eb059c..0da78b962 100644 --- a/glib/gatomic.c +++ b/glib/gatomic.c @@ -1,35 +1,27 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald +/* + * Copyright © 2011 Ryan Lortie * - * g_atomic_*: atomic operations. - * Copyright (C) 2003 Sebastian Wilhelmi - * Copyright (C) 2007 Nokia Corporation + * 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 of the + * licence, or (at your option) any later version. * - * 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 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 + * 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. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + * + * Author: Ryan Lortie */ #include "config.h" -#if defined (G_ATOMIC_ARM) -#include -#endif - #include "gatomic.h" -#include "gthread.h" -#include "gthreadprivate.h" /** * SECTION:atomic_operations @@ -37,1150 +29,774 @@ * @short_description: basic atomic integer and pointer operations * @see_also: #GMutex * - * The following functions can be used to atomically access integers and - * pointers. They are implemented as inline assembler function on most - * platforms and use slower fall-backs otherwise. Using them can sometimes - * save you from using a performance-expensive #GMutex to protect the - * integer or pointer. + * The following is a collection of compiler macros to provide atomic + * access to integer and pointer-sized values. * - * The most important usage is reference counting. Using - * g_atomic_int_inc() and g_atomic_int_dec_and_test() makes reference - * counting a very fast operation. + * The macros that have 'int' in the name will operate on pointers to + * #gint and #guint. The macros with 'pointer' in the name will operate + * on pointers to any pointer-sized value, including #gsize. There is + * no support for 64bit operations on platforms with 32bit pointers + * because it is not generally possible to perform these operations + * atomically. * - * You must not directly read integers or pointers concurrently - * accessed by multiple threads, but use the atomic accessor functions - * instead. That is, always use g_atomic_int_get() and g_atomic_pointer_get() - * for read outs. They provide the neccessary synchonization mechanisms - * like memory barriers to access memory locations concurrently. - * + * The get, set and exchange operations for integers and pointers + * nominally operate on #gint and #gpointer, respectively. Of the + * arithmetic operations, the 'add' operation operates on (and returns) + * signed integer values (#gint and #gssize) and the 'and', 'or', and + * 'xor' operations operate on (and return) unsigned integer values + * (#guint and #gsize). * - * If you are using those functions for anything apart from - * simple reference counting, you should really be aware of the implications - * of doing that. There are literally thousands of ways to shoot yourself - * in the foot. So if in doubt, use a #GMutex. If you don't know, what - * memory barriers are, do not use anything but g_atomic_int_inc() and - * g_atomic_int_dec_and_test(). - * + * All of the operations act as a full compiler and (where appropriate) + * hardware memory barrier. Acquire and release or producer and + * consumer barrier semantics are not available through this API. * - * It is not safe to set an integer or pointer just by assigning - * to it, when it is concurrently accessed by other threads with the following - * functions. Use g_atomic_int_compare_and_exchange() or - * g_atomic_pointer_compare_and_exchange() respectively. - * - */ + * On GCC, these macros are implemented using GCC intrinsic operations. + * On non-GCC compilers they will evaluate to function calls to + * functions implemented by GLib. + * + * If GLib itself was compiled with GCC then these functions will again + * be implemented by the GCC intrinsics. On Windows without GCC, the + * interlocked API is used to implement the functions. + * + * With non-GCC compilers on non-Windows systems, the functions are + * currently incapable of implementing true atomic operations -- + * instead, they fallback to holding a global lock while performing the + * operation. This provides atomicity between the threads of one + * process, but not between separate processes. For this reason, one + * should exercise caution when attempting to use these options on + * shared memory regions. + * + * It is very important that all accesses to a particular integer or + * pointer be performed using only this API and that different sizes of + * operation are not mixed or used on overlapping memory regions. Never + * read or assign directly from or to a value -- always use this API. + * + * For simple reference counting purposes you should use + * g_atomic_int_inc() and g_atomic_int_dec_and_test(). Other uses that + * fall outside of simple reference counting patterns are prone to + * subtle bugs and occasionally undefined behaviour. It is also worth + * noting that since all of these operations require global + * synchronisation of the entire machine, they can be quite slow. In + * the case of performing multiple atomic operations it can often be + * faster to simply acquire a mutex lock around the critical area, + * perform the operations normally and then release the lock. + **/ -#if defined (__GNUC__) -# if defined (G_ATOMIC_I486) -/* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h - */ -gint -g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result; +#ifdef G_ATOMIC_OP_USE_GCC_BUILTINS - __asm__ __volatile__ ("lock; xaddl %0,%1" - : "=r" (result), "=m" (*atomic) - : "0" (val), "m" (*atomic)); - return result; -} - -void -g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - __asm__ __volatile__ ("lock; addl %1,%0" - : "=m" (*atomic) - : "ir" (val), "m" (*atomic)); -} - -gboolean -g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval) -{ - gint result; - - __asm__ __volatile__ ("lock; cmpxchgl %2, %1" - : "=a" (result), "=m" (*atomic) - : "r" (newval), "m" (*atomic), "0" (oldval)); - - return result == oldval; -} - -/* The same code as above, as on i386 gpointer is 32 bit as well. - * Duplicating the code here seems more natural than casting the - * arguments and calling the former function */ - -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gpointer result; - - __asm__ __volatile__ ("lock; cmpxchgl %2, %1" - : "=a" (result), "=m" (*atomic) - : "r" (newval), "m" (*atomic), "0" (oldval)); - - return result == oldval; -} - -# elif defined (G_ATOMIC_SPARCV9) -/* Adapted from CVS version 1.3 of glibc's sysdeps/sparc/sparc64/bits/atomic.h - */ -# define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ - ({ \ - gint __result; \ - __asm__ __volatile__ ("cas [%4], %2, %0" \ - : "=r" (__result), "=m" (*(atomic)) \ - : "r" (oldval), "m" (*(atomic)), "r" (atomic),\ - "0" (newval)); \ - __result == oldval; \ - }) - -# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gpointer result; - __asm__ __volatile__ ("cas [%4], %2, %0" - : "=r" (result), "=m" (*atomic) - : "r" (oldval), "m" (*atomic), "r" (atomic), - "0" (newval)); - return result == oldval; -} -# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gpointer result; - gpointer *a = atomic; - __asm__ __volatile__ ("casx [%4], %2, %0" - : "=r" (result), "=m" (*a) - : "r" (oldval), "m" (*a), "r" (a), - "0" (newval)); - return result == oldval; -} -# else /* What's that */ -# error "Your system has an unsupported pointer size" -# endif /* GLIB_SIZEOF_VOID_P */ -# define G_ATOMIC_MEMORY_BARRIER \ - __asm__ __volatile__ ("membar #LoadLoad | #LoadStore" \ - " | #StoreLoad | #StoreStore" : : : "memory") - -# elif defined (G_ATOMIC_ALPHA) -/* Adapted from CVS version 1.3 of glibc's sysdeps/alpha/bits/atomic.h - */ -# define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ - ({ \ - gint __result; \ - gint __prev; \ - __asm__ __volatile__ ( \ - " mb\n" \ - "1: ldl_l %0,%2\n" \ - " cmpeq %0,%3,%1\n" \ - " beq %1,2f\n" \ - " mov %4,%1\n" \ - " stl_c %1,%2\n" \ - " beq %1,1b\n" \ - " mb\n" \ - "2:" \ - : "=&r" (__prev), \ - "=&r" (__result) \ - : "m" (*(atomic)), \ - "Ir" (oldval), \ - "Ir" (newval) \ - : "memory"); \ - __result != 0; \ - }) -# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gint result; - gpointer prev; - __asm__ __volatile__ ( - " mb\n" - "1: ldl_l %0,%2\n" - " cmpeq %0,%3,%1\n" - " beq %1,2f\n" - " mov %4,%1\n" - " stl_c %1,%2\n" - " beq %1,1b\n" - " mb\n" - "2:" - : "=&r" (prev), - "=&r" (result) - : "m" (*atomic), - "Ir" (oldval), - "Ir" (newval) - : "memory"); - return result != 0; -} -# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gint result; - gpointer prev; - __asm__ __volatile__ ( - " mb\n" - "1: ldq_l %0,%2\n" - " cmpeq %0,%3,%1\n" - " beq %1,2f\n" - " mov %4,%1\n" - " stq_c %1,%2\n" - " beq %1,1b\n" - " mb\n" - "2:" - : "=&r" (prev), - "=&r" (result) - : "m" (*atomic), - "Ir" (oldval), - "Ir" (newval) - : "memory"); - return result != 0; -} -# else /* What's that */ -# error "Your system has an unsupported pointer size" -# endif /* GLIB_SIZEOF_VOID_P */ -# define G_ATOMIC_MEMORY_BARRIER __asm__ ("mb" : : : "memory") -# elif defined (G_ATOMIC_X86_64) -/* Adapted from CVS version 1.9 of glibc's sysdeps/x86_64/bits/atomic.h - */ -gint -g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result; - - __asm__ __volatile__ ("lock; xaddl %0,%1" - : "=r" (result), "=m" (*atomic) - : "0" (val), "m" (*atomic)); - return result; -} - -void -g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - __asm__ __volatile__ ("lock; addl %1,%0" - : "=m" (*atomic) - : "ir" (val), "m" (*atomic)); -} - -gboolean -g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval) -{ - gint result; - - __asm__ __volatile__ ("lock; cmpxchgl %2, %1" - : "=a" (result), "=m" (*atomic) - : "r" (newval), "m" (*atomic), "0" (oldval)); - - return result == oldval; -} - -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gpointer result; - - __asm__ __volatile__ ("lock; cmpxchgq %q2, %1" - : "=a" (result), "=m" (*atomic) - : "r" (newval), "m" (*atomic), "0" (oldval)); - - return result == oldval; -} - -# elif defined (G_ATOMIC_POWERPC) -/* Adapted from CVS version 1.16 of glibc's sysdeps/powerpc/bits/atomic.h - * and CVS version 1.4 of glibc's sysdeps/powerpc/powerpc32/bits/atomic.h - * and CVS version 1.7 of glibc's sysdeps/powerpc/powerpc64/bits/atomic.h - */ -# ifdef __OPTIMIZE__ -/* Non-optimizing compile bails on the following two asm statements - * for reasons unknown to the author */ -gint -g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result, temp; -#if ASM_NUMERIC_LABELS - __asm__ __volatile__ ("1: lwarx %0,0,%3\n" - " add %1,%0,%4\n" - " stwcx. %1,0,%3\n" - " bne- 1b" - : "=&b" (result), "=&r" (temp), "=m" (*atomic) - : "b" (atomic), "r" (val), "m" (*atomic) - : "cr0", "memory"); -#else - __asm__ __volatile__ (".Lieaa%=: lwarx %0,0,%3\n" - " add %1,%0,%4\n" - " stwcx. %1,0,%3\n" - " bne- .Lieaa%=" - : "=&b" (result), "=&r" (temp), "=m" (*atomic) - : "b" (atomic), "r" (val), "m" (*atomic) - : "cr0", "memory"); +#ifndef __GNUC__ +#error Using GCC builtin atomic ops, but not compiling with GCC? #endif - return result; -} - -/* The same as above, to save a function call repeated here */ -void -g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result, temp; -#if ASM_NUMERIC_LABELS - __asm__ __volatile__ ("1: lwarx %0,0,%3\n" - " add %1,%0,%4\n" - " stwcx. %1,0,%3\n" - " bne- 1b" - : "=&b" (result), "=&r" (temp), "=m" (*atomic) - : "b" (atomic), "r" (val), "m" (*atomic) - : "cr0", "memory"); -#else - __asm__ __volatile__ (".Lia%=: lwarx %0,0,%3\n" - " add %1,%0,%4\n" - " stwcx. %1,0,%3\n" - " bne- .Lia%=" - : "=&b" (result), "=&r" (temp), "=m" (*atomic) - : "b" (atomic), "r" (val), "m" (*atomic) - : "cr0", "memory"); -#endif -} -# else /* !__OPTIMIZE__ */ -gint -g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result; - do - result = *atomic; - while (!g_atomic_int_compare_and_exchange (atomic, result, result + val)); - - return result; -} - -void -g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result; - do - result = *atomic; - while (!g_atomic_int_compare_and_exchange (atomic, result, result + val)); -} -# endif /* !__OPTIMIZE__ */ - -# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ -gboolean -g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval) -{ - gint result; -#if ASM_NUMERIC_LABELS - __asm__ __volatile__ ("sync\n" - "1: lwarx %0,0,%1\n" - " subf. %0,%2,%0\n" - " bne 2f\n" - " stwcx. %3,0,%1\n" - " bne- 1b\n" - "2: isync" - : "=&r" (result) - : "b" (atomic), "r" (oldval), "r" (newval) - : "cr0", "memory"); -#else - __asm__ __volatile__ ("sync\n" - ".L1icae%=: lwarx %0,0,%1\n" - " subf. %0,%2,%0\n" - " bne .L2icae%=\n" - " stwcx. %3,0,%1\n" - " bne- .L1icae%=\n" - ".L2icae%=: isync" - : "=&r" (result) - : "b" (atomic), "r" (oldval), "r" (newval) - : "cr0", "memory"); -#endif - return result == 0; -} - -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gpointer result; -#if ASM_NUMERIC_LABELS - __asm__ __volatile__ ("sync\n" - "1: lwarx %0,0,%1\n" - " subf. %0,%2,%0\n" - " bne 2f\n" - " stwcx. %3,0,%1\n" - " bne- 1b\n" - "2: isync" - : "=&r" (result) - : "b" (atomic), "r" (oldval), "r" (newval) - : "cr0", "memory"); -#else - __asm__ __volatile__ ("sync\n" - ".L1pcae%=: lwarx %0,0,%1\n" - " subf. %0,%2,%0\n" - " bne .L2pcae%=\n" - " stwcx. %3,0,%1\n" - " bne- .L1pcae%=\n" - ".L2pcae%=: isync" - : "=&r" (result) - : "b" (atomic), "r" (oldval), "r" (newval) - : "cr0", "memory"); -#endif - return result == 0; -} -# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ -gboolean -g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval) -{ - gpointer result; -#if ASM_NUMERIC_LABELS - __asm__ __volatile__ ("sync\n" - "1: lwarx %0,0,%1\n" - " extsw %0,%0\n" - " subf. %0,%2,%0\n" - " bne 2f\n" - " stwcx. %3,0,%1\n" - " bne- 1b\n" - "2: isync" - : "=&r" (result) - : "b" (atomic), "r" (oldval), "r" (newval) - : "cr0", "memory"); -#else - __asm__ __volatile__ ("sync\n" - ".L1icae%=: lwarx %0,0,%1\n" - " extsw %0,%0\n" - " subf. %0,%2,%0\n" - " bne .L2icae%=\n" - " stwcx. %3,0,%1\n" - " bne- .L1icae%=\n" - ".L2icae%=: isync" - : "=&r" (result) - : "b" (atomic), "r" (oldval), "r" (newval) - : "cr0", "memory"); -#endif - return result == 0; -} - -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gpointer result; -#if ASM_NUMERIC_LABELS - __asm__ __volatile__ ("sync\n" - "1: ldarx %0,0,%1\n" - " subf. %0,%2,%0\n" - " bne 2f\n" - " stdcx. %3,0,%1\n" - " bne- 1b\n" - "2: isync" - : "=&r" (result) - : "b" (atomic), "r" (oldval), "r" (newval) - : "cr0", "memory"); -#else - __asm__ __volatile__ ("sync\n" - ".L1pcae%=: ldarx %0,0,%1\n" - " subf. %0,%2,%0\n" - " bne .L2pcae%=\n" - " stdcx. %3,0,%1\n" - " bne- .L1pcae%=\n" - ".L2pcae%=: isync" - : "=&r" (result) - : "b" (atomic), "r" (oldval), "r" (newval) - : "cr0", "memory"); -#endif - return result == 0; -} -# else /* What's that */ -# error "Your system has an unsupported pointer size" -# endif /* GLIB_SIZEOF_VOID_P */ - -# define G_ATOMIC_MEMORY_BARRIER __asm__ ("sync" : : : "memory") - -# elif defined (G_ATOMIC_IA64) -/* Adapted from CVS version 1.8 of glibc's sysdeps/ia64/bits/atomic.h - */ -gint -g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - return __sync_fetch_and_add (atomic, val); -} - -void -g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - __sync_fetch_and_add (atomic, val); -} - -gboolean -g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval) -{ - return __sync_bool_compare_and_swap (atomic, oldval, newval); -} - -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - return __sync_bool_compare_and_swap ((long *)atomic, - (long)oldval, (long)newval); -} - -# define G_ATOMIC_MEMORY_BARRIER __sync_synchronize () -# elif defined (G_ATOMIC_S390) -/* Adapted from glibc's sysdeps/s390/bits/atomic.h - */ -# define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ - ({ \ - gint __result = oldval; \ - __asm__ __volatile__ ("cs %0, %2, %1" \ - : "+d" (__result), "=Q" (*(atomic)) \ - : "d" (newval), "m" (*(atomic)) : "cc" ); \ - __result == oldval; \ - }) - -# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gpointer result = oldval; - __asm__ __volatile__ ("cs %0, %2, %1" - : "+d" (result), "=Q" (*(atomic)) - : "d" (newval), "m" (*(atomic)) : "cc" ); - return result == oldval; -} -# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gpointer result = oldval; - gpointer *a = atomic; - __asm__ __volatile__ ("csg %0, %2, %1" - : "+d" (result), "=Q" (*a) - : "d" ((long)(newval)), "m" (*a) : "cc" ); - return result == oldval; -} -# else /* What's that */ -# error "Your system has an unsupported pointer size" -# endif /* GLIB_SIZEOF_VOID_P */ -# elif defined (G_ATOMIC_ARM) -static volatile int atomic_spin = 0; - -static int atomic_spin_trylock (void) -{ - int result; - - asm volatile ( - "swp %0, %1, [%2]\n" - : "=&r,&r" (result) - : "r,0" (1), "r,r" (&atomic_spin) - : "memory"); - if (result == 0) - return 0; - else - return -1; -} - -static void atomic_spin_lock (void) -{ - while (atomic_spin_trylock()) - sched_yield(); -} - -static void atomic_spin_unlock (void) -{ - atomic_spin = 0; -} - -gint -g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result; - - atomic_spin_lock(); - result = *atomic; - *atomic += val; - atomic_spin_unlock(); - - return result; -} - -void -g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - atomic_spin_lock(); - *atomic += val; - atomic_spin_unlock(); -} - -gboolean -g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval) -{ - gboolean result; - - atomic_spin_lock(); - if (*atomic == oldval) - { - result = TRUE; - *atomic = newval; - } - else - result = FALSE; - atomic_spin_unlock(); - - return result; -} - -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gboolean result; - - atomic_spin_lock(); - if (*atomic == oldval) - { - result = TRUE; - *atomic = newval; - } - else - result = FALSE; - atomic_spin_unlock(); - - return result; -} -# elif defined (G_ATOMIC_CRIS) || defined (G_ATOMIC_CRISV32) -# ifdef G_ATOMIC_CRIS -# define CRIS_ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ - ({ \ - gboolean __result; \ - __asm__ __volatile__ ("\n" \ - "0:\tclearf\n\t" \ - "cmp.d [%[Atomic]], %[OldVal]\n\t" \ - "bne 1f\n\t" \ - "ax\n\t" \ - "move.d %[NewVal], [%[Atomic]]\n\t" \ - "bwf 0b\n" \ - "1:\tseq %[Result]" \ - : [Result] "=&r" (__result), \ - "=m" (*(atomic)) \ - : [Atomic] "r" (atomic), \ - [OldVal] "r" (oldval), \ - [NewVal] "r" (newval), \ - "g" (*(gpointer*) (atomic)) \ - : "memory"); \ - __result; \ - }) -# else -# define CRIS_ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ - ({ \ - gboolean __result; \ - __asm__ __volatile__ ("\n" \ - "0:\tclearf p\n\t" \ - "cmp.d [%[Atomic]], %[OldVal]\n\t" \ - "bne 1f\n\t" \ - "ax\n\t" \ - "move.d %[NewVal], [%[Atomic]]\n\t" \ - "bcs 0b\n" \ - "1:\tseq %[Result]" \ - : [Result] "=&r" (__result), \ - "=m" (*(atomic)) \ - : [Atomic] "r" (atomic), \ - [OldVal] "r" (oldval), \ - [NewVal] "r" (newval), \ - "g" (*(gpointer*) (atomic)) \ - : "memory"); \ - __result; \ - }) -# endif - -#define CRIS_CACHELINE_SIZE 32 -#define CRIS_ATOMIC_BREAKS_CACHELINE(atomic) \ - (((gulong)(atomic) & (CRIS_CACHELINE_SIZE - 1)) > (CRIS_CACHELINE_SIZE - sizeof (atomic))) - -gint __g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val); -void __g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val); -gboolean __g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval); -gboolean __g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval); - -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - if (G_UNLIKELY (CRIS_ATOMIC_BREAKS_CACHELINE (atomic))) - return __g_atomic_pointer_compare_and_exchange (atomic, oldval, newval); - - return CRIS_ATOMIC_INT_CMP_XCHG (atomic, oldval, newval); -} - -gboolean -g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval) -{ - if (G_UNLIKELY (CRIS_ATOMIC_BREAKS_CACHELINE (atomic))) - return __g_atomic_int_compare_and_exchange (atomic, oldval, newval); - - return CRIS_ATOMIC_INT_CMP_XCHG (atomic, oldval, newval); -} - -gint -g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result; - - if (G_UNLIKELY (CRIS_ATOMIC_BREAKS_CACHELINE (atomic))) - return __g_atomic_int_exchange_and_add (atomic, val); - - do - result = *atomic; - while (!CRIS_ATOMIC_INT_CMP_XCHG (atomic, result, result + val)); - - return result; -} - -void -g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result; - - if (G_UNLIKELY (CRIS_ATOMIC_BREAKS_CACHELINE (atomic))) - return __g_atomic_int_add (atomic, val); - - do - result = *atomic; - while (!CRIS_ATOMIC_INT_CMP_XCHG (atomic, result, result + val)); -} - -/* We need the atomic mutex for atomic operations where the atomic variable - * breaks the 32 byte cache line since the CRIS architecture does not support - * atomic operations on such variables. Fortunately this should be rare. - */ -# define DEFINE_WITH_MUTEXES -# define g_atomic_int_exchange_and_add __g_atomic_int_exchange_and_add -# define g_atomic_int_add __g_atomic_int_add -# define g_atomic_int_compare_and_exchange __g_atomic_int_compare_and_exchange -# define g_atomic_pointer_compare_and_exchange __g_atomic_pointer_compare_and_exchange - -# else /* !G_ATOMIC_* */ -# define DEFINE_WITH_MUTEXES -# endif /* G_ATOMIC_* */ -#else /* !__GNUC__ */ -# ifdef G_PLATFORM_WIN32 -# define DEFINE_WITH_WIN32_INTERLOCKED -# else -# define DEFINE_WITH_MUTEXES -# endif -#endif /* __GNUC__ */ - -#ifdef DEFINE_WITH_WIN32_INTERLOCKED -# include -/* Following indicates that InterlockedCompareExchangePointer is - * declared in winbase.h (included by windows.h) and needs to be - * commented out if not true. It is defined iff WINVER > 0x0400, - * which is usually correct but can be wrong if WINVER is set before - * windows.h is included. - */ -# if WINVER > 0x0400 -# define HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER -# endif - -gint32 -g_atomic_int_exchange_and_add (volatile gint32 G_GNUC_MAY_ALIAS *atomic, - gint32 val) -{ - return InterlockedExchangeAdd (atomic, val); -} - -void -g_atomic_int_add (volatile gint32 G_GNUC_MAY_ALIAS *atomic, - gint32 val) -{ - InterlockedExchangeAdd (atomic, val); -} - -gboolean -g_atomic_int_compare_and_exchange (volatile gint32 G_GNUC_MAY_ALIAS *atomic, - gint32 oldval, - gint32 newval) -{ -#ifndef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER - return (guint32) InterlockedCompareExchange ((PVOID*)atomic, - (PVOID)newval, - (PVOID)oldval) == oldval; -#else - return InterlockedCompareExchange (atomic, - newval, - oldval) == oldval; -#endif -} - -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ -# ifdef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER - return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval; -# else -# if GLIB_SIZEOF_VOID_P != 4 /* no 32-bit system */ -# error "InterlockedCompareExchangePointer needed" -# else - return InterlockedCompareExchange (atomic, newval, oldval) == oldval; -# endif -# endif -} -#endif /* DEFINE_WITH_WIN32_INTERLOCKED */ - -#ifdef DEFINE_WITH_MUTEXES -/* We have to use the slow, but safe locking method */ -static GMutex *g_atomic_mutex; - -/** - * g_atomic_int_exchange_and_add: - * @atomic: a pointer to an integer - * @val: the value to add to *@atomic - * - * Atomically adds @val to the integer pointed to by @atomic. - * It returns the value of *@atomic just before the addition - * took place. Also acts as a memory barrier. - * - * Returns: the value of *@atomic before the addition. - * - * Since: 2.4 - */ -gint -g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result; - - g_mutex_lock (g_atomic_mutex); - result = *atomic; - *atomic += val; - g_mutex_unlock (g_atomic_mutex); - - return result; -} - -/** - * g_atomic_int_add: - * @atomic: a pointer to an integer - * @val: the value to add to *@atomic - * - * Atomically adds @val to the integer pointed to by @atomic. - * Also acts as a memory barrier. - * - * Since: 2.4 - */ -void -g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - g_mutex_lock (g_atomic_mutex); - *atomic += val; - g_mutex_unlock (g_atomic_mutex); -} - -/** - * g_atomic_int_compare_and_exchange: - * @atomic: a pointer to an integer - * @oldval: the assumed old value of *@atomic - * @newval: the new value of *@atomic - * - * Compares @oldval with the integer pointed to by @atomic and - * if they are equal, atomically exchanges *@atomic with @newval. - * Also acts as a memory barrier. - * - * Returns: %TRUE, if *@atomic was equal @oldval. %FALSE otherwise. - * - * Since: 2.4 - */ -gboolean -g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval) -{ - gboolean result; - - g_mutex_lock (g_atomic_mutex); - if (*atomic == oldval) - { - result = TRUE; - *atomic = newval; - } - else - result = FALSE; - g_mutex_unlock (g_atomic_mutex); - - return result; -} - -/** - * g_atomic_pointer_compare_and_exchange: - * @atomic: a pointer to a #gpointer - * @oldval: the assumed old value of *@atomic - * @newval: the new value of *@atomic - * - * Compares @oldval with the pointer pointed to by @atomic and - * if they are equal, atomically exchanges *@atomic with @newval. - * Also acts as a memory barrier. - * - * Returns: %TRUE, if *@atomic was equal @oldval. %FALSE otherwise. - * - * Since: 2.4 - */ -gboolean -g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval) -{ - gboolean result; - - g_mutex_lock (g_atomic_mutex); - if (*atomic == oldval) - { - result = TRUE; - *atomic = newval; - } - else - result = FALSE; - g_mutex_unlock (g_atomic_mutex); - - return result; -} - -#ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED /** * g_atomic_int_get: - * @atomic: a pointer to an integer + * @atomic: a pointer to a #gint or #guint * - * Reads the value of the integer pointed to by @atomic. - * Also acts as a memory barrier. + * Gets the current value of @atomic. * - * Returns: the value of *@atomic + * This call acts as a full compiler and hardware memory barrier (before + * the get). + * + * Returns: the value of the integer * * Since: 2.4 - */ + **/ gint -(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic) -{ - gint result; - - g_mutex_lock (g_atomic_mutex); - result = *atomic; - g_mutex_unlock (g_atomic_mutex); - - return result; -} - -/** - * g_atomic_int_set: - * @atomic: a pointer to an integer - * @newval: the new value - * - * Sets the value of the integer pointed to by @atomic. - * Also acts as a memory barrier. - * - * Since: 2.10 - */ -void -(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint newval) -{ - g_mutex_lock (g_atomic_mutex); - *atomic = newval; - g_mutex_unlock (g_atomic_mutex); -} - -/** - * g_atomic_pointer_get: - * @atomic: a pointer to a #gpointer. - * - * Reads the value of the pointer pointed to by @atomic. - * Also acts as a memory barrier. - * - * Returns: the value to add to *@atomic. - * - * Since: 2.4 - */ -gpointer -(g_atomic_pointer_get) (volatile gpointer G_GNUC_MAY_ALIAS *atomic) -{ - gpointer result; - - g_mutex_lock (g_atomic_mutex); - result = *atomic; - g_mutex_unlock (g_atomic_mutex); - - return result; -} - -/** - * g_atomic_pointer_set: - * @atomic: a pointer to a #gpointer - * @newval: the new value - * - * Sets the value of the pointer pointed to by @atomic. - * Also acts as a memory barrier. - * - * Since: 2.10 - */ -void -(g_atomic_pointer_set) (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer newval) -{ - g_mutex_lock (g_atomic_mutex); - *atomic = newval; - g_mutex_unlock (g_atomic_mutex); -} -#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ -#elif defined (G_ATOMIC_OP_MEMORY_BARRIER_NEEDED) -gint -(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic) -{ - G_ATOMIC_MEMORY_BARRIER; - return *atomic; -} - -void -(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint newval) -{ - *atomic = newval; - G_ATOMIC_MEMORY_BARRIER; -} - -gpointer -(g_atomic_pointer_get) (volatile gpointer G_GNUC_MAY_ALIAS *atomic) -{ - G_ATOMIC_MEMORY_BARRIER; - return *atomic; -} - -void -(g_atomic_pointer_set) (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer newval) -{ - *atomic = newval; - G_ATOMIC_MEMORY_BARRIER; -} -#endif /* DEFINE_WITH_MUTEXES || G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ - -#ifdef ATOMIC_INT_CMP_XCHG -gboolean -g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval) -{ - return ATOMIC_INT_CMP_XCHG (atomic, oldval, newval); -} - -gint -g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result; - do - result = *atomic; - while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val)); - - return result; -} - -void -g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val) -{ - gint result; - do - result = *atomic; - while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val)); -} -#endif /* ATOMIC_INT_CMP_XCHG */ - -void -_g_atomic_thread_init (void) -{ -#ifdef DEFINE_WITH_MUTEXES - g_atomic_mutex = g_mutex_new (); -#endif /* DEFINE_WITH_MUTEXES */ -} - -#ifndef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED -gint -(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic) +(g_atomic_int_get) (volatile gint *atomic) { return g_atomic_int_get (atomic); } +/** + * g_atomic_int_set: + * @atomic: a pointer to a #gint or #guint + * @newval: a new value to store + * + * Sets the value of @atomic to @newval. + * + * This call acts as a full compiler and hardware memory barrier (after + * the set). + * + * Since: 2.4 + **/ void -(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint newval) +(g_atomic_int_set) (volatile gint *atomic, + gint newval) { g_atomic_int_set (atomic, newval); } -gpointer -(g_atomic_pointer_get) (volatile gpointer G_GNUC_MAY_ALIAS *atomic) +/** + * g_atomic_int_inc: + * @atomic: a pointer to a #gint or #guint + * + * Increments the value of @atomic by 1. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Since: 2.4 + **/ +void +(g_atomic_int_inc) (volatile gint *atomic) { - return g_atomic_pointer_get (atomic); + g_atomic_int_inc (atomic); +} + +/** + * g_atomic_int_dec_and_test: + * @atomic: a pointer to a #gint or #guint + * + * Decrements the value of @atomic by 1. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Returns: %TRUE if the resultant value is zero + * + * Since: 2.4 + **/ +gboolean +(g_atomic_int_dec_and_test) (volatile gint *atomic) +{ + return g_atomic_int_dec_and_test (atomic); +} + +/** + * g_atomic_int_compare_and_exchange: + * @atomic: a pointer to a #gint or #guint + * @oldval: the value to compare with + * @newval: the value to conditionally replace with + * + * 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. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Returns: %TRUE if the exchange took place + * + * Since: 2.4 + **/ +gboolean +(g_atomic_int_compare_and_exchange) (volatile gint *atomic, + gint oldval, + gint newval) +{ + return g_atomic_int_compare_and_exchange (atomic, oldval, newval); +} + +/** + * g_atomic_int_add: + * @atomic: a pointer to a #gint or #guint + * @val: the value to add + * + * Atomically adds @val to the value of @atomic. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Returns: the value of @atomic before the add, signed + * + * Since: 2.4 + **/ +gint +(g_atomic_int_add) (volatile gint *atomic, + gint val) +{ + return g_atomic_int_add (atomic, val); +} + +/** + * g_atomic_int_and: + * @atomic: a pointer to a #gint or #guint + * @val: the value to 'and' + * + * 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. + * + * Returns: the value of @atomic before the operation, unsigned + * + * Since: 2.30 + **/ +guint +(g_atomic_int_and) (volatile guint *atomic, + guint val) +{ + return g_atomic_int_and (atomic, val); +} + +/** + * g_atomic_int_or: + * @atomic: a pointer to a #gint or #guint + * @val: the value to 'or' + * + * Performs an atomic bitwise 'or' of the value of @atomic and @val, + * storing the result back in @atomic. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Returns: the value of @atomic before the operation, unsigned + * + * Since: 2.30 + **/ +guint +(g_atomic_int_or) (volatile guint *atomic, + guint val) +{ + return g_atomic_int_or (atomic, val); +} + +/** + * g_atomic_int_xor: + * @atomic: a pointer to a #gint or #guint + * @val: the value to 'xor' + * + * Performs an atomic bitwise 'xor' of the value of @atomic and @val, + * storing the result back in @atomic. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Returns: the value of @atomic before the operation, unsigned + * + * Since: 2.30 + **/ +guint +(g_atomic_int_xor) (volatile guint *atomic, + guint val) +{ + return g_atomic_int_xor (atomic, val); +} + + +/** + * g_atomic_pointer_get: + * @atomic: a pointer to a #gpointer-sized value + * + * Gets the current value of @atomic. + * + * This call acts as a full compiler and hardware memory barrier (before + * the get). + * + * Returns: the value of the pointer + * + * Since: 2.4 + **/ +gpointer +(g_atomic_pointer_get) (volatile void *atomic) +{ + return g_atomic_pointer_get ((volatile gpointer *) atomic); +} + +/** + * g_atomic_pointer_set: + * @atomic: a pointer to a #gpointer-sized value + * @newval: a new value to store + * + * Sets the value of @atomic to @newval. + * + * This call acts as a full compiler and hardware memory barrier (after + * the set). + * + * Since: 2.4 + **/ +void +(g_atomic_pointer_set) (volatile void *atomic, + gpointer newval) +{ + g_atomic_pointer_set ((volatile gpointer *) atomic, newval); +} + +/** + * g_atomic_pointer_compare_and_exchange: + * @atomic: a pointer to a #gpointer-sized value + * @oldval: the value to compare with + * @newval: the value to conditionally replace with + * + * 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. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Returns: %TRUE if the exchange took place + * + * Since: 2.4 + **/ +gboolean +(g_atomic_pointer_compare_and_exchange) (volatile void *atomic, + gpointer oldval, + gpointer newval) +{ + return g_atomic_pointer_compare_and_exchange ((volatile gpointer *) atomic, + oldval, newval); +} + +/** + * g_atomic_pointer_add: + * @atomic: a pointer to a #gpointer-sized value + * @val: the value to add + * + * Atomically adds @val to the value of @atomic. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Returns: the value of @atomic before the add, signed + * + * Since: 2.30 + **/ +gssize +(g_atomic_pointer_add) (volatile void *atomic, + gssize val) +{ + return g_atomic_pointer_add ((volatile gpointer *) atomic, val); +} + +/** + * g_atomic_pointer_and: + * @atomic: a pointer to a #gpointer-sized value + * @val: the value to 'and' + * + * 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. + * + * Returns: the value of @atomic before the operation, unsigned + * + * Since: 2.30 + **/ +gsize +(g_atomic_pointer_and) (volatile void *atomic, + gsize val) +{ + return g_atomic_pointer_and ((volatile gpointer *) atomic, val); +} + +/** + * g_atomic_pointer_or: + * @atomic: a pointer to a #gpointer-sized value + * @val: the value to 'or' + * + * Performs an atomic bitwise 'or' of the value of @atomic and @val, + * storing the result back in @atomic. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Returns: the value of @atomic before the operation, unsigned + * + * Since: 2.30 + **/ +gsize +(g_atomic_pointer_or) (volatile void *atomic, + gsize val) +{ + return g_atomic_pointer_or ((volatile gpointer *) atomic, val); +} + +/** + * g_atomic_pointer_xor: + * @atomic: a pointer to a #gpointer-sized value + * @val: the value to 'xor' + * + * Performs an atomic bitwise 'xor' of the value of @atomic and @val, + * storing the result back in @atomic. + * + * This call acts as a full compiler and hardware memory barrier. + * + * Returns: the value of @atomic before the operation, unsigned + * + * Since: 2.30 + **/ +gsize +(g_atomic_pointer_xor) (volatile void *atomic, + gsize val) +{ + return g_atomic_pointer_xor ((volatile gpointer *) atomic, val); +} + +#elif defined (G_PLATFORM_WIN32) + +/* + * http://msdn.microsoft.com/en-us/library/ms684122(v=vs.85).aspx + */ +gint +(g_atomic_int_get) (volatile gint *atomic) +{ + MemoryBarrier (); + return *atomic; } void -(g_atomic_pointer_set) (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer newval) +(g_atomic_int_set) (volatile gint *atomic, + gint newval) { - g_atomic_pointer_set (atomic, newval); + *atomic = newval; + MemoryBarrier (); +} + +void +(g_atomic_int_inc) (volatile gint *atomic) +{ + InterlockedIncrement (atomic); +} + +gboolean +(g_atomic_int_dec_and_test) (volatile gint *atomic) +{ + return InterlockedDecrement (atomic) == 0; +} + +gboolean +(g_atomic_int_compare_and_exchange) (volatile gint *atomic, + gint oldval, + gint newval) +{ + return InterlockedCompareExchange (atomic, newval, oldval) == oldval; +} + +gint +(g_atomic_int_add) (volatile gint *atomic, + gint val) +{ + return InterlockedExchangeAdd (atomic, val); +} + +guint +(g_atomic_int_and) (volatile guint *atomic, + guint val) +{ + return InterlockedAnd (atomic, val); +} + +guint +(g_atomic_int_or) (volatile guint *atomic, + guint val) +{ + return InterlockedOr (atomic, val); +} + +guint +(g_atomic_int_xor) (volatile guint *atomic, + guint val) +{ + return InterlockedXor (atomic, val); +} + + +gpointer +(g_atomic_pointer_get) (volatile void *atomic) +{ + volatile gpointer *ptr = atomic; + + MemoryBarrier (); + return *ptr; +} + +void +(g_atomic_pointer_set) (volatile void *atomic, + gpointer newval) +{ + volatile gpointer *ptr = atomic; + + *ptr = newval; + MemoryBarrier (); +} + +gboolean +(g_atomic_pointer_compare_and_exchange) (volatile void *atomic, + gpointer oldval, + gpointer newval) +{ + return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval; +} + +gssize +(g_atomic_pointer_add) (volatile void *atomic, + gssize val) +{ +#if GLIB_SIZEOF_VOID_P == 8 + return InterlockedExchangeAdd64 (atomic, val); +#else + return InterlockedExchangeAdd (atomic, val); +#endif +} + +gsize +(g_atomic_pointer_and) (volatile void *atomic, + gsize val) +{ +#if GLIB_SIZEOF_VOID_P == 8 + return InterlockedAnd64 (atomic, val); +#else + return InterlockedAnd (atomic, val); +#endif +} + +gsize +(g_atomic_pointer_or) (volatile void *atomic, + gsize val) +{ +#if GLIB_SIZEOF_VOID_P == 8 + return InterlockedOr64 (atomic, val); +#else + return InterlockedOr (atomic, val); +#endif +} + +gsize +(g_atomic_pointer_xor) (volatile void *atomic, + gsize val) +{ +#if GLIB_SIZEOF_VOID_P == 8 + return InterlockedXor64 (atomic, val); +#else + return InterlockedXor (atomic, val); +#endif +} + +#else + +#include "gthread.h" + +static GStaticMutex g_atomic_lock; + +gint +(g_atomic_int_get) (volatile gint *atomic) +{ + gint value; + + g_static_mutex_lock (&g_atomic_lock); + value = *atomic; + g_static_mutex_unlock (&g_atomic_lock); + + return value; +} + +void +(g_atomic_int_set) (volatile gint *atomic, + gint value) +{ + g_static_mutex_lock (&g_atomic_lock); + *atomic = value; + g_static_mutex_unlock (&g_atomic_lock); +} + +void +(g_atomic_int_inc) (volatile gint *atomic) +{ + g_static_mutex_lock (&g_atomic_lock); + (*atomic)++; + g_static_mutex_unlock (&g_atomic_lock); +} + +gboolean +(g_atomic_int_dec_and_test) (volatile gint *atomic) +{ + gboolean is_zero; + + g_static_mutex_lock (&g_atomic_lock); + is_zero = --(*atomic) == 0; + g_static_mutex_unlock (&g_atomic_lock); + + return is_zero; +} + +gboolean +(g_atomic_int_compare_and_exchange) (volatile gint *atomic, + gint oldval, + gint newval) +{ + gboolean success; + + g_static_mutex_lock (&g_atomic_lock); + + if ((success = (*atomic == oldval))) + *atomic = newval; + + g_static_mutex_unlock (&g_atomic_lock); + + return success; +} + +gint +(g_atomic_int_add) (volatile gint *atomic, + gint val) +{ + gint oldval; + + g_static_mutex_lock (&g_atomic_lock); + oldval = *atomic; + *atomic = oldval + val; + g_static_mutex_unlock (&g_atomic_lock); + + return oldval; +} + +guint +(g_atomic_int_and) (volatile guint *atomic, + guint val) +{ + guint oldval; + + g_static_mutex_lock (&g_atomic_lock); + oldval = *atomic; + *atomic = oldval & val; + g_static_mutex_unlock (&g_atomic_lock); + + return oldval; +} + +guint +(g_atomic_int_or) (volatile guint *atomic, + guint val) +{ + guint oldval; + + g_static_mutex_lock (&g_atomic_lock); + oldval = *atomic; + *atomic = oldval | val; + g_static_mutex_unlock (&g_atomic_lock); + + return oldval; +} + +guint +(g_atomic_int_xor) (volatile guint *atomic, + guint val) +{ + guint oldval; + + g_static_mutex_lock (&g_atomic_lock); + oldval = *atomic; + *atomic = oldval ^ val; + g_static_mutex_unlock (&g_atomic_lock); + + return oldval; +} + + +gpointer +(g_atomic_pointer_get) (volatile void *atomic) +{ + volatile gpointer *ptr = atomic; + gpointer value; + + g_static_mutex_lock (&g_atomic_lock); + value = *ptr; + g_static_mutex_unlock (&g_atomic_lock); + + return value; +} + +void +(g_atomic_pointer_set) (volatile void *atomic, + gpointer newval) +{ + volatile gpointer *ptr = atomic; + + g_static_mutex_lock (&g_atomic_lock); + *ptr = newval; + g_static_mutex_unlock (&g_atomic_lock); +} + +gboolean +(g_atomic_pointer_compare_and_exchange) (volatile void *atomic, + gpointer oldval, + gpointer newval) +{ + volatile gpointer *ptr = atomic; + gboolean success; + + g_static_mutex_lock (&g_atomic_lock); + + if ((success = (*ptr == oldval))) + *ptr = newval; + + g_static_mutex_unlock (&g_atomic_lock); + + return success; +} + +gssize +(g_atomic_pointer_add) (volatile void *atomic, + gssize val) +{ + volatile gssize *ptr = atomic; + gssize oldval; + + g_static_mutex_lock (&g_atomic_lock); + oldval = *ptr; + *ptr = oldval + val; + g_static_mutex_unlock (&g_atomic_lock); + + return oldval; +} + +gsize +(g_atomic_pointer_and) (volatile void *atomic, + gsize val) +{ + volatile gsize *ptr = atomic; + gsize oldval; + + g_static_mutex_lock (&g_atomic_lock); + oldval = *ptr; + *ptr = oldval & val; + g_static_mutex_unlock (&g_atomic_lock); + + return oldval; +} + +gsize +(g_atomic_pointer_or) (volatile void *atomic, + gsize val) +{ + volatile gsize *ptr = atomic; + gsize oldval; + + g_static_mutex_lock (&g_atomic_lock); + oldval = *ptr; + *ptr = oldval | val; + g_static_mutex_unlock (&g_atomic_lock); + + return oldval; +} + +gsize +(g_atomic_pointer_xor) (volatile void *atomic, + gsize val) +{ + volatile gsize *ptr = atomic; + gsize oldval; + + g_static_mutex_lock (&g_atomic_lock); + oldval = *ptr; + *ptr = oldval ^ val; + g_static_mutex_unlock (&g_atomic_lock); + + return oldval; +} + +#endif + +/** + * g_atomic_int_exchange_and_add: + * @atomic: a pointer to a #gint + * @val: the value to add + * + * This function existed before g_atomic_int_add() returned the prior + * value of the integer (which it now does). It is retained only for + * compatibility reasons. Don't use this function in new code. + * + * Returns: the value of @atomic before the add, signed + * Since: 2.4 + * Deprecated: 2.30: Use g_atomic_int_add() instead. + **/ +gint +g_atomic_int_exchange_and_add (volatile gint *atomic, + gint val) +{ + return (g_atomic_int_add) (atomic, val); } -#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ diff --git a/glib/gatomic.h b/glib/gatomic.h index 544b6f15e..16b8e3dcb 100644 --- a/glib/gatomic.h +++ b/glib/gatomic.h @@ -1,30 +1,22 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald +/* + * Copyright © 2011 Ryan Lortie * - * g_atomic_*: atomic operations. - * Copyright (C) 2003 Sebastian Wilhelmi + * 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 of the + * licence, or (at your option) any later version. * - * 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 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 + * 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. - */ - -/* - * Modified by the GLib Team and others 1997-2000. See the AUTHORS - * file for a list of people on the GLib Team. See the ChangeLog - * files for a list of changes. These files are distributed with - * GLib at ftp://ftp.gtk.org/pub/gtk/. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + * + * Author: Ryan Lortie */ #if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) @@ -34,122 +26,192 @@ #ifndef __G_ATOMIC_H__ #define __G_ATOMIC_H__ -#include +#include "glib/gtypes.h" G_BEGIN_DECLS -gint g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val); -void g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint val); -gboolean g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint oldval, - gint newval); -gboolean g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer oldval, - gpointer newval); +gint g_atomic_int_get (volatile gint *atomic); +void g_atomic_int_set (volatile gint *atomic, + gint newval); +void g_atomic_int_inc (volatile gint *atomic); +gboolean g_atomic_int_dec_and_test (volatile gint *atomic); +gboolean g_atomic_int_compare_and_exchange (volatile gint *atomic, + gint oldval, + gint newval); +gint g_atomic_int_add (volatile gint *atomic, + gint val); +guint g_atomic_int_and (volatile guint *atomic, + guint val); +guint g_atomic_int_or (volatile guint *atomic, + guint val); +guint g_atomic_int_xor (volatile guint *atomic, + guint val); -gint g_atomic_int_get (volatile gint G_GNUC_MAY_ALIAS *atomic); -void g_atomic_int_set (volatile gint G_GNUC_MAY_ALIAS *atomic, - gint newval); -gpointer g_atomic_pointer_get (volatile gpointer G_GNUC_MAY_ALIAS *atomic); -void g_atomic_pointer_set (volatile gpointer G_GNUC_MAY_ALIAS *atomic, - gpointer newval); +gpointer g_atomic_pointer_get (volatile void *atomic); +void g_atomic_pointer_set (volatile void *atomic, + gpointer newval); +gboolean g_atomic_pointer_compare_and_exchange (volatile void *atomic, + gpointer oldval, + gpointer newval); +gssize g_atomic_pointer_add (volatile void *atomic, + gssize val); +gsize g_atomic_pointer_and (volatile void *atomic, + gsize val); +gsize g_atomic_pointer_or (volatile void *atomic, + gsize val); +gsize g_atomic_pointer_xor (volatile void *atomic, + gsize val); -#if defined(__GNUC__) && defined(G_ATOMIC_OP_USE_GCC_BUILTINS) - -#define g_atomic_int_exchange_and_add(atomic,val) \ - __extension__ ({ G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)); \ - __sync_fetch_and_add((atomic),(val)); }) - -#define g_atomic_int_add(atomic,val) \ - __extension__ ({ G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)); \ - __sync_fetch_and_add((atomic),(val)); }) - -#define g_atomic_int_compare_and_exchange(atomic,oldval,newval) \ - __extension__ ({ G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)); \ - __sync_bool_compare_and_swap((atomic),(oldval),(newval)); }) - -#define g_atomic_int_get(atomic) \ - __extension__ ({ G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)); \ - __sync_synchronize(); *(atomic); }) - -#define g_atomic_int_set(atomic,newval) \ - __extension__ ({ G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)); \ - *(atomic) = (newval); __sync_synchronize(); }) - -#define g_atomic_pointer_compare_and_exchange(atomic,oldval,newval) \ - __extension__ ({ G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gpointer)); \ - __sync_bool_compare_and_swap((atomic),(oldval),(newval)); }) - -#define g_atomic_pointer_get(atomic) \ - __extension__ ({ G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gpointer)); \ - __sync_synchronize(); *(atomic); }) - -#define g_atomic_pointer_set(atomic,newval) \ - __extension__ ({ G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gpointer)); \ - *(atomic) = (newval); __sync_synchronize(); }) - -#elif !defined(G_ATOMIC_OP_MEMORY_BARRIER_NEEDED) - -# define g_atomic_int_get(atomic) ((gint)*(atomic)) -# define g_atomic_int_set(atomic, newval) ((void) (*(atomic) = (newval))) -# define g_atomic_pointer_get(atomic) ((gpointer)*(atomic)) -# define g_atomic_pointer_set(atomic, newval) ((void) (*(atomic) = (newval))) - -#else - -#define g_atomic_int_exchange_and_add(atomic,val) \ - (G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)), \ - (g_atomic_int_exchange_and_add) ((volatile gint G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (val))) -#define g_atomic_int_add(atomic,val) \ - (G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)), \ - (g_atomic_int_add) ((volatile gint G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (val))) -#define g_atomic_int_compare_and_exchange(atomic,oldval,newval) \ - (G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)), \ - (g_atomic_int_compare_and_exchange) ((volatile gint G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (oldval), (newval))) -#define g_atomic_pointer_compare_and_exchange(atomic,oldval,newval) \ - (G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gpointer)), \ - (g_atomic_pointer_compare_and_exchange) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (oldval), (newval))) -#define g_atomic_int_get(atomic) \ - (G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)), \ - (g_atomic_int_get) ((volatile gint G_GNUC_MAY_ALIAS *) (volatile void *) (atomic))) -#define g_atomic_int_set(atomic, newval) \ - (G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)), \ - (g_atomic_int_set) ((volatile gint G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval))) -#define g_atomic_pointer_get(atomic) \ - (G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gpointer)), \ - (g_atomic_pointer_get) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic))) -#define g_atomic_pointer_set(atomic, newval) \ - (G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gpointer)), \ - (g_atomic_pointer_set) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval))) - -#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ - -/** - * g_atomic_int_inc: - * @atomic: a pointer to an integer. - * - * Atomically increments the integer pointed to by @atomic by 1. - * - * Since: 2.4 - */ -#define g_atomic_int_inc(atomic) (g_atomic_int_add ((atomic), 1)) - -/** - * g_atomic_int_dec_and_test: - * @atomic: a pointer to an integer - * - * Atomically decrements the integer pointed to by @atomic by 1. - * - * Returns: %TRUE if the integer pointed to by @atomic is 0 - * after decrementing it - * - * Since: 2.4 - */ -#define g_atomic_int_dec_and_test(atomic) \ - (g_atomic_int_exchange_and_add ((atomic), -1) == 1) +#ifndef G_DISABLE_DEPRECATED +gint g_atomic_int_exchange_and_add (volatile gint *atomic, + gint val); +#endif G_END_DECLS +#if defined(__GNUC__) && defined(G_ATOMIC_OP_USE_GCC_BUILTINS) + +#define g_atomic_int_get(atomic) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ + (void) (0 ? *(atomic) ^ *(atomic) : 0); \ + __sync_synchronize (); \ + (gint) *(atomic); \ + })) +#define g_atomic_int_set(atomic, newval) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ + (void) (0 ? *(atomic) ^ (newval) : 0); \ + *(atomic) = (newval); \ + __sync_synchronize (); \ + })) +#define g_atomic_int_inc(atomic) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ + (void) (0 ? *(atomic) ^ *(atomic) : 0); \ + (void) __sync_fetch_and_add ((atomic), 1); \ + })) +#define g_atomic_int_dec_and_test(atomic) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ + (void) (0 ? *(atomic) ^ *(atomic) : 0); \ + __sync_fetch_and_sub ((atomic), 1) == 1; \ + })) +#define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ + (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 0); \ + (gboolean) __sync_bool_compare_and_swap ((atomic), (oldval), (newval)); \ + })) +#define g_atomic_int_add(atomic, val) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ + (void) (0 ? *(atomic) ^ (val) : 0); \ + (gint) __sync_fetch_and_add ((atomic), (val)); \ + })) +#define g_atomic_int_and(atomic, val) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ + (void) (0 ? *(atomic) ^ (val) : 0); \ + (guint) __sync_fetch_and_and ((atomic), (val)); \ + })) +#define g_atomic_int_or(atomic, val) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ + (void) (0 ? *(atomic) ^ (val) : 0); \ + (guint) __sync_fetch_and_or ((atomic), (val)); \ + })) +#define g_atomic_int_xor(atomic, val) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ + (void) (0 ? *(atomic) ^ (val) : 0); \ + (guint) __sync_fetch_and_xor ((atomic), (val)); \ + })) + +#define g_atomic_pointer_get(atomic) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ + __sync_synchronize (); \ + (gpointer) *(atomic); \ + })) +#define g_atomic_pointer_set(atomic, newval) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ + (void) (0 ? (gpointer) *(atomic) : 0); \ + *(atomic) = (__typeof__ (*(atomic))) (gsize) (newval); \ + __sync_synchronize (); \ + })) +#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ + (void) (0 ? (gpointer) *(atomic) : 0); \ + (gboolean) __sync_bool_compare_and_swap ((atomic), (oldval), (newval)); \ + })) +#define g_atomic_pointer_add(atomic, val) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ + (void) (0 ? (gpointer) *(atomic) : 0); \ + (void) (0 ? (val) ^ (val) : 0); \ + (gssize) __sync_fetch_and_add ((atomic), (val)); \ + })) +#define g_atomic_pointer_and(atomic, val) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ + (void) (0 ? (gpointer) *(atomic) : 0); \ + (void) (0 ? (val) ^ (val) : 0); \ + (gsize) __sync_fetch_and_and ((atomic), (val)); \ + })) +#define g_atomic_pointer_or(atomic, val) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ + (void) (0 ? (gpointer) *(atomic) : 0); \ + (void) (0 ? (val) ^ (val) : 0); \ + (gsize) __sync_fetch_and_or ((atomic), (val)); \ + })) +#define g_atomic_pointer_xor(atomic, val) \ + (__extension__ ({ \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ + (void) (0 ? (gpointer) *(atomic) : 0); \ + (void) (0 ? (val) ^ (val) : 0); \ + (gsize) __sync_fetch_and_xor ((atomic), (val)); \ + })) + +#else /* defined(__GNUC__) && defined(G_ATOMIC_OP_USE_GCC_BUILTINS) */ + +#define g_atomic_int_get(atomic) \ + (g_atomic_int_get ((gint *) (atomic))) +#define g_atomic_int_set(atomic, newval) \ + (g_atomic_int_set ((gint *) (atomic), (gint) (newval))) +#define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \ + (g_atomic_int_compare_and_exchange ((gint *) (atomic), (oldval), (newval))) +#define g_atomic_int_add(atomic, val) \ + (g_atomic_int_add ((gint *) (atomic), (val))) +#define g_atomic_int_and(atomic, val) \ + (g_atomic_int_and ((gint *) (atomic), (val))) +#define g_atomic_int_or(atomic, val) \ + (g_atomic_int_or ((gint *) (atomic), (val))) +#define g_atomic_int_xor(atomic, val) \ + (g_atomic_int_xor ((gint *) (atomic), (val))) +#define g_atomic_int_inc(atomic) \ + (g_atomic_int_inc ((gint *) (atomic))) +#define g_atomic_int_dec_and_test(atomic) \ + (g_atomic_int_dec_and_test ((gint *) (atomic))) + +#define g_atomic_pointer_get(atomic) \ + (g_atomic_pointer_get (atomic)) +#define g_atomic_pointer_set(atomic, newval) \ + (g_atomic_pointer_set ((atomic), (gpointer) (newval))) +#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \ + (g_atomic_pointer_compare_and_exchange ((atomic), (gpointer) (oldval), (gpointer) (newval))) +#define g_atomic_pointer_add(atomic, val) \ + (g_atomic_pointer_add ((atomic), (gssize) (val))) +#define g_atomic_pointer_and(atomic, val) \ + (g_atomic_pointer_and ((atomic), (gsize) (val))) +#define g_atomic_pointer_or(atomic, val) \ + (g_atomic_pointer_or ((atomic), (gsize) (val))) +#define g_atomic_pointer_xor(atomic, val) \ + (g_atomic_pointer_xor ((atomic), (gsize) (val))) + +#endif /* defined(__GNUC__) && defined(G_ATOMIC_OP_USE_GCC_BUILTINS) */ + #endif /* __G_ATOMIC_H__ */ diff --git a/glib/glib.symbols b/glib/glib.symbols index f3ae0a95f..c26bd91e8 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -69,13 +69,22 @@ g_async_queue_unref g_async_queue_ref_unlocked g_async_queue_unref_and_unlock g_atomic_int_add +g_atomic_int_and g_atomic_int_compare_and_exchange +g_atomic_int_dec_and_test g_atomic_int_exchange_and_add -g_atomic_pointer_compare_and_exchange g_atomic_int_get -g_atomic_pointer_get +g_atomic_int_inc +g_atomic_int_or g_atomic_int_set +g_atomic_int_xor +g_atomic_pointer_add +g_atomic_pointer_and +g_atomic_pointer_compare_and_exchange +g_atomic_pointer_get +g_atomic_pointer_or g_atomic_pointer_set +g_atomic_pointer_xor g_on_error_query g_on_error_stack_trace g_base64_encode_step diff --git a/glib/gthread.c b/glib/gthread.c index 61cc01f1d..5a811ce08 100644 --- a/glib/gthread.c +++ b/glib/gthread.c @@ -945,7 +945,6 @@ g_thread_init_glib (void) _g_messages_thread_init_nomessage (); /* we may run full-fledged initializers from here */ - _g_atomic_thread_init (); _g_convert_thread_init (); _g_rand_thread_init (); _g_main_thread_init (); diff --git a/glib/gthreadpool.c b/glib/gthreadpool.c index d6fac9253..bde519f5a 100644 --- a/glib/gthreadpool.c +++ b/glib/gthreadpool.c @@ -207,7 +207,7 @@ g_thread_pool_wait_for_new_pool (void) } else { - if (g_atomic_int_exchange_and_add (&kill_unused_threads, -1) > 0) + if (g_atomic_int_add (&kill_unused_threads, -1) > 0) { pool = NULL; break; diff --git a/glib/tests/atomic.c b/glib/tests/atomic.c index e16baf02e..771e85346 100644 --- a/glib/tests/atomic.c +++ b/glib/tests/atomic.c @@ -12,7 +12,6 @@ main (void) g_atomic_int_set (&u, 5); g_atomic_int_get (&u); g_atomic_int_compare_and_exchange (&u, 6, 7); - g_atomic_int_exchange_and_add (&u, 1); g_atomic_int_add (&u, 1); g_atomic_int_inc (&u); (void) g_atomic_int_dec_and_test (&u); @@ -20,7 +19,6 @@ main (void) g_atomic_int_set (&s, 5); g_atomic_int_get (&s); g_atomic_int_compare_and_exchange (&s, 6, 7); - g_atomic_int_exchange_and_add (&s, 1); g_atomic_int_add (&s, 1); g_atomic_int_inc (&s); (void) g_atomic_int_dec_and_test (&s); diff --git a/gobject/gobject.c b/gobject/gobject.c index ead907195..33c978592 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -2654,7 +2654,7 @@ g_object_ref (gpointer _object) #endif /* G_ENABLE_DEBUG */ - old_val = g_atomic_int_exchange_and_add ((int *)&object->ref_count, 1); + old_val = g_atomic_int_add (&object->ref_count, 1); if (old_val == 1 && OBJECT_HAS_TOGGLE_REF (object)) toggle_refs_notify (object, FALSE); @@ -2735,7 +2735,7 @@ g_object_unref (gpointer _object) g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); /* decrement the last reference */ - old_ref = g_atomic_int_exchange_and_add ((int *)&object->ref_count, -1); + old_ref = g_atomic_int_add (&object->ref_count, -1); TRACE (GOBJECT_OBJECT_UNREF(object,G_TYPE_FROM_INSTANCE(object),old_ref));