mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-14 22:37:15 +01:00
New files to implement atomic operations for different platforms. Fixes
2004-02-26 Sebastian Wilhelmi <seppi@seppi.de> * glib/gatomic.c, glib/gatomic.h: New files to implement atomic operations for different platforms. Fixes bug #63621. * glib/glib.h: Include gatomic.h. * configure.in: Add test for assembler routines for atomic operations. * glib/Makefile.am: Add gatomic.c, gatomic.h. * tests/Makefile.am, tests/atomic-test.c: Unit test for atomic operations. * glib/glib-overrides.txt, glib/glib-sections.txt, glib/glib-docs.sgml, glib/tmpl/atomic_operations.sgml: Add docs for atomic operations.
This commit is contained in:
parent
fc9afe0d21
commit
dbbb29f608
14
ChangeLog
14
ChangeLog
@ -1,3 +1,17 @@
|
||||
2004-02-26 Sebastian Wilhelmi <seppi@seppi.de>
|
||||
|
||||
* glib/gatomic.c, glib/gatomic.h: New files to implement atomic
|
||||
operations for different platforms. Fixes bug #63621.
|
||||
|
||||
* glib/glib.h: Include gatomic.h.
|
||||
|
||||
* configure.in: Add test for assembler routines for atomic operations.
|
||||
|
||||
* glib/Makefile.am: Add gatomic.c, gatomic.h.
|
||||
|
||||
* tests/Makefile.am, tests/atomic-test.c: Unit test for atomic
|
||||
operations.
|
||||
|
||||
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* glib/glib.def : added g_hash_table_find and a
|
||||
|
@ -1,3 +1,17 @@
|
||||
2004-02-26 Sebastian Wilhelmi <seppi@seppi.de>
|
||||
|
||||
* glib/gatomic.c, glib/gatomic.h: New files to implement atomic
|
||||
operations for different platforms. Fixes bug #63621.
|
||||
|
||||
* glib/glib.h: Include gatomic.h.
|
||||
|
||||
* configure.in: Add test for assembler routines for atomic operations.
|
||||
|
||||
* glib/Makefile.am: Add gatomic.c, gatomic.h.
|
||||
|
||||
* tests/Makefile.am, tests/atomic-test.c: Unit test for atomic
|
||||
operations.
|
||||
|
||||
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* glib/glib.def : added g_hash_table_find and a
|
||||
|
@ -1,3 +1,17 @@
|
||||
2004-02-26 Sebastian Wilhelmi <seppi@seppi.de>
|
||||
|
||||
* glib/gatomic.c, glib/gatomic.h: New files to implement atomic
|
||||
operations for different platforms. Fixes bug #63621.
|
||||
|
||||
* glib/glib.h: Include gatomic.h.
|
||||
|
||||
* configure.in: Add test for assembler routines for atomic operations.
|
||||
|
||||
* glib/Makefile.am: Add gatomic.c, gatomic.h.
|
||||
|
||||
* tests/Makefile.am, tests/atomic-test.c: Unit test for atomic
|
||||
operations.
|
||||
|
||||
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* glib/glib.def : added g_hash_table_find and a
|
||||
|
@ -1,3 +1,17 @@
|
||||
2004-02-26 Sebastian Wilhelmi <seppi@seppi.de>
|
||||
|
||||
* glib/gatomic.c, glib/gatomic.h: New files to implement atomic
|
||||
operations for different platforms. Fixes bug #63621.
|
||||
|
||||
* glib/glib.h: Include gatomic.h.
|
||||
|
||||
* configure.in: Add test for assembler routines for atomic operations.
|
||||
|
||||
* glib/Makefile.am: Add gatomic.c, gatomic.h.
|
||||
|
||||
* tests/Makefile.am, tests/atomic-test.c: Unit test for atomic
|
||||
operations.
|
||||
|
||||
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* glib/glib.def : added g_hash_table_find and a
|
||||
|
@ -1,3 +1,17 @@
|
||||
2004-02-26 Sebastian Wilhelmi <seppi@seppi.de>
|
||||
|
||||
* glib/gatomic.c, glib/gatomic.h: New files to implement atomic
|
||||
operations for different platforms. Fixes bug #63621.
|
||||
|
||||
* glib/glib.h: Include gatomic.h.
|
||||
|
||||
* configure.in: Add test for assembler routines for atomic operations.
|
||||
|
||||
* glib/Makefile.am: Add gatomic.c, gatomic.h.
|
||||
|
||||
* tests/Makefile.am, tests/atomic-test.c: Unit test for atomic
|
||||
operations.
|
||||
|
||||
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* glib/glib.def : added g_hash_table_find and a
|
||||
|
@ -1,3 +1,17 @@
|
||||
2004-02-26 Sebastian Wilhelmi <seppi@seppi.de>
|
||||
|
||||
* glib/gatomic.c, glib/gatomic.h: New files to implement atomic
|
||||
operations for different platforms. Fixes bug #63621.
|
||||
|
||||
* glib/glib.h: Include gatomic.h.
|
||||
|
||||
* configure.in: Add test for assembler routines for atomic operations.
|
||||
|
||||
* glib/Makefile.am: Add gatomic.c, gatomic.h.
|
||||
|
||||
* tests/Makefile.am, tests/atomic-test.c: Unit test for atomic
|
||||
operations.
|
||||
|
||||
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* glib/glib.def : added g_hash_table_find and a
|
||||
|
63
configure.in
63
configure.in
@ -1864,6 +1864,63 @@ if test $mutex_has_default = yes ; then
|
||||
LIBS="$glib_save_LIBS"
|
||||
fi
|
||||
|
||||
dnl *****************************
|
||||
dnl *** GAtomic tests for gcc ***
|
||||
dnl *****************************
|
||||
|
||||
AC_MSG_CHECKING([whether to use inline assembler routines for atomic integers])
|
||||
|
||||
if test x"$GCC" = xyes; then
|
||||
case $host_cpu in
|
||||
i386)
|
||||
AC_MSG_RESULT([no])
|
||||
;;
|
||||
i?86)
|
||||
AC_MSG_RESULT([i486])
|
||||
glib_atomic_inlined_implementation=I486
|
||||
;;
|
||||
sparc*)
|
||||
SPARCV9_WARNING="Try to rerun configure with CFLAGS='-mcpu=v9',
|
||||
when you are using a sparc with v9 instruction set (most
|
||||
sparcs nowadays). This will make the code for atomic
|
||||
operations much faster. The resulting code will not run
|
||||
on very old sparcs though."
|
||||
|
||||
AC_LINK_IFELSE([[
|
||||
main ()
|
||||
{
|
||||
int tmp1, tmp2, tmp3;
|
||||
__asm__ __volatile__("casx [%2], %0, %1"
|
||||
: "=&r" (tmp1), "=&r" (tmp2) : "r" (&tmp3));
|
||||
}]],
|
||||
AC_MSG_RESULT([sparcv9])
|
||||
glib_atomic_inlined_implementation=SPARCV9,
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_WARN([[$SPARCV9_WARNING]]))
|
||||
;;
|
||||
alpha)
|
||||
AC_MSG_RESULT([alpha])
|
||||
glib_atomic_inlined_implementation=ALPHA
|
||||
;;
|
||||
x86_64)
|
||||
AC_MSG_RESULT([x86_64])
|
||||
glib_atomic_inlined_implementation=X86_64
|
||||
;;
|
||||
powerpc*)
|
||||
AC_MSG_RESULT([powerpc])
|
||||
glib_atomic_inlined_implementation=POWERPC
|
||||
;;
|
||||
ia64)
|
||||
AC_MSG_RESULT([ia64])
|
||||
glib_atomic_inlined_implementation=IA64
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT([none])
|
||||
glib_atomic_inlined_implementation=NONE
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
dnl ****************************************
|
||||
dnl *** GLib POLL* compatibility defines ***
|
||||
dnl ****************************************
|
||||
@ -2237,6 +2294,10 @@ union _GSystemThread
|
||||
long dummy_long;
|
||||
};
|
||||
_______EOF
|
||||
if test x"$g_atomic_inlined_implementation" != x; then
|
||||
echo >>$outfile
|
||||
echo "#define G_ATOMIC_INLINED_IMPLEMENTATION_$g_atomic_inlined_implementation" >>$outfile
|
||||
fi
|
||||
|
||||
echo >>$outfile
|
||||
g_bit_sizes="16 32 64"
|
||||
@ -2540,6 +2601,8 @@ g_mutex_sizeof="$glib_cv_sizeof_gmutex"
|
||||
g_system_thread_sizeof="$glib_cv_sizeof_system_thread"
|
||||
g_mutex_contents="$glib_cv_byte_contents_gmutex"
|
||||
|
||||
g_atomic_inlined_implementation="$glib_atomic_inlined_implementation"
|
||||
|
||||
g_module_suffix="$glib_gmodule_suffix"
|
||||
|
||||
g_pid_type="$glib_pid_type"
|
||||
|
@ -1,3 +1,9 @@
|
||||
2004-02-26 Sebastian Wilhelmi <seppi@seppi.de>
|
||||
|
||||
* glib/glib-overrides.txt, glib/glib-sections.txt,
|
||||
glib/glib-docs.sgml, glib/tmpl/atomic_operations.sgml: Add docs
|
||||
for atomic operations.
|
||||
|
||||
Tue Feb 24 14:09:21 2004 Owen Taylor <otaylor@redhat.com>
|
||||
|
||||
* === Released 2.3.3 ===
|
||||
|
@ -8,6 +8,7 @@
|
||||
<!ENTITY glib-Byte-Order-Macros SYSTEM "xml/byte_order.xml">
|
||||
<!ENTITY glib-Numerical-Definitions SYSTEM "xml/numerical.xml">
|
||||
<!ENTITY glib-Miscellaneous-Macros SYSTEM "xml/macros_misc.xml">
|
||||
<!ENTITY glib-Atomic-Operations SYSTEM "xml/atomic_operations.xml">
|
||||
<!ENTITY glib-Memory-Allocation SYSTEM "xml/memory.xml">
|
||||
<!ENTITY glib-Error-Reporting SYSTEM "xml/error_reporting.xml">
|
||||
<!ENTITY glib-Warnings-and-Assertions SYSTEM "xml/warnings.xml">
|
||||
@ -106,6 +107,7 @@ synchronize their operation.
|
||||
&glib-Byte-Order-Macros;
|
||||
&glib-Numerical-Definitions;
|
||||
&glib-Miscellaneous-Macros;
|
||||
&glib-Atomic-Operations;
|
||||
</chapter>
|
||||
|
||||
<chapter id="glib-core">
|
||||
|
@ -288,6 +288,62 @@ gchar c
|
||||
gchar c
|
||||
</FUNCTION>
|
||||
|
||||
# g_atomic
|
||||
|
||||
<FUNCTION>
|
||||
<NAME>g_atomic_int_get</NAME>
|
||||
<RETURNS>gint32</RETURNS>
|
||||
gint32 *atomic
|
||||
</FUNCTION>
|
||||
|
||||
<FUNCTION>
|
||||
<NAME>g_atomic_int_exchange_and_add</NAME>
|
||||
<RETURNS>gint32</RETURNS>
|
||||
gint32 *atomic
|
||||
gint32 val
|
||||
</FUNCTION>
|
||||
|
||||
<FUNCTION>
|
||||
<NAME>g_atomic_int_add</NAME>
|
||||
<RETURNS>void</RETURNS>
|
||||
gint32 *atomic
|
||||
gint32 val
|
||||
</FUNCTION>
|
||||
|
||||
<FUNCTION>
|
||||
<NAME>g_atomic_int_compare_and_exchange</NAME>
|
||||
<RETURNS>gboolean</RETURNS>
|
||||
gint32 *atomic
|
||||
gint32 oldval
|
||||
gint32 newval
|
||||
</FUNCTION>
|
||||
|
||||
<FUNCTION>
|
||||
<NAME>g_atomic_pointer_get</NAME>
|
||||
<RETURNS>gpointer</RETURNS>
|
||||
gpointer *atomic
|
||||
</FUNCTION>
|
||||
|
||||
<FUNCTION>
|
||||
<NAME>g_atomic_pointer_compare_and_exchange</NAME>
|
||||
<RETURNS>gboolean</RETURNS>
|
||||
gpointer *atomic
|
||||
gpointer oldval
|
||||
gpointer newval
|
||||
</FUNCTION>
|
||||
|
||||
<FUNCTION>
|
||||
<NAME>g_atomic_int_inc</NAME>
|
||||
<RETURNS>void</RETURNS>
|
||||
gint32 *atomic
|
||||
</FUNCTION>
|
||||
|
||||
<FUNCTION>
|
||||
<NAME>g_atomic_int_dec_and_test</NAME>
|
||||
<RETURNS>gboolean</RETURNS>
|
||||
gint32 *atomic
|
||||
</FUNCTION>
|
||||
|
||||
<STRUCT>
|
||||
<NAME>GIConv</NAME>
|
||||
</STRUCT>
|
||||
|
@ -652,6 +652,25 @@ g_async_queue_timed_pop_unlocked
|
||||
g_async_queue_length_unlocked
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<TITLE>Atomic Operations</TITLE>
|
||||
<FILE>atomic_operations</FILE>
|
||||
g_atomic_int_get
|
||||
g_atomic_int_add
|
||||
g_atomic_int_exchange_and_add
|
||||
g_atomic_int_compare_and_exchange
|
||||
g_atomic_pointer_get
|
||||
g_atomic_pointer_compare_and_exchange
|
||||
g_atomic_int_inc
|
||||
g_atomic_int_dec_and_test
|
||||
</SECTION>
|
||||
|
||||
<SUBSECTION Private>
|
||||
g_atomic_int_add_fallback
|
||||
g_atomic_int_exchange_and_add_fallback
|
||||
g_atomic_int_compare_and_exchange_fallback
|
||||
g_atomic_pointer_compare_and_exchange_fallback
|
||||
|
||||
<SECTION>
|
||||
<TITLE>IO Channels</TITLE>
|
||||
<FILE>iochannels</FILE>
|
||||
|
156
docs/reference/glib/tmpl/atomic_operations.sgml
Normal file
156
docs/reference/glib/tmpl/atomic_operations.sgml
Normal file
@ -0,0 +1,156 @@
|
||||
<!-- ##### SECTION Title ##### -->
|
||||
Atomic Operations
|
||||
|
||||
<!-- ##### SECTION Short_Description ##### -->
|
||||
basic atomic integer and pointer operations
|
||||
|
||||
<!-- ##### SECTION Long_Description ##### -->
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
You must not directly read integers or pointers concurrently accessed
|
||||
by other threads with with the following functions directly. Always use
|
||||
g_atomic_int_get() and g_atomic_pointer_get() respectively. They are
|
||||
acting as a memory barrier.
|
||||
</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>
|
||||
|
||||
<!-- ##### SECTION See_Also ##### -->
|
||||
<para>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term>#GMutex</term>
|
||||
<listitem><para>GLib mutual exclusions.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<!-- ##### FUNCTION g_atomic_int_get ##### -->
|
||||
<para>
|
||||
Reads the value of the integer pointed to by @atomic. Also acts as
|
||||
a memory barrier.
|
||||
</para>
|
||||
|
||||
@atomic: a pointer to a 32-bit integer.
|
||||
@Returns: the value of *@atomic.
|
||||
@Since: 2.4
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_atomic_int_add ##### -->
|
||||
<para>
|
||||
Atomically adds @val to the integer pointed to by @atomic.
|
||||
Also acts as a memory barrier.
|
||||
</para>
|
||||
|
||||
@atomic: a pointer to a 32-bit integer.
|
||||
@val: the value to add to *@atomic.
|
||||
@Since: 2.4
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_atomic_int_exchange_and_add ##### -->
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
@atomic: a pointer to a 32-bit integer.
|
||||
@val: the value to add to *@atomic.
|
||||
@Returns: the value of *@atomic before the addition.
|
||||
@Since: 2.4
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_atomic_int_compare_and_exchange ##### -->
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
@atomic: a pointer to a 32-bit integer.
|
||||
@oldval: the assumed old value of *@atomic.
|
||||
@newval: the new value of *@atomic.
|
||||
@Returns: %TRUE, if *@atomic was equal @oldval. %FALSE otherwise.
|
||||
@Since: 2.4
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_atomic_pointer_get ##### -->
|
||||
<para>
|
||||
Reads the value of the pointer pointed to by @atomic. Also acts as
|
||||
a memory barrier.
|
||||
</para>
|
||||
|
||||
@atomic: a pointer to a #gpointer.
|
||||
@Returns: the value to add to *@atomic.
|
||||
@Since: 2.4
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_atomic_pointer_compare_and_exchange ##### -->
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
@atomic: a pointer to a #gpointer.
|
||||
@oldval: the assumed old value of *@atomic.
|
||||
@newval: the new value of *@atomic.
|
||||
@Returns: %TRUE, if *@atomic was equal @oldval. %FALSE otherwise.
|
||||
@Since: 2.4
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_atomic_int_inc ##### -->
|
||||
<para>
|
||||
Atomically increments the integer pointed to by @atomic by 1.
|
||||
</para>
|
||||
|
||||
@atomic: a pointer to a 32-bit integer.
|
||||
@Since: 2.4
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_atomic_int_dec_and_test ##### -->
|
||||
<para>
|
||||
Atomically decrements the integer pointed to by @atomic by 1.
|
||||
</para>
|
||||
|
||||
@atomic: a pointer to a 32-bit integer.
|
||||
@Returns: %TRUE, if the integer pointed to by @atomic is 0 after
|
||||
decrementing it.
|
||||
@Since: 2.4
|
||||
|
||||
|
@ -44,6 +44,7 @@ endif
|
||||
libglib_2_0_la_SOURCES = \
|
||||
garray.c \
|
||||
gasyncqueue.c \
|
||||
gatomic.c \
|
||||
gbacktrace.c \
|
||||
gbsearcharray.h \
|
||||
gcache.c \
|
||||
@ -112,6 +113,7 @@ glibsubinclude_HEADERS = \
|
||||
galloca.h \
|
||||
garray.h \
|
||||
gasyncqueue.h \
|
||||
gatomic.h \
|
||||
gbacktrace.h \
|
||||
gcache.h \
|
||||
gcompletion.h \
|
||||
|
178
glib/gatomic.c
Normal file
178
glib/gatomic.c
Normal file
@ -0,0 +1,178 @@
|
||||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* GAtomic: atomic integer operation.
|
||||
* 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 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 <glib.h>
|
||||
|
||||
#ifdef G_THREADS_ENABLED
|
||||
# if !defined (G_ATOMIC_USE_FALLBACK_IMPLEMENTATION)
|
||||
/* We have an inline implementation, which we can now use for the
|
||||
* fallback implementation. This fallback implementation is only used by
|
||||
* modules, which are not compliled with gcc
|
||||
*/
|
||||
|
||||
gint32
|
||||
g_atomic_int_exchange_and_add_fallback (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
return g_atomic_int_exchange_and_add (atomic, val);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
g_atomic_int_add_fallback (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
g_atomic_int_add (atomic, val);
|
||||
}
|
||||
|
||||
gboolean
|
||||
g_atomic_int_compare_and_exchange_fallback (gint32 *atomic,
|
||||
gint32 oldval,
|
||||
gint32 newval)
|
||||
{
|
||||
return g_atomic_int_compare_and_exchange (atomic, oldval, newval);
|
||||
}
|
||||
|
||||
gboolean
|
||||
g_atomic_pointer_compare_and_exchange_fallback (gpointer *atomic,
|
||||
gpointer oldval,
|
||||
gpointer newval)
|
||||
{
|
||||
return g_atomic_pointer_compare_and_exchange (atomic, oldval, newval);
|
||||
}
|
||||
|
||||
gint32
|
||||
g_atomic_int_get_fallback (gint32 *atomic)
|
||||
{
|
||||
return g_atomic_int_get (atomic);
|
||||
}
|
||||
|
||||
gint32
|
||||
g_atomic_pointer_get_fallback (gpointer *atomic)
|
||||
{
|
||||
return g_atomic_int_get (atomic);
|
||||
}
|
||||
|
||||
# else /* !G_ATOMIC_USE_FALLBACK_IMPLEMENTATION */
|
||||
/* We have to use the slow, but safe locking method */
|
||||
G_LOCK_DEFINE_STATIC (g_atomic_lock);
|
||||
|
||||
gint32
|
||||
g_atomic_int_exchange_and_add_fallback (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
gint32 result;
|
||||
|
||||
G_LOCK (g_atomic_lock);
|
||||
result = *atomic;
|
||||
*atomic += val;
|
||||
G_UNLOCK (g_atomic_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
g_atomic_int_add_fallback (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
G_LOCK (g_atomic_lock);
|
||||
*atomic += val;
|
||||
G_UNLOCK (g_atomic_lock);
|
||||
}
|
||||
|
||||
gboolean
|
||||
g_atomic_int_compare_and_exchange_fallback (gint32 *atomic,
|
||||
gint32 oldval,
|
||||
gint32 newval)
|
||||
{
|
||||
gboolean result;
|
||||
|
||||
G_LOCK (g_atomic_lock);
|
||||
if (*atomic == oldval)
|
||||
{
|
||||
result = TRUE;
|
||||
*atomic = newval;
|
||||
}
|
||||
else
|
||||
result = FALSE;
|
||||
G_UNLOCK (g_atomic_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean
|
||||
g_atomic_pointer_compare_and_exchange_fallback (gpointer *atomic,
|
||||
gpointer oldval,
|
||||
gpointer newval)
|
||||
{
|
||||
gboolean result;
|
||||
|
||||
G_LOCK (g_atomic_lock);
|
||||
if (*atomic == oldval)
|
||||
{
|
||||
result = TRUE;
|
||||
*atomic = newval;
|
||||
}
|
||||
else
|
||||
result = FALSE;
|
||||
G_UNLOCK (g_atomic_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline gint32
|
||||
g_atomic_int_get_fallback (gint32 *atomic)
|
||||
{
|
||||
gint32 result;
|
||||
|
||||
G_LOCK (g_atomic_lock);
|
||||
result = *atomic;
|
||||
G_UNLOCK (g_atomic_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline gpointer
|
||||
g_atomic_pointer_get_fallback (gpointer *atomic)
|
||||
{
|
||||
gpointer result;
|
||||
|
||||
G_LOCK (g_atomic_lock);
|
||||
result = *atomic;
|
||||
G_UNLOCK (g_atomic_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
# endif /* G_ATOMIC_USE_FALLBACK_IMPLEMENTATION */
|
||||
#else /* !G_THREADS_ENABLED */
|
||||
gint32 g_atomic_int_exchange_and_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
gint32 result = *atomic;
|
||||
*atomic += val;
|
||||
return result;
|
||||
}
|
||||
#endif /* G_THREADS_ENABLED */
|
||||
|
545
glib/gatomic.h
Normal file
545
glib/gatomic.h
Normal file
@ -0,0 +1,545 @@
|
||||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* GAtomic: atomic integer operation.
|
||||
* 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 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
#ifndef __G_ATOMIC_H__
|
||||
#define __G_ATOMIC_H__
|
||||
|
||||
#include <glib/gtypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifdef G_THREADS_ENABLED
|
||||
|
||||
gint32 g_atomic_int_exchange_and_add_fallback (gint32 *atomic,
|
||||
gint32 val);
|
||||
void g_atomic_int_add_fallback (gint32 *atomic,
|
||||
gint32 val);
|
||||
gboolean g_atomic_int_compare_and_exchange_fallback (gint32 *atomic,
|
||||
gint32 oldval,
|
||||
gint32 newval);
|
||||
gboolean g_atomic_pointer_compare_and_exchange_fallback (gpointer *atomic,
|
||||
gpointer oldval,
|
||||
gpointer newval);
|
||||
|
||||
# if defined (__GNUC__)
|
||||
# if defined (G_ATOMIC_INLINED_IMPLEMENTATION_I486)
|
||||
/* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h
|
||||
*/
|
||||
static inline gint32
|
||||
g_atomic_int_exchange_and_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
gint32 result;
|
||||
|
||||
__asm__ __volatile__ ("lock; xaddl %0,%1"
|
||||
: "=r" (result), "=m" (*atomic)
|
||||
: "0" (val), "m" (*atomic));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
g_atomic_int_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
__asm__ __volatile__ ("lock; addl %1,%0"
|
||||
: "=m" (*atomic)
|
||||
: "ir" (val), "m" (*atomic));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
g_atomic_int_compare_and_exchange (gint32 *atomic,
|
||||
gint32 oldval,
|
||||
gint32 newval)
|
||||
{
|
||||
gint32 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 */
|
||||
|
||||
static inline gboolean
|
||||
g_atomic_pointer_compare_and_exchange (gpointer *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;
|
||||
}
|
||||
|
||||
# define G_ATOMIC_MEMORY_BARRIER() /* Not needed */
|
||||
|
||||
# elif defined(G_ATOMIC_INLINED_IMPLEMENTATION_SPARCV9) \
|
||||
&& (defined(__sparcv8) || defined(__sparcv9) || defined(__sparc_v9__))
|
||||
/* Adapted from CVS version 1.3 of glibc's sysdeps/sparc/sparc64/bits/atomic.h
|
||||
*/
|
||||
/* Why the test for __sparcv8, wheras really the sparcv9 architecture
|
||||
* is required for the folowing assembler instructions? On
|
||||
* sparc-solaris the only difference detectable at compile time
|
||||
* between no -m and -mcpu=v9 is __sparcv8.
|
||||
*
|
||||
* However, in case -mcpu=v8 is set, the assembler will fail. This
|
||||
* should be rare however, as there are only very few v8-not-v9
|
||||
* machines still out there (and we can't do better).
|
||||
*/
|
||||
static inline gboolean
|
||||
g_atomic_int_compare_and_exchange (gint32 *atomic,
|
||||
gint32 oldval,
|
||||
gint32 newval)
|
||||
{
|
||||
gint32 result;
|
||||
__asm __volatile ("cas [%4], %2, %0"
|
||||
: "=r" (result), "=m" (*atomic)
|
||||
: "r" (oldval), "m" (*atomic), "r" (atomic),
|
||||
"0" (newval));
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
|
||||
static inline gboolean
|
||||
g_atomic_pointer_compare_and_exchange (gpointer *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 != 0;
|
||||
}
|
||||
# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
|
||||
static inline gboolean
|
||||
g_atomic_pointer_compare_and_exchange (gpointer *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 != 0;
|
||||
}
|
||||
# else /* What's that */
|
||||
# error "Your system has an unsupported pointer size"
|
||||
# endif /* GLIB_SIZEOF_VOID_P */
|
||||
static inline gint32
|
||||
g_atomic_int_exchange_and_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
gint32 result;
|
||||
do
|
||||
result = *atomic;
|
||||
while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
g_atomic_int_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
g_atomic_int_exchange_and_add (atomic, val);
|
||||
}
|
||||
|
||||
# define G_ATOMIC_MEMORY_BARRIER() \
|
||||
__asm __volatile ("membar #LoadLoad | #LoadStore" \
|
||||
" | #StoreLoad | #StoreStore" : : : "memory")
|
||||
|
||||
# elif defined(G_ATOMIC_INLINED_IMPLEMENTATION_ALPHA)
|
||||
/* Adapted from CVS version 1.3 of glibc's sysdeps/alpha/bits/atomic.h
|
||||
*/
|
||||
static inline gboolean
|
||||
g_atomic_int_compare_and_exchange (gint32 *atomic,
|
||||
gint32 oldval,
|
||||
gint32 newval)
|
||||
{
|
||||
gint32 result;
|
||||
gint32 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" ((gint64)oldval),
|
||||
"Ir" (newval)
|
||||
: "memory");
|
||||
return result != 0;
|
||||
}
|
||||
# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
|
||||
static inline gboolean
|
||||
g_atomic_pointer_compare_and_exchange (gpointer *atomic,
|
||||
gpointer oldval,
|
||||
gpointer newval)
|
||||
{
|
||||
gint32 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" ((gint64)oldval),
|
||||
"Ir" (newval)
|
||||
: "memory");
|
||||
return result != 0;
|
||||
}
|
||||
# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
|
||||
static inline gboolean
|
||||
g_atomic_pointer_compare_and_exchange (gpointer *atomic,
|
||||
gpointer oldval,
|
||||
gpointer newval)
|
||||
{
|
||||
gint32 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" ((gint64)oldval),
|
||||
"Ir" (newval)
|
||||
: "memory");
|
||||
return result != 0;
|
||||
}
|
||||
# else /* What's that */
|
||||
# error "Your system has an unsupported pointer size"
|
||||
# endif /* GLIB_SIZEOF_VOID_P */
|
||||
static inline gint32
|
||||
g_atomic_int_exchange_and_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
gint32 result;
|
||||
do
|
||||
result = *atomic;
|
||||
while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
g_atomic_int_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
g_atomic_int_exchange_and_add (atomic, val);
|
||||
}
|
||||
|
||||
# define G_ATOMIC_MEMORY_BARRIER() __asm ("mb" : : : "memory")
|
||||
|
||||
# elif defined(G_ATOMIC_INLINED_IMPLEMENTATION_X86_64)
|
||||
/* Adapted from CVS version 1.9 of glibc's sysdeps/x86_64/bits/atomic.h
|
||||
*/
|
||||
static inline gint32
|
||||
g_atomic_int_exchange_and_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
gint32 result;
|
||||
|
||||
__asm__ __volatile__ ("lock; xaddl %0,%1"
|
||||
: "=r" (result), "=m" (*atomic)
|
||||
: "0" (val), "m" (*atomic));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
g_atomic_int_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
__asm__ __volatile__ ("lock; addl %1,%0"
|
||||
: "=m" (*atomic)
|
||||
: "ir" (val), "m" (*atomic));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
g_atomic_int_compare_and_exchange (gint32 *atomic,
|
||||
gint32 oldval,
|
||||
gint32 newval)
|
||||
{
|
||||
gint32 result;
|
||||
|
||||
__asm __volatile ("lock; cmpxchgl %2, %1"
|
||||
: "=a" (result), "=m" (*atomic)
|
||||
: "r" (newval), "m" (*atomic), "0" (oldval));
|
||||
|
||||
return result == oldval;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
g_atomic_pointer_compare_and_exchange (gpointer *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;
|
||||
}
|
||||
|
||||
# define G_ATOMIC_MEMORY_BARRIER() /* Not needed */
|
||||
|
||||
# elif defined(G_ATOMIC_INLINED_IMPLEMENTATION_POWERPC)
|
||||
/* Adapted from CVS version 1.12 of glibc's sysdeps/powerpc/bits/atomic.h
|
||||
* and CVS version 1.3 of glibc's sysdeps/powerpc/powerpc32/bits/atomic.h
|
||||
* and CVS version 1.2 of glibc's sysdeps/powerpc/powerpc64/bits/atomic.h
|
||||
*/
|
||||
static inline gint32
|
||||
g_atomic_int_exchange_and_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
gint32 result, temp;
|
||||
__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), "2" (*atomic)
|
||||
: "cr0", "memory");
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
g_atomic_int_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
g_atomic_int_exchange_and_add (atomic, val);
|
||||
}
|
||||
|
||||
# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
|
||||
static inline gboolean
|
||||
g_atomic_int_compare_and_exchange (gint32 *atomic,
|
||||
gint32 oldval,
|
||||
gint32 newval)
|
||||
{
|
||||
gint32 result;
|
||||
__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");
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
g_atomic_pointer_compare_and_exchange (gpointer *atomic,
|
||||
gpointer oldval,
|
||||
gpointer newval)
|
||||
{
|
||||
gpointer result;
|
||||
__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");
|
||||
return result == 0;
|
||||
}
|
||||
# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
|
||||
static inline gboolean
|
||||
g_atomic_int_compare_and_exchange (gint32 *atomic,
|
||||
gint32 oldval,
|
||||
gint32 newval)
|
||||
{
|
||||
__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");
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
g_atomic_pointer_compare_and_exchange (gpointer *atomic,
|
||||
gpointer oldval,
|
||||
gpointer newval)
|
||||
{
|
||||
gpointer result;
|
||||
__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");
|
||||
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_INLINED_IMPLEMENTATION_IA64)
|
||||
/* Adapted from CVS version 1.8 of glibc's sysdeps/ia64/bits/atomic.h
|
||||
*/
|
||||
static inline gint32
|
||||
g_atomic_int_exchange_and_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
return __sync_fetch_and_add_si (atomic, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
g_atomic_int_add (gint32 *atomic,
|
||||
gint32 val)
|
||||
{
|
||||
__sync_fetch_and_add_si (atomic, val);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
g_atomic_int_compare_and_exchange (gint32 *atomic,
|
||||
gint32 oldval,
|
||||
gint32 newval)
|
||||
{
|
||||
return __sync_bool_compare_and_exchange_si (atomic, oldval, newval);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
g_atomic_pointer_compare_and_exchange (gpointer *atomic,
|
||||
gpointer oldval,
|
||||
gpointer newval)
|
||||
{
|
||||
return __sync_bool_compare_and_exchange_di ((long *)atomic,
|
||||
(long)oldval, (long)newval);
|
||||
}
|
||||
|
||||
# define G_ATOMIC_MEMORY_BARRIER() __sync_synchronize ()
|
||||
|
||||
# else /* !G_ATOMIC_INLINED_IMPLEMENTATION_... */
|
||||
# define G_ATOMIC_USE_FALLBACK_IMPLEMENTATION
|
||||
# endif /* G_ATOMIC_INLINED_IMPLEMENTATION_... */
|
||||
# else /* !__GNU__ */
|
||||
# define G_ATOMIC_USE_FALLBACK_IMPLEMENTATION
|
||||
# endif /* __GNUC__ */
|
||||
#else /* !G_THREADS_ENABLED */
|
||||
gint32 g_atomic_int_exchange_and_add (gint32 *atomic, gint32 val);
|
||||
# define g_atomic_int_add(atomic, val) (void)(*(atomic) += (val))
|
||||
# define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
|
||||
(*(atomic) == (oldval) ? (*(atomic) = (newval), TRUE) : FALSE)
|
||||
# define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
|
||||
(*(atomic) == (oldval) ? (*(atomic) = (newval), TRUE) : FALSE)
|
||||
# define g_atomic_int_get(atomic) (*(atomic))
|
||||
# define g_atomic_pointer_get(atomic) (*(atomic))
|
||||
#endif /* G_THREADS_ENABLED */
|
||||
|
||||
#ifdef G_ATOMIC_USE_FALLBACK_IMPLEMENTATION
|
||||
# define g_atomic_int_exchange_and_add \
|
||||
g_atomic_int_exchange_and_add_fallback
|
||||
# define g_atomic_int_add \
|
||||
g_atomic_int_add_fallback
|
||||
# define g_atomic_int_compare_and_exchange \
|
||||
g_atomic_int_compare_and_exchange_fallback
|
||||
# define g_atomic_pointer_compare_and_exchange \
|
||||
g_atomic_pointer_compare_and_exchange_fallback
|
||||
# define g_atomic_int_get \
|
||||
g_atomic_int_get_fallback
|
||||
# define g_atomic_pointer_get \
|
||||
g_atomic_pointer_get_fallback
|
||||
#else /* !G_ATOMIC_USE_FALLBACK_IMPLEMENTATION */
|
||||
static inline gint32
|
||||
g_atomic_int_get (gint32 *atomic)
|
||||
{
|
||||
gint32 result = *atomic;
|
||||
G_ATOMIC_MEMORY_BARRIER ();
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline gpointer
|
||||
g_atomic_pointer_get (gpointer *atomic)
|
||||
{
|
||||
gpointer result = *atomic;
|
||||
G_ATOMIC_MEMORY_BARRIER ();
|
||||
return result;
|
||||
}
|
||||
#endif /* G_ATOMIC_USE_FALLBACK_IMPLEMENTATION */
|
||||
|
||||
#define g_atomic_int_inc(atomic) (g_atomic_int_add ((atomic), 1))
|
||||
#define g_atomic_int_dec_and_test(atomic) \
|
||||
(g_atomic_int_exchange_and_add ((atomic), -1) == 1)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_ATOMIC_H__ */
|
@ -30,6 +30,7 @@
|
||||
#include <glib/galloca.h>
|
||||
#include <glib/garray.h>
|
||||
#include <glib/gasyncqueue.h>
|
||||
#include <glib/gatomic.h>
|
||||
#include <glib/gbacktrace.h>
|
||||
#include <glib/gcache.h>
|
||||
#include <glib/gcompletion.h>
|
||||
|
@ -64,6 +64,7 @@ timeloop_closure_LDADD = $(libglib) $(libgobject)
|
||||
endif
|
||||
|
||||
test_programs = \
|
||||
atomic-test \
|
||||
array-test \
|
||||
$(CXX_TEST) \
|
||||
child-test \
|
||||
@ -115,6 +116,7 @@ progs_ldadd = $(EFENCE) $(libglib) $(EFENCE)
|
||||
thread_ldadd = $(libgthread) $(G_THREAD_LIBS) $(progs_ldadd)
|
||||
module_ldadd = $(libgmodule) $(G_MODULE_LIBS) $(progs_ldadd)
|
||||
|
||||
atomic_test_LDADD = $(progs_ldadd)
|
||||
array_test_LDADD = $(progs_ldadd)
|
||||
child_test_LDADD = $(thread_ldadd)
|
||||
completion_test_LDADD = $(progs_ldadd)
|
||||
|
57
tests/atomic-test.c
Normal file
57
tests/atomic-test.c
Normal file
@ -0,0 +1,57 @@
|
||||
#undef G_DISABLE_ASSERT
|
||||
#undef G_LOG_DOMAIN
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/* Obviously we can't test that the operations are atomic, but we can
|
||||
* at least test, that they do, what they ought to do */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
gint i;
|
||||
gint32 atomic = -5;
|
||||
gpointer atomic_pointer = NULL;
|
||||
gpointer biggest_pointer = atomic_pointer - 1;
|
||||
|
||||
for (i = 0; i < 15; i++)
|
||||
g_atomic_int_inc (&atomic);
|
||||
g_assert (atomic == 10);
|
||||
for (i = 0; i < 9; i++)
|
||||
g_assert (!g_atomic_int_dec_and_test (&atomic));
|
||||
g_assert (g_atomic_int_dec_and_test (&atomic));
|
||||
g_assert (atomic == 0);
|
||||
|
||||
g_assert (g_atomic_int_exchange_and_add (&atomic, 5) == 0);
|
||||
g_assert (atomic == 5);
|
||||
|
||||
g_assert (g_atomic_int_exchange_and_add (&atomic, -10) == 5);
|
||||
g_assert (atomic == -5);
|
||||
|
||||
g_atomic_int_add (&atomic, 20);
|
||||
g_assert (atomic == 15);
|
||||
|
||||
g_atomic_int_add (&atomic, -35);
|
||||
g_assert (atomic == -20);
|
||||
|
||||
g_assert (atomic == g_atomic_int_get (&atomic));
|
||||
|
||||
g_assert (g_atomic_int_compare_and_exchange (&atomic, -20, 20));
|
||||
g_assert (atomic == 20);
|
||||
|
||||
g_assert (!g_atomic_int_compare_and_exchange (&atomic, 42, 12));
|
||||
g_assert (atomic == 20);
|
||||
|
||||
g_assert (g_atomic_pointer_compare_and_exchange (&atomic_pointer,
|
||||
NULL, biggest_pointer));
|
||||
g_assert (atomic_pointer == biggest_pointer);
|
||||
|
||||
g_assert (atomic_pointer == g_atomic_pointer_get (&atomic_pointer));
|
||||
|
||||
g_assert (g_atomic_pointer_compare_and_exchange (&atomic_pointer,
|
||||
biggest_pointer, NULL));
|
||||
g_assert (atomic_pointer == NULL);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user