added g_list_nth_prev() which walks ->prev instead of ->next.
[platform/upstream/glib.git] / gthread.c
index bbb18ac..8ee0c99 100644 (file)
--- a/gthread.c
+++ b/gthread.c
 #include "config.h"
 #include "glib.h"
 
+#ifdef G_THREAD_USE_PID_SURROGATE
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <errno.h>
+#endif /* G_THREAD_USE_PID_SURROGATE */
+
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 
+#include <string.h>
+
 #if GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P
 # define g_system_thread_equal(thread1, thread2)                       \
    (thread1.dummy_pointer == thread2.dummy_pointer)
@@ -52,7 +61,7 @@
 #endif /* GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P */
 
 GQuark 
-g_thread_error_quark()
+g_thread_error_quark (void)
 {
   static GQuark quark;
   if (!quark)
@@ -60,6 +69,7 @@ g_thread_error_quark()
   return quark;
 }
 
+/* Keep this in sync with GRealThread in gmain.c! */
 typedef struct _GRealThread GRealThread;
 struct  _GRealThread
 {
@@ -67,9 +77,26 @@ struct  _GRealThread
   GThreadFunc func;
   gpointer arg;
   gpointer private_data;
+  GMainContext *context;
   GSystemThread system_thread;
+#ifdef G_THREAD_USE_PID_SURROGATE
+  pid_t pid;
+#endif /* G_THREAD_USE_PID_SURROGATE */
 };
 
+#ifdef G_THREAD_USE_PID_SURROGATE
+static gint priority_map[] = { 15, 0, -15, -20 };
+static gboolean prio_warned = FALSE;
+# define SET_PRIO(pid, prio) G_STMT_START{                             \
+  gint error = setpriority (PRIO_PROCESS, (pid), priority_map[prio]);  \
+  if (error == -1 && errno == EACCES && !prio_warned)                  \
+    {                                                                  \
+      prio_warned = TRUE;                                              \
+      g_warning ("Priorities can only be increased by root.");         \
+    }                                                                  \
+  }G_STMT_END
+#endif /* G_THREAD_USE_PID_SURROGATE */
+
 typedef struct _GStaticPrivateNode GStaticPrivateNode;
 struct _GStaticPrivateNode
 {
@@ -86,7 +113,7 @@ static GSystemThread zero_thread; /* This is initialized to all zero */
 gboolean g_thread_use_default_impl = TRUE;
 gboolean g_threads_got_initialized = FALSE;
 
-#if defined(G_OS_WIN32) && defined(__GNUC__)
+#if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
 __declspec(dllexport)
 #endif
 GThreadFunctions g_thread_functions_for_glib_use = {
@@ -117,8 +144,11 @@ GThreadFunctions g_thread_functions_for_glib_use = {
 /* Local data */
 
 static GMutex   *g_mutex_protect_static_mutex_allocation = NULL;
-static GMutex   *g_thread_specific_mutex = NULL;
 static GPrivate *g_thread_specific_private = NULL;
+static GSList   *g_thread_all_threads = NULL;
+static GSList   *g_thread_free_indeces = NULL;
+
+G_LOCK_DEFINE_STATIC (g_thread);
 
 /* This must be called only once, before any threads are created.
  * It will only be called from g_thread_init() in -lgthread.
@@ -137,8 +167,17 @@ g_mutex_init (void)
   G_THREAD_UF (private_set, (g_thread_specific_private, main_thread));
   G_THREAD_UF (thread_self, (&main_thread->system_thread));
 
-  g_mutex_protect_static_mutex_allocation = g_mutex_new();
-  g_thread_specific_mutex = g_mutex_new();
+  g_mutex_protect_static_mutex_allocation = g_mutex_new ();
+}
+
+void 
+g_static_mutex_init (GStaticMutex *mutex)
+{
+  static GStaticMutex init_mutex = G_STATIC_MUTEX_INIT;
+
+  g_return_if_fail (mutex);
+
+  memcpy (mutex, &init_mutex, sizeof (GStaticMutex));
 }
 
 GMutex *
@@ -152,7 +191,7 @@ g_static_mutex_get_mutex_impl (GMutex** mutex)
   g_mutex_lock (g_mutex_protect_static_mutex_allocation);
 
   if (!(*mutex)) 
-    *mutex = g_mutex_new(); 
+    *mutex = g_mutex_new (); 
 
   g_mutex_unlock (g_mutex_protect_static_mutex_allocation);
   
@@ -160,6 +199,33 @@ g_static_mutex_get_mutex_impl (GMutex** mutex)
 }
 
 void
+g_static_mutex_free (GStaticMutex* mutex)
+{
+  GMutex **runtime_mutex;
+  
+  g_return_if_fail (mutex);
+
+  /* The runtime_mutex is the first (or only) member of GStaticMutex,
+   * see both versions (of glibconfig.h) in configure.in */
+  runtime_mutex = ((GMutex**)mutex);
+  
+  if (*runtime_mutex)
+    g_mutex_free (*runtime_mutex);
+
+  *runtime_mutex = NULL;
+}
+
+void     
+g_static_rec_mutex_init (GStaticRecMutex *mutex)
+{
+  static GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT;
+  
+  g_return_if_fail (mutex);
+
+  memcpy (mutex, &init_mutex, sizeof (GStaticRecMutex));
+}
+
+void
 g_static_rec_mutex_lock (GStaticRecMutex* mutex)
 {
   GSystemThread self;
@@ -228,13 +294,21 @@ void
 g_static_rec_mutex_lock_full   (GStaticRecMutex *mutex,
                                guint            depth)
 {
+  GSystemThread self;
   g_return_if_fail (mutex);
 
   if (!g_thread_supported ())
     return;
 
+  G_THREAD_UF (thread_self, (&self));
+
+  if (g_system_thread_equal (self, mutex->owner))
+    {
+      mutex->depth += depth;
+      return;
+    }
   g_static_mutex_lock (&mutex->mutex);
-  G_THREAD_UF (thread_self, (&mutex->owner));
+  g_system_thread_assign (mutex->owner, self);
   mutex->depth = depth;
 }
 
@@ -257,21 +331,25 @@ g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex)
   return depth;
 }
 
+void
+g_static_rec_mutex_free (GStaticRecMutex *mutex)
+{
+  g_return_if_fail (mutex);
+
+  g_static_mutex_free (&mutex->mutex);
+}
 
-gpointer
-g_static_private_get (GStaticPrivate *private_key)
+void     
+g_static_private_init (GStaticPrivate *private_key)
 {
-  return g_static_private_get_for_thread (private_key, g_thread_self ());
+  private_key->index = 0;
 }
 
 gpointer
-g_static_private_get_for_thread (GStaticPrivate *private_key,
-                                GThread        *thread)
+g_static_private_get (GStaticPrivate *private_key)
 {
+  GRealThread *self = (GRealThread*) g_thread_self ();
   GArray *array;
-  GRealThread *self = (GRealThread*) thread;
-
-  g_return_val_if_fail (thread, NULL);
 
   array = self->private_data;
   if (!array)
@@ -280,7 +358,8 @@ g_static_private_get_for_thread (GStaticPrivate *private_key,
   if (!private_key->index)
     return NULL;
   else if (private_key->index <= array->len)
-    return g_array_index (array, GStaticPrivateNode, private_key->index - 1).data;
+    return g_array_index (array, GStaticPrivateNode, 
+                         private_key->index - 1).data;
   else
     return NULL;
 }
@@ -290,23 +369,11 @@ g_static_private_set (GStaticPrivate *private_key,
                      gpointer        data,
                      GDestroyNotify  notify)
 {
-  g_static_private_set_for_thread (private_key, g_thread_self (), 
-                                  data, notify);
-}
-
-void
-g_static_private_set_for_thread (GStaticPrivate *private_key, 
-                                GThread        *thread,
-                                gpointer        data,
-                                GDestroyNotify  notify)
-{
+  GRealThread *self = (GRealThread*) g_thread_self ();
   GArray *array;
-  GRealThread *self =(GRealThread*) thread;
   static guint next_index = 0;
   GStaticPrivateNode *node;
 
-  g_return_if_fail (thread);
-  
   array = self->private_data;
   if (!array)
     {
@@ -316,12 +383,23 @@ g_static_private_set_for_thread (GStaticPrivate *private_key,
 
   if (!private_key->index)
     {
-      g_mutex_lock (g_thread_specific_mutex);
+      G_LOCK (g_thread);
 
       if (!private_key->index)
-       private_key->index = ++next_index;
+       {
+         if (g_thread_free_indeces)
+           {
+             private_key->index = 
+               GPOINTER_TO_UINT (g_thread_free_indeces->data);
+             g_thread_free_indeces = 
+               g_slist_delete_link (g_thread_free_indeces,
+                                    g_thread_free_indeces);
+           }
+         else
+           private_key->index = ++next_index;
+       }
 
-      g_mutex_unlock (g_thread_specific_mutex);
+      G_UNLOCK (g_thread);
     }
 
   if (private_key->index > array->len)
@@ -345,6 +423,51 @@ g_static_private_set_for_thread (GStaticPrivate *private_key,
     }
 }
 
+void     
+g_static_private_free (GStaticPrivate *private_key)
+{
+  guint index = private_key->index;
+  GSList *list;
+
+  if (!index)
+    return;
+  
+  private_key->index = 0;
+
+  G_LOCK (g_thread);
+  list =  g_thread_all_threads;
+  while (list)
+    {
+      GRealThread *thread = list->data;
+      GArray *array = thread->private_data;
+      list = list->next;
+
+      if (array && index <= array->len)
+       {
+         GStaticPrivateNode *node = &g_array_index (array, 
+                                                    GStaticPrivateNode, 
+                                                    index - 1);
+         gpointer ddata = node->data;
+         GDestroyNotify ddestroy = node->destroy;
+
+         node->data = NULL;
+         node->destroy = NULL;
+
+         if (ddestroy) 
+           {
+             G_UNLOCK (g_thread);
+             ddestroy (ddata);
+             G_LOCK (g_thread);
+             }
+       }
+    }
+  g_thread_free_indeces = g_slist_prepend (g_thread_free_indeces, 
+                                          GUINT_TO_POINTER (index));
+  G_UNLOCK (g_thread);
+}
+
+void g_main_context_destroy (GMainContext *context);
+
 static void
 g_thread_cleanup (gpointer data)
 {
@@ -365,10 +488,17 @@ g_thread_cleanup (gpointer data)
            }
          g_array_free (array, TRUE);
        }
+      if (thread->context)
+       g_main_context_destroy (thread->context);
+
       /* We only free the thread structure, if it isn't joinable. If
          it is, the structure is freed in g_thread_join */
       if (!thread->thread.joinable)
        {
+         G_LOCK (g_thread);
+         g_thread_all_threads = g_slist_remove (g_thread_all_threads, data);
+         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);
@@ -382,8 +512,6 @@ g_thread_fail (void)
   g_error ("The thread system is not yet initialized.");
 }
 
-G_LOCK_DEFINE_STATIC (g_thread_create);
-
 static void 
 g_thread_create_proxy (gpointer data)
 {
@@ -391,13 +519,22 @@ g_thread_create_proxy (gpointer data)
 
   g_assert (data);
 
+#ifdef G_THREAD_USE_PID_SURROGATE
+  thread->pid = getpid ();
+#endif /* G_THREAD_USE_PID_SURROGATE */
+
   /* This has to happen before G_LOCK, as that might call g_thread_self */
   g_private_set (g_thread_specific_private, data);
 
   /* the lock makes sure, that thread->system_thread is written,
      before thread->func is called. See g_thread_create. */
-  G_LOCK (g_thread_create);
-  G_UNLOCK (g_thread_create);
+  G_LOCK (g_thread);
+  G_UNLOCK (g_thread);
+#ifdef G_THREAD_USE_PID_SURROGATE
+  if (g_thread_use_default_impl)
+    SET_PRIO (thread->pid, thread->thread.priority);
+#endif /* G_THREAD_USE_PID_SURROGATE */
 
   thread->func (thread->arg);
 }
@@ -423,11 +560,13 @@ g_thread_create (GThreadFunc               thread_func,
   result->func = thread_func;
   result->arg = arg;
   result->private_data = NULL; 
-  G_LOCK (g_thread_create);
+  result->context = NULL;
+  G_LOCK (g_thread);
   G_THREAD_UF (thread_create, (g_thread_create_proxy, result, 
                               stack_size, joinable, bound, priority,
                               &result->system_thread, &local_error));
-  G_UNLOCK (g_thread_create);
+  g_thread_all_threads = g_slist_prepend (g_thread_all_threads, result);
+  G_UNLOCK (g_thread);
 
   if (local_error)
     {
@@ -451,6 +590,10 @@ g_thread_join (GThread* thread)
 
   G_THREAD_UF (thread_join, (&real->system_thread));
 
+  G_LOCK (g_thread);
+  g_thread_all_threads = g_slist_remove (g_thread_all_threads, thread);
+  G_UNLOCK (g_thread);
+
   /* Just to make sure, this isn't used any more */
   thread->joinable = 0;
   g_system_thread_assign (real->system_thread, zero_thread);
@@ -474,11 +617,18 @@ g_thread_set_priority (GThread* thread,
   g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
 
   thread->priority = priority;
-  G_THREAD_CF (thread_set_priority, (void)0, (&real->system_thread, priority));
+
+#ifdef G_THREAD_USE_PID_SURROGATE
+  if (g_thread_use_default_impl)
+    SET_PRIO (real->pid, priority);
+  else
+#endif /* G_THREAD_USE_PID_SURROGATE */
+    G_THREAD_CF (thread_set_priority, (void)0, 
+                (&real->system_thread, priority));
 }
 
 GThread*
-g_thread_self()
+g_thread_self (void)
 {
   GRealThread* thread = g_private_get (g_thread_specific_private);
 
@@ -495,24 +645,45 @@ g_thread_self()
       thread->func = NULL;
       thread->arg = NULL;
       thread->private_data = NULL;
+      thread->context = NULL;
 
       if (g_thread_supported ())
        G_THREAD_UF (thread_self, (&thread->system_thread));
 
-      g_private_set (g_thread_specific_private, thread);
+#ifdef G_THREAD_USE_PID_SURROGATE
+      thread->pid = getpid ();
+#endif /* G_THREAD_USE_PID_SURROGATE */
+      
+      g_private_set (g_thread_specific_private, thread); 
+      
+      G_LOCK (g_thread);
+      g_thread_all_threads = g_slist_prepend (g_thread_all_threads, thread);
+      G_UNLOCK (g_thread);
     }
   
   return (GThread*)thread;
 }
 
-static void inline g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex)
+void
+g_static_rw_lock_init (GStaticRWLock* lock)
+{
+  static GStaticRWLock init_lock = G_STATIC_RW_LOCK_INIT;
+
+  g_return_if_fail (lock);
+
+  memcpy (lock, &init_lock, sizeof (GStaticRWLock));
+}
+
+static void inline 
+g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex)
 {
   if (!*cond)
       *cond = g_cond_new ();
   g_cond_wait (*cond, g_static_mutex_get_mutex (mutex));
 }
 
-static void inline g_static_rw_lock_signal (GStaticRWLock* lock)
+static void inline 
+g_static_rw_lock_signal (GStaticRWLock* lock)
 {
   if (lock->want_to_write && lock->write_cond)
     g_cond_signal (lock->write_cond);
@@ -520,7 +691,8 @@ static void inline g_static_rw_lock_signal (GStaticRWLock* lock)
     g_cond_broadcast (lock->read_cond);
 }
 
-void g_static_rw_lock_reader_lock (GStaticRWLock* lock)
+void 
+g_static_rw_lock_reader_lock (GStaticRWLock* lock)
 {
   g_return_if_fail (lock);
 
@@ -534,7 +706,8 @@ void g_static_rw_lock_reader_lock (GStaticRWLock* lock)
   g_static_mutex_unlock (&lock->mutex);
 }
 
-gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock)
+gboolean 
+g_static_rw_lock_reader_trylock (GStaticRWLock* lock)
 {
   gboolean ret_val = FALSE;
 
@@ -553,7 +726,8 @@ gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock)
   return ret_val;
 }
 
-void g_static_rw_lock_reader_unlock  (GStaticRWLock* lock)
+void 
+g_static_rw_lock_reader_unlock  (GStaticRWLock* lock)
 {
   g_return_if_fail (lock);
 
@@ -567,7 +741,8 @@ void g_static_rw_lock_reader_unlock  (GStaticRWLock* lock)
   g_static_mutex_unlock (&lock->mutex);
 }
 
-void g_static_rw_lock_writer_lock (GStaticRWLock* lock)
+void 
+g_static_rw_lock_writer_lock (GStaticRWLock* lock)
 {
   g_return_if_fail (lock);
 
@@ -583,7 +758,8 @@ void g_static_rw_lock_writer_lock (GStaticRWLock* lock)
   g_static_mutex_unlock (&lock->mutex);
 }
 
-gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock)
+gboolean 
+g_static_rw_lock_writer_trylock (GStaticRWLock* lock)
 {
   gboolean ret_val = FALSE;
 
@@ -602,7 +778,8 @@ gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock)
   return ret_val;
 }
 
-void g_static_rw_lock_writer_unlock (GStaticRWLock* lock)
+void 
+g_static_rw_lock_writer_unlock (GStaticRWLock* lock)
 {
   g_return_if_fail (lock);
   
@@ -615,14 +792,20 @@ void g_static_rw_lock_writer_unlock (GStaticRWLock* lock)
   g_static_mutex_unlock (&lock->mutex);
 }
 
-void g_static_rw_lock_free (GStaticRWLock* lock)
+void 
+g_static_rw_lock_free (GStaticRWLock* lock)
 {
   g_return_if_fail (lock);
   
   if (lock->read_cond)
-    g_cond_free (lock->read_cond);
+    {
+      g_cond_free (lock->read_cond);
+      lock->read_cond = NULL;
+    }
   if (lock->write_cond)
-    g_cond_free (lock->write_cond);
-  
+    {
+      g_cond_free (lock->write_cond);
+      lock->write_cond = NULL;
+    }
+  g_static_mutex_free (&lock->mutex);
 }
-