#include "config.h"
+/* we know we are deprecated here, no need for warnings */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
#include "gmessages.h"
#include "gslice.h"
#include "gmain.h"
#include "gthreadprivate.h"
#include "deprecated/gthread.h"
+#include "gutils.h"
+
/* {{{1 Documentation */
/**
+ * SECTION:threads-deprecated
+ * @title: Deprecated thread API
+ * @short_description: old thread APIs (for reference only)
+ * @see_also: #GThread
+ *
+ * These APIs are deprecated. You should not use them in new code.
+ * This section remains only to assist with understanding code that was
+ * written to use these APIs at some point in the past.
+ **/
+
+/**
* GThreadPriority:
* @G_THREAD_PRIORITY_LOW: a priority lower than normal
* @G_THREAD_PRIORITY_NORMAL: the default priority
* @G_THREAD_PRIORITY_HIGH: a priority higher than normal
* @G_THREAD_PRIORITY_URGENT: the highest priority
*
- * Deprecated:2.32: thread priorities no longer have any effect.
+ * Deprecated:2.32: Thread priorities no longer have any effect.
*/
/**
* to initialize the thread system.
*/
+/**
+ * G_THREADS_IMPL_POSIX:
+ *
+ * This macro is defined if POSIX style threads are used.
+ *
+ * Deprecated:2.32:POSIX threads are in use on all non-Windows systems.
+ * Use G_OS_WIN32 to detect Windows.
+ */
+
+/**
+ * G_THREADS_IMPL_WIN32:
+ *
+ * This macro is defined if Windows style threads are used.
+ *
+ * Deprecated:2.32:Use G_OS_WIN32 to detect Windows.
+ */
+
+
/* {{{1 Exported Variables */
-gboolean g_thread_use_default_impl = TRUE;
+/* Set this FALSE to have previously-compiled GStaticMutex code use the
+ * slow path (ie: call into us) to avoid compatibility problems.
+ */
+gboolean g_thread_use_default_impl = FALSE;
GThreadFunctions g_thread_functions_for_glib_use =
{
guint64 (*g_thread_gettime) (void) = gettime;
+/* Initialisation {{{1 ---------------------------------------------------- */
+gboolean g_threads_got_initialized = TRUE;
+
+/**
+ * g_thread_init:
+ * @vtable: a function table of type #GThreadFunctions, that provides
+ * the entry points to the thread system to be used. Since 2.32,
+ * this parameter is ignored and should always be %NULL
+ *
+ * If you use GLib from more than one thread, you must initialize the
+ * thread system by calling g_thread_init().
+ *
+ * Since version 2.24, calling g_thread_init() multiple times is allowed,
+ * but nothing happens except for the first call.
+ *
+ * Since version 2.32, GLib does not support custom thread implementations
+ * anymore and the @vtable parameter is ignored and you should pass %NULL.
+ *
+ * <note><para>g_thread_init() must not be called directly or indirectly
+ * in a callback from GLib. Also no mutexes may be currently locked while
+ * calling g_thread_init().</para></note>
+ *
+ * <note><para>To use g_thread_init() in your program, you have to link
+ * with the libraries that the command <command>pkg-config --libs
+ * gthread-2.0</command> outputs. This is not the case for all the
+ * other thread-related functions of GLib. Those can be used without
+ * having to link with the thread libraries.</para></note>
+ */
+
+/**
+ * g_thread_get_initialized:
+ *
+ * Indicates if g_thread_init() has been called.
+ *
+ * Returns: %TRUE if threads have been initialized.
+ *
+ * Since: 2.20
+ */
+gboolean
+g_thread_get_initialized (void)
+{
+ return g_thread_supported ();
+}
+
+/* We need this for ABI compatibility */
+void g_thread_init_glib (void) { }
+
/* Internal variables {{{1 */
-static GRealThread *g_thread_all_threads = NULL;
+static GSList *g_thread_all_threads = NULL;
static GSList *g_thread_free_indices = NULL;
/* Protects g_thread_all_threads and g_thread_free_indices */
+G_LOCK_DEFINE_STATIC (g_static_mutex);
G_LOCK_DEFINE_STATIC (g_thread);
/* Misc. GThread functions {{{1 */
}
/**
+ * g_thread_foreach:
+ * @thread_func: function to call for all #GThread structures
+ * @user_data: second argument to @thread_func
+ *
+ * Call @thread_func on all #GThreads that have been
+ * created with g_thread_create().
+ *
+ * Note that threads may decide to exit while @thread_func is
+ * running, so without intimate knowledge about the lifetime of
+ * foreign threads, @thread_func shouldn't access the GThread*
+ * pointer passed in as first argument. However, @thread_func will
+ * not be called for threads which are known to have exited already.
+ *
+ * Due to thread lifetime checks, this function has an execution complexity
+ * which is quadratic in the number of existing threads.
+ *
+ * Since: 2.10
+ *
+ * Deprecated:2.32: There aren't many things you can do with a #GThread,
+ * except comparing it with one that was returned from g_thread_create().
+ * There are better ways to find out if your thread is still alive.
+ */
+void
+g_thread_foreach (GFunc thread_func,
+ gpointer user_data)
+{
+ GSList *slist = NULL;
+ GRealThread *thread;
+ g_return_if_fail (thread_func != NULL);
+ /* snapshot the list of threads for iteration */
+ G_LOCK (g_thread);
+ slist = g_slist_copy (g_thread_all_threads);
+ G_UNLOCK (g_thread);
+ /* walk the list, skipping non-existent threads */
+ while (slist)
+ {
+ GSList *node = slist;
+ slist = node->next;
+ /* check whether the current thread still exists */
+ G_LOCK (g_thread);
+ if (g_slist_find (g_thread_all_threads, node->data))
+ thread = node->data;
+ else
+ thread = NULL;
+ G_UNLOCK (g_thread);
+ if (thread)
+ thread_func (thread, user_data);
+ g_slist_free_1 (node);
+ }
+}
+
+static void
+g_enumerable_thread_remove (gpointer data)
+{
+ GRealThread *thread = data;
+
+ G_LOCK (g_thread);
+ g_thread_all_threads = g_slist_remove (g_thread_all_threads, thread);
+ G_UNLOCK (g_thread);
+}
+
+GPrivate enumerable_thread_private = G_PRIVATE_INIT (g_enumerable_thread_remove);
+
+static void
+g_enumerable_thread_add (GRealThread *thread)
+{
+ G_LOCK (g_thread);
+ g_thread_all_threads = g_slist_prepend (g_thread_all_threads, thread);
+ G_UNLOCK (g_thread);
+
+ g_private_set (&enumerable_thread_private, thread);
+}
+
+static gpointer
+g_deprecated_thread_proxy (gpointer data)
+{
+ GRealThread *real = data;
+
+ g_enumerable_thread_add (real);
+
+ return g_thread_proxy (data);
+}
+
+/**
* g_thread_create:
* @func: a function to execute in the new thread
* @data: an argument to supply to the new thread
*
* This function creates a new thread.
*
- * If @joinable is %TRUE, you can wait for this threads termination
- * calling g_thread_join(). Otherwise the thread will just disappear
- * when it terminates.
- *
* The new thread executes the function @func with the argument @data.
* If the thread was created successfully, it is returned.
*
* @error can be %NULL to ignore errors, or non-%NULL to report errors.
* The error is set, if and only if the function returns %NULL.
*
+ * This function returns a reference to the created thread only if
+ * @joinable is %TRUE. In that case, you must free this reference by
+ * calling g_thread_unref() or g_thread_join(). If @joinable is %FALSE
+ * then you should probably not touch the return value.
+ *
* Returns: the new #GThread on success
*
* Deprecated:2.32: Use g_thread_new() instead
gboolean joinable,
GError **error)
{
- return g_thread_new_internal (NULL, func, data, joinable, 0, TRUE, error);
+ return g_thread_create_full (func, data, 0, joinable, 0, 0, error);
}
/**
* This function creates a new thread.
*
* Deprecated:2.32: The @bound and @priority arguments are now ignored.
- * Use g_thread_new() or g_thread_new_full() instead.
+ * Use g_thread_new().
*/
GThread *
g_thread_create_full (GThreadFunc func,
GThreadPriority priority,
GError **error)
{
- return g_thread_new_internal (NULL, func, data, joinable, stack_size, TRUE, error);
-}
+ GThread *thread;
-/**
- * g_thread_foreach:
- * @thread_func: function to call for all #GThread structures
- * @user_data: second argument to @thread_func
- *
- * Call @thread_func on all #GThreads that have been
- * created with g_thread_create().
- *
- * Note that threads may decide to exit while @thread_func is
- * running, so without intimate knowledge about the lifetime of
- * foreign threads, @thread_func shouldn't access the GThread*
- * pointer passed in as first argument. However, @thread_func will
- * not be called for threads which are known to have exited already.
- *
- * Due to thread lifetime checks, this function has an execution complexity
- * which is quadratic in the number of existing threads.
- *
- * Since: 2.10
- *
- * Deprecated:2.32: There are not very many interesting things you can
- * do with a #GThread, except comparing it with one that was returned
- * from g_thread_create(). There are better ways to find out if your
- * thread is still alive.
- */
-void
-g_thread_foreach (GFunc thread_func,
- gpointer user_data)
-{
- GSList *slist = NULL;
- GRealThread *thread;
- g_return_if_fail (thread_func != NULL);
- /* snapshot the list of threads for iteration */
- G_LOCK (g_thread);
- for (thread = g_thread_all_threads; thread; thread = thread->next)
- slist = g_slist_prepend (slist, thread);
- G_UNLOCK (g_thread);
- /* walk the list, skipping non-existent threads */
- while (slist)
+ thread = g_thread_new_internal (NULL, g_deprecated_thread_proxy,
+ func, data, stack_size, error);
+
+ if (!joinable)
{
- GSList *node = slist;
- slist = node->next;
- /* check whether the current thread still exists */
- G_LOCK (g_thread);
- for (thread = g_thread_all_threads; thread; thread = thread->next)
- if (thread == node->data)
- break;
- G_UNLOCK (g_thread);
- if (thread)
- thread_func (thread, user_data);
- g_slist_free_1 (node);
+ thread->joinable = FALSE;
+ g_thread_unref (thread);
}
-}
-void
-g_enumerable_thread_add (GRealThread *thread)
-{
- G_LOCK (g_thread);
- thread->next = g_thread_all_threads;
- g_thread_all_threads = thread;
- G_UNLOCK (g_thread);
+ return thread;
}
-void
-g_enumerable_thread_remove (GRealThread *thread)
+/* GOnce {{{1 ------------------------------------------------------------- */
+gboolean
+g_once_init_enter_impl (volatile gsize *location)
{
- GRealThread *t, *p;
-
- G_LOCK (g_thread);
- for (t = g_thread_all_threads, p = NULL; t; p = t, t = t->next)
- {
- if (t == thread)
- {
- if (p)
- p->next = t->next;
- else
- g_thread_all_threads = t->next;
- break;
- }
- }
- G_UNLOCK (g_thread);
+ return (g_once_init_enter) (location);
}
/* GStaticMutex {{{1 ------------------------------------------------------ */
* Deprecated: 2.32: Just use a #GMutex
*/
GMutex *
-g_static_mutex_get_mutex_impl (GMutex** mutex)
+g_static_mutex_get_mutex_impl (GStaticMutex* mutex)
{
GMutex *result;
if (!g_thread_supported ())
return NULL;
- result = g_atomic_pointer_get (mutex);
+ result = g_atomic_pointer_get (&mutex->mutex);
if (!result)
{
- g_mutex_lock (&g_once_mutex);
+ G_LOCK (g_static_mutex);
- result = *mutex;
+ result = mutex->mutex;
if (!result)
{
result = g_mutex_new ();
- g_atomic_pointer_set (mutex, result);
+ g_atomic_pointer_set (&mutex->mutex, result);
}
- g_mutex_unlock (&g_once_mutex);
+ G_UNLOCK (g_static_mutex);
}
return result;
*mutex = init_mutex;
}
+static GRecMutex *
+g_static_rec_mutex_get_rec_mutex_impl (GStaticRecMutex* mutex)
+{
+ GRecMutex *result;
+
+ if (!g_thread_supported ())
+ return NULL;
+
+ result = g_atomic_pointer_get (&mutex->mutex.mutex);
+
+ if (!result)
+ {
+ G_LOCK (g_static_mutex);
+
+ result = (GRecMutex *) mutex->mutex.mutex;
+ if (!result)
+ {
+ result = g_slice_new (GRecMutex);
+ g_rec_mutex_init (result);
+ g_atomic_pointer_set (&mutex->mutex.mutex, result);
+ }
+
+ G_UNLOCK (g_static_mutex);
+ }
+
+ return result;
+}
+
/**
* g_static_rec_mutex_lock:
* @mutex: a #GStaticRecMutex to lock.
void
g_static_rec_mutex_lock (GStaticRecMutex* mutex)
{
- GSystemThread self;
-
- g_return_if_fail (mutex);
-
- if (!g_thread_supported ())
- return;
-
- g_system_thread_self (&self);
-
- if (g_system_thread_equal (&self, &mutex->owner))
- {
- mutex->depth++;
- return;
- }
- g_static_mutex_lock (&mutex->mutex);
- g_system_thread_assign (mutex->owner, self);
- mutex->depth = 1;
+ GRecMutex *rm;
+ rm = g_static_rec_mutex_get_rec_mutex_impl (mutex);
+ g_rec_mutex_lock (rm);
+ mutex->depth++;
}
/**
gboolean
g_static_rec_mutex_trylock (GStaticRecMutex* mutex)
{
- GSystemThread self;
-
- g_return_val_if_fail (mutex, FALSE);
-
- if (!g_thread_supported ())
- return TRUE;
-
- g_system_thread_self (&self);
+ GRecMutex *rm;
+ rm = g_static_rec_mutex_get_rec_mutex_impl (mutex);
- if (g_system_thread_equal (&self, &mutex->owner))
+ if (g_rec_mutex_trylock (rm))
{
mutex->depth++;
return TRUE;
}
-
- if (!g_static_mutex_trylock (&mutex->mutex))
+ else
return FALSE;
-
- g_system_thread_assign (mutex->owner, self);
- mutex->depth = 1;
- return TRUE;
}
/**
void
g_static_rec_mutex_unlock (GStaticRecMutex* mutex)
{
- g_return_if_fail (mutex);
-
- if (!g_thread_supported ())
- return;
-
- if (mutex->depth > 1)
- {
- mutex->depth--;
- return;
- }
- g_system_thread_assign (mutex->owner, zero_thread);
- g_static_mutex_unlock (&mutex->mutex);
+ GRecMutex *rm;
+ rm = g_static_rec_mutex_get_rec_mutex_impl (mutex);
+ mutex->depth--;
+ g_rec_mutex_unlock (rm);
}
/**
g_static_rec_mutex_lock_full (GStaticRecMutex *mutex,
guint depth)
{
- GSystemThread self;
- g_return_if_fail (mutex);
-
- if (!g_thread_supported ())
- return;
+ GRecMutex *rm;
- if (depth == 0)
- return;
-
- g_system_thread_self (&self);
-
- if (g_system_thread_equal (&self, &mutex->owner))
+ rm = g_static_rec_mutex_get_rec_mutex_impl (mutex);
+ while (depth--)
{
- mutex->depth += depth;
- return;
+ g_rec_mutex_lock (rm);
+ mutex->depth++;
}
- g_static_mutex_lock (&mutex->mutex);
- g_system_thread_assign (mutex->owner, self);
- mutex->depth = depth;
}
/**
guint
g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex)
{
- guint depth;
-
- g_return_val_if_fail (mutex, 0);
-
- if (!g_thread_supported ())
- return 1;
+ GRecMutex *rm;
+ gint depth;
+ rm = g_static_rec_mutex_get_rec_mutex_impl (mutex);
depth = mutex->depth;
-
- g_system_thread_assign (mutex->owner, zero_thread);
- mutex->depth = 0;
- g_static_mutex_unlock (&mutex->mutex);
+ while (mutex->depth--)
+ g_rec_mutex_unlock (rm);
return depth;
}
{
g_return_if_fail (mutex);
- g_static_mutex_free (&mutex->mutex);
+ if (mutex->mutex.mutex)
+ {
+ GRecMutex *rm = (GRecMutex *) mutex->mutex.mutex;
+
+ g_rec_mutex_clear (rm);
+ g_slice_free (GRecMutex, rm);
+ }
}
/* GStaticRWLock {{{1 ----------------------------------------------------- */
GStaticPrivate *owner;
};
+static void
+g_static_private_cleanup (gpointer data)
+{
+ GArray *array = data;
+ guint i;
+
+ for (i = 0; i < array->len; i++ )
+ {
+ GStaticPrivateNode *node = &g_array_index (array, GStaticPrivateNode, i);
+ if (node->destroy)
+ node->destroy (node->data);
+ }
+
+ g_array_free (array, TRUE);
+}
+
+GPrivate static_private_private = G_PRIVATE_INIT (g_static_private_cleanup);
+
/**
* GStaticPrivate:
*
gpointer
g_static_private_get (GStaticPrivate *private_key)
{
- GRealThread *self = (GRealThread*) g_thread_self ();
GArray *array;
gpointer ret = NULL;
- array = self->private_data;
+
+ array = g_private_get (&static_private_private);
if (array && private_key->index != 0 && private_key->index <= array->len)
{
gpointer data,
GDestroyNotify notify)
{
- GRealThread *self = (GRealThread*) g_thread_self ();
GArray *array;
static guint next_index = 0;
GStaticPrivateNode *node;
G_UNLOCK (g_thread);
}
- array = self->private_data;
+ array = g_private_get (&static_private_private);
if (!array)
{
array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
- self->private_data = array;
+ g_private_set (&static_private_private, array);
}
if (private_key->index > array->len)
g_array_set_size (array, private_key->index);
G_UNLOCK (g_thread);
}
+/* GMutex {{{1 ------------------------------------------------------ */
+
+/**
+ * g_mutex_new:
+ *
+ * Allocates and initializes a new #GMutex.
+ *
+ * Returns: a newly allocated #GMutex. Use g_mutex_free() to free
+ *
+ * Deprecated:3.32:GMutex can now be statically allocated, or embedded
+ * in structures and initialised with g_mutex_init().
+ */
+GMutex *
+g_mutex_new (void)
+{
+ GMutex *mutex;
+
+ mutex = g_slice_new (GMutex);
+ g_mutex_init (mutex);
+
+ return mutex;
+}
+
+/**
+ * g_mutex_free:
+ * @mutex: a #GMutex
+ *
+ * Destroys a @mutex that has been created with g_mutex_new().
+ *
+ * Calling g_mutex_free() on a locked mutex may result
+ * in undefined behaviour.
+ *
+ * Deprecated:3.32:GMutex can now be statically allocated, or embedded
+ * in structures and initialised with g_mutex_init().
+ */
void
-g_static_private_cleanup (GRealThread *thread)
+g_mutex_free (GMutex *mutex)
{
- GArray *array;
+ g_mutex_clear (mutex);
+ g_slice_free (GMutex, mutex);
+}
- array = thread->private_data;
- thread->private_data = NULL;
+/* GCond {{{1 ------------------------------------------------------ */
- if (array)
- {
- guint i;
+/**
+ * g_cond_new:
+ *
+ * Allocates and initializes a new #GCond.
+ *
+ * Returns: a newly allocated #GCond. Free with g_cond_free()
+ *
+ * Deprecated:3.32:GCond can now be statically allocated, or embedded
+ * in structures and initialised with g_cond_init().
+ */
+GCond *
+g_cond_new (void)
+{
+ GCond *cond;
- for (i = 0; i < array->len; i++ )
- {
- GStaticPrivateNode *node = &g_array_index (array, GStaticPrivateNode, i);
- if (node->destroy)
- node->destroy (node->data);
- }
- g_array_free (array, TRUE);
- }
+ cond = g_slice_new (GCond);
+ g_cond_init (cond);
+
+ return cond;
+}
+
+/**
+ * g_cond_free:
+ * @cond: a #GCond
+ *
+ * Destroys a #GCond that has been created with g_cond_new().
+ *
+ * Calling g_cond_free() for a #GCond on which threads are
+ * blocking leads to undefined behaviour.
+ *
+ * Deprecated:3.32:GCond can now be statically allocated, or embedded
+ * in structures and initialised with g_cond_init().
+ */
+void
+g_cond_free (GCond *cond)
+{
+ g_cond_clear (cond);
+ g_slice_free (GCond, cond);
}
/* {{{1 Epilogue */