mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-05-21 04:52:11 +02: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>
|
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||||
|
|
||||||
* glib/glib.def : added g_hash_table_find and a
|
* 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>
|
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||||
|
|
||||||
* glib/glib.def : added g_hash_table_find and a
|
* 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>
|
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||||
|
|
||||||
* glib/glib.def : added g_hash_table_find and a
|
* 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>
|
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||||
|
|
||||||
* glib/glib.def : added g_hash_table_find and a
|
* 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>
|
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||||
|
|
||||||
* glib/glib.def : added g_hash_table_find and a
|
* 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>
|
2003-02-26 Hans Breuer <hans@breuer.org>
|
||||||
|
|
||||||
* glib/glib.def : added g_hash_table_find and a
|
* 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"
|
LIBS="$glib_save_LIBS"
|
||||||
fi
|
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 ****************************************
|
||||||
dnl *** GLib POLL* compatibility defines ***
|
dnl *** GLib POLL* compatibility defines ***
|
||||||
dnl ****************************************
|
dnl ****************************************
|
||||||
@ -2237,6 +2294,10 @@ union _GSystemThread
|
|||||||
long dummy_long;
|
long dummy_long;
|
||||||
};
|
};
|
||||||
_______EOF
|
_______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
|
echo >>$outfile
|
||||||
g_bit_sizes="16 32 64"
|
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_system_thread_sizeof="$glib_cv_sizeof_system_thread"
|
||||||
g_mutex_contents="$glib_cv_byte_contents_gmutex"
|
g_mutex_contents="$glib_cv_byte_contents_gmutex"
|
||||||
|
|
||||||
|
g_atomic_inlined_implementation="$glib_atomic_inlined_implementation"
|
||||||
|
|
||||||
g_module_suffix="$glib_gmodule_suffix"
|
g_module_suffix="$glib_gmodule_suffix"
|
||||||
|
|
||||||
g_pid_type="$glib_pid_type"
|
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>
|
Tue Feb 24 14:09:21 2004 Owen Taylor <otaylor@redhat.com>
|
||||||
|
|
||||||
* === Released 2.3.3 ===
|
* === Released 2.3.3 ===
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<!ENTITY glib-Byte-Order-Macros SYSTEM "xml/byte_order.xml">
|
<!ENTITY glib-Byte-Order-Macros SYSTEM "xml/byte_order.xml">
|
||||||
<!ENTITY glib-Numerical-Definitions SYSTEM "xml/numerical.xml">
|
<!ENTITY glib-Numerical-Definitions SYSTEM "xml/numerical.xml">
|
||||||
<!ENTITY glib-Miscellaneous-Macros SYSTEM "xml/macros_misc.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-Memory-Allocation SYSTEM "xml/memory.xml">
|
||||||
<!ENTITY glib-Error-Reporting SYSTEM "xml/error_reporting.xml">
|
<!ENTITY glib-Error-Reporting SYSTEM "xml/error_reporting.xml">
|
||||||
<!ENTITY glib-Warnings-and-Assertions SYSTEM "xml/warnings.xml">
|
<!ENTITY glib-Warnings-and-Assertions SYSTEM "xml/warnings.xml">
|
||||||
@ -106,6 +107,7 @@ synchronize their operation.
|
|||||||
&glib-Byte-Order-Macros;
|
&glib-Byte-Order-Macros;
|
||||||
&glib-Numerical-Definitions;
|
&glib-Numerical-Definitions;
|
||||||
&glib-Miscellaneous-Macros;
|
&glib-Miscellaneous-Macros;
|
||||||
|
&glib-Atomic-Operations;
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter id="glib-core">
|
<chapter id="glib-core">
|
||||||
|
@ -288,6 +288,62 @@ gchar c
|
|||||||
gchar c
|
gchar c
|
||||||
</FUNCTION>
|
</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>
|
<STRUCT>
|
||||||
<NAME>GIConv</NAME>
|
<NAME>GIConv</NAME>
|
||||||
</STRUCT>
|
</STRUCT>
|
||||||
|
@ -652,6 +652,25 @@ g_async_queue_timed_pop_unlocked
|
|||||||
g_async_queue_length_unlocked
|
g_async_queue_length_unlocked
|
||||||
</SECTION>
|
</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>
|
<SECTION>
|
||||||
<TITLE>IO Channels</TITLE>
|
<TITLE>IO Channels</TITLE>
|
||||||
<FILE>iochannels</FILE>
|
<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 = \
|
libglib_2_0_la_SOURCES = \
|
||||||
garray.c \
|
garray.c \
|
||||||
gasyncqueue.c \
|
gasyncqueue.c \
|
||||||
|
gatomic.c \
|
||||||
gbacktrace.c \
|
gbacktrace.c \
|
||||||
gbsearcharray.h \
|
gbsearcharray.h \
|
||||||
gcache.c \
|
gcache.c \
|
||||||
@ -112,6 +113,7 @@ glibsubinclude_HEADERS = \
|
|||||||
galloca.h \
|
galloca.h \
|
||||||
garray.h \
|
garray.h \
|
||||||
gasyncqueue.h \
|
gasyncqueue.h \
|
||||||
|
gatomic.h \
|
||||||
gbacktrace.h \
|
gbacktrace.h \
|
||||||
gcache.h \
|
gcache.h \
|
||||||
gcompletion.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/galloca.h>
|
||||||
#include <glib/garray.h>
|
#include <glib/garray.h>
|
||||||
#include <glib/gasyncqueue.h>
|
#include <glib/gasyncqueue.h>
|
||||||
|
#include <glib/gatomic.h>
|
||||||
#include <glib/gbacktrace.h>
|
#include <glib/gbacktrace.h>
|
||||||
#include <glib/gcache.h>
|
#include <glib/gcache.h>
|
||||||
#include <glib/gcompletion.h>
|
#include <glib/gcompletion.h>
|
||||||
|
@ -64,6 +64,7 @@ timeloop_closure_LDADD = $(libglib) $(libgobject)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
test_programs = \
|
test_programs = \
|
||||||
|
atomic-test \
|
||||||
array-test \
|
array-test \
|
||||||
$(CXX_TEST) \
|
$(CXX_TEST) \
|
||||||
child-test \
|
child-test \
|
||||||
@ -115,6 +116,7 @@ progs_ldadd = $(EFENCE) $(libglib) $(EFENCE)
|
|||||||
thread_ldadd = $(libgthread) $(G_THREAD_LIBS) $(progs_ldadd)
|
thread_ldadd = $(libgthread) $(G_THREAD_LIBS) $(progs_ldadd)
|
||||||
module_ldadd = $(libgmodule) $(G_MODULE_LIBS) $(progs_ldadd)
|
module_ldadd = $(libgmodule) $(G_MODULE_LIBS) $(progs_ldadd)
|
||||||
|
|
||||||
|
atomic_test_LDADD = $(progs_ldadd)
|
||||||
array_test_LDADD = $(progs_ldadd)
|
array_test_LDADD = $(progs_ldadd)
|
||||||
child_test_LDADD = $(thread_ldadd)
|
child_test_LDADD = $(thread_ldadd)
|
||||||
completion_test_LDADD = $(progs_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