Commit dbbb29f6 authored by Sebastian Wilhelmi's avatar Sebastian Wilhelmi Committed by Sebastian Wilhelmi

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.
parent fc9afe0d
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
......
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
......
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
......
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
......
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
......
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
......
......@@ -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"
......
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>
......
<!-- ##### 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 \
......
/* 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 */
/* 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 */