mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-04-15 12:08:04 +02:00
Support for one-time initialization functions. (#69668, Sebastian
2003-07-09 Matthias Clasen <maclas@gmx.de> Support for one-time initialization functions. (#69668, Sebastian Wilhelmi) * configure.in: Check whether double checked locking is safe, define g_once() in glibconfig.h accordingly. * glib/gthread.h: Add GOnce, GOnceStatus, G_ONCE_INIT and g_once_impl. * glib/gthread.c (g_once_impl): Fallback implementation using a mutex if double checked locking is unsafe. * tests/thread-test.c: Add tests for g_once().
This commit is contained in:
parent
238c7c368b
commit
876f907863
11
ChangeLog
11
ChangeLog
@ -1,3 +1,14 @@
|
|||||||
|
2003-07-09 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
Support for one-time initialization functions. (#69668, Sebastian Wilhelmi)
|
||||||
|
|
||||||
|
* configure.in: Check whether double checked locking is safe, define g_once() in
|
||||||
|
glibconfig.h accordingly.
|
||||||
|
* glib/gthread.h: Add GOnce, GOnceStatus, G_ONCE_INIT and g_once_impl.
|
||||||
|
* glib/gthread.c (g_once_impl): Fallback implementation using a mutex if double checked
|
||||||
|
locking is unsafe.
|
||||||
|
* tests/thread-test.c: Add tests for g_once().
|
||||||
|
|
||||||
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
2003-07-09 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
Support for one-time initialization functions. (#69668, Sebastian Wilhelmi)
|
||||||
|
|
||||||
|
* configure.in: Check whether double checked locking is safe, define g_once() in
|
||||||
|
glibconfig.h accordingly.
|
||||||
|
* glib/gthread.h: Add GOnce, GOnceStatus, G_ONCE_INIT and g_once_impl.
|
||||||
|
* glib/gthread.c (g_once_impl): Fallback implementation using a mutex if double checked
|
||||||
|
locking is unsafe.
|
||||||
|
* tests/thread-test.c: Add tests for g_once().
|
||||||
|
|
||||||
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
2003-07-09 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
Support for one-time initialization functions. (#69668, Sebastian Wilhelmi)
|
||||||
|
|
||||||
|
* configure.in: Check whether double checked locking is safe, define g_once() in
|
||||||
|
glibconfig.h accordingly.
|
||||||
|
* glib/gthread.h: Add GOnce, GOnceStatus, G_ONCE_INIT and g_once_impl.
|
||||||
|
* glib/gthread.c (g_once_impl): Fallback implementation using a mutex if double checked
|
||||||
|
locking is unsafe.
|
||||||
|
* tests/thread-test.c: Add tests for g_once().
|
||||||
|
|
||||||
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
2003-07-09 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
Support for one-time initialization functions. (#69668, Sebastian Wilhelmi)
|
||||||
|
|
||||||
|
* configure.in: Check whether double checked locking is safe, define g_once() in
|
||||||
|
glibconfig.h accordingly.
|
||||||
|
* glib/gthread.h: Add GOnce, GOnceStatus, G_ONCE_INIT and g_once_impl.
|
||||||
|
* glib/gthread.c (g_once_impl): Fallback implementation using a mutex if double checked
|
||||||
|
locking is unsafe.
|
||||||
|
* tests/thread-test.c: Add tests for g_once().
|
||||||
|
|
||||||
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
2003-07-09 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
Support for one-time initialization functions. (#69668, Sebastian Wilhelmi)
|
||||||
|
|
||||||
|
* configure.in: Check whether double checked locking is safe, define g_once() in
|
||||||
|
glibconfig.h accordingly.
|
||||||
|
* glib/gthread.h: Add GOnce, GOnceStatus, G_ONCE_INIT and g_once_impl.
|
||||||
|
* glib/gthread.c (g_once_impl): Fallback implementation using a mutex if double checked
|
||||||
|
locking is unsafe.
|
||||||
|
* tests/thread-test.c: Add tests for g_once().
|
||||||
|
|
||||||
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
2003-07-09 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
Support for one-time initialization functions. (#69668, Sebastian Wilhelmi)
|
||||||
|
|
||||||
|
* configure.in: Check whether double checked locking is safe, define g_once() in
|
||||||
|
glibconfig.h accordingly.
|
||||||
|
* glib/gthread.h: Add GOnce, GOnceStatus, G_ONCE_INIT and g_once_impl.
|
||||||
|
* glib/gthread.c (g_once_impl): Fallback implementation using a mutex if double checked
|
||||||
|
locking is unsafe.
|
||||||
|
* tests/thread-test.c: Add tests for g_once().
|
||||||
|
|
||||||
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
2003-07-02 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
* glib/gstrfuncs.c (g_strfreev): Move docs inline, document behavior
|
||||||
|
49
configure.in
49
configure.in
@ -1170,6 +1170,27 @@ esac
|
|||||||
AC_MSG_RESULT($GIO)
|
AC_MSG_RESULT($GIO)
|
||||||
AC_SUBST(GIO)
|
AC_SUBST(GIO)
|
||||||
|
|
||||||
|
dnl check for cpu to enable double checked locking when possible
|
||||||
|
dnl ************************************************************
|
||||||
|
|
||||||
|
if test x"$have_threads" != xno; then
|
||||||
|
AC_MSG_CHECKING(whether double checked locking is safe)
|
||||||
|
# According to glibc/linuxthreads the following platforms do
|
||||||
|
# not have the notion of a read or write memory barrier and
|
||||||
|
# therefore the double checked locking should be safe. Have a
|
||||||
|
# look at pthread_once in glibc/linuxthreads/mutex.c to see,
|
||||||
|
# what this means.
|
||||||
|
case $host_cpu in
|
||||||
|
arm|hppa|i386|i686|ia64|m68k|sh|cris|x86_64)
|
||||||
|
g_use_double_checked_locking=yes
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
g_use_double_checked_locking=no
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
AC_MSG_RESULT($g_use_double_checked_locking)
|
||||||
|
fi
|
||||||
|
|
||||||
dnl ****************************************
|
dnl ****************************************
|
||||||
dnl *** platform dependent source checks ***
|
dnl *** platform dependent source checks ***
|
||||||
dnl ****************************************
|
dnl ****************************************
|
||||||
@ -2134,9 +2155,9 @@ struct _GStaticMutex
|
|||||||
} static_mutex;
|
} static_mutex;
|
||||||
};
|
};
|
||||||
#define G_STATIC_MUTEX_INIT { NULL, { { $g_mutex_contents} } }
|
#define G_STATIC_MUTEX_INIT { NULL, { { $g_mutex_contents} } }
|
||||||
#define g_static_mutex_get_mutex(mutex) \
|
#define g_static_mutex_get_mutex(mutex) \\
|
||||||
(g_thread_use_default_impl ? ((GMutex*) &((mutex)->static_mutex)) : \
|
(g_thread_use_default_impl ? ((GMutex*) &((mutex)->static_mutex)) : \\
|
||||||
g_static_mutex_get_mutex_impl (&((mutex)->runtime_mutex)))
|
g_static_mutex_get_mutex_impl_shortcut (&((mutex)->runtime_mutex)))
|
||||||
_______EOF
|
_______EOF
|
||||||
else
|
else
|
||||||
cat >>$outfile <<_______EOF
|
cat >>$outfile <<_______EOF
|
||||||
@ -2144,10 +2165,29 @@ $g_enable_threads_def G_THREADS_ENABLED
|
|||||||
#define G_THREADS_IMPL_$g_threads_impl_def
|
#define G_THREADS_IMPL_$g_threads_impl_def
|
||||||
typedef struct _GMutex* GStaticMutex;
|
typedef struct _GMutex* GStaticMutex;
|
||||||
#define G_STATIC_MUTEX_INIT NULL
|
#define G_STATIC_MUTEX_INIT NULL
|
||||||
#define g_static_mutex_get_mutex(mutex) (g_static_mutex_get_mutex_impl (mutex))
|
#define g_static_mutex_get_mutex(mutex) \\
|
||||||
|
(g_static_mutex_get_mutex_impl_shortcut (mutex))
|
||||||
_______EOF
|
_______EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test x$g_use_double_checked_locking = xyes; then
|
||||||
|
cat >>$outfile <<_______EOF
|
||||||
|
/* double checked locking can be used on this platform */
|
||||||
|
#define g_once(once, func, arg) \\
|
||||||
|
((once)->status == G_ONCE_STATUS_READY ? (once)->retval : \\
|
||||||
|
g_once_impl (once, func, arg));
|
||||||
|
#define g_static_mutex_get_mutex_impl_shortcut(mutex) \\
|
||||||
|
(*(mutex) ? *(mutex) : g_static_mutex_get_mutex_impl (mutex))
|
||||||
|
_______EOF
|
||||||
|
else
|
||||||
|
cat >>$outfile <<_______EOF
|
||||||
|
/* double checked locking is unsafe to use on this platform, do full locking */
|
||||||
|
#define g_once(once, func, arg) (g_once_impl(once, func, arg))
|
||||||
|
#define g_static_mutex_get_mutex_impl_shortcut(mutex) \\
|
||||||
|
(g_static_mutex_get_mutex_impl (mutex))
|
||||||
|
_______EOF
|
||||||
|
fi
|
||||||
|
|
||||||
cat >>$outfile <<_______EOF
|
cat >>$outfile <<_______EOF
|
||||||
/* This represents a system thread as used by the implementation. An
|
/* This represents a system thread as used by the implementation. An
|
||||||
* alien implementaion, as loaded by g_thread_init can only count on
|
* alien implementaion, as loaded by g_thread_init can only count on
|
||||||
@ -2426,6 +2466,7 @@ xno) g_enable_threads_def="#undef";;
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
g_threads_impl_def=$g_threads_impl
|
g_threads_impl_def=$g_threads_impl
|
||||||
|
g_use_double_checked_locking=$g_use_double_checked_locking
|
||||||
|
|
||||||
g_mutex_has_default="$mutex_has_default"
|
g_mutex_has_default="$mutex_has_default"
|
||||||
g_mutex_sizeof="$glib_cv_sizeof_gmutex"
|
g_mutex_sizeof="$glib_cv_sizeof_gmutex"
|
||||||
|
@ -554,6 +554,12 @@ g_static_private_get
|
|||||||
g_static_private_set
|
g_static_private_set
|
||||||
g_static_private_free
|
g_static_private_free
|
||||||
|
|
||||||
|
<SUBSECTION>
|
||||||
|
GOnce
|
||||||
|
GOnceStatus
|
||||||
|
G_ONCE_INIT
|
||||||
|
g_once
|
||||||
|
|
||||||
<SUBSECTION Private>
|
<SUBSECTION Private>
|
||||||
G_THREAD_ECF
|
G_THREAD_ECF
|
||||||
G_THREAD_CF
|
G_THREAD_CF
|
||||||
@ -569,6 +575,7 @@ g_threads_got_initialized
|
|||||||
g_thread_functions_for_glib_use
|
g_thread_functions_for_glib_use
|
||||||
g_thread_init_glib
|
g_thread_init_glib
|
||||||
g_thread_error_quark
|
g_thread_error_quark
|
||||||
|
g_once_impl
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
@ -1606,3 +1606,72 @@ you should also free the #GStaticPrivate.
|
|||||||
@private_key: a #GStaticPrivate to be freed.
|
@private_key: a #GStaticPrivate to be freed.
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ##### STRUCT GOnce ##### -->
|
||||||
|
<para>
|
||||||
|
A <structname>GOnce</structname> struct controls a one-time initialization function.
|
||||||
|
Any one-time initialization function must have its own unique <structname>GOnce</structname>
|
||||||
|
struct.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@Since: 2.4
|
||||||
|
|
||||||
|
<!-- ##### ENUM GOnceStatus ##### -->
|
||||||
|
<para>
|
||||||
|
The possible stati of a one-time initialization function controlled by a #GOnce struct.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@G_ONCE_STATUS_NOTCALLED: the function has not been called yet.
|
||||||
|
@G_ONCE_STATUS_PROGRESS: the function call is currently in progress.
|
||||||
|
@G_ONCE_STATUS_READY: the function has been called.
|
||||||
|
|
||||||
|
<!-- ##### MACRO G_ONCE_INIT ##### -->
|
||||||
|
<para>
|
||||||
|
A #GOnce must be initialized with this macro, before it can be used.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<informalexample>
|
||||||
|
<programlisting>
|
||||||
|
GOnce my_once = G_ONCE_INIT;
|
||||||
|
</programlisting>
|
||||||
|
</informalexample>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ##### MACRO g_once ##### -->
|
||||||
|
<para>
|
||||||
|
The first call to this routine by a process with a given #GOnce struct calls @func with the given
|
||||||
|
argument. Thereafter, subsequent calls to g_once() with the same #GOnce struct do not call @func
|
||||||
|
again, but return the stored result of the first call. On return from g_once(), the status of @once
|
||||||
|
will be %G_ONCE_STATUS_READY.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
For example, a mutex or a thread-specific data key must be created exactly once. In a threaded
|
||||||
|
environment, calling g_once() ensures that the initialization is serialized across multiple threads.
|
||||||
|
</para>
|
||||||
|
<note><para>
|
||||||
|
Calling g_once() recursively on the same #GOnce struct in @func will lead to a deadlock.
|
||||||
|
</para></note>
|
||||||
|
<para>
|
||||||
|
<informalexample>
|
||||||
|
<programlisting>
|
||||||
|
gpointer
|
||||||
|
get_debug_flags ()
|
||||||
|
{
|
||||||
|
static GOnce my_once = G_ONCE_INIT;
|
||||||
|
|
||||||
|
g_once (&my_once, parse_debug_flags, NULL);
|
||||||
|
|
||||||
|
return my_once.retval;
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</informalexample>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@once: a #GOnce structure
|
||||||
|
@func: the function associated to @once. This function is called only once, regardless of the
|
||||||
|
number of times it and its associated #GOnce struct are passed to g_once() .
|
||||||
|
@arg: data to be passed to @func
|
||||||
|
@Since: 2.4
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* GLIB - Library of useful routines for C programming
|
/* GLIB - Library of useful routines for C programming
|
||||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||||
*
|
*
|
||||||
* gmutex.c: MT safety related functions
|
* gthread.c: MT safety related functions
|
||||||
* Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
|
* Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
|
||||||
* Owen Taylor
|
* Owen Taylor
|
||||||
*
|
*
|
||||||
@ -148,7 +148,8 @@ GThreadFunctions g_thread_functions_for_glib_use = {
|
|||||||
|
|
||||||
/* Local data */
|
/* Local data */
|
||||||
|
|
||||||
static GMutex *g_mutex_protect_static_mutex_allocation = NULL;
|
static GMutex *g_once_mutex = NULL;
|
||||||
|
static GCond *g_once_cond = NULL;
|
||||||
static GPrivate *g_thread_specific_private = NULL;
|
static GPrivate *g_thread_specific_private = NULL;
|
||||||
static GSList *g_thread_all_threads = NULL;
|
static GSList *g_thread_all_threads = NULL;
|
||||||
static GSList *g_thread_free_indeces = NULL;
|
static GSList *g_thread_free_indeces = NULL;
|
||||||
@ -167,7 +168,8 @@ g_thread_init_glib (void)
|
|||||||
*/
|
*/
|
||||||
GRealThread* main_thread = (GRealThread*) g_thread_self ();
|
GRealThread* main_thread = (GRealThread*) g_thread_self ();
|
||||||
|
|
||||||
g_mutex_protect_static_mutex_allocation = g_mutex_new ();
|
g_once_mutex = g_mutex_new ();
|
||||||
|
g_once_cond = g_cond_new ();
|
||||||
|
|
||||||
_g_convert_thread_init ();
|
_g_convert_thread_init ();
|
||||||
_g_rand_thread_init ();
|
_g_rand_thread_init ();
|
||||||
@ -198,6 +200,33 @@ g_thread_init_glib (void)
|
|||||||
}
|
}
|
||||||
#endif /* G_THREADS_ENABLED */
|
#endif /* G_THREADS_ENABLED */
|
||||||
|
|
||||||
|
gpointer
|
||||||
|
g_once_impl (GOnce *once,
|
||||||
|
GThreadFunc func,
|
||||||
|
gpointer arg)
|
||||||
|
{
|
||||||
|
g_mutex_lock (g_once_mutex);
|
||||||
|
|
||||||
|
while (once->status == G_ONCE_STATUS_PROGRESS)
|
||||||
|
g_cond_wait (g_once_cond, g_once_mutex);
|
||||||
|
|
||||||
|
if (once->status != G_ONCE_STATUS_READY)
|
||||||
|
{
|
||||||
|
once->status = G_ONCE_STATUS_PROGRESS;
|
||||||
|
g_mutex_unlock (g_once_mutex);
|
||||||
|
|
||||||
|
once->retval = func (arg);
|
||||||
|
|
||||||
|
g_mutex_lock (g_once_mutex);
|
||||||
|
once->status = G_ONCE_STATUS_READY;
|
||||||
|
g_cond_broadcast (g_once_cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_unlock (g_once_mutex);
|
||||||
|
|
||||||
|
return once->retval;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
g_static_mutex_init (GStaticMutex *mutex)
|
g_static_mutex_init (GStaticMutex *mutex)
|
||||||
{
|
{
|
||||||
@ -214,14 +243,23 @@ g_static_mutex_get_mutex_impl (GMutex** mutex)
|
|||||||
if (!g_thread_supported ())
|
if (!g_thread_supported ())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
g_assert (g_mutex_protect_static_mutex_allocation);
|
g_assert (g_once_mutex);
|
||||||
|
|
||||||
g_mutex_lock (g_mutex_protect_static_mutex_allocation);
|
g_mutex_lock (g_once_mutex);
|
||||||
|
|
||||||
if (!(*mutex))
|
if (!(*mutex))
|
||||||
*mutex = g_mutex_new ();
|
{
|
||||||
|
GMutex *new_mutex = g_mutex_new ();
|
||||||
|
|
||||||
|
/* The following is a memory barrier to avoid the write
|
||||||
|
* to *new_mutex being reordered to after writing *mutex */
|
||||||
|
g_mutex_lock (new_mutex);
|
||||||
|
g_mutex_unlock (new_mutex);
|
||||||
|
|
||||||
|
*mutex = new_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
g_mutex_unlock (g_mutex_protect_static_mutex_allocation);
|
g_mutex_unlock (g_once_mutex);
|
||||||
|
|
||||||
return *mutex;
|
return *mutex;
|
||||||
}
|
}
|
||||||
|
@ -284,6 +284,24 @@ gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock);
|
|||||||
void g_static_rw_lock_writer_unlock (GStaticRWLock* lock);
|
void g_static_rw_lock_writer_unlock (GStaticRWLock* lock);
|
||||||
void g_static_rw_lock_free (GStaticRWLock* lock);
|
void g_static_rw_lock_free (GStaticRWLock* lock);
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
G_ONCE_STATUS_NOTCALLED,
|
||||||
|
G_ONCE_STATUS_PROGRESS,
|
||||||
|
G_ONCE_STATUS_READY
|
||||||
|
} GOnceStatus;
|
||||||
|
|
||||||
|
typedef struct _GOnce GOnce;
|
||||||
|
struct _GOnce
|
||||||
|
{
|
||||||
|
volatile GOnceStatus status;
|
||||||
|
volatile gpointer retval;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define G_ONCE_INIT { G_ONCE_STATUS_NOTCALLED, NULL }
|
||||||
|
|
||||||
|
gpointer g_once_impl (GOnce *once, GThreadFunc func, gpointer arg);
|
||||||
|
|
||||||
/* these are some convenience macros that expand to nothing if GLib
|
/* these are some convenience macros that expand to nothing if GLib
|
||||||
* was configured with --disable-threads. for using StaticMutexes,
|
* was configured with --disable-threads. for using StaticMutexes,
|
||||||
* you define them with G_LOCK_DEFINE_STATIC (name) or G_LOCK_DEFINE (name)
|
* you define them with G_LOCK_DEFINE_STATIC (name) or G_LOCK_DEFINE (name)
|
||||||
|
@ -297,14 +297,92 @@ test_g_static_rw_lock ()
|
|||||||
g_assert (test_g_static_rw_lock_state == 0);
|
g_assert (test_g_static_rw_lock_state == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define G_ONCE_SIZE 100
|
||||||
|
#define G_ONCE_THREADS 10
|
||||||
|
|
||||||
|
G_LOCK_DEFINE (test_g_once);
|
||||||
|
static guint test_g_once_guint_array[G_ONCE_SIZE];
|
||||||
|
static GOnce test_g_once_array[G_ONCE_SIZE];
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
test_g_once_init_func(gpointer arg)
|
||||||
|
{
|
||||||
|
guint *count = arg;
|
||||||
|
g_usleep (g_random_int_range (20,1000));
|
||||||
|
(*count)++;
|
||||||
|
g_usleep (g_random_int_range (20,1000));
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
test_g_once_thread (gpointer ignore)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
G_LOCK (test_g_once);
|
||||||
|
/* Don't start before all threads are created */
|
||||||
|
G_UNLOCK (test_g_once);
|
||||||
|
for (i = 0; i < 1000; i++)
|
||||||
|
{
|
||||||
|
guint pos = g_random_int_range (0, G_ONCE_SIZE);
|
||||||
|
gpointer ret = g_once (test_g_once_array + pos, test_g_once_init_func,
|
||||||
|
test_g_once_guint_array + pos);
|
||||||
|
g_assert (ret == test_g_once_guint_array + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure, that all counters are touched at least once */
|
||||||
|
for (i = 0; i < G_ONCE_SIZE; i++)
|
||||||
|
{
|
||||||
|
gpointer ret = g_once (test_g_once_array + i, test_g_once_init_func,
|
||||||
|
test_g_once_guint_array + i);
|
||||||
|
g_assert (ret == test_g_once_guint_array + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_g_thread_once (void)
|
||||||
|
{
|
||||||
|
static GOnce once_init = G_ONCE_INIT;
|
||||||
|
GThread *threads[G_ONCE_THREADS];
|
||||||
|
guint i;
|
||||||
|
for (i = 0; i < G_ONCE_SIZE; i++)
|
||||||
|
{
|
||||||
|
test_g_once_array[i] = once_init;
|
||||||
|
test_g_once_guint_array[i] = i;
|
||||||
|
}
|
||||||
|
G_LOCK (test_g_once);
|
||||||
|
for (i = 0; i < G_ONCE_THREADS; i++)
|
||||||
|
{
|
||||||
|
threads[i] = g_thread_create (test_g_once_thread, (gpointer)(i%2),
|
||||||
|
TRUE, NULL);
|
||||||
|
}
|
||||||
|
G_UNLOCK (test_g_once);
|
||||||
|
for (i = 0; i < G_ONCE_THREADS; i++)
|
||||||
|
{
|
||||||
|
g_thread_join (threads[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < G_ONCE_SIZE; i++)
|
||||||
|
{
|
||||||
|
g_assert (test_g_once_guint_array[i] == i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* run all the tests */
|
/* run all the tests */
|
||||||
void
|
void
|
||||||
run_all_tests()
|
run_all_tests()
|
||||||
{
|
{
|
||||||
test_g_mutex ();
|
test_g_mutex ();
|
||||||
|
g_print (".");
|
||||||
test_g_static_rec_mutex ();
|
test_g_static_rec_mutex ();
|
||||||
|
g_print (".");
|
||||||
test_g_static_private ();
|
test_g_static_private ();
|
||||||
|
g_print (".");
|
||||||
test_g_static_rw_lock ();
|
test_g_static_rw_lock ();
|
||||||
|
g_print (".");
|
||||||
|
test_g_thread_once ();
|
||||||
|
g_print (".");
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -323,6 +401,7 @@ main (int argc,
|
|||||||
|
|
||||||
g_thread_use_default_impl = FALSE;
|
g_thread_use_default_impl = FALSE;
|
||||||
run_all_tests ();
|
run_all_tests ();
|
||||||
|
g_print ("\n");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user