GStaticPrivate: implement via GPrivate
[platform/upstream/glib.git] / glib / deprecated / gthread-deprecated.c
index 16ab732..209d776 100644 (file)
@@ -23,6 +23,9 @@
 
 #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 =
 {
@@ -109,6 +146,63 @@ gettime (void)
 
 guint64 (*g_thread_gettime) (void) = gettime;
 
+/* Initialisation {{{1 ---------------------------------------------------- */
+gboolean         g_threads_got_initialized = TRUE;
+GSystemThread    zero_thread; /* This is initialized to all zero */
+
+
+/**
+ * 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_free_indices = NULL;
+
+/* Protects g_thread_all_threads and g_thread_free_indices */
+G_LOCK_DEFINE_STATIC (g_thread);
+
 /* Misc. GThread functions {{{1 */
 
 /**
@@ -155,7 +249,7 @@ g_thread_create (GThreadFunc   func,
                  gboolean      joinable,
                  GError      **error)
 {
-  return g_thread_new_full (NULL, func, data, joinable, 0, error);
+  return g_thread_new_internal (NULL, func, data, joinable, 0, TRUE, error);
 }
 
 /**
@@ -183,7 +277,95 @@ g_thread_create_full (GThreadFunc       func,
                       GThreadPriority   priority,
                       GError          **error)
 {
-  return g_thread_new_full (NULL, func, data, joinable, stack_size, 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 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);
+  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);
+}
+
+/* GOnce {{{1 ------------------------------------------------------------- */
+gboolean
+g_once_init_enter_impl (volatile gsize *location)
+{
+  return (g_once_init_enter) (location);
 }
 
 /* GStaticMutex {{{1 ------------------------------------------------------ */
@@ -308,24 +490,24 @@ g_static_mutex_init (GStaticMutex *mutex)
  * 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);
 
-      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);
@@ -1029,5 +1211,316 @@ g_private_new (GDestroyNotify notify)
   return key;
 }
 
-/* Epilogue {{{1 */
+/* {{{1 GStaticPrivate */
+
+typedef struct _GStaticPrivateNode GStaticPrivateNode;
+struct _GStaticPrivateNode
+{
+  gpointer        data;
+  GDestroyNotify  destroy;
+  GStaticPrivate *owner;
+};
+
+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:
+ *
+ * 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 (&amp;current_number_key);
+ *
+ *     if (!current_number)
+ *       {
+ *         current_number = g_new (int,1);
+ *         *current_number = 0;
+ *         g_static_private_set (&amp;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)
+{
+  GArray *array;
+  gpointer ret = NULL;
+
+  array = g_private_get (&static_private_private);
+
+  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)
+{
+  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 = g_private_get (&static_private_private);
+  if (!array)
+    {
+      array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
+      g_private_set (&static_private_private, 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);
+}
+
+/* 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_mutex_free (GMutex *mutex)
+{
+  g_mutex_clear (mutex);
+  g_slice_free (GMutex, mutex);
+}
+
+/* GCond {{{1 ------------------------------------------------------ */
+
+/**
+ * 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;
+
+  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 */
 /* vim: set foldmethod=marker: */