mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
Deprecate GStaticPrivate and g_thread_foreach
This commit moves GStaticPrivate, g_thread_foreach and all related functions and variables to gthread-deprecated.c. We introduce some internal API to make this possible. g_thread_foreach is not a very useful function, since there is virtually nothing you can do with a GThread*, and implementing it requires us to keep a list of threads around. GStaticPrivate has been made redundant by adding comparable capabilities to GPrivate. https://bugzilla.gnome.org/show_bug.cgi?id=660635
This commit is contained in:
parent
12287c8cc7
commit
3d4846d923
@ -109,6 +109,14 @@ gettime (void)
|
||||
|
||||
guint64 (*g_thread_gettime) (void) = gettime;
|
||||
|
||||
/* Internal variables {{{1 */
|
||||
|
||||
static GRealThread *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_thread);
|
||||
|
||||
/* Misc. GThread functions {{{1 */
|
||||
|
||||
/**
|
||||
@ -186,6 +194,88 @@ g_thread_create_full (GThreadFunc func,
|
||||
return g_thread_new_internal (NULL, func, data, joinable, stack_size, TRUE, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
g_enumerable_thread_remove (GRealThread *thread)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* GStaticMutex {{{1 ------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
@ -1029,5 +1119,237 @@ g_private_new (GDestroyNotify notify)
|
||||
return key;
|
||||
}
|
||||
|
||||
/* Epilogue {{{1 */
|
||||
/* {{{1 GStaticPrivate */
|
||||
|
||||
typedef struct _GStaticPrivateNode GStaticPrivateNode;
|
||||
struct _GStaticPrivateNode
|
||||
{
|
||||
gpointer data;
|
||||
GDestroyNotify destroy;
|
||||
GStaticPrivate *owner;
|
||||
};
|
||||
|
||||
/**
|
||||
* GStaticPrivate:
|
||||
*
|
||||
* A #GStaticPrivate works almost like a #GPrivate, but it has one
|
||||
* significant advantage. It doesn't need to be created at run-time
|
||||
* like a #GPrivate, but can be defined at compile-time. This is
|
||||
* similar to the difference between #GMutex and #GStaticMutex. Now
|
||||
* look at our <function>give_me_next_number()</function> example with
|
||||
* #GStaticPrivate:
|
||||
*
|
||||
* <example>
|
||||
* <title>Using GStaticPrivate for per-thread data</title>
|
||||
* <programlisting>
|
||||
* int
|
||||
* give_me_next_number (<!-- -->)
|
||||
* {
|
||||
* static GStaticPrivate current_number_key = G_STATIC_PRIVATE_INIT;
|
||||
* int *current_number = g_static_private_get (&current_number_key);
|
||||
*
|
||||
* if (!current_number)
|
||||
* {
|
||||
* current_number = g_new (int,1);
|
||||
* *current_number = 0;
|
||||
* g_static_private_set (&current_number_key, current_number, g_free);
|
||||
* }
|
||||
*
|
||||
* *current_number = calc_next_number (*current_number);
|
||||
*
|
||||
* return *current_number;
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*/
|
||||
|
||||
/**
|
||||
* G_STATIC_PRIVATE_INIT:
|
||||
*
|
||||
* Every #GStaticPrivate must be initialized with this macro, before it
|
||||
* can be used.
|
||||
*
|
||||
* |[
|
||||
* GStaticPrivate my_private = G_STATIC_PRIVATE_INIT;
|
||||
* ]|
|
||||
*/
|
||||
|
||||
/**
|
||||
* g_static_private_init:
|
||||
* @private_key: a #GStaticPrivate to be initialized
|
||||
*
|
||||
* Initializes @private_key. Alternatively you can initialize it with
|
||||
* #G_STATIC_PRIVATE_INIT.
|
||||
*/
|
||||
void
|
||||
g_static_private_init (GStaticPrivate *private_key)
|
||||
{
|
||||
private_key->index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_static_private_get:
|
||||
* @private_key: a #GStaticPrivate
|
||||
*
|
||||
* Works like g_private_get() only for a #GStaticPrivate.
|
||||
*
|
||||
* This function works even if g_thread_init() has not yet been called.
|
||||
*
|
||||
* Returns: the corresponding pointer
|
||||
*/
|
||||
gpointer
|
||||
g_static_private_get (GStaticPrivate *private_key)
|
||||
{
|
||||
GRealThread *self = (GRealThread*) g_thread_self ();
|
||||
GArray *array;
|
||||
gpointer ret = NULL;
|
||||
array = self->private_data;
|
||||
|
||||
if (array && private_key->index != 0 && private_key->index <= array->len)
|
||||
{
|
||||
GStaticPrivateNode *node;
|
||||
|
||||
node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
|
||||
|
||||
/* Deal with the possibility that the GStaticPrivate which used
|
||||
* to have this index got freed and the index got allocated to
|
||||
* a new one. In this case, the data in the node is stale, so
|
||||
* free it and return NULL.
|
||||
*/
|
||||
if (G_UNLIKELY (node->owner != private_key))
|
||||
{
|
||||
if (node->destroy)
|
||||
node->destroy (node->data);
|
||||
node->destroy = NULL;
|
||||
node->data = NULL;
|
||||
node->owner = NULL;
|
||||
}
|
||||
ret = node->data;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_static_private_set:
|
||||
* @private_key: a #GStaticPrivate
|
||||
* @data: the new pointer
|
||||
* @notify: a function to be called with the pointer whenever the
|
||||
* current thread ends or sets this pointer again
|
||||
*
|
||||
* Sets the pointer keyed to @private_key for the current thread and
|
||||
* the function @notify to be called with that pointer (%NULL or
|
||||
* non-%NULL), whenever the pointer is set again or whenever the
|
||||
* current thread ends.
|
||||
*
|
||||
* This function works even if g_thread_init() has not yet been called.
|
||||
* If g_thread_init() is called later, the @data keyed to @private_key
|
||||
* will be inherited only by the main thread, i.e. the one that called
|
||||
* g_thread_init().
|
||||
*
|
||||
* <note><para>@notify is used quite differently from @destructor in
|
||||
* g_private_new().</para></note>
|
||||
*/
|
||||
void
|
||||
g_static_private_set (GStaticPrivate *private_key,
|
||||
gpointer data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
GRealThread *self = (GRealThread*) g_thread_self ();
|
||||
GArray *array;
|
||||
static guint next_index = 0;
|
||||
GStaticPrivateNode *node;
|
||||
|
||||
if (!private_key->index)
|
||||
{
|
||||
G_LOCK (g_thread);
|
||||
|
||||
if (!private_key->index)
|
||||
{
|
||||
if (g_thread_free_indices)
|
||||
{
|
||||
private_key->index = GPOINTER_TO_UINT (g_thread_free_indices->data);
|
||||
g_thread_free_indices = g_slist_delete_link (g_thread_free_indices,
|
||||
g_thread_free_indices);
|
||||
}
|
||||
else
|
||||
private_key->index = ++next_index;
|
||||
}
|
||||
|
||||
G_UNLOCK (g_thread);
|
||||
}
|
||||
|
||||
array = self->private_data;
|
||||
if (!array)
|
||||
{
|
||||
array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
|
||||
self->private_data = array;
|
||||
}
|
||||
if (private_key->index > array->len)
|
||||
g_array_set_size (array, private_key->index);
|
||||
|
||||
node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
|
||||
|
||||
if (node->destroy)
|
||||
node->destroy (node->data);
|
||||
|
||||
node->data = data;
|
||||
node->destroy = notify;
|
||||
node->owner = private_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_static_private_free:
|
||||
* @private_key: a #GStaticPrivate to be freed
|
||||
*
|
||||
* Releases all resources allocated to @private_key.
|
||||
*
|
||||
* You don't have to call this functions for a #GStaticPrivate with an
|
||||
* unbounded lifetime, i.e. objects declared 'static', but if you have
|
||||
* a #GStaticPrivate as a member of a structure and the structure is
|
||||
* freed, you should also free the #GStaticPrivate.
|
||||
*/
|
||||
void
|
||||
g_static_private_free (GStaticPrivate *private_key)
|
||||
{
|
||||
guint idx = private_key->index;
|
||||
|
||||
if (!idx)
|
||||
return;
|
||||
|
||||
private_key->index = 0;
|
||||
|
||||
/* Freeing the per-thread data is deferred to either the
|
||||
* thread end or the next g_static_private_get() call for
|
||||
* the same index.
|
||||
*/
|
||||
G_LOCK (g_thread);
|
||||
g_thread_free_indices = g_slist_prepend (g_thread_free_indices,
|
||||
GUINT_TO_POINTER (idx));
|
||||
G_UNLOCK (g_thread);
|
||||
}
|
||||
|
||||
void
|
||||
g_static_private_cleanup (GRealThread *thread)
|
||||
{
|
||||
GArray *array;
|
||||
|
||||
array = thread->private_data;
|
||||
thread->private_data = NULL;
|
||||
|
||||
if (array)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* {{{1 Epilogue */
|
||||
/* vim: set foldmethod=marker: */
|
||||
|
@ -114,6 +114,9 @@ GThread* g_thread_create_full (GThreadFunc func,
|
||||
void g_thread_set_priority (GThread *thread,
|
||||
GThreadPriority priority);
|
||||
|
||||
void g_thread_foreach (GFunc thread_func,
|
||||
gpointer user_data);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
typedef GMutex * GStaticMutex;
|
||||
#define G_STATIC_MUTEX_INIT NULL
|
||||
@ -179,9 +182,22 @@ gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock);
|
||||
void g_static_rw_lock_writer_unlock (GStaticRWLock* lock);
|
||||
void g_static_rw_lock_free (GStaticRWLock* lock);
|
||||
|
||||
|
||||
GPrivate * g_private_new (GDestroyNotify notify);
|
||||
|
||||
struct _GStaticPrivate
|
||||
{
|
||||
/*< private >*/
|
||||
guint index;
|
||||
};
|
||||
|
||||
#define G_STATIC_PRIVATE_INIT { 0 }
|
||||
void g_static_private_init (GStaticPrivate *private_key);
|
||||
gpointer g_static_private_get (GStaticPrivate *private_key);
|
||||
void g_static_private_set (GStaticPrivate *private_key,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
void g_static_private_free (GStaticPrivate *private_key);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DEPRECATED_THREAD_H__ */
|
||||
|
346
glib/gthread.c
346
glib/gthread.c
@ -42,7 +42,6 @@
|
||||
|
||||
#include "gthread.h"
|
||||
#include "gthreadprivate.h"
|
||||
#include "deprecated/gthread.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -57,9 +56,7 @@
|
||||
#include <windows.h>
|
||||
#endif /* G_OS_WIN32 */
|
||||
|
||||
#include "garray.h"
|
||||
#include "gslice.h"
|
||||
#include "gslist.h"
|
||||
#include "gtestutils.h"
|
||||
|
||||
/**
|
||||
@ -576,20 +573,6 @@ g_thread_error_quark (void)
|
||||
return g_quark_from_static_string ("g_thread_error");
|
||||
}
|
||||
|
||||
/* Miscellaneous Structures {{{1 ------------------------------------------ */
|
||||
|
||||
typedef struct _GRealThread GRealThread;
|
||||
struct _GRealThread
|
||||
{
|
||||
GThread thread;
|
||||
GArray *private_data;
|
||||
GRealThread *next;
|
||||
const gchar *name;
|
||||
gboolean enumerable;
|
||||
gpointer retval;
|
||||
GSystemThread system_thread;
|
||||
};
|
||||
|
||||
/* Local Data {{{1 -------------------------------------------------------- */
|
||||
|
||||
gboolean g_threads_got_initialized = FALSE;
|
||||
@ -601,11 +584,8 @@ static GSList *g_once_init_list = NULL;
|
||||
|
||||
static void g_thread_cleanup (gpointer data);
|
||||
static GPrivate g_thread_specific_private = G_PRIVATE_INIT (g_thread_cleanup);
|
||||
static GRealThread *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_thread);
|
||||
G_LOCK_DEFINE_STATIC (g_thread_new);
|
||||
|
||||
/* Initialisation {{{1 ---------------------------------------------------- */
|
||||
|
||||
@ -859,219 +839,6 @@ g_once_init_leave (volatile gsize *value_location,
|
||||
g_mutex_unlock (&g_once_mutex);
|
||||
}
|
||||
|
||||
/* GStaticPrivate {{{1 ---------------------------------------------------- */
|
||||
|
||||
typedef struct _GStaticPrivateNode GStaticPrivateNode;
|
||||
struct _GStaticPrivateNode
|
||||
{
|
||||
gpointer data;
|
||||
GDestroyNotify destroy;
|
||||
GStaticPrivate *owner;
|
||||
};
|
||||
|
||||
/**
|
||||
* GStaticPrivate:
|
||||
*
|
||||
* A #GStaticPrivate works almost like a #GPrivate, but it has one
|
||||
* significant advantage. It doesn't need to be created at run-time
|
||||
* like a #GPrivate, but can be defined at compile-time. This is
|
||||
* similar to the difference between #GMutex and #GStaticMutex. Now
|
||||
* look at our <function>give_me_next_number()</function> example with
|
||||
* #GStaticPrivate:
|
||||
*
|
||||
* <example>
|
||||
* <title>Using GStaticPrivate for per-thread data</title>
|
||||
* <programlisting>
|
||||
* int
|
||||
* give_me_next_number (<!-- -->)
|
||||
* {
|
||||
* static GStaticPrivate current_number_key = G_STATIC_PRIVATE_INIT;
|
||||
* int *current_number = g_static_private_get (&current_number_key);
|
||||
*
|
||||
* if (!current_number)
|
||||
* {
|
||||
* current_number = g_new (int,1);
|
||||
* *current_number = 0;
|
||||
* g_static_private_set (&current_number_key, current_number, g_free);
|
||||
* }
|
||||
*
|
||||
* *current_number = calc_next_number (*current_number);
|
||||
*
|
||||
* return *current_number;
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*/
|
||||
|
||||
/**
|
||||
* G_STATIC_PRIVATE_INIT:
|
||||
*
|
||||
* Every #GStaticPrivate must be initialized with this macro, before it
|
||||
* can be used.
|
||||
*
|
||||
* |[
|
||||
* GStaticPrivate my_private = G_STATIC_PRIVATE_INIT;
|
||||
* ]|
|
||||
*/
|
||||
|
||||
/**
|
||||
* g_static_private_init:
|
||||
* @private_key: a #GStaticPrivate to be initialized
|
||||
*
|
||||
* Initializes @private_key. Alternatively you can initialize it with
|
||||
* #G_STATIC_PRIVATE_INIT.
|
||||
*/
|
||||
void
|
||||
g_static_private_init (GStaticPrivate *private_key)
|
||||
{
|
||||
private_key->index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_static_private_get:
|
||||
* @private_key: a #GStaticPrivate
|
||||
*
|
||||
* Works like g_private_get() only for a #GStaticPrivate.
|
||||
*
|
||||
* This function works even if g_thread_init() has not yet been called.
|
||||
*
|
||||
* Returns: the corresponding pointer
|
||||
*/
|
||||
gpointer
|
||||
g_static_private_get (GStaticPrivate *private_key)
|
||||
{
|
||||
GRealThread *self = (GRealThread*) g_thread_self ();
|
||||
GArray *array;
|
||||
gpointer ret = NULL;
|
||||
|
||||
array = self->private_data;
|
||||
|
||||
if (array && private_key->index != 0 && private_key->index <= array->len)
|
||||
{
|
||||
GStaticPrivateNode *node;
|
||||
|
||||
node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
|
||||
|
||||
/* Deal with the possibility that the GStaticPrivate which used
|
||||
* to have this index got freed and the index got allocated to
|
||||
* a new one. In this case, the data in the node is stale, so
|
||||
* free it and return NULL.
|
||||
*/
|
||||
if (G_UNLIKELY (node->owner != private_key))
|
||||
{
|
||||
if (node->destroy)
|
||||
node->destroy (node->data);
|
||||
node->destroy = NULL;
|
||||
node->data = NULL;
|
||||
node->owner = NULL;
|
||||
}
|
||||
|
||||
ret = node->data;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_static_private_set:
|
||||
* @private_key: a #GStaticPrivate
|
||||
* @data: the new pointer
|
||||
* @notify: a function to be called with the pointer whenever the
|
||||
* current thread ends or sets this pointer again
|
||||
*
|
||||
* Sets the pointer keyed to @private_key for the current thread and
|
||||
* the function @notify to be called with that pointer (%NULL or
|
||||
* non-%NULL), whenever the pointer is set again or whenever the
|
||||
* current thread ends.
|
||||
*
|
||||
* This function works even if g_thread_init() has not yet been called.
|
||||
* If g_thread_init() is called later, the @data keyed to @private_key
|
||||
* will be inherited only by the main thread, i.e. the one that called
|
||||
* g_thread_init().
|
||||
*
|
||||
* <note><para>@notify is used quite differently from @destructor in
|
||||
* g_private_new().</para></note>
|
||||
*/
|
||||
void
|
||||
g_static_private_set (GStaticPrivate *private_key,
|
||||
gpointer data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
GRealThread *self = (GRealThread*) g_thread_self ();
|
||||
GArray *array;
|
||||
static guint next_index = 0;
|
||||
GStaticPrivateNode *node;
|
||||
|
||||
if (!private_key->index)
|
||||
{
|
||||
G_LOCK (g_thread);
|
||||
|
||||
if (!private_key->index)
|
||||
{
|
||||
if (g_thread_free_indices)
|
||||
{
|
||||
private_key->index = GPOINTER_TO_UINT (g_thread_free_indices->data);
|
||||
g_thread_free_indices = g_slist_delete_link (g_thread_free_indices,
|
||||
g_thread_free_indices);
|
||||
}
|
||||
else
|
||||
private_key->index = ++next_index;
|
||||
}
|
||||
|
||||
G_UNLOCK (g_thread);
|
||||
}
|
||||
|
||||
array = self->private_data;
|
||||
if (!array)
|
||||
{
|
||||
array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
|
||||
self->private_data = array;
|
||||
}
|
||||
|
||||
if (private_key->index > array->len)
|
||||
g_array_set_size (array, private_key->index);
|
||||
|
||||
node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
|
||||
|
||||
if (node->destroy)
|
||||
node->destroy (node->data);
|
||||
|
||||
node->data = data;
|
||||
node->destroy = notify;
|
||||
node->owner = private_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_static_private_free:
|
||||
* @private_key: a #GStaticPrivate to be freed
|
||||
*
|
||||
* Releases all resources allocated to @private_key.
|
||||
*
|
||||
* You don't have to call this functions for a #GStaticPrivate with an
|
||||
* unbounded lifetime, i.e. objects declared 'static', but if you have
|
||||
* a #GStaticPrivate as a member of a structure and the structure is
|
||||
* freed, you should also free the #GStaticPrivate.
|
||||
*/
|
||||
void
|
||||
g_static_private_free (GStaticPrivate *private_key)
|
||||
{
|
||||
guint idx = private_key->index;
|
||||
|
||||
if (!idx)
|
||||
return;
|
||||
|
||||
private_key->index = 0;
|
||||
|
||||
/* Freeing the per-thread data is deferred to either the
|
||||
* thread end or the next g_static_private_get() call for
|
||||
* the same index.
|
||||
*/
|
||||
G_LOCK (g_thread);
|
||||
g_thread_free_indices = g_slist_prepend (g_thread_free_indices,
|
||||
GUINT_TO_POINTER (idx));
|
||||
G_UNLOCK (g_thread);
|
||||
}
|
||||
|
||||
/* GThread {{{1 -------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
@ -1080,23 +847,8 @@ g_thread_cleanup (gpointer data)
|
||||
if (data)
|
||||
{
|
||||
GRealThread* thread = data;
|
||||
GArray *array;
|
||||
|
||||
array = thread->private_data;
|
||||
thread->private_data = NULL;
|
||||
|
||||
if (array)
|
||||
{
|
||||
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);
|
||||
}
|
||||
g_static_private_cleanup (thread);
|
||||
|
||||
/* We only free the thread structure if it isn't joinable.
|
||||
* If it is, the structure is freed in g_thread_join()
|
||||
@ -1104,23 +856,8 @@ g_thread_cleanup (gpointer data)
|
||||
if (!thread->thread.joinable)
|
||||
{
|
||||
if (thread->enumerable)
|
||||
{
|
||||
GRealThread *t, *p;
|
||||
g_enumerable_thread_remove (thread);
|
||||
|
||||
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);
|
||||
}
|
||||
/* Just to make sure, this isn't used any more */
|
||||
g_system_thread_assign (thread->system_thread, zero_thread);
|
||||
g_free (thread);
|
||||
@ -1144,8 +881,8 @@ g_thread_create_proxy (gpointer data)
|
||||
/* The lock makes sure that thread->system_thread is written,
|
||||
* before thread->thread.func is called. See g_thread_create().
|
||||
*/
|
||||
G_LOCK (g_thread);
|
||||
G_UNLOCK (g_thread);
|
||||
G_LOCK (g_thread_new);
|
||||
G_UNLOCK (g_thread_new);
|
||||
|
||||
thread->retval = thread->thread.func (thread->thread.data);
|
||||
|
||||
@ -1260,16 +997,13 @@ g_thread_new_internal (const gchar *name,
|
||||
result->private_data = NULL;
|
||||
result->enumerable = enumerable;
|
||||
result->name = name;
|
||||
G_LOCK (g_thread);
|
||||
G_LOCK (g_thread_new);
|
||||
g_system_thread_create (g_thread_create_proxy, result,
|
||||
stack_size, joinable,
|
||||
&result->system_thread, &local_error);
|
||||
if (enumerable && !local_error)
|
||||
{
|
||||
result->next = g_thread_all_threads;
|
||||
g_thread_all_threads = result;
|
||||
}
|
||||
G_UNLOCK (g_thread);
|
||||
g_enumerable_thread_add (result);
|
||||
G_UNLOCK (g_thread_new);
|
||||
|
||||
if (local_error)
|
||||
{
|
||||
@ -1328,7 +1062,6 @@ gpointer
|
||||
g_thread_join (GThread *thread)
|
||||
{
|
||||
GRealThread *real = (GRealThread*) thread;
|
||||
GRealThread *p, *t;
|
||||
gpointer retval;
|
||||
|
||||
g_return_val_if_fail (thread, NULL);
|
||||
@ -1340,21 +1073,8 @@ g_thread_join (GThread *thread)
|
||||
retval = real->retval;
|
||||
|
||||
if (real->enumerable)
|
||||
{
|
||||
G_LOCK (g_thread);
|
||||
for (t = g_thread_all_threads, p = NULL; t; p = t, t = t->next)
|
||||
{
|
||||
if (t == real)
|
||||
{
|
||||
if (p)
|
||||
p->next = t->next;
|
||||
else
|
||||
g_thread_all_threads = t->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
G_UNLOCK (g_thread);
|
||||
}
|
||||
g_enumerable_thread_remove (real);
|
||||
|
||||
/* Just to make sure, this isn't used any more */
|
||||
thread->joinable = 0;
|
||||
g_system_thread_assign (real->system_thread, zero_thread);
|
||||
@ -1402,52 +1122,6 @@ g_thread_self (void)
|
||||
return (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 existing #GThread structures.
|
||||
* 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
|
||||
*/
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* GMutex {{{1 ------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
|
@ -152,22 +152,6 @@ void g_thread_exit (gpointer retval);
|
||||
gpointer g_thread_join (GThread *thread);
|
||||
void g_thread_yield (void);
|
||||
|
||||
void g_thread_foreach (GFunc thread_func,
|
||||
gpointer user_data);
|
||||
|
||||
struct _GStaticPrivate
|
||||
{
|
||||
/*< private >*/
|
||||
guint index;
|
||||
};
|
||||
#define G_STATIC_PRIVATE_INIT { 0 }
|
||||
void g_static_private_init (GStaticPrivate *private_key);
|
||||
gpointer g_static_private_get (GStaticPrivate *private_key);
|
||||
void g_static_private_set (GStaticPrivate *private_key,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
void g_static_private_free (GStaticPrivate *private_key);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
G_ONCE_STATUS_NOTCALLED,
|
||||
|
@ -23,6 +23,10 @@
|
||||
#ifndef __G_THREADPRIVATE_H__
|
||||
#define __G_THREADPRIVATE_H__
|
||||
|
||||
#include "deprecated/gthread.h"
|
||||
#include "garray.h"
|
||||
#include "gslist.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* System thread identifier comparison and assignment */
|
||||
@ -56,9 +60,25 @@ G_GNUC_INTERNAL GThread *g_thread_new_internal (const gchar *name,
|
||||
gboolean enumerable,
|
||||
GError **error);
|
||||
|
||||
typedef struct _GRealThread GRealThread;
|
||||
struct _GRealThread
|
||||
{
|
||||
GThread thread;
|
||||
GArray *private_data;
|
||||
GRealThread *next;
|
||||
const gchar *name;
|
||||
gboolean enumerable;
|
||||
gpointer retval;
|
||||
GSystemThread system_thread;
|
||||
};
|
||||
|
||||
G_GNUC_INTERNAL GSystemThread zero_thread;
|
||||
G_GNUC_INTERNAL GMutex g_once_mutex;
|
||||
|
||||
G_GNUC_INTERNAL void g_static_private_cleanup (GRealThread *thread);
|
||||
G_GNUC_INTERNAL void g_enumerable_thread_add (GRealThread *thread);
|
||||
G_GNUC_INTERNAL void g_enumerable_thread_remove (GRealThread *thread);
|
||||
|
||||
/* Is called from gthread/gthread-impl.c */
|
||||
void g_thread_init_glib (void);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user