Simplify checks for CLOCK_MONOTONIC
[platform/upstream/glib.git] / glib / gmain.c
index 95266b8..3cf1fa8 100644 (file)
@@ -49,6 +49,7 @@
 
 #ifdef G_OS_UNIX
 #include "glib-unix.h"
+#include <pthread.h>
 #ifdef HAVE_EVENTFD
 #include <sys/eventfd.h>
 #endif
@@ -86,7 +87,6 @@
 #include "gqueue.h"
 #include "gstrfuncs.h"
 #include "gtestutils.h"
-#include "gthreadprivate.h"
 
 #ifdef G_OS_WIN32
 #include "gwin32.h"
@@ -98,7 +98,7 @@
 
 #include "gwakeup.h"
 
-#include "glibprivate.h"
+#include "glib-private.h"
 
 /**
  * SECTION:main
  * <graphic fileref="mainloop-states.gif" format="GIF"></graphic>
  * </figure>
  * </refsect2>
+ *
+ * On Unix, the GLib mainloop is incompatible with fork().  Any program
+ * using the mainloop must either exec() or exit() from the child
+ * without returning to the mainloop.
  */
 
 /* Types */
@@ -215,8 +219,8 @@ struct _GMainContext
   /* The following lock is used for both the list of sources
    * and the list of poll records
    */
-  GStaticMutex mutex;
-  GCond *cond;
+  GMutex mutex;
+  GCond cond;
   GThread *owner;
   guint owner_count;
   GSList *waiters;
@@ -238,7 +242,6 @@ struct _GMainContext
   GWakeup *wakeup;
 
   GPollFD wake_up_rec;
-  gboolean poll_waiting;
 
 /* Flag indicating whether the set of fd's changed during a poll */
   gboolean poll_changed;
@@ -305,8 +308,8 @@ struct _GSourcePrivate
   GSource *parent_source;
 };
 
-#define LOCK_CONTEXT(context) g_static_mutex_lock (&context->mutex)
-#define UNLOCK_CONTEXT(context) g_static_mutex_unlock (&context->mutex)
+#define LOCK_CONTEXT(context) g_mutex_lock (&context->mutex)
+#define UNLOCK_CONTEXT(context) g_mutex_unlock (&context->mutex)
 #define G_THREAD_SELF g_thread_self ()
 
 #define SOURCE_DESTROYED(source) (((source)->flags & G_HOOK_FLAG_ACTIVE) == 0)
@@ -343,7 +346,6 @@ static void g_main_context_add_poll_unlocked    (GMainContext *context,
                                                 GPollFD      *fd);
 static void g_main_context_remove_poll_unlocked (GMainContext *context,
                                                 GPollFD      *fd);
-static void g_main_context_wakeup_unlocked      (GMainContext *context);
 
 static gboolean g_timeout_prepare  (GSource     *source,
                                    gint        *timeout);
@@ -376,6 +378,7 @@ static gboolean g_idle_dispatch    (GSource     *source,
                                    gpointer     user_data);
 
 static GMainContext *glib_worker_context;
+static gboolean      g_main_context_fork_detected;
 
 G_LOCK_DEFINE_STATIC (main_loop);
 static GMainContext *default_main_context;
@@ -484,7 +487,7 @@ g_main_context_unref (GMainContext *context)
       source = next;
     }
 
-  g_static_mutex_free (&context->mutex);
+  g_mutex_clear (&context->mutex);
 
   g_ptr_array_free (context->pending_dispatches, TRUE);
   g_free (context->cached_poll_array);
@@ -492,20 +495,18 @@ g_main_context_unref (GMainContext *context)
   poll_rec_list_free (context, context->poll_records);
 
   g_wakeup_free (context->wakeup);
-
-  if (context->cond != NULL)
-    g_cond_free (context->cond);
+  g_cond_clear (&context->cond);
 
   g_free (context);
 }
 
+#ifdef G_OS_UNIX
 static void
-g_main_context_init_pipe (GMainContext *context)
+g_main_context_forked (void)
 {
-  context->wakeup = g_wakeup_new ();
-  g_wakeup_get_pollfd (context->wakeup, &context->wake_up_rec);
-  g_main_context_add_poll_unlocked (context, 0, &context->wake_up_rec);
+  g_main_context_fork_detected = TRUE;
 }
+#endif
 
 /**
  * g_main_context_new:
@@ -517,26 +518,27 @@ g_main_context_init_pipe (GMainContext *context)
 GMainContext *
 g_main_context_new (void)
 {
+  static gsize initialised;
   GMainContext *context;
 
-  g_thread_init_glib ();
-
-  context = g_new0 (GMainContext, 1);
-
+  if (g_once_init_enter (&initialised))
+    {
 #ifdef G_MAIN_POLL_DEBUG
-  {
-    static gboolean beenhere = FALSE;
-
-    if (!beenhere)
-      {
-       if (getenv ("G_MAIN_POLL_DEBUG") != NULL)
-         _g_main_poll_debug = TRUE;
-       beenhere = TRUE;
-      }
-  }
+      if (getenv ("G_MAIN_POLL_DEBUG") != NULL)
+        _g_main_poll_debug = TRUE;
+#endif
+
+#ifdef G_OS_UNIX
+      pthread_atfork (NULL, NULL, g_main_context_forked);
 #endif
 
-  g_static_mutex_init (&context->mutex);
+      g_once_init_leave (&initialised, TRUE);
+    }
+
+  context = g_new0 (GMainContext, 1);
+
+  g_mutex_init (&context->mutex);
+  g_cond_init (&context->cond);
 
   context->owner = NULL;
   context->waiters = NULL;
@@ -556,7 +558,9 @@ g_main_context_new (void)
   
   context->time_is_fresh = FALSE;
   
-  g_main_context_init_pipe (context);
+  context->wakeup = g_wakeup_new ();
+  g_wakeup_get_pollfd (context->wakeup, &context->wake_up_rec);
+  g_main_context_add_poll_unlocked (context, 0, &context->wake_up_rec);
 
   G_LOCK (main_context_list);
   main_context_list = g_slist_append (main_context_list, context);
@@ -602,8 +606,6 @@ g_main_context_default (void)
   return default_main_context;
 }
 
-static GStaticPrivate thread_context_stack = G_STATIC_PRIVATE_INIT;
-
 static void
 free_context_stack (gpointer data)
 {
@@ -615,11 +617,13 @@ free_context_stack (gpointer data)
       context = g_queue_pop_head (stack);
       g_main_context_release (context);
       if (context)
-       g_main_context_unref (context);
+        g_main_context_unref (context);
     }
   g_queue_free (stack);
 }
 
+static GPrivate thread_context_stack = G_PRIVATE_INIT (free_context_stack);
+
 /**
  * g_main_context_push_thread_default:
  * @context: a #GMainContext, or %NULL for the global default context
@@ -669,12 +673,11 @@ g_main_context_push_thread_default (GMainContext *context)
   else if (context)
     g_main_context_ref (context);
 
-  stack = g_static_private_get (&thread_context_stack);
+  stack = g_private_get (&thread_context_stack);
   if (!stack)
     {
       stack = g_queue_new ();
-      g_static_private_set (&thread_context_stack, stack,
-                           free_context_stack);
+      g_private_set (&thread_context_stack, stack);
     }
 
   g_queue_push_head (stack, context);
@@ -697,7 +700,7 @@ g_main_context_pop_thread_default (GMainContext *context)
   if (context == g_main_context_default ())
     context = NULL;
 
-  stack = g_static_private_get (&thread_context_stack);
+  stack = g_private_get (&thread_context_stack);
 
   g_return_if_fail (stack != NULL);
   g_return_if_fail (g_queue_peek_head (stack) == context);
@@ -714,11 +717,15 @@ g_main_context_pop_thread_default (GMainContext *context)
  *
  * Gets the thread-default #GMainContext for this thread. Asynchronous
  * operations that want to be able to be run in contexts other than
- * the default one should call this method to get a #GMainContext to
- * add their #GSource<!-- -->s to. (Note that even in single-threaded
+ * the default one should call this method or
+ * g_main_context_ref_thread_default() to get a #GMainContext to add
+ * their #GSource<!-- -->s to. (Note that even in single-threaded
  * programs applications may sometimes want to temporarily push a
  * non-default context, so it is not safe to assume that this will
- * always return %NULL if threads are not initialized.)
+ * always return %NULL if you are running in the default thread.)
+ *
+ * If you need to hold a reference on the context, use
+ * g_main_context_ref_thread_default() instead.
  *
  * Returns: (transfer none): the thread-default #GMainContext, or
  * %NULL if the thread-default context is the global default context.
@@ -730,13 +737,39 @@ g_main_context_get_thread_default (void)
 {
   GQueue *stack;
 
-  stack = g_static_private_get (&thread_context_stack);
+  stack = g_private_get (&thread_context_stack);
   if (stack)
     return g_queue_peek_head (stack);
   else
     return NULL;
 }
 
+/**
+ * g_main_context_ref_thread_default:
+ *
+ * Gets the thread-default #GMainContext for this thread, as with
+ * g_main_context_get_thread_default(), but also adds a reference to
+ * it with g_main_context_ref(). In addition, unlike
+ * g_main_context_get_thread_default(), if the thread-default context
+ * is the global default context, this will return that #GMainContext
+ * (with a ref added to it) rather than returning %NULL.
+ *
+ * Returns: (transfer full): the thread-default #GMainContext. Unref
+ *     with g_main_context_unref() when you are done with it.
+ *
+ * Since: 2.32
+ */
+GMainContext *
+g_main_context_ref_thread_default (void)
+{
+  GMainContext *context;
+
+  context = g_main_context_get_thread_default ();
+  if (!context)
+    context = g_main_context_default ();
+  return g_main_context_ref (context);
+}
+
 /* Hooks for adding to the main loop */
 
 /**
@@ -893,8 +926,11 @@ g_source_attach (GSource      *source,
 
   result = g_source_attach_unlocked (source, context);
 
-  /* Now wake up the main loop if it is waiting in the poll() */
-  g_main_context_wakeup_unlocked (context);
+  /* If another thread has acquired the context, wake it up since it
+   * might be in poll() right now.
+   */
+  if (context->owner && context->owner != G_THREAD_SELF)
+    g_wakeup_signal (context->wakeup);
 
   UNLOCK_CONTEXT (context);
 
@@ -1977,66 +2013,50 @@ g_get_monotonic_time (void)
 {
 #ifdef HAVE_CLOCK_GETTIME
   /* librt clock_gettime() is our first choice */
-  {
-#ifdef HAVE_MONOTONIC_CLOCK
-    static volatile gsize clockid = 0;
+  struct timespec ts;
+
+#ifdef CLOCK_MONOTONIC
+  clock_gettime (CLOCK_MONOTONIC, &ts);
 #else
-    static clockid_t clockid = CLOCK_REALTIME;
-#endif
-    struct timespec ts;
-
-#ifdef HAVE_MONOTONIC_CLOCK
-    if (g_once_init_enter (&clockid))
-      {
-       clockid_t best_clockid;
-
-       if (sysconf (_SC_MONOTONIC_CLOCK) >= 0)
-         best_clockid = CLOCK_MONOTONIC;
-       else
-         best_clockid = CLOCK_REALTIME;
-       g_once_init_leave (&clockid, (gsize)best_clockid);
-      }
+  clock_gettime (CLOCK_REALTIME, &ts);
 #endif
 
-    clock_gettime (clockid, &ts);
-
-    /* In theory monotonic time can have any epoch.
-     *
-     * glib presently assumes the following:
-     *
-     *   1) The epoch comes some time after the birth of Jesus of Nazareth, but
-     *      not more than 10000 years later.
-     *
-     *   2) The current time also falls sometime within this range.
-     *
-     * These two reasonable assumptions leave us with a maximum deviation from
-     * the epoch of 10000 years, or 315569520000000000 seconds.
-     *
-     * If we restrict ourselves to this range then the number of microseconds
-     * will always fit well inside the constraints of a int64 (by a factor of
-     * about 29).
-     *
-     * If you actually hit the following assertion, probably you should file a
-     * bug against your operating system for being excessively silly.
-     **/
-    g_assert (G_GINT64_CONSTANT (-315569520000000000) < ts.tv_sec &&
-              ts.tv_sec < G_GINT64_CONSTANT (315569520000000000));
-
-    return (((gint64) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000);
-  }
-#else
+  /* In theory monotonic time can have any epoch.
+   *
+   * glib presently assumes the following:
+   *
+   *   1) The epoch comes some time after the birth of Jesus of Nazareth, but
+   *      not more than 10000 years later.
+   *
+   *   2) The current time also falls sometime within this range.
+   *
+   * These two reasonable assumptions leave us with a maximum deviation from
+   * the epoch of 10000 years, or 315569520000000000 seconds.
+   *
+   * If we restrict ourselves to this range then the number of microseconds
+   * will always fit well inside the constraints of a int64 (by a factor of
+   * about 29).
+   *
+   * If you actually hit the following assertion, probably you should file a
+   * bug against your operating system for being excessively silly.
+   **/
+  g_assert (G_GINT64_CONSTANT (-315569520000000000) < ts.tv_sec &&
+            ts.tv_sec < G_GINT64_CONSTANT (315569520000000000));
+
+  return (((gint64) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000);
+
+#else /* !HAVE_CLOCK_GETTIME */
+
   /* It may look like we are discarding accuracy on Windows (since its
    * current time is expressed in 100s of nanoseconds) but according to
    * many sources, the time is only updated 64 times per second, so
    * microsecond accuracy is more than enough.
    */
-  {
-    GTimeVal tv;
+  GTimeVal tv;
 
-    g_get_current_time (&tv);
+  g_get_current_time (&tv);
 
-    return (((gint64) tv.tv_sec) * 1000000) + tv.tv_usec;
-  }
+  return (((gint64) tv.tv_sec) * 1000000) + tv.tv_usec;
 #endif
 }
 
@@ -2051,12 +2071,15 @@ g_main_dispatch_free (gpointer dispatch)
 static GMainDispatch *
 get_dispatch (void)
 {
-  static GStaticPrivate depth_private = G_STATIC_PRIVATE_INIT;
-  GMainDispatch *dispatch = g_static_private_get (&depth_private);
+  static GPrivate depth_private = G_PRIVATE_INIT (g_main_dispatch_free);
+  GMainDispatch *dispatch;
+
+  dispatch = g_private_get (&depth_private);
+
   if (!dispatch)
     {
       dispatch = g_slice_new0 (GMainDispatch);
-      g_static_private_set (&depth_private, dispatch, g_main_dispatch_free);
+      g_private_set (&depth_private, dispatch);
     }
 
   return dispatch;
@@ -2504,8 +2527,7 @@ g_main_context_release (GMainContext *context)
       if (context->waiters)
        {
          GMainWaiter *waiter = context->waiters->data;
-         gboolean loop_internal_waiter =
-           (waiter->mutex == g_static_mutex_get_mutex (&context->mutex));
+         gboolean loop_internal_waiter = (waiter->mutex == &context->mutex);
          context->waiters = g_slist_delete_link (context->waiters,
                                                  context->waiters);
          if (!loop_internal_waiter)
@@ -2548,7 +2570,7 @@ g_main_context_wait (GMainContext *context,
   if (context == NULL)
     context = g_main_context_default ();
 
-  loop_internal_waiter = (mutex == g_static_mutex_get_mutex (&context->mutex));
+  loop_internal_waiter = (mutex == &context->mutex);
   
   if (!loop_internal_waiter)
     LOCK_CONTEXT (context);
@@ -2625,15 +2647,6 @@ g_main_context_prepare (GMainContext *context,
       return FALSE;
     }
 
-  if (context->poll_waiting)
-    {
-      g_warning("g_main_context_prepare(): main loop already active in another thread");
-      UNLOCK_CONTEXT (context);
-      return FALSE;
-    }
-  
-  context->poll_waiting = TRUE;
-
 #if 0
   /* If recursing, finish up current dispatch, before starting over */
   if (context->pending_dispatches)
@@ -2828,8 +2841,6 @@ g_main_context_check (GMainContext *context,
   if (context->wake_up_rec.events)
     g_wakeup_acknowledge (context->wakeup);
 
-  context->poll_waiting = FALSE;
-
   /* If the set of poll file descriptors changed, bail out
    * and let the main loop rerun
    */
@@ -2953,12 +2964,9 @@ g_main_context_iterate (GMainContext *context,
       if (!block)
        return FALSE;
 
-      if (!context->cond)
-       context->cond = g_cond_new ();
-
       got_ownership = g_main_context_wait (context,
-                                          context->cond,
-                                          g_static_mutex_get_mutex (&context->mutex));
+                                           &context->cond,
+                                           &context->mutex);
 
       if (!got_ownership)
        return FALSE;
@@ -2992,6 +3000,7 @@ g_main_context_iterate (GMainContext *context,
   if (!block)
     timeout = 0;
   
+  g_assert (!g_main_context_fork_detected);
   g_main_context_poll (context, timeout, max_priority, fds, nfds);
   
   some_ready = g_main_context_check (context, max_priority, fds, nfds);
@@ -3162,13 +3171,10 @@ g_main_loop_run (GMainLoop *loop)
       if (!loop->is_running)
        loop->is_running = TRUE;
 
-      if (!loop->context->cond)
-       loop->context->cond = g_cond_new ();
-          
       while (loop->is_running && !got_ownership)
        got_ownership = g_main_context_wait (loop->context,
-                                            loop->context->cond,
-                                            g_static_mutex_get_mutex (&loop->context->mutex));
+                                             &loop->context->cond,
+                                             &loop->context->mutex);
       
       if (!loop->is_running)
        {
@@ -3221,10 +3227,9 @@ g_main_loop_quit (GMainLoop *loop)
 
   LOCK_CONTEXT (loop->context);
   loop->is_running = FALSE;
-  g_main_context_wakeup_unlocked (loop->context);
+  g_wakeup_signal (loop->context->wakeup);
 
-  if (loop->context->cond)
-    g_cond_broadcast (loop->context->cond);
+  g_cond_broadcast (&loop->context->cond);
 
   UNLOCK_CONTEXT (loop->context);
 }
@@ -3422,7 +3427,7 @@ g_main_context_add_poll_unlocked (GMainContext *context,
   context->poll_changed = TRUE;
 
   /* Now wake up the main loop if it is waiting in the poll() */
-  g_main_context_wakeup_unlocked (context);
+  g_wakeup_signal (context->wakeup);
 }
 
 /**
@@ -3484,7 +3489,7 @@ g_main_context_remove_poll_unlocked (GMainContext *context,
   context->poll_changed = TRUE;
   
   /* Now wake up the main loop if it is waiting in the poll() */
-  g_main_context_wakeup_unlocked (context);
+  g_wakeup_signal (context->wakeup);
 }
 
 /**
@@ -3602,18 +3607,6 @@ g_main_context_get_poll_func (GMainContext *context)
   return result;
 }
 
-/* HOLDS: context's lock */
-/* Wake the main loop up from a poll() */
-static void
-g_main_context_wakeup_unlocked (GMainContext *context)
-{
-  if (context->poll_waiting)
-    {
-      context->poll_waiting = FALSE;
-      g_wakeup_signal (context->wakeup);
-    }
-}
-
 /**
  * g_main_context_wakeup:
  * @context: a #GMainContext
@@ -3626,12 +3619,10 @@ g_main_context_wakeup (GMainContext *context)
 {
   if (!context)
     context = g_main_context_default ();
-  
+
   g_return_if_fail (g_atomic_int_get (&context->ref_count) > 0);
 
-  LOCK_CONTEXT (context);
-  g_main_context_wakeup_unlocked (context);
-  UNLOCK_CONTEXT (context);
+  g_wakeup_signal (context->wakeup);
 }
 
 /**
@@ -4041,7 +4032,6 @@ g_child_watch_prepare (GSource *source,
   return FALSE;
 }
 
-
 static gboolean 
 g_child_watch_check (GSource  *source)
 {
@@ -4077,6 +4067,11 @@ g_child_watch_check (GSource  *source)
   return child_exited;
 }
 
+static void
+g_child_watch_finalize (GSource *source)
+{
+}
+
 #else /* G_OS_WIN32 */
 
 static void
@@ -4250,7 +4245,7 @@ ensure_unix_signal_handler_installed_unlocked (int signum)
   if (!initialized)
     {
       sigemptyset (&installed_signal_mask);
-      glib_get_worker_context ();
+      g_get_worker_context ();
       initialized = TRUE;
     }
 
@@ -4288,7 +4283,7 @@ _g_main_create_unix_signal_watch (int signum)
   return source;
 }
 
-static void 
+static void
 g_unix_signal_watch_finalize (GSource    *source)
 {
   G_LOCK (unix_signal_lock);
@@ -4296,8 +4291,6 @@ g_unix_signal_watch_finalize (GSource    *source)
   G_UNLOCK (unix_signal_lock);
 }
 
-#endif /* G_OS_WIN32 */
-
 static void
 g_child_watch_finalize (GSource *source)
 {
@@ -4306,6 +4299,8 @@ g_child_watch_finalize (GSource *source)
   G_UNLOCK (unix_signal_lock);
 }
 
+#endif /* G_OS_WIN32 */
+
 static gboolean
 g_child_watch_dispatch (GSource    *source, 
                        GSourceFunc callback,
@@ -4746,26 +4741,26 @@ glib_worker_main (gpointer data)
     {
       g_main_context_iteration (glib_worker_context, TRUE);
 
+#ifdef G_OS_UNIX
       if (any_unix_signal_pending)
         dispatch_unix_signals ();
+#endif
     }
 
   return NULL; /* worst GCC warning message ever... */
 }
 
 GMainContext *
-glib_get_worker_context (void)
+g_get_worker_context (void)
 {
   static gsize initialised;
 
-  g_thread_init_glib ();
-
   if (g_once_init_enter (&initialised))
     {
       GError *error = NULL;
 
       glib_worker_context = g_main_context_new ();
-      if (g_thread_create (glib_worker_main, NULL, FALSE, &error) == NULL)
+      if (g_thread_new ("gmain", glib_worker_main, NULL, FALSE, &error) == NULL)
         g_error ("Creating GLib worker thread failed: %s\n", error->message);
 
       g_once_init_leave (&initialised, TRUE);