Renamed to glib/gthreadprivate.h and moved system thread identifier
[platform/upstream/glib.git] / glib / gthread.c
index 9505b15..72ffcb0 100644 (file)
 
 #include <string.h>
 
-#include "galias.h"
 #include "glib.h"
-#include "gthreadinit.h"
-
-#if GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P
-# define g_system_thread_equal_simple(thread1, thread2)                        \
-   ((thread1).dummy_pointer == (thread2).dummy_pointer)
-# define g_system_thread_assign(dest, src)                             \
-   ((dest).dummy_pointer = (src).dummy_pointer)
-#else /* GLIB_SIZEOF_SYSTEM_THREAD != SIZEOF_VOID_P */
-# define g_system_thread_equal_simple(thread1, thread2)                        \
-   (memcmp (&(thread1), &(thread2), GLIB_SIZEOF_SYSTEM_THREAD) == 0)
-# define g_system_thread_assign(dest, src)                             \
-   (memcpy (&(dest), &(src), GLIB_SIZEOF_SYSTEM_THREAD))
-#endif /* GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P */
-
-#define g_system_thread_equal(thread1, thread2)                                \
-  (g_thread_functions_for_glib_use.thread_equal ?                      \
-   g_thread_functions_for_glib_use.thread_equal (&(thread1), &(thread2)) :\
-   g_system_thread_equal_simple((thread1), (thread2)))
+#include "gthreadprivate.h"
+#include "galias.h"
 
 GQuark 
 g_thread_error_quark (void)
 {
-  static GQuark quark;
-  if (!quark)
-    quark = g_quark_from_static_string ("g_thread_error");
-  return quark;
+  return g_quark_from_static_string ("g_thread_error");
 }
 
 /* Keep this in sync with GRealThread in gmain.c! */
@@ -76,6 +56,7 @@ struct  _GRealThread
 {
   GThread thread;
   gpointer private_data;
+  GRealThread *next;
   gpointer retval;
   GSystemThread system_thread;
 };
@@ -126,7 +107,7 @@ GThreadFunctions g_thread_functions_for_glib_use = {
 static GMutex   *g_once_mutex = NULL;
 static GCond    *g_once_cond = NULL;
 static GPrivate *g_thread_specific_private = NULL;
-static GSList   *g_thread_all_threads = NULL;
+static GRealThread *g_thread_all_threads = NULL;
 static GSList   *g_thread_free_indeces = NULL;
 
 G_LOCK_DEFINE_STATIC (g_thread);
@@ -143,25 +124,34 @@ g_thread_init_glib (void)
    */
   GRealThread* main_thread = (GRealThread*) g_thread_self ();
 
+  /* mutex and cond creation works without g_threads_got_initialized */
   g_once_mutex = g_mutex_new ();
   g_once_cond = g_cond_new ();
 
-  _g_convert_thread_init ();
-  _g_rand_thread_init ();
-  _g_main_thread_init ();
-  _g_mem_thread_init ();
-  _g_messages_thread_init ();
-  _g_atomic_thread_init ();
-  g_threads_got_initialized = TRUE;
+  /* we may only create mutex and cond in here */
+  _g_mem_thread_init_noprivate_nomessage ();
 
+  /* setup the basic threading system */
+  g_threads_got_initialized = TRUE;
   g_thread_specific_private = g_private_new (g_thread_cleanup);
   g_private_set (g_thread_specific_private, main_thread);
   G_THREAD_UF (thread_self, (&main_thread->system_thread));
 
-  _g_mem_thread_private_init ();
-  _g_messages_thread_private_init ();
+  /* complete memory system initialization, g_private_*() works now */
+  _g_slice_thread_init_nomessage ();
 
+  /* accomplish log system initialization to enable messaging */
+  _g_messages_thread_init_nomessage ();
+
+  /* we may run full-fledged initializers from here */
+  _g_convert_thread_init ();
+  _g_rand_thread_init ();
+  _g_main_thread_init ();
+  _g_atomic_thread_init ();
+  _g_utils_thread_init ();
+#ifdef G_OS_WIN32
+  _g_win32_thread_init ();
+#endif
 }
 #endif /* G_THREADS_ENABLED */
 
@@ -195,7 +185,7 @@ g_once_impl (GOnce       *once,
 void 
 g_static_mutex_init (GStaticMutex *mutex)
 {
-  static GStaticMutex init_mutex = G_STATIC_MUTEX_INIT;
+  static const GStaticMutex init_mutex = G_STATIC_MUTEX_INIT;
 
   g_return_if_fail (mutex);
 
@@ -249,7 +239,7 @@ g_static_mutex_free (GStaticMutex* mutex)
 void     
 g_static_rec_mutex_init (GStaticRecMutex *mutex)
 {
-  static GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT;
+  static const GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT;
   
   g_return_if_fail (mutex);
 
@@ -331,6 +321,9 @@ g_static_rec_mutex_lock_full   (GStaticRecMutex *mutex,
   if (!g_thread_supported ())
     return;
 
+  if (depth == 0)
+    return;
+
   G_THREAD_UF (thread_self, (&self));
 
   if (g_system_thread_equal (self, mutex->owner))
@@ -458,7 +451,7 @@ void
 g_static_private_free (GStaticPrivate *private_key)
 {
   guint index = private_key->index;
-  GSList *list;
+  GRealThread *thread;
 
   if (!index)
     return;
@@ -466,12 +459,12 @@ g_static_private_free (GStaticPrivate *private_key)
   private_key->index = 0;
 
   G_LOCK (g_thread);
-  list =  g_thread_all_threads;
-  while (list)
+  
+  thread = g_thread_all_threads;
+  while (thread)
     {
-      GRealThread *thread = list->data;
       GArray *array = thread->private_data;
-      list = list->next;
+      thread = thread->next;
 
       if (array && index <= array->len)
        {
@@ -522,8 +515,20 @@ g_thread_cleanup (gpointer data)
          it is, the structure is freed in g_thread_join */
       if (!thread->thread.joinable)
        {
+         GRealThread *t, *p;
+
          G_LOCK (g_thread);
-         g_thread_all_threads = g_slist_remove (g_thread_all_threads, data);
+         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 */
@@ -574,7 +579,7 @@ g_thread_create_full (GThreadFunc            func,
   g_return_val_if_fail (priority >= G_THREAD_PRIORITY_LOW, NULL);
   g_return_val_if_fail (priority <= G_THREAD_PRIORITY_URGENT, NULL);
   
-  result = g_new (GRealThread, 1);
+  result = g_new0 (GRealThread, 1);
 
   result->thread.joinable = joinable;
   result->thread.priority = priority;
@@ -585,7 +590,8 @@ g_thread_create_full (GThreadFunc            func,
   G_THREAD_UF (thread_create, (g_thread_create_proxy, result, 
                               stack_size, joinable, bound, priority,
                               &result->system_thread, &local_error));
-  g_thread_all_threads = g_slist_prepend (g_thread_all_threads, result);
+  result->next = g_thread_all_threads;
+  g_thread_all_threads = result;
   G_UNLOCK (g_thread);
 
   if (local_error)
@@ -610,6 +616,7 @@ gpointer
 g_thread_join (GThread* thread)
 {
   GRealThread* real = (GRealThread*) thread;
+  GRealThread *p, *t;
   gpointer retval;
 
   g_return_val_if_fail (thread, NULL);
@@ -622,7 +629,17 @@ g_thread_join (GThread* thread)
   retval = real->retval;
 
   G_LOCK (g_thread);
-  g_thread_all_threads = g_slist_remove (g_thread_all_threads, thread);
+  for (t = g_thread_all_threads, p = NULL; t; p = t, t = t->next)
+    {
+      if (t == (GRealThread*) 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 */
@@ -665,7 +682,7 @@ g_thread_self (void)
       /* If no thread data is available, provide and set one.  This
          can happen for the main thread and for threads, that are not
          created by GLib. */
-      thread = g_new (GRealThread, 1);
+      thread = g_new0 (GRealThread, 1);
       thread->thread.joinable = FALSE; /* This is a save guess */
       thread->thread.priority = G_THREAD_PRIORITY_NORMAL; /* This is
                                                             just a guess */
@@ -679,7 +696,8 @@ g_thread_self (void)
       g_private_set (g_thread_specific_private, thread); 
       
       G_LOCK (g_thread);
-      g_thread_all_threads = g_slist_prepend (g_thread_all_threads, thread);
+      thread->next = g_thread_all_threads;
+      g_thread_all_threads = thread;
       G_UNLOCK (g_thread);
     }
   
@@ -689,14 +707,14 @@ g_thread_self (void)
 void
 g_static_rw_lock_init (GStaticRWLock* lock)
 {
-  static GStaticRWLock init_lock = G_STATIC_RW_LOCK_INIT;
+  static const GStaticRWLock init_lock = G_STATIC_RW_LOCK_INIT;
 
   g_return_if_fail (lock);
 
   *lock = init_lock;
 }
 
-static void inline 
+inline static void 
 g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex)
 {
   if (!*cond)
@@ -704,7 +722,7 @@ g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex)
   g_cond_wait (*cond, g_static_mutex_get_mutex (mutex));
 }
 
-static void inline 
+inline static void 
 g_static_rw_lock_signal (GStaticRWLock* lock)
 {
   if (lock->want_to_write && lock->write_cond)
@@ -833,3 +851,52 @@ g_static_rw_lock_free (GStaticRWLock* lock)
     }
   g_static_mutex_free (&lock->mutex);
 }
+
+/**
+ * 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-existant 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);
+    }
+}
+
+#define __G_THREAD_C__
+#include "galiasdef.c"