[glib] glib: Rewrite gatomic.[ch]
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] glib: Rewrite gatomic.[ch]
- Date: Sat, 28 May 2011 20:16:26 +0000 (UTC)
commit 83821352657a9481dbff6ab04e8ae60566c17d5e
Author: Ryan Lortie <desrt desrt ca>
Date: Sat May 28 15:59:18 2011 -0400
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 | 1608 +++++++++++++--------------------
glib/gatomic.h | 312 ++++---
glib/glib.symbols | 13 +-
glib/gthread.c | 1 -
glib/gthreadpool.c | 2 +-
glib/tests/atomic.c | 2 -
gobject/gobject.c | 4 +-
10 files changed, 830 insertions(+), 1245 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index f1a8c4f..a290ac1 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -759,17 +759,28 @@ g_async_queue_sort_unlocked
<SECTION>
<TITLE>Atomic Operations</TITLE>
-<FILE>atomic_operations</FILE>g
+<FILE>atomic_operations</FILE>
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
+
+<SUBSECTION>
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
+
+<SUBSECTION>
+g_atomic_int_exchange_and_add
<SUBSECTION Private>
G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
diff --git a/glib/Makefile.am b/glib/Makefile.am
index d0da7b2..7d333a8 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.c b/glib/gatomic.c
index f90eb05..0da78b9 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 <desrt desrt ca>
*/
#include "config.h"
-#if defined (G_ATOMIC_ARM)
-#include <sched.h>
-#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 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.
- *
- * <note><para>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.
- * </para></note>
- *
- * <note><para>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().
- * </para></note>
- *
- * <note><para>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.
- * </para></note>
- */
+ * The following is a collection of compiler macros to provide atomic
+ * access to integer and pointer-sized values.
+ *
+ * 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.
+ *
+ * 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).
+ *
+ * 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.
+ *
+ * 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.
+ **/
+
+#ifdef G_ATOMIC_OP_USE_GCC_BUILTINS
+
+#ifndef __GNUC__
+#error Using GCC builtin atomic ops, but not compiling with GCC?
+#endif
-#if defined (__GNUC__)
-# if defined (G_ATOMIC_I486)
-/* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h
- */
+/**
+ * g_atomic_int_get:
+ * @atomic: a pointer to a #gint or #guint
+ *
+ * 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 integer
+ *
+ * Since: 2.4
+ **/
gint
-g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint val)
+(g_atomic_int_get) (volatile gint *atomic)
{
- gint result;
-
- __asm__ __volatile__ ("lock; xaddl %0,%1"
- : "=r" (result), "=m" (*atomic)
- : "0" (val), "m" (*atomic));
- return result;
+ 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_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint val)
+(g_atomic_int_set) (volatile gint *atomic,
+ gint newval)
{
- __asm__ __volatile__ ("lock; addl %1,%0"
- : "=m" (*atomic)
- : "ir" (val), "m" (*atomic));
+ g_atomic_int_set (atomic, newval);
}
-gboolean
-g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint oldval,
- gint newval)
+/**
+ * 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)
{
- gint result;
-
- __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
- : "=a" (result), "=m" (*atomic)
- : "r" (newval), "m" (*atomic), "0" (oldval));
-
- return result == oldval;
+ g_atomic_int_inc (atomic);
}
-/* 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 */
-
+/**
+ * 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_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
- gpointer oldval,
- gpointer newval)
+(g_atomic_int_dec_and_test) (volatile gint *atomic)
{
- gpointer result;
-
- __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
- : "=a" (result), "=m" (*atomic)
- : "r" (newval), "m" (*atomic), "0" (oldval));
-
- return result == oldval;
+ return g_atomic_int_dec_and_test (atomic);
}
-# 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 */
+/**
+ * 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_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
- gpointer oldval,
- gpointer newval)
+(g_atomic_int_compare_and_exchange) (volatile gint *atomic,
+ gint oldval,
+ gint 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;
+ return g_atomic_int_compare_and_exchange (atomic, oldval, newval);
}
-# 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
- */
+
+/**
+ * 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_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint val)
+(g_atomic_int_add) (volatile gint *atomic,
+ gint val)
{
- gint result;
-
- __asm__ __volatile__ ("lock; xaddl %0,%1"
- : "=r" (result), "=m" (*atomic)
- : "0" (val), "m" (*atomic));
- return result;
+ return g_atomic_int_add (atomic, val);
}
-
-void
-g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint 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)
{
- __asm__ __volatile__ ("lock; addl %1,%0"
- : "=m" (*atomic)
- : "ir" (val), "m" (*atomic));
+ return g_atomic_int_and (atomic, val);
}
-gboolean
-g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint oldval,
- gint newval)
+/**
+ * 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)
{
- gint result;
-
- __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
- : "=a" (result), "=m" (*atomic)
- : "r" (newval), "m" (*atomic), "0" (oldval));
-
- return result == oldval;
+ return g_atomic_int_or (atomic, val);
}
-gboolean
-g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
- gpointer oldval,
- gpointer newval)
+/**
+ * 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)
{
- gpointer result;
-
- __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
- : "=a" (result), "=m" (*atomic)
- : "r" (newval), "m" (*atomic), "0" (oldval));
-
- return result == oldval;
+ return g_atomic_int_xor (atomic, val);
}
-# 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)
+
+/**
+ * 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)
{
- 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");
-#endif
- return result;
+ return g_atomic_pointer_get ((volatile gpointer *) atomic);
}
-
-/* The same as above, to save a function call repeated here */
+
+/**
+ * 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_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint val)
+(g_atomic_pointer_set) (volatile void *atomic,
+ gpointer newval)
{
- 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
+ g_atomic_pointer_set ((volatile gpointer *) atomic, newval);
}
-# 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)
+/**
+ * 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)
{
- gint result;
- do
- result = *atomic;
- while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
+ return g_atomic_pointer_compare_and_exchange ((volatile gpointer *) atomic,
+ oldval, newval);
}
-# 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)
+/**
+ * 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)
{
- 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;
+ return g_atomic_pointer_add ((volatile gpointer *) atomic, val);
}
-gboolean
-g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
- gpointer oldval,
- gpointer newval)
+/**
+ * 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)
{
- 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;
+ return g_atomic_pointer_and ((volatile gpointer *) atomic, val);
}
-# 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)
+
+/**
+ * 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)
{
- 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;
+ return g_atomic_pointer_or ((volatile gpointer *) atomic, val);
}
-gboolean
-g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
- gpointer oldval,
- gpointer newval)
+/**
+ * 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)
{
- 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;
+ return g_atomic_pointer_xor ((volatile gpointer *) atomic, val);
}
-# 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_PLATFORM_WIN32)
-# elif defined (G_ATOMIC_IA64)
-/* Adapted from CVS version 1.8 of glibc's sysdeps/ia64/bits/atomic.h
+/*
+ * http://msdn.microsoft.com/en-us/library/ms684122(v=vs.85).aspx
*/
gint
-g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint val)
+(g_atomic_int_get) (volatile gint *atomic)
{
- return __sync_fetch_and_add (atomic, val);
+ MemoryBarrier ();
+ return *atomic;
}
-
+
void
-g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint val)
+(g_atomic_int_set) (volatile gint *atomic,
+ gint newval)
{
- __sync_fetch_and_add (atomic, val);
+ *atomic = newval;
+ MemoryBarrier ();
}
-gboolean
-g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint oldval,
- gint newval)
+void
+(g_atomic_int_inc) (volatile gint *atomic)
{
- return __sync_bool_compare_and_swap (atomic, oldval, newval);
+ InterlockedIncrement (atomic);
}
gboolean
-g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
- gpointer oldval,
- gpointer newval)
+(g_atomic_int_dec_and_test) (volatile gint *atomic)
{
- return __sync_bool_compare_and_swap ((long *)atomic,
- (long)oldval, (long)newval);
+ return InterlockedDecrement (atomic) == 0;
}
-# 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)
+(g_atomic_int_compare_and_exchange) (volatile gint *atomic,
+ gint oldval,
+ gint newval)
{
- 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;
+ return InterlockedCompareExchange (atomic, newval, oldval) == oldval;
}
gint
-g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint val)
+(g_atomic_int_add) (volatile gint *atomic,
+ gint val)
{
- gint result;
-
- atomic_spin_lock();
- result = *atomic;
- *atomic += val;
- atomic_spin_unlock();
-
- return result;
+ return InterlockedExchangeAdd (atomic, val);
}
-void
-g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint val)
+guint
+(g_atomic_int_and) (volatile guint *atomic,
+ guint val)
{
- atomic_spin_lock();
- *atomic += val;
- atomic_spin_unlock();
+ return InterlockedAnd (atomic, val);
}
-gboolean
-g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint oldval,
- gint newval)
+guint
+(g_atomic_int_or) (volatile guint *atomic,
+ guint val)
{
- gboolean result;
-
- atomic_spin_lock();
- if (*atomic == oldval)
- {
- result = TRUE;
- *atomic = newval;
- }
- else
- result = FALSE;
- atomic_spin_unlock();
-
- return result;
+ return InterlockedOr (atomic, val);
}
-gboolean
-g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
- gpointer oldval,
- gpointer newval)
+guint
+(g_atomic_int_xor) (volatile guint *atomic,
+ guint val)
{
- gboolean result;
-
- atomic_spin_lock();
- if (*atomic == oldval)
- {
- result = TRUE;
- *atomic = newval;
- }
- else
- result = FALSE;
- atomic_spin_unlock();
-
- return result;
+ return InterlockedXor (atomic, val);
}
-# 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)
+gpointer
+(g_atomic_pointer_get) (volatile void *atomic)
{
- if (G_UNLIKELY (CRIS_ATOMIC_BREAKS_CACHELINE (atomic)))
- return __g_atomic_int_compare_and_exchange (atomic, oldval, newval);
+ volatile gpointer *ptr = atomic;
- return CRIS_ATOMIC_INT_CMP_XCHG (atomic, oldval, newval);
+ MemoryBarrier ();
+ return *ptr;
}
-gint
-g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint val)
+void
+(g_atomic_pointer_set) (volatile void *atomic,
+ gpointer newval)
{
- gint result;
-
- if (G_UNLIKELY (CRIS_ATOMIC_BREAKS_CACHELINE (atomic)))
- return __g_atomic_int_exchange_and_add (atomic, val);
+ volatile gpointer *ptr = atomic;
- do
- result = *atomic;
- while (!CRIS_ATOMIC_INT_CMP_XCHG (atomic, result, result + val));
-
- return result;
+ *ptr = newval;
+ MemoryBarrier ();
}
-void
-g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint val)
+gboolean
+(g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
+ gpointer oldval,
+ gpointer newval)
{
- 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));
+ return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval;
}
-/* 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 <windows.h>
-/* 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)
+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
}
-void
-g_atomic_int_add (volatile gint32 G_GNUC_MAY_ALIAS *atomic,
- gint32 val)
+gsize
+(g_atomic_pointer_and) (volatile void *atomic,
+ gsize val)
{
- InterlockedExchangeAdd (atomic, val);
+#if GLIB_SIZEOF_VOID_P == 8
+ return InterlockedAnd64 (atomic, val);
+#else
+ return InterlockedAnd (atomic, val);
+#endif
}
-gboolean
-g_atomic_int_compare_and_exchange (volatile gint32 G_GNUC_MAY_ALIAS *atomic,
- gint32 oldval,
- gint32 newval)
+gsize
+(g_atomic_pointer_or) (volatile void *atomic,
+ gsize val)
{
-#ifndef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
- return (guint32) InterlockedCompareExchange ((PVOID*)atomic,
- (PVOID)newval,
- (PVOID)oldval) == oldval;
+#if GLIB_SIZEOF_VOID_P == 8
+ return InterlockedOr64 (atomic, val);
#else
- return InterlockedCompareExchange (atomic,
- newval,
- oldval) == oldval;
+ return InterlockedOr (atomic, val);
#endif
}
-gboolean
-g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
- gpointer oldval,
- gpointer newval)
+gsize
+(g_atomic_pointer_xor) (volatile void *atomic,
+ gsize val)
{
-# 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
+#if GLIB_SIZEOF_VOID_P == 8
+ return InterlockedXor64 (atomic, val);
+#else
+ return InterlockedXor (atomic, val);
+#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;
+#else
+
+#include "gthread.h"
+
+static GStaticMutex g_atomic_lock;
-/**
- * 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)
+(g_atomic_int_get) (volatile gint *atomic)
{
- gint result;
-
- g_mutex_lock (g_atomic_mutex);
- result = *atomic;
- *atomic += val;
- g_mutex_unlock (g_atomic_mutex);
-
- return result;
+ gint value;
+
+ g_static_mutex_lock (&g_atomic_lock);
+ value = *atomic;
+ g_static_mutex_unlock (&g_atomic_lock);
+
+ return value;
}
-/**
- * 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_atomic_int_set) (volatile gint *atomic,
+ gint value)
{
- g_mutex_lock (g_atomic_mutex);
- *atomic += val;
- g_mutex_unlock (g_atomic_mutex);
+ g_static_mutex_lock (&g_atomic_lock);
+ *atomic = value;
+ g_static_mutex_unlock (&g_atomic_lock);
}
-/**
- * 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)
+void
+(g_atomic_int_inc) (volatile gint *atomic)
{
- 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_static_mutex_lock (&g_atomic_lock);
+ (*atomic)++;
+ g_static_mutex_unlock (&g_atomic_lock);
}
-/**
- * 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)
+(g_atomic_int_dec_and_test) (volatile gint *atomic)
{
- 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;
-}
+ gboolean is_zero;
-#ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
+ g_static_mutex_lock (&g_atomic_lock);
+ is_zero = --(*atomic) == 0;
+ g_static_mutex_unlock (&g_atomic_lock);
-/**
- * g_atomic_int_get:
- * @atomic: a pointer to an integer
- *
- * Reads the value of the integer pointed to by @atomic.
- * Also acts as a memory barrier.
- *
- * Returns: the value of * atomic
- *
- * Since: 2.4
- */
-gint
-(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic)
+ return is_zero;
+}
+
+gboolean
+(g_atomic_int_compare_and_exchange) (volatile gint *atomic,
+ gint oldval,
+ gint newval)
{
- gint result;
+ gboolean success;
- g_mutex_lock (g_atomic_mutex);
- result = *atomic;
- g_mutex_unlock (g_atomic_mutex);
+ g_static_mutex_lock (&g_atomic_lock);
- return result;
-}
+ if ((success = (*atomic == oldval)))
+ *atomic = newval;
-/**
- * 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_static_mutex_unlock (&g_atomic_lock);
+
+ return success;
}
-/**
- * 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)
+gint
+(g_atomic_int_add) (volatile gint *atomic,
+ gint val)
{
- gpointer result;
+ gint oldval;
- g_mutex_lock (g_atomic_mutex);
- result = *atomic;
- g_mutex_unlock (g_atomic_mutex);
+ g_static_mutex_lock (&g_atomic_lock);
+ oldval = *atomic;
+ *atomic = oldval + val;
+ g_static_mutex_unlock (&g_atomic_lock);
- return result;
+ return oldval;
}
-/**
- * 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)
+guint
+(g_atomic_int_and) (volatile guint *atomic,
+ guint val)
{
- g_mutex_lock (g_atomic_mutex);
- *atomic = newval;
- g_mutex_unlock (g_atomic_mutex);
+ guint oldval;
+
+ g_static_mutex_lock (&g_atomic_lock);
+ oldval = *atomic;
+ *atomic = oldval & val;
+ g_static_mutex_unlock (&g_atomic_lock);
+
+ return oldval;
}
-#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)
+
+guint
+(g_atomic_int_or) (volatile guint *atomic,
+ guint val)
{
- G_ATOMIC_MEMORY_BARRIER;
- return *atomic;
+ guint oldval;
+
+ g_static_mutex_lock (&g_atomic_lock);
+ oldval = *atomic;
+ *atomic = oldval | val;
+ g_static_mutex_unlock (&g_atomic_lock);
+
+ return oldval;
}
-void
-(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint newval)
+guint
+(g_atomic_int_xor) (volatile guint *atomic,
+ guint val)
{
- *atomic = newval;
- G_ATOMIC_MEMORY_BARRIER;
+ 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 gpointer G_GNUC_MAY_ALIAS *atomic)
+(g_atomic_pointer_get) (volatile void *atomic)
{
- G_ATOMIC_MEMORY_BARRIER;
- return *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 gpointer G_GNUC_MAY_ALIAS *atomic,
- gpointer newval)
+(g_atomic_pointer_set) (volatile void *atomic,
+ gpointer newval)
{
- *atomic = newval;
- G_ATOMIC_MEMORY_BARRIER;
+ volatile gpointer *ptr = atomic;
+
+ g_static_mutex_lock (&g_atomic_lock);
+ *ptr = newval;
+ g_static_mutex_unlock (&g_atomic_lock);
}
-#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)
+(g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
+ gpointer oldval,
+ gpointer newval)
{
- return ATOMIC_INT_CMP_XCHG (atomic, oldval, newval);
-}
+ volatile gpointer *ptr = atomic;
+ gboolean success;
-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));
+ g_static_mutex_lock (&g_atomic_lock);
- 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));
+ if ((success = (*ptr == oldval)))
+ *ptr = newval;
+
+ g_static_mutex_unlock (&g_atomic_lock);
+
+ return success;
}
-#endif /* ATOMIC_INT_CMP_XCHG */
-void
-_g_atomic_thread_init (void)
+gssize
+(g_atomic_pointer_add) (volatile void *atomic,
+ gssize val)
{
-#ifdef DEFINE_WITH_MUTEXES
- g_atomic_mutex = g_mutex_new ();
-#endif /* DEFINE_WITH_MUTEXES */
+ 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;
}
-#ifndef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
-gint
-(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic)
+gsize
+(g_atomic_pointer_and) (volatile void *atomic,
+ gsize val)
{
- return g_atomic_int_get (atomic);
+ 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;
}
-void
-(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic,
- gint newval)
+gsize
+(g_atomic_pointer_or) (volatile void *atomic,
+ gsize val)
{
- g_atomic_int_set (atomic, newval);
+ 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;
}
-gpointer
-(g_atomic_pointer_get) (volatile gpointer G_GNUC_MAY_ALIAS *atomic)
+gsize
+(g_atomic_pointer_xor) (volatile void *atomic,
+ gsize val)
{
- return g_atomic_pointer_get (atomic);
+ 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;
}
-void
-(g_atomic_pointer_set) (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
- gpointer newval)
+#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)
{
- g_atomic_pointer_set (atomic, newval);
+ 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 544b6f1..16b8e3d 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
- *
- * g_atomic_*: atomic operations.
- * Copyright (C) 2003 Sebastian Wilhelmi
+/*
+ * Copyright © 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 of the License, 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
+ * licence, 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 <desrt desrt ca>
*/
#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 <glib/gtypes.h>
+#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 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);
-
-#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); })
+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);
+
+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);
+
+#ifndef G_DISABLE_DEPRECATED
+gint g_atomic_int_exchange_and_add (volatile gint *atomic,
+ gint val);
+#endif
-#define g_atomic_int_set(atomic,newval) \
- __extension__ ({ G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gint)); \
- *(atomic) = (newval); __sync_synchronize(); })
+G_END_DECLS
-#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)); })
+#if defined(__GNUC__) && defined(G_ATOMIC_OP_USE_GCC_BUILTINS)
-#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)))
+ (__extension__ ({ \
+ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
+ (void) (0 ? *(atomic) ^ *(atomic) : 0); \
+ __sync_synchronize (); \
+ (gint) *(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)))
+ (__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) \
- (G_STATIC_ASSERT_EXPR(sizeof (*(atomic)) == sizeof (gpointer)), \
- (g_atomic_pointer_get) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic)))
+ (__extension__ ({ \
+ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
+ __sync_synchronize (); \
+ (gpointer) *(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))
+ (__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) */
-/**
- * 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_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_exchange_and_add ((atomic), -1) == 1)
+ (g_atomic_int_dec_and_test ((gint *) (atomic)))
-G_END_DECLS
+#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 f3ae0a9..c26bd91 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 61cc01f..5a811ce 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 d6fac92..bde519f 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 e16baf0..771e853 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 ead9071..33c9785 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));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]