mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-04 01:58:54 +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:
		@@ -109,6 +109,14 @@ gettime (void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
guint64 (*g_thread_gettime) (void) = gettime;
 | 
					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 */
 | 
					/* 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);
 | 
					  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 ------------------------------------------------------ */
 | 
					/* GStaticMutex {{{1 ------------------------------------------------------ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -1029,5 +1119,237 @@ g_private_new (GDestroyNotify notify)
 | 
				
			|||||||
  return key;
 | 
					  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: */
 | 
					/* vim: set foldmethod=marker: */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,6 +114,9 @@ GThread* g_thread_create_full  (GThreadFunc            func,
 | 
				
			|||||||
void g_thread_set_priority     (GThread         *thread,
 | 
					void g_thread_set_priority     (GThread         *thread,
 | 
				
			||||||
                                GThreadPriority  priority);
 | 
					                                GThreadPriority  priority);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void     g_thread_foreach      (GFunc         thread_func,
 | 
				
			||||||
 | 
					                                gpointer      user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef G_OS_WIN32
 | 
					#ifdef G_OS_WIN32
 | 
				
			||||||
typedef GMutex * GStaticMutex;
 | 
					typedef GMutex * GStaticMutex;
 | 
				
			||||||
#define G_STATIC_MUTEX_INIT NULL
 | 
					#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_writer_unlock  (GStaticRWLock* lock);
 | 
				
			||||||
void      g_static_rw_lock_free           (GStaticRWLock* lock);
 | 
					void      g_static_rw_lock_free           (GStaticRWLock* lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
GPrivate *      g_private_new             (GDestroyNotify  notify);
 | 
					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
 | 
					G_END_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __G_DEPRECATED_THREAD_H__ */
 | 
					#endif /* __G_DEPRECATED_THREAD_H__ */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										346
									
								
								glib/gthread.c
									
									
									
									
									
								
							
							
						
						
									
										346
									
								
								glib/gthread.c
									
									
									
									
									
								
							@@ -42,7 +42,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "gthread.h"
 | 
					#include "gthread.h"
 | 
				
			||||||
#include "gthreadprivate.h"
 | 
					#include "gthreadprivate.h"
 | 
				
			||||||
#include "deprecated/gthread.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -57,9 +56,7 @@
 | 
				
			|||||||
#include <windows.h>
 | 
					#include <windows.h>
 | 
				
			||||||
#endif /* G_OS_WIN32 */
 | 
					#endif /* G_OS_WIN32 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "garray.h"
 | 
					 | 
				
			||||||
#include "gslice.h"
 | 
					#include "gslice.h"
 | 
				
			||||||
#include "gslist.h"
 | 
					 | 
				
			||||||
#include "gtestutils.h"
 | 
					#include "gtestutils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -576,20 +573,6 @@ g_thread_error_quark (void)
 | 
				
			|||||||
  return g_quark_from_static_string ("g_thread_error");
 | 
					  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 -------------------------------------------------------- */
 | 
					/* Local Data {{{1 -------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gboolean         g_threads_got_initialized = FALSE;
 | 
					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 void g_thread_cleanup (gpointer data);
 | 
				
			||||||
static GPrivate     g_thread_specific_private = G_PRIVATE_INIT (g_thread_cleanup);
 | 
					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_new);
 | 
				
			||||||
G_LOCK_DEFINE_STATIC (g_thread);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Initialisation {{{1 ---------------------------------------------------- */
 | 
					/* Initialisation {{{1 ---------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -859,219 +839,6 @@ g_once_init_leave (volatile gsize *value_location,
 | 
				
			|||||||
  g_mutex_unlock (&g_once_mutex);
 | 
					  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 -------------------------------------------------------- */
 | 
					/* GThread {{{1 -------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@@ -1080,23 +847,8 @@ g_thread_cleanup (gpointer data)
 | 
				
			|||||||
  if (data)
 | 
					  if (data)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      GRealThread* thread = data;
 | 
					      GRealThread* thread = data;
 | 
				
			||||||
      GArray *array;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      array = thread->private_data;
 | 
					      g_static_private_cleanup (thread);
 | 
				
			||||||
      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);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      /* We only free the thread structure if it isn't joinable.
 | 
					      /* We only free the thread structure if it isn't joinable.
 | 
				
			||||||
       * If it is, the structure is freed in g_thread_join()
 | 
					       * 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->thread.joinable)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          if (thread->enumerable)
 | 
					          if (thread->enumerable)
 | 
				
			||||||
            {
 | 
					            g_enumerable_thread_remove (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);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          /* Just to make sure, this isn't used any more */
 | 
					          /* Just to make sure, this isn't used any more */
 | 
				
			||||||
          g_system_thread_assign (thread->system_thread, zero_thread);
 | 
					          g_system_thread_assign (thread->system_thread, zero_thread);
 | 
				
			||||||
          g_free (thread);
 | 
					          g_free (thread);
 | 
				
			||||||
@@ -1144,8 +881,8 @@ g_thread_create_proxy (gpointer data)
 | 
				
			|||||||
  /* The lock makes sure that thread->system_thread is written,
 | 
					  /* The lock makes sure that thread->system_thread is written,
 | 
				
			||||||
   * before thread->thread.func is called. See g_thread_create().
 | 
					   * before thread->thread.func is called. See g_thread_create().
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  G_LOCK (g_thread);
 | 
					  G_LOCK (g_thread_new);
 | 
				
			||||||
  G_UNLOCK (g_thread);
 | 
					  G_UNLOCK (g_thread_new);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  thread->retval = thread->thread.func (thread->thread.data);
 | 
					  thread->retval = thread->thread.func (thread->thread.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1260,16 +997,13 @@ g_thread_new_internal (const gchar  *name,
 | 
				
			|||||||
  result->private_data = NULL;
 | 
					  result->private_data = NULL;
 | 
				
			||||||
  result->enumerable = enumerable;
 | 
					  result->enumerable = enumerable;
 | 
				
			||||||
  result->name = name;
 | 
					  result->name = name;
 | 
				
			||||||
  G_LOCK (g_thread);
 | 
					  G_LOCK (g_thread_new);
 | 
				
			||||||
  g_system_thread_create (g_thread_create_proxy, result,
 | 
					  g_system_thread_create (g_thread_create_proxy, result,
 | 
				
			||||||
                          stack_size, joinable,
 | 
					                          stack_size, joinable,
 | 
				
			||||||
                          &result->system_thread, &local_error);
 | 
					                          &result->system_thread, &local_error);
 | 
				
			||||||
  if (enumerable && !local_error)
 | 
					  if (enumerable && !local_error)
 | 
				
			||||||
    {
 | 
					    g_enumerable_thread_add (result);
 | 
				
			||||||
      result->next = g_thread_all_threads;
 | 
					  G_UNLOCK (g_thread_new);
 | 
				
			||||||
      g_thread_all_threads = result;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  G_UNLOCK (g_thread);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (local_error)
 | 
					  if (local_error)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -1328,7 +1062,6 @@ gpointer
 | 
				
			|||||||
g_thread_join (GThread *thread)
 | 
					g_thread_join (GThread *thread)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  GRealThread *real = (GRealThread*) thread;
 | 
					  GRealThread *real = (GRealThread*) thread;
 | 
				
			||||||
  GRealThread *p, *t;
 | 
					 | 
				
			||||||
  gpointer retval;
 | 
					  gpointer retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  g_return_val_if_fail (thread, NULL);
 | 
					  g_return_val_if_fail (thread, NULL);
 | 
				
			||||||
@@ -1340,21 +1073,8 @@ g_thread_join (GThread *thread)
 | 
				
			|||||||
  retval = real->retval;
 | 
					  retval = real->retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (real->enumerable)
 | 
					  if (real->enumerable)
 | 
				
			||||||
    {
 | 
					    g_enumerable_thread_remove (real);
 | 
				
			||||||
      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);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  /* Just to make sure, this isn't used any more */
 | 
					  /* Just to make sure, this isn't used any more */
 | 
				
			||||||
  thread->joinable = 0;
 | 
					  thread->joinable = 0;
 | 
				
			||||||
  g_system_thread_assign (real->system_thread, zero_thread);
 | 
					  g_system_thread_assign (real->system_thread, zero_thread);
 | 
				
			||||||
@@ -1402,52 +1122,6 @@ g_thread_self (void)
 | 
				
			|||||||
  return (GThread*)thread;
 | 
					  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 ------------------------------------------------------ */
 | 
					/* GMutex {{{1 ------------------------------------------------------ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -152,22 +152,6 @@ void     g_thread_exit                   (gpointer      retval);
 | 
				
			|||||||
gpointer g_thread_join                   (GThread      *thread);
 | 
					gpointer g_thread_join                   (GThread      *thread);
 | 
				
			||||||
void     g_thread_yield                  (void);
 | 
					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
 | 
					typedef enum
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  G_ONCE_STATUS_NOTCALLED,
 | 
					  G_ONCE_STATUS_NOTCALLED,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,10 @@
 | 
				
			|||||||
#ifndef __G_THREADPRIVATE_H__
 | 
					#ifndef __G_THREADPRIVATE_H__
 | 
				
			||||||
#define __G_THREADPRIVATE_H__
 | 
					#define __G_THREADPRIVATE_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "deprecated/gthread.h"
 | 
				
			||||||
 | 
					#include "garray.h"
 | 
				
			||||||
 | 
					#include "gslist.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_BEGIN_DECLS
 | 
					G_BEGIN_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* System thread identifier comparison and assignment */
 | 
					/* System thread identifier comparison and assignment */
 | 
				
			||||||
@@ -56,9 +60,25 @@ G_GNUC_INTERNAL GThread *g_thread_new_internal (const gchar  *name,
 | 
				
			|||||||
                                                gboolean      enumerable,
 | 
					                                                gboolean      enumerable,
 | 
				
			||||||
                                                GError      **error);
 | 
					                                                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 GSystemThread zero_thread;
 | 
				
			||||||
G_GNUC_INTERNAL GMutex g_once_mutex;
 | 
					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 */
 | 
					/* Is called from gthread/gthread-impl.c */
 | 
				
			||||||
void g_thread_init_glib (void);
 | 
					void g_thread_init_glib (void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user