mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 11:26:16 +01:00
Move docs for atomic operations inline
This commit is contained in:
parent
e8503fddee
commit
e57291efdc
@ -2,64 +2,16 @@
|
|||||||
Atomic Operations
|
Atomic Operations
|
||||||
|
|
||||||
<!-- ##### SECTION Short_Description ##### -->
|
<!-- ##### SECTION Short_Description ##### -->
|
||||||
basic atomic integer and pointer operations
|
|
||||||
|
|
||||||
<!-- ##### SECTION Long_Description ##### -->
|
<!-- ##### SECTION Long_Description ##### -->
|
||||||
<para>
|
<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>
|
</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 ##### -->
|
<!-- ##### SECTION See_Also ##### -->
|
||||||
<para>
|
<para>
|
||||||
<variablelist>
|
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term>#GMutex</term>
|
|
||||||
<listitem><para>GLib mutual exclusions.</para></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
</variablelist>
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<!-- ##### SECTION Stability_Level ##### -->
|
<!-- ##### SECTION Stability_Level ##### -->
|
||||||
@ -70,117 +22,89 @@ g_atomic_pointer_compare_and_exchange() respectively.
|
|||||||
|
|
||||||
<!-- ##### FUNCTION g_atomic_int_get ##### -->
|
<!-- ##### FUNCTION g_atomic_int_get ##### -->
|
||||||
<para>
|
<para>
|
||||||
Reads the value of the integer pointed to by @atomic. Also acts as
|
|
||||||
a memory barrier.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@atomic: a pointer to an integer
|
@atomic:
|
||||||
@Returns: the value of *@atomic
|
|
||||||
@Since: 2.4
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_atomic_int_set ##### -->
|
<!-- ##### FUNCTION g_atomic_int_set ##### -->
|
||||||
<para>
|
<para>
|
||||||
Sets the value of the integer pointed to by @atomic.
|
|
||||||
Also acts as a memory barrier.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@atomic: a pointer to an integer
|
@atomic:
|
||||||
@newval: the new value
|
@newval:
|
||||||
@Since: 2.10
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_atomic_int_add ##### -->
|
<!-- ##### FUNCTION g_atomic_int_add ##### -->
|
||||||
<para>
|
<para>
|
||||||
Atomically adds @val to the integer pointed to by @atomic.
|
|
||||||
Also acts as a memory barrier.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@atomic: a pointer to an integer.
|
@atomic:
|
||||||
@val: the value to add to *@atomic.
|
@val:
|
||||||
@Since: 2.4
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_atomic_int_exchange_and_add ##### -->
|
<!-- ##### FUNCTION g_atomic_int_exchange_and_add ##### -->
|
||||||
<para>
|
<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>
|
</para>
|
||||||
|
|
||||||
@atomic: a pointer to an integer.
|
@atomic:
|
||||||
@val: the value to add to *@atomic.
|
@val:
|
||||||
@Returns: the value of *@atomic before the addition.
|
|
||||||
@Since: 2.4
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_atomic_int_compare_and_exchange ##### -->
|
<!-- ##### FUNCTION g_atomic_int_compare_and_exchange ##### -->
|
||||||
<para>
|
<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>
|
</para>
|
||||||
|
|
||||||
@atomic: a pointer to an integer.
|
@atomic:
|
||||||
@oldval: the assumed old value of *@atomic.
|
@oldval:
|
||||||
@newval: the new value of *@atomic.
|
@newval:
|
||||||
@Returns: %TRUE, if *@atomic was equal @oldval. %FALSE otherwise.
|
|
||||||
@Since: 2.4
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_atomic_pointer_get ##### -->
|
<!-- ##### FUNCTION g_atomic_pointer_get ##### -->
|
||||||
<para>
|
<para>
|
||||||
Reads the value of the pointer pointed to by @atomic. Also acts as
|
|
||||||
a memory barrier.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@atomic: a pointer to a #gpointer.
|
@atomic:
|
||||||
@Returns: the value to add to *@atomic.
|
|
||||||
@Since: 2.4
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_atomic_pointer_set ##### -->
|
<!-- ##### FUNCTION g_atomic_pointer_set ##### -->
|
||||||
<para>
|
<para>
|
||||||
Sets the value of the pointer pointed to by @atomic.
|
|
||||||
Also acts as a memory barrier.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@atomic: a pointer to a #gpointer
|
@atomic:
|
||||||
@newval: the new value
|
@newval:
|
||||||
@Since: 2.10
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_atomic_pointer_compare_and_exchange ##### -->
|
<!-- ##### FUNCTION g_atomic_pointer_compare_and_exchange ##### -->
|
||||||
<para>
|
<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>
|
</para>
|
||||||
|
|
||||||
@atomic: a pointer to a #gpointer.
|
@atomic:
|
||||||
@oldval: the assumed old value of *@atomic.
|
@oldval:
|
||||||
@newval: the new value of *@atomic.
|
@newval:
|
||||||
@Returns: %TRUE, if *@atomic was equal @oldval. %FALSE otherwise.
|
|
||||||
@Since: 2.4
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_atomic_int_inc ##### -->
|
<!-- ##### FUNCTION g_atomic_int_inc ##### -->
|
||||||
<para>
|
<para>
|
||||||
Atomically increments the integer pointed to by @atomic by 1.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@atomic: a pointer to an integer.
|
@atomic:
|
||||||
@Since: 2.4
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_atomic_int_dec_and_test ##### -->
|
<!-- ##### FUNCTION g_atomic_int_dec_and_test ##### -->
|
||||||
<para>
|
<para>
|
||||||
Atomically decrements the integer pointed to by @atomic by 1.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@atomic: a pointer to an integer.
|
@atomic:
|
||||||
@Returns: %TRUE, if the integer pointed to by @atomic is 0 after
|
|
||||||
decrementing it.
|
|
||||||
@Since: 2.4
|
|
||||||
|
|
||||||
|
|
||||||
|
133
glib/gatomic.c
133
glib/gatomic.c
@ -30,6 +30,44 @@
|
|||||||
#include "glib.h"
|
#include "glib.h"
|
||||||
#include "gthreadprivate.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 (__GNUC__)
|
||||||
# if defined (G_ATOMIC_I486)
|
# if defined (G_ATOMIC_I486)
|
||||||
/* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h
|
/* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h
|
||||||
@ -846,6 +884,19 @@ g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomi
|
|||||||
/* We have to use the slow, but safe locking method */
|
/* We have to use the slow, but safe locking method */
|
||||||
static GMutex *g_atomic_mutex;
|
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
|
gint
|
||||||
g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
||||||
gint val)
|
gint val)
|
||||||
@ -860,7 +911,16 @@ g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
|||||||
return result;
|
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
|
void
|
||||||
g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
||||||
gint val)
|
gint val)
|
||||||
@ -870,6 +930,20 @@ g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
|||||||
g_mutex_unlock (g_atomic_mutex);
|
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
|
gboolean
|
||||||
g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
||||||
gint oldval,
|
gint oldval,
|
||||||
@ -890,6 +964,20 @@ g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
|||||||
return result;
|
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
|
gboolean
|
||||||
g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
|
g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
|
||||||
gpointer oldval,
|
gpointer oldval,
|
||||||
@ -911,6 +999,18 @@ g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomi
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
|
#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
|
gint
|
||||||
(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic)
|
(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic)
|
||||||
{
|
{
|
||||||
@ -923,6 +1023,16 @@ gint
|
|||||||
return result;
|
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
|
void
|
||||||
(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic,
|
||||||
gint newval)
|
gint newval)
|
||||||
@ -932,6 +1042,17 @@ void
|
|||||||
g_mutex_unlock (g_atomic_mutex);
|
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
|
gpointer
|
||||||
(g_atomic_pointer_get) (volatile gpointer G_GNUC_MAY_ALIAS *atomic)
|
(g_atomic_pointer_get) (volatile gpointer G_GNUC_MAY_ALIAS *atomic)
|
||||||
{
|
{
|
||||||
@ -944,6 +1065,16 @@ gpointer
|
|||||||
return result;
|
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
|
void
|
||||||
(g_atomic_pointer_set) (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
|
(g_atomic_pointer_set) (volatile gpointer G_GNUC_MAY_ALIAS *atomic,
|
||||||
gpointer newval)
|
gpointer newval)
|
||||||
|
@ -76,8 +76,28 @@ void g_atomic_pointer_set (volatile gpointer G_GNUC_MAY_ALI
|
|||||||
(g_atomic_pointer_set) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval)))
|
(g_atomic_pointer_set) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval)))
|
||||||
#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
|
#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_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_atomic_int_exchange_and_add ((atomic), -1) == 1)
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
Loading…
Reference in New Issue
Block a user