mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-16 12:45:13 +01:00
gatomic: introduce G_ATOMIC_LOCK_FREE
We clean up the detection of if we should do 'real' atomic operations or mutex-emulated ones with the introduction of a new (public) macro: G_ATOMIC_LOCK_FREE. If defined, our atomic operations are guaranteed to be done in hardware. We need to use __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 to determine if our compiler supports GCC-style atomic operations from the gatomic.h header because we might be building a program against GLib using a different set of compiler options (or a different compiler) than was used to build GLib itself. Unfortunately, this macro is not available on clang, so it has currently regressed to using the mutex emulation. A bug about that has been opened here: http://llvm.org/bugs/show_bug.cgi?id=11174
This commit is contained in:
parent
c9b6c3c85a
commit
aba0f0c38b
63
configure.ac
63
configure.ac
@ -2407,6 +2407,47 @@ dnl ************************
|
|||||||
dnl *** g_atomic_* tests ***
|
dnl *** g_atomic_* tests ***
|
||||||
dnl ************************
|
dnl ************************
|
||||||
|
|
||||||
|
dnl We need to decide at configure time if GLib will use real atomic
|
||||||
|
dnl operations ("lock free") or emulated ones with a mutex. This is
|
||||||
|
dnl because we must put this information in glibconfig.h so we know if
|
||||||
|
dnl it is safe or not to inline using compiler intrinsics directly from
|
||||||
|
dnl the header.
|
||||||
|
dnl
|
||||||
|
dnl We also publish the information via G_ATOMIC_LOCK_FREE in case the
|
||||||
|
dnl user is interested in knowing if they can use the atomic ops across
|
||||||
|
dnl processes.
|
||||||
|
dnl
|
||||||
|
dnl We can currently support the atomic ops natively when building GLib
|
||||||
|
dnl with recent versions of GCC or MSVC. MSVC doesn't run ./configure,
|
||||||
|
dnl so we skip that case here and define G_ATOMIC_LOCK_FREE exactly when
|
||||||
|
dnl we are using GCC.
|
||||||
|
dnl
|
||||||
|
dnl Note that the atomic ops are only available with GCC on x86 when
|
||||||
|
dnl using -march=i486 or higher. If we detect that the atomic ops are
|
||||||
|
dnl not available but would be available given the right flags, we want
|
||||||
|
dnl to abort and advise the user to fix their CFLAGS. It's better to do
|
||||||
|
dnl that then to silently fall back on emulated atomic ops just because
|
||||||
|
dnl the user had the wrong build environment.
|
||||||
|
|
||||||
|
dnl We may add other compilers here in the future...
|
||||||
|
AC_MSG_CHECKING([for lock-free atomic intrinsics])
|
||||||
|
AC_TRY_COMPILE([],
|
||||||
|
[__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;],
|
||||||
|
[g_atomic_lock_free=yes],
|
||||||
|
[g_atomic_lock_free=no])
|
||||||
|
AC_MSG_RESULT($g_atomic_lock_free)
|
||||||
|
|
||||||
|
if test "$g_atomic_lock_free" = "no"; then
|
||||||
|
SAVE_CFLAGS="${CFLAGS}"
|
||||||
|
CFLAGS="-march=i486"
|
||||||
|
AC_TRY_COMPILE([],
|
||||||
|
[__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;],
|
||||||
|
[AC_MSG_ERROR([GLib must be build with -march=i486 or later.])],
|
||||||
|
[])
|
||||||
|
CFLAGS="${SAVE_CFLAGS}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl We need a more robust approach here...
|
||||||
case $host_cpu in
|
case $host_cpu in
|
||||||
i?86|x86_64|s390|s390x|arm*|crisv32*|etrax*)
|
i?86|x86_64|s390|s390x|arm*|crisv32*|etrax*)
|
||||||
glib_memory_barrier_needed=no
|
glib_memory_barrier_needed=no
|
||||||
@ -2419,24 +2460,6 @@ dnl ************************
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
glib_cv_gcc_has_builtin_atomic_operations=no
|
|
||||||
if test x"$GCC" = xyes; then
|
|
||||||
AC_MSG_CHECKING([whether GCC supports built-in atomic intrinsics])
|
|
||||||
AC_TRY_LINK([],
|
|
||||||
[int i;
|
|
||||||
__sync_synchronize ();
|
|
||||||
__sync_bool_compare_and_swap (&i, 0, 1);
|
|
||||||
__sync_fetch_and_add (&i, 1);
|
|
||||||
],
|
|
||||||
[glib_cv_gcc_has_builtin_atomic_operations=yes],
|
|
||||||
[glib_cv_gcc_has_builtin_atomic_operations=no])
|
|
||||||
|
|
||||||
AC_MSG_RESULT($glib_cv_gcc_has_builtin_atomic_operations)
|
|
||||||
fi
|
|
||||||
|
|
||||||
AM_CONDITIONAL(HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS,
|
|
||||||
[test $glib_cv_gcc_has_builtin_atomic_operations = yes])
|
|
||||||
|
|
||||||
dnl ************************
|
dnl ************************
|
||||||
dnl ** Check for futex(2) **
|
dnl ** Check for futex(2) **
|
||||||
dnl ************************
|
dnl ************************
|
||||||
@ -3085,9 +3108,9 @@ _______EOF
|
|||||||
echo >>$outfile
|
echo >>$outfile
|
||||||
echo "#define G_ATOMIC_OP_MEMORY_BARRIER_NEEDED 1" >>$outfile
|
echo "#define G_ATOMIC_OP_MEMORY_BARRIER_NEEDED 1" >>$outfile
|
||||||
fi
|
fi
|
||||||
if test x"$g_gcc_atomic_ops" != xno; then
|
if test x"$g_atomic_lock_free" = xyes; then
|
||||||
echo >>$outfile
|
echo >>$outfile
|
||||||
echo "#define G_ATOMIC_OP_USE_GCC_BUILTINS 1" >>$outfile
|
echo "#define G_ATOMIC_LOCK_FREE" >>$outfile
|
||||||
fi
|
fi
|
||||||
echo >>$outfile
|
echo >>$outfile
|
||||||
g_bit_sizes="16 32 64"
|
g_bit_sizes="16 32 64"
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
# This file makes most of the thread related macros look like
|
# This file makes most of the thread related macros look like
|
||||||
# functions, which they really were, if possible easy.
|
# functions, which they really were, if possible easy.
|
||||||
|
|
||||||
|
<MACRO>
|
||||||
|
<NAME>G_ATOMIC_LOCK_FREE</NAME>
|
||||||
|
#define G_ATOMIC_LOCK_FREE
|
||||||
|
</MACRO>
|
||||||
|
|
||||||
# default thread implementation
|
# default thread implementation
|
||||||
|
|
||||||
<MACRO>
|
<MACRO>
|
||||||
|
@ -806,6 +806,9 @@ g_async_queue_sort_unlocked
|
|||||||
<SECTION>
|
<SECTION>
|
||||||
<TITLE>Atomic Operations</TITLE>
|
<TITLE>Atomic Operations</TITLE>
|
||||||
<FILE>atomic_operations</FILE>
|
<FILE>atomic_operations</FILE>
|
||||||
|
G_ATOMIC_LOCK_FREE
|
||||||
|
|
||||||
|
<SUBSECTION>
|
||||||
g_atomic_int_get
|
g_atomic_int_get
|
||||||
g_atomic_int_set
|
g_atomic_int_set
|
||||||
g_atomic_int_inc
|
g_atomic_int_inc
|
||||||
|
@ -50,22 +50,6 @@
|
|||||||
* hardware memory barrier. Acquire and release or producer and
|
* hardware memory barrier. Acquire and release or producer and
|
||||||
* consumer barrier semantics are not available through this API.
|
* 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
|
* It is very important that all accesses to a particular integer or
|
||||||
* pointer be performed using only this API and that different sizes of
|
* pointer be performed using only this API and that different sizes of
|
||||||
* operation are not mixed or used on overlapping memory regions. Never
|
* operation are not mixed or used on overlapping memory regions. Never
|
||||||
@ -82,6 +66,19 @@
|
|||||||
* perform the operations normally and then release the lock.
|
* 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:
|
/* NOTE CAREFULLY:
|
||||||
*
|
*
|
||||||
* This file is the lowest-level part of GLib.
|
* This file is the lowest-level part of GLib.
|
||||||
@ -93,12 +90,13 @@
|
|||||||
* without risking recursion.
|
* without risking recursion.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef G_ATOMIC_OP_USE_GCC_BUILTINS
|
#ifdef G_ATOMIC_LOCK_FREE
|
||||||
|
|
||||||
#ifndef __GNUC__
|
/* if G_ATOMIC_LOCK_FREE was defined by ./configure then we MUST
|
||||||
#error Using GCC builtin atomic ops, but not compiling with GCC?
|
* implement the atomic operations in a lock-free manner.
|
||||||
#endif
|
*/
|
||||||
|
|
||||||
|
#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
|
||||||
/**
|
/**
|
||||||
* g_atomic_int_get:
|
* g_atomic_int_get:
|
||||||
* @atomic: a pointer to a #gint or #guint
|
* @atomic: a pointer to a #gint or #guint
|
||||||
@ -612,9 +610,17 @@ gsize
|
|||||||
return InterlockedXor (atomic, val);
|
return InterlockedXor (atomic, val);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#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
|
/* We are not permitted to call into any GLib functions from here, so we
|
||||||
* can not use GMutex.
|
* can not use GMutex.
|
||||||
*
|
*
|
||||||
|
@ -70,7 +70,7 @@ gint g_atomic_int_exchange_and_add (volatile gint *a
|
|||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#if defined(__GNUC__) && defined(G_ATOMIC_OP_USE_GCC_BUILTINS)
|
#if defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
|
||||||
|
|
||||||
#define g_atomic_int_get(atomic) \
|
#define g_atomic_int_get(atomic) \
|
||||||
(G_GNUC_EXTENSION ({ \
|
(G_GNUC_EXTENSION ({ \
|
||||||
@ -177,7 +177,7 @@ G_END_DECLS
|
|||||||
(gsize) __sync_fetch_and_xor ((atomic), (val)); \
|
(gsize) __sync_fetch_and_xor ((atomic), (val)); \
|
||||||
}))
|
}))
|
||||||
|
|
||||||
#else /* defined(__GNUC__) && defined(G_ATOMIC_OP_USE_GCC_BUILTINS) */
|
#else /* defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
|
||||||
|
|
||||||
#define g_atomic_int_get(atomic) \
|
#define g_atomic_int_get(atomic) \
|
||||||
(g_atomic_int_get ((gint *) (atomic)))
|
(g_atomic_int_get ((gint *) (atomic)))
|
||||||
|
@ -207,6 +207,8 @@ typedef unsigned __int64 guintptr;
|
|||||||
#define G_THREADS_ENABLED
|
#define G_THREADS_ENABLED
|
||||||
#define G_THREADS_IMPL_WIN32
|
#define G_THREADS_IMPL_WIN32
|
||||||
|
|
||||||
|
#define G_ATOMIC_LOCK_FREE
|
||||||
|
|
||||||
#define GINT16_TO_LE(val) ((gint16) (val))
|
#define GINT16_TO_LE(val) ((gint16) (val))
|
||||||
#define GUINT16_TO_LE(val) ((guint16) (val))
|
#define GUINT16_TO_LE(val) ((guint16) (val))
|
||||||
#define GINT16_TO_BE(val) ((gint16) GUINT16_SWAP_LE_BE (val))
|
#define GINT16_TO_BE(val) ((gint16) GUINT16_SWAP_LE_BE (val))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user