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 multiple threads, but use the atomic accessor functions instead.
-That is, always use g_atomic_int_get() and g_atomic_pointer_get() for
-read outs.
-They provide the neccessary synchonization mechanisms like memory
-barriers to access memory locations concurrently.
-</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>
<!-- ##### SECTION Stability_Level ##### -->
<!-- ##### 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 an integer
-@Returns: the value of *@atomic
-@Since: 2.4
+@atomic:
<!-- ##### FUNCTION g_atomic_int_set ##### -->
<para>
-Sets the value of the integer pointed to by @atomic.
-Also acts as a memory barrier.
+
</para>
-@atomic: a pointer to an integer
-@newval: the new value
-@Since: 2.10
+@atomic:
+@newval:
<!-- ##### 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 an integer.
-@val: the value to add to *@atomic.
-@Since: 2.4
+@atomic:
+@val:
<!-- ##### 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 an integer.
-@val: the value to add to *@atomic.
-@Returns: the value of *@atomic before the addition.
-@Since: 2.4
+@atomic:
+@val:
<!-- ##### 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 an 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
+@atomic:
+@oldval:
+@newval:
<!-- ##### 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
+@atomic:
<!-- ##### FUNCTION g_atomic_pointer_set ##### -->
<para>
-Sets the value of the pointer pointed to by @atomic.
-Also acts as a memory barrier.
+
</para>
-@atomic: a pointer to a #gpointer
-@newval: the new value
-@Since: 2.10
+@atomic:
+@newval:
<!-- ##### 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
+@atomic:
+@oldval:
+@newval:
<!-- ##### FUNCTION g_atomic_int_inc ##### -->
<para>
-Atomically increments the integer pointed to by @atomic by 1.
+
</para>
-@atomic: a pointer to an integer.
-@Since: 2.4
+@atomic:
<!-- ##### FUNCTION g_atomic_int_dec_and_test ##### -->
<para>
-Atomically decrements the integer pointed to by @atomic by 1.
+
</para>
-@atomic: a pointer to an integer.
-@Returns: %TRUE, if the integer pointed to by @atomic is 0 after
-decrementing it.
-@Since: 2.4
+@atomic:
#include "glib.h"
#include "gthreadprivate.h"
+/**
+ * SECTION:atomic_operations
+ * @title: Atomic Operations
+ * @shot_description: basic atomic integer and pointer operations
+ * @see_also: #GMutex
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * <note><para>You must not directly read integers or pointers concurrently
+ * accessed by multiple threads, but use the atomic accessor functions
+ * instead. That is, always use g_atomic_int_get() and g_atomic_pointer_get()
+ * for read outs. They provide the neccessary synchonization mechanisms
+ * like memory barriers to access memory locations concurrently.
+ * </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>
+ */
+
#if defined (__GNUC__)
# if defined (G_ATOMIC_I486)
/* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h
/* We have to use the slow, but safe locking method */
static GMutex *g_atomic_mutex;
+/**
+ * g_atomic_int_exchange_and_add:
+ * @atomic: a pointer to an integer
+ * @val: the value to add to *@atomic
+ *
+ * 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.
+ *
+ * Returns: the value of *@atomic before the addition.
+ *
+ * Since: 2.4
+ */
gint
g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
gint val)
return result;
}
-
+/**
+ * g_atomic_int_add:
+ * @atomic: a pointer to an integer
+ * @val: the value to add to *@atomic
+ *
+ * Atomically adds @val to the integer pointed to by @atomic.
+ * Also acts as a memory barrier.
+ *
+ * Since: 2.4
+ */
void
g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
gint val)
g_mutex_unlock (g_atomic_mutex);
}
+/**
+ * g_atomic_int_compare_and_exchange:
+ * @atomic: a pointer to an integer
+ * @oldval: the assumed old value of *@atomic
+ * @newval: the new value of *@atomic
+ *
+ * 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.
+ *
+ * Returns: %TRUE, if *@atomic was equal @oldval. %FALSE otherwise.
+ *
+ * Since: 2.4
+ */
gboolean
g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic,
gint oldval,
return result;
}
+/**
+ * g_atomic_pointer_compare_and_exchange:
+ * @atomic: a pointer to a #gpointer
+ * @oldval: the assumed old value of *@atomic
+ * @newval: the new value of *@atomic
+ *
+ * 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.
+ *
+ * Returns: %TRUE, if *@atomic was equal @oldval. %FALSE otherwise.
+ *
+ * Since: 2.4
+ */
gboolean
g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
gpointer oldval,
}
#ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
+
+/**
+ * g_atomic_int_get:
+ * @atomic: a pointer to an integer
+ *
+ * Reads the value of the integer pointed to by @atomic.
+ * Also acts as a memory barrier.
+ *
+ * Returns: the value of *@atomic
+ *
+ * Since: 2.4
+ */
gint
(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic)
{
return result;
}
+/**
+ * g_atomic_int_set:
+ * @atomic: a pointer to an integer
+ * @newval: the new value
+ *
+ * Sets the value of the integer pointed to by @atomic.
+ * Also acts as a memory barrier.
+ *
+ * Since: 2.10
+ */
void
(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic,
gint newval)
g_mutex_unlock (g_atomic_mutex);
}
+/**
+ * g_atomic_pointer_get:
+ * @atomic: a pointer to a #gpointer.
+ *
+ * Reads the value of the pointer pointed to by @atomic.
+ * Also acts as a memory barrier.
+ *
+ * Returns: the value to add to *@atomic.
+ *
+ * Since: 2.4
+ */
gpointer
(g_atomic_pointer_get) (volatile gpointer G_GNUC_MAY_ALIAS *atomic)
{
return result;
}
+/**
+ * g_atomic_pointer_set:
+ * @atomic: a pointer to a #gpointer
+ * @newval: the new value
+ *
+ * Sets the value of the pointer pointed to by @atomic.
+ * Also acts as a memory barrier.
+ *
+ * Since: 2.10
+ */
void
(g_atomic_pointer_set) (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
gpointer newval)
(g_atomic_pointer_set) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval)))
#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
+/**
+ * g_atomic_int_inc:
+ * @atomic: a pointer to an integer.
+ *
+ * Atomically increments the integer pointed to by @atomic by 1.
+ *
+ * Since: 2.4
+ */
#define g_atomic_int_inc(atomic) (g_atomic_int_add ((atomic), 1))
-#define g_atomic_int_dec_and_test(atomic) \
+
+/**
+ * g_atomic_int_dec_and_test:
+ * @atomic: a pointer to an integer
+ *
+ * Atomically decrements the integer pointed to by @atomic by 1.
+ *
+ * Returns: %TRUE if the integer pointed to by @atomic is 0
+ * after decrementing it
+ *
+ * Since: 2.4
+ */
+#define g_atomic_int_dec_and_test(atomic) \
(g_atomic_int_exchange_and_add ((atomic), -1) == 1)
G_END_DECLS