X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgatomic.c;h=30a5c5d51f22af55eeb107a2d7ebd15eecb24695;hb=7e3d32b7053b47ca7feecf185abac96b619770c2;hp=5b354c44aaa63580b27f3460a1e9523117feddd1;hpb=e2ae75ad4be9107ee172c644c096e5949598c4a8;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gatomic.c b/glib/gatomic.c index 5b354c4..30a5c5d 100644 --- a/glib/gatomic.c +++ b/glib/gatomic.c @@ -12,9 +12,7 @@ * 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, see . * * Author: Ryan Lortie */ @@ -50,22 +48,6 @@ * 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 @@ -76,12 +58,24 @@ * 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 + * 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. **/ +/** + * G_ATOMIC_LOCK_FREE: + * + * This macro is defined if the atomic operations of GLib are + * implemented using real hardware atomic operations. This means that + * the GLib atomic API can be used between processes and safely mixed + * with other (hardware) atomic APIs. + * + * If this macro is not defined, the atomic operations may be + * emulated using a mutex. In that case, the GLib atomic operations are + * only atomic relative to themselves and within a single process. + **/ + /* NOTE CAREFULLY: * * This file is the lowest-level part of GLib. @@ -93,12 +87,13 @@ * without risking recursion. */ -#ifdef G_ATOMIC_OP_USE_GCC_BUILTINS +#ifdef G_ATOMIC_LOCK_FREE -#ifndef __GNUC__ -#error Using GCC builtin atomic ops, but not compiling with GCC? -#endif +/* if G_ATOMIC_LOCK_FREE was defined by ./configure then we MUST + * implement the atomic operations in a lock-free manner. + */ +#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) /** * g_atomic_int_get: * @atomic: a pointer to a #gint or #guint @@ -113,7 +108,7 @@ * Since: 2.4 **/ gint -(g_atomic_int_get) (volatile gint *atomic) +(g_atomic_int_get) (const volatile gint *atomic) { return g_atomic_int_get (atomic); } @@ -143,8 +138,7 @@ void * * Increments the value of @atomic by 1. * - * Think of this operation as an atomic version of - * { *@atomic += 1; } + * Think of this operation as an atomic version of `{ *atomic += 1; }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -163,7 +157,7 @@ void * Decrements the value of @atomic by 1. * * Think of this operation as an atomic version of - * { *@atomic -= 1; return (*@atomic == 0); } + * `{ *atomic -= 1; return (*atomic == 0); }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -189,7 +183,7 @@ gboolean * This compare and exchange is done atomically. * * Think of this operation as an atomic version of - * { if (*@atomic == @oldval) { *@atomic = @newval; return TRUE; } else return FALSE; } + * `{ if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -213,7 +207,7 @@ gboolean * Atomically adds @val to the value of @atomic. * * Think of this operation as an atomic version of - * { tmp = *atomic; *@atomic += @val; return tmp; } + * `{ tmp = *atomic; *atomic += val; return tmp; }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -242,7 +236,7 @@ gint * This call acts as a full compiler and hardware memory barrier. * * Think of this operation as an atomic version of - * { tmp = *atomic; *@atomic &= @val; return tmp; } + * `{ tmp = *atomic; *atomic &= val; return tmp; }`. * * Returns: the value of @atomic before the operation, unsigned * @@ -264,7 +258,7 @@ guint * storing the result back in @atomic. * * Think of this operation as an atomic version of - * { tmp = *atomic; *@atomic |= @val; return tmp; } + * `{ tmp = *atomic; *atomic |= val; return tmp; }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -288,7 +282,7 @@ guint * storing the result back in @atomic. * * Think of this operation as an atomic version of - * { tmp = *atomic; *@atomic ^= @val; return tmp; } + * `{ tmp = *atomic; *atomic ^= val; return tmp; }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -318,9 +312,9 @@ guint * Since: 2.4 **/ gpointer -(g_atomic_pointer_get) (volatile void *atomic) +(g_atomic_pointer_get) (const volatile void *atomic) { - return g_atomic_pointer_get ((volatile gpointer *) atomic); + return g_atomic_pointer_get ((const volatile gpointer *) atomic); } /** @@ -354,7 +348,7 @@ void * This compare and exchange is done atomically. * * Think of this operation as an atomic version of - * { if (*@atomic == @oldval) { *@atomic = @newval; return TRUE; } else return FALSE; } + * `{ if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -379,7 +373,7 @@ gboolean * Atomically adds @val to the value of @atomic. * * Think of this operation as an atomic version of - * { tmp = *atomic; *@atomic += @val; return tmp; } + * `{ tmp = *atomic; *atomic += val; return tmp; }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -403,7 +397,7 @@ gssize * storing the result back in @atomic. * * Think of this operation as an atomic version of - * { tmp = *atomic; *@atomic &= @val; return tmp; } + * `{ tmp = *atomic; *atomic &= val; return tmp; }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -427,7 +421,7 @@ gsize * storing the result back in @atomic. * * Think of this operation as an atomic version of - * { tmp = *atomic; *@atomic |= @val; return tmp; } + * `{ tmp = *atomic; *atomic |= val; return tmp; }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -451,7 +445,7 @@ gsize * storing the result back in @atomic. * * Think of this operation as an atomic version of - * { tmp = *atomic; *@atomic ^= @val; return tmp; } + * `{ tmp = *atomic; *atomic ^= val; return tmp; }`. * * This call acts as a full compiler and hardware memory barrier. * @@ -466,20 +460,70 @@ gsize return g_atomic_pointer_xor ((volatile gpointer *) atomic, val); } -#elif defined (G_PLATFORM_WIN32) && defined(HAVE_WIN32_BUILTINS_FOR_ATOMIC_OPERATIONS) +#elif defined (G_PLATFORM_WIN32) #include -#if !defined(_M_AMD64) && !defined (_M_IA64) && !defined(_M_X64) +#if !defined(_M_AMD64) && !defined (_M_IA64) && !defined(_M_X64) && !(defined _MSC_VER && _MSC_VER <= 1200) #define InterlockedAnd _InterlockedAnd #define InterlockedOr _InterlockedOr #define InterlockedXor _InterlockedXor #endif +#if !defined (_MSC_VER) || _MSC_VER <= 1200 +#include "gmessages.h" +/* Inlined versions for older compiler */ +static LONG +_gInterlockedAnd (volatile guint *atomic, + guint val) +{ + LONG i, j; + + j = *atomic; + do { + i = j; + j = InterlockedCompareExchange(atomic, i & val, i); + } while (i != j); + + return j; +} +#define InterlockedAnd(a,b) _gInterlockedAnd(a,b) +static LONG +_gInterlockedOr (volatile guint *atomic, + guint val) +{ + LONG i, j; + + j = *atomic; + do { + i = j; + j = InterlockedCompareExchange(atomic, i | val, i); + } while (i != j); + + return j; +} +#define InterlockedOr(a,b) _gInterlockedOr(a,b) +static LONG +_gInterlockedXor (volatile guint *atomic, + guint val) +{ + LONG i, j; + + j = *atomic; + do { + i = j; + j = InterlockedCompareExchange(atomic, i ^ val, i); + } while (i != j); + + return j; +} +#define InterlockedXor(a,b) _gInterlockedXor(a,b) +#endif + /* * http://msdn.microsoft.com/en-us/library/ms684122(v=vs.85).aspx */ gint -(g_atomic_int_get) (volatile gint *atomic) +(g_atomic_int_get) (const volatile gint *atomic) { MemoryBarrier (); return *atomic; @@ -543,9 +587,9 @@ guint gpointer -(g_atomic_pointer_get) (volatile void *atomic) +(g_atomic_pointer_get) (const volatile void *atomic) { - volatile gpointer *ptr = atomic; + const volatile gpointer *ptr = atomic; MemoryBarrier (); return *ptr; @@ -612,9 +656,17 @@ gsize return InterlockedXor (atomic, val); #endif } - #else +/* This error occurs when ./configure decided that we should be capable + * of lock-free atomics but we find at compile-time that we are not. + */ +#error G_ATOMIC_LOCK_FREE defined, but incapable of lock-free atomics. + +#endif /* defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */ + +#else /* G_ATOMIC_LOCK_FREE */ + /* We are not permitted to call into any GLib functions from here, so we * can not use GMutex. * @@ -626,7 +678,7 @@ gsize static pthread_mutex_t g_atomic_lock = PTHREAD_MUTEX_INITIALIZER; gint -(g_atomic_int_get) (volatile gint *atomic) +(g_atomic_int_get) (const volatile gint *atomic) { gint value; @@ -741,9 +793,9 @@ guint gpointer -(g_atomic_pointer_get) (volatile void *atomic) +(g_atomic_pointer_get) (const volatile void *atomic) { - volatile gpointer *ptr = atomic; + const volatile gpointer *ptr = atomic; gpointer value; pthread_mutex_lock (&g_atomic_lock);