Merge g_thread_functions_for_glib_use
[platform/upstream/glib.git] / glib / gthread-posix.c
index 1fcc3dd..01bd092 100644 (file)
@@ -27,8 +27,8 @@
  * GLib at ftp://ftp.gtk.org/pub/gtk/.
  */
 
-/* The GMutex and GCond implementations in this file are some of the
- * lowest-level code in GLib.  All other parts of GLib (messages,
+/* The GMutex, GCond and GPrivate implementations in this file are some
+ * of the lowest-level code in GLib.  All other parts of GLib (messages,
  * memory, slices, etc) assume that they can freely use these facilities
  * without risking recursion.
  *
@@ -42,6 +42,7 @@
 #include "config.h"
 
 #include "gthread.h"
+#include "gthreadprivate.h"
 
 #include <pthread.h>
 #include <stdlib.h>
@@ -59,6 +60,37 @@ g_thread_abort (gint         status,
 }
 
 /* {{{1 GMutex */
+
+/**
+ * g_mutex_init:
+ * @mutex: an uninitialized #GMutex
+ *
+ * Initializes a #GMutex so that it can be used.
+ *
+ * This function is useful to initialize a mutex that has been
+ * allocated on the stack, or as part of a larger structure.
+ * It is not necessary to initialize a mutex that has been
+ * created with g_mutex_new(). Also see #G_MUTEX_INITIALIZER
+ * for an alternative way to initialize statically allocated mutexes.
+ *
+ * |[
+ *   typedef struct {
+ *     GMutex m;
+ *     /&ast; ... &ast;/
+ *   } Blob;
+ *
+ * Blob *b;
+ *
+ * b = g_new (Blob, 1);
+ * g_mutex_init (&b->m);
+ * /&ast; ... &ast;/
+ * ]|
+ *
+ * To undo the effect of g_mutex_init() when a mutex is no longer
+ * needed, use g_mutex_clear().
+ *
+ * Since: 2.32
+ */
 void
 g_mutex_init (GMutex *mutex)
 {
@@ -68,6 +100,17 @@ g_mutex_init (GMutex *mutex)
     g_thread_abort (status, "pthread_mutex_init");
 }
 
+/**
+ * g_mutex_clear:
+ * @mutex: an initialized #GMutex
+ *
+ * Frees the resources allocated to a mutex with g_mutex_init().
+ *
+ * #GMutexes that have have been created with g_mutex_new() should
+ * be freed with g_mutex_free() instead.
+ *
+ * Sine: 2.32
+ */
 void
 g_mutex_clear (GMutex *mutex)
 {
@@ -77,41 +120,74 @@ g_mutex_clear (GMutex *mutex)
     g_thread_abort (status, "pthread_mutex_destroy");
 }
 
+/**
+ * g_mutex_lock:
+ * @mutex: a #GMutex
+ *
+ * Locks @mutex. If @mutex is already locked by another thread, the
+ * current thread will block until @mutex is unlocked by the other
+ * thread.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will do nothing.
+ *
+ * <note>#GMutex is neither guaranteed to be recursive nor to be
+ * non-recursive, i.e. a thread could deadlock while calling
+ * g_mutex_lock(), if it already has locked @mutex. Use
+ * #GStaticRecMutex, if you need recursive mutexes.</note>
+ */
 void
 g_mutex_lock (GMutex *mutex)
 {
   gint status;
 
-  /* temporary until we fix libglib */
-  if (mutex == NULL)
-    return;
-
   if G_UNLIKELY ((status = pthread_mutex_lock (&mutex->impl)) != 0)
     g_thread_abort (status, "pthread_mutex_lock");
 }
 
+/**
+ * g_mutex_unlock:
+ * @mutex: a #GMutex
+ *
+ * Unlocks @mutex. If another thread is blocked in a g_mutex_lock()
+ * call for @mutex, it will be woken and can lock @mutex itself.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will do nothing.
+ */
 void
 g_mutex_unlock (GMutex *mutex)
 {
   gint status;
 
-  /* temporary until we fix libglib */
-  if (mutex == NULL)
-    return;
-
   if G_UNLIKELY ((status = pthread_mutex_unlock (&mutex->impl)) != 0)
     g_thread_abort (status, "pthread_mutex_lock");
 }
 
+/**
+ * g_mutex_trylock:
+ * @mutex: a #GMutex
+ *
+ * Tries to lock @mutex. If @mutex is already locked by another thread,
+ * it immediately returns %FALSE. Otherwise it locks @mutex and returns
+ * %TRUE.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will immediately return %TRUE.
+ *
+ * <note>#GMutex is neither guaranteed to be recursive nor to be
+ * non-recursive, i.e. the return value of g_mutex_trylock() could be
+ * both %FALSE or %TRUE, if the current thread already has locked
+ * @mutex. Use #GStaticRecMutex, if you need recursive
+ * mutexes.</note>
+
+ * Returns: %TRUE, if @mutex could be locked
+ */
 gboolean
 g_mutex_trylock (GMutex *mutex)
 {
   gint status;
 
-  /* temporary until we fix libglib */
-  if (mutex == NULL)
-    return TRUE;
-
   if G_LIKELY ((status = pthread_mutex_trylock (&mutex->impl)) == 0)
     return TRUE;
 
@@ -123,6 +199,21 @@ g_mutex_trylock (GMutex *mutex)
 
 /* {{{1 GCond */
 
+/**
+ * g_cond_init:
+ * @cond: an uninitialized #GCond
+ *
+ * Initialized a #GCond so that it can be used.
+ *
+ * This function is useful to initialize a #GCond that has been
+ * allocated on the stack, or as part of a larger structure.
+ * It is not necessary to initialize a #GCond that has been
+ * created with g_cond_new(). Also see #G_COND_INITIALIZER
+ * for an alternative way to initialize statically allocated
+ * #GConds.
+ *
+ * Since: 2.32
+ */
 void
 g_cond_init (GCond *cond)
 {
@@ -132,6 +223,17 @@ g_cond_init (GCond *cond)
     g_thread_abort (status, "pthread_cond_init");
 }
 
+/**
+ * g_cond_clear:
+ * @cond: an initialized #GCond
+ *
+ * Frees the resources allocated ot a #GCond with g_cond_init().
+ *
+ * #GConds that have been created with g_cond_new() should
+ * be freed with g_cond_free() instead.
+ *
+ * Since: 2.32
+ */
 void
 g_cond_clear (GCond *cond)
 {
@@ -141,6 +243,18 @@ g_cond_clear (GCond *cond)
     g_thread_abort (status, "pthread_cond_destroy");
 }
 
+/**
+ * g_cond_wait:
+ * @cond: a #GCond
+ * @mutex: a #GMutex that is currently locked
+ *
+ * Waits until this thread is woken up on @cond.
+ * The @mutex is unlocked before falling asleep
+ * and locked again before resuming.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will immediately return.
+ */
 void
 g_cond_wait (GCond  *cond,
              GMutex *mutex)
@@ -151,32 +265,66 @@ g_cond_wait (GCond  *cond,
     g_thread_abort (status, "pthread_cond_wait");
 }
 
+/**
+ * g_cond_signal:
+ * @cond: a #GCond
+ *
+ * If threads are waiting for @cond, exactly one of them is woken up.
+ * It is good practice to hold the same lock as the waiting thread
+ * while calling this function, though not required.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will do nothing.
+ */
 void
 g_cond_signal (GCond *cond)
 {
   gint status;
 
-  /* temporary until we fix libglib */
-  if (cond == NULL)
-    return;
-
   if G_UNLIKELY ((status = pthread_cond_signal (&cond->impl)) != 0)
     g_thread_abort (status, "pthread_cond_signal");
 }
 
+/**
+ * g_cond_broadcast:
+ * @cond: a #GCond
+ *
+ * If threads are waiting for @cond, all of them are woken up.
+ * It is good practice to lock the same mutex as the waiting threads
+ * while calling this function, though not required.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will do nothing.
+ */
 void
 g_cond_broadcast (GCond *cond)
 {
   gint status;
 
-  /* temporary until we fix libglib */
-  if (cond == NULL)
-    return;
-
   if G_UNLIKELY ((status = pthread_cond_broadcast (&cond->impl)) != 0)
     g_thread_abort (status, "pthread_cond_broadcast");
 }
 
+/**
+ * g_cond_timed_wait:
+ * @cond: a #GCond
+ * @mutex: a #GMutex that is currently locked
+ * @abs_time: a #GTimeVal, determining the final time
+ *
+ * Waits until this thread is woken up on @cond, but not longer than
+ * until the time specified by @abs_time. The @mutex is unlocked before
+ * falling asleep and locked again before resuming.
+ *
+ * If @abs_time is %NULL, g_cond_timed_wait() acts like g_cond_wait().
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will immediately return %TRUE.
+ *
+ * To easily calculate @abs_time a combination of g_get_current_time()
+ * and g_time_val_add() can be used.
+ *
+ * Returns: %TRUE if @cond was signalled, or %FALSE on timeout
+ */
 gboolean
 g_cond_timed_wait (GCond    *cond,
                    GMutex   *mutex,
@@ -203,6 +351,20 @@ g_cond_timed_wait (GCond    *cond,
   return FALSE;
 }
 
+/**
+ * g_cond_timedwait:
+ * @cond: a #GCond
+ * @mutex: a #GMutex that is currently locked
+ * @abs_time: the final time, in microseconds
+ *
+ * A variant of g_cond_timed_wait() that takes @abs_time
+ * as a #gint64 instead of a #GTimeVal.
+ * See g_cond_timed_wait() for details.
+ *
+ * Returns: %TRUE if @cond was signalled, or %FALSE on timeout
+ *
+ * Since: 2.32
+ */
 gboolean
 g_cond_timedwait (GCond  *cond,
                   GMutex *mutex,
@@ -223,51 +385,73 @@ g_cond_timedwait (GCond  *cond,
   return FALSE;
 }
 
-/* {{{1 new/free API */
-
-GMutex *
-g_mutex_new (void)
-{
-  GMutex *mutex;
-
-  /* malloc() is temporary until all libglib users are ported away */
-  mutex = malloc (sizeof (GMutex));
-  if G_UNLIKELY (mutex == NULL)
-    g_thread_abort (errno, "malloc");
-  g_mutex_init (mutex);
-
-  return mutex;
-}
+/* {{{1 GPrivate */
 
 void
-g_mutex_free (GMutex *mutex)
+g_private_init (GPrivate       *key,
+                GDestroyNotify  notify)
 {
-  g_mutex_clear (mutex);
-  free (mutex);
+  pthread_key_create (&key->key, notify);
+  key->ready = TRUE;
 }
 
-GCond *
-g_cond_new (void)
+/**
+ * g_private_get:
+ * @private_key: a #GPrivate
+ *
+ * Returns the pointer keyed to @private_key for the current thread. If
+ * g_private_set() hasn't been called for the current @private_key and
+ * thread yet, this pointer will be %NULL.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will return the value of @private_key
+ * casted to #gpointer. Note however, that private data set
+ * <emphasis>before</emphasis> g_thread_init() will
+ * <emphasis>not</emphasis> be retained <emphasis>after</emphasis> the
+ * call. Instead, %NULL will be returned in all threads directly after
+ * g_thread_init(), regardless of any g_private_set() calls issued
+ * before threading system initialization.
+ *
+ * Returns: the corresponding pointer
+ */
+gpointer
+g_private_get (GPrivate *key)
 {
-  GCond *cond;
+  if (!key->ready)
+    return key->single_value;
 
-  /* malloc() is temporary until all libglib users are ported away */
-  cond = malloc (sizeof (GCond));
-  if G_UNLIKELY (cond == NULL)
-    g_thread_abort (errno, "malloc");
-  g_cond_init (cond);
-
-  return cond;
+  /* quote POSIX: No errors are returned from pthread_getspecific(). */
+  return pthread_getspecific (key->key);
 }
 
+/**
+ * g_private_set:
+ * @private_key: a #GPrivate
+ * @data: the new pointer
+ *
+ * Sets the pointer keyed to @private_key for the current thread.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will set @private_key to @data casted to
+ * #GPrivate*. See g_private_get() for resulting caveats.
+ */
 void
-g_cond_free (GCond *cond)
+g_private_set (GPrivate *key,
+               gpointer  value)
 {
-  g_cond_clear (cond);
-  free (cond);
+  gint status;
+
+  if (!key->ready)
+    {
+      key->single_value = value;
+      return;
+    }
+
+  if G_UNLIKELY ((status = pthread_setspecific (key->key, value)) != 0)
+    g_thread_abort (status, "pthread_setspecific");
 }
 
-/* {{{1 GPrivate */
+/* {{{1 GThread */
 
 #include "glib.h"
 #include "gthreadprivate.h"
@@ -296,74 +480,6 @@ g_cond_free (GCond *cond)
 
 #define posix_check_cmd(cmd) posix_check_err (cmd, #cmd)
 
-#ifdef G_ENABLE_DEBUG
-static gboolean posix_check_cmd_prio_warned = FALSE;
-# define posix_check_cmd_prio(cmd) G_STMT_START{                       \
-    int err = (cmd);                                                   \
-    if (err == EPERM)                                                  \
-      {                                                                \
-        if (!posix_check_cmd_prio_warned)                              \
-          {                                                            \
-            posix_check_cmd_prio_warned = TRUE;                                \
-            g_warning ("Priorities can only be changed "               \
-                        "(resp. increased) by root.");                         \
-          }                                                            \
-      }                                                                        \
-    else                                                               \
-      posix_check_err (err, #cmd);                                     \
-     }G_STMT_END
-#else /* G_ENABLE_DEBUG */
-# define posix_check_cmd_prio(cmd) G_STMT_START{                       \
-    int err = (cmd);                                                   \
-    if (err != EPERM)                                                  \
-      posix_check_err (err, #cmd);                                     \
-     }G_STMT_END
-#endif /* G_ENABLE_DEBUG */
-
-#if defined (POSIX_MIN_PRIORITY) && defined (POSIX_MAX_PRIORITY)
-# define HAVE_PRIORITIES 1
-static gint priority_normal_value;
-# ifdef __FreeBSD__
-   /* FreeBSD threads use different priority values from the POSIX_
-    * defines so we just set them here. The corresponding macros
-    * PTHREAD_MIN_PRIORITY and PTHREAD_MAX_PRIORITY are implied to be
-    * exported by the docs, but they aren't.
-    */
-#  define PRIORITY_LOW_VALUE      0
-#  define PRIORITY_URGENT_VALUE   31
-# else /* !__FreeBSD__ */
-#  define PRIORITY_LOW_VALUE      POSIX_MIN_PRIORITY
-#  define PRIORITY_URGENT_VALUE   POSIX_MAX_PRIORITY
-# endif /* !__FreeBSD__ */
-# define PRIORITY_NORMAL_VALUE    priority_normal_value
-
-# define PRIORITY_HIGH_VALUE \
-    ((PRIORITY_NORMAL_VALUE + PRIORITY_URGENT_VALUE * 2) / 3)
-
-static gint
-g_thread_priority_map (GThreadPriority priority)
-{
-  switch (priority)
-    {
-    case G_THREAD_PRIORITY_LOW:
-      return PRIORITY_LOW_VALUE;
-
-    case G_THREAD_PRIORITY_NORMAL:
-      return PRIORITY_NORMAL_VALUE;
-
-    case G_THREAD_PRIORITY_HIGH:
-      return PRIORITY_HIGH_VALUE;
-
-    case G_THREAD_PRIORITY_URGENT:
-      return PRIORITY_URGENT_VALUE;
-
-    default:
-      g_assert_not_reached ();
-    }
-}
-
-#endif /* POSIX_MIN_PRIORITY && POSIX_MAX_PRIORITY */
-
 static gulong g_thread_min_stack_size = 0;
 
 #define G_MUTEX_SIZE (sizeof (pthread_mutex_t))
@@ -374,63 +490,22 @@ _g_thread_impl_init(void)
 #ifdef _SC_THREAD_STACK_MIN
   g_thread_min_stack_size = MAX (sysconf (_SC_THREAD_STACK_MIN), 0);
 #endif /* _SC_THREAD_STACK_MIN */
-#ifdef HAVE_PRIORITIES
-  {
-    struct sched_param sched;
-    int policy;
-    posix_check_cmd (pthread_getschedparam (pthread_self(), &policy, &sched));
-    priority_normal_value = sched.sched_priority;
-  }
-#endif /* HAVE_PRIORITIES */
 }
 
-static GPrivate *
-g_private_new_posix_impl (GDestroyNotify destructor)
-{
-  GPrivate *result = (GPrivate *) g_new (pthread_key_t, 1);
-  posix_check_cmd (pthread_key_create ((pthread_key_t *) result, destructor));
-  return result;
-}
-
-/* NOTE: the functions g_private_get and g_private_set may not use
-   functions from gmem.c and gmessages.c */
-
-static void
-g_private_set_posix_impl (GPrivate * private_key, gpointer value)
-{
-  if (!private_key)
-    return;
-  pthread_setspecific (*(pthread_key_t *) private_key, value);
-}
-
-static gpointer
-g_private_get_posix_impl (GPrivate * private_key)
-{
-  if (!private_key)
-    return NULL;
-
-  return pthread_getspecific (*(pthread_key_t *) private_key);
-}
-
-/* {{{1 GThread */
-
-
-static void
-g_thread_create_posix_impl (GThreadFunc thread_func,
-                           gpointer arg,
-                           gulong stack_size,
-                           gboolean joinable,
-                           gboolean bound,
-                           GThreadPriority priority,
-                           gpointer thread,
-                           GError **error)
+void
+g_system_thread_create (GThreadFunc       thread_func,
+                        gpointer          arg,
+                        gulong            stack_size,
+                        gboolean          joinable,
+                        gboolean          bound,
+                        GThreadPriority   priority,
+                        gpointer          thread,
+                        GError          **error)
 {
   pthread_attr_t attr;
   gint ret;
 
   g_return_if_fail (thread_func);
-  g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
-  g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
 
   posix_check_cmd (pthread_attr_init (&attr));
 
@@ -454,14 +529,6 @@ g_thread_create_posix_impl (GThreadFunc thread_func,
   posix_check_cmd (pthread_attr_setdetachstate (&attr,
           joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
 
-#ifdef HAVE_PRIORITIES
-  {
-    struct sched_param sched;
-    posix_check_cmd (pthread_attr_getschedparam (&attr, &sched));
-    sched.sched_priority = g_thread_priority_map (priority);
-    posix_check_cmd_prio (pthread_attr_setschedparam (&attr, &sched));
-  }
-#endif /* HAVE_PRIORITIES */
   ret = pthread_create (thread, &attr, (void* (*)(void*))thread_func, arg);
 
   posix_check_cmd (pthread_attr_destroy (&attr));
@@ -476,79 +543,46 @@ g_thread_create_posix_impl (GThreadFunc thread_func,
   posix_check_err (ret, "pthread_create");
 }
 
-static void
-g_thread_yield_posix_impl (void)
+/**
+ * g_thread_yield:
+ *
+ * Gives way to other threads waiting to be scheduled.
+ *
+ * This function is often used as a method to make busy wait less evil.
+ * But in most cases you will encounter, there are better methods to do
+ * that. So in general you shouldn't use this function.
+ */
+void
+g_thread_yield (void)
 {
-  POSIX_YIELD_FUNC;
+  sched_yield ();
 }
 
-static void
-g_thread_join_posix_impl (gpointer thread)
+void
+g_system_thread_join (gpointer thread)
 {
   gpointer ignore;
   posix_check_cmd (pthread_join (*(pthread_t*)thread, &ignore));
 }
 
-static void
-g_thread_exit_posix_impl (void)
+void
+g_system_thread_exit (void)
 {
   pthread_exit (NULL);
 }
 
-static void
-g_thread_set_priority_posix_impl (gpointer thread, GThreadPriority priority)
-{
-  g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
-  g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
-#ifdef HAVE_PRIORITIES
-  {
-    struct sched_param sched;
-    int policy;
-    posix_check_cmd (pthread_getschedparam (*(pthread_t*)thread, &policy,
-                                           &sched));
-    sched.sched_priority = g_thread_priority_map (priority);
-    posix_check_cmd_prio (pthread_setschedparam (*(pthread_t*)thread, policy,
-                                                &sched));
-  }
-#endif /* HAVE_PRIORITIES */
-}
-
-static void
-g_thread_self_posix_impl (gpointer thread)
+void
+g_system_thread_self (gpointer thread)
 {
   *(pthread_t*)thread = pthread_self();
 }
 
-static gboolean
-g_thread_equal_posix_impl (gpointer thread1, gpointer thread2)
+gboolean
+g_system_thread_equal (gpointer thread1,
+                       gpointer thread2)
 {
   return (pthread_equal (*(pthread_t*)thread1, *(pthread_t*)thread2) != 0);
 }
 
 /* {{{1 Epilogue */
-GThreadFunctions g_thread_functions_for_glib_use =
-{
-  g_mutex_new,
-  g_mutex_lock,
-  g_mutex_trylock,
-  g_mutex_unlock,
-  g_mutex_free,
-  g_cond_new,
-  g_cond_signal,
-  g_cond_broadcast,
-  g_cond_wait,
-  g_cond_timed_wait,
-  g_cond_free,
-  g_private_new_posix_impl,
-  g_private_get_posix_impl,
-  g_private_set_posix_impl,
-  g_thread_create_posix_impl,
-  g_thread_yield_posix_impl,
-  g_thread_join_posix_impl,
-  g_thread_exit_posix_impl,
-  g_thread_set_priority_posix_impl,
-  g_thread_self_posix_impl,
-  g_thread_equal_posix_impl
-};
-
 /* vim:set foldmethod=marker: */