Add new thread creation API
[platform/upstream/glib.git] / glib / gmain.c
index 855e63a..797aea9 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
  * <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,7 +220,7 @@ struct _GMainContext
   /* The following lock is used for both the list of sources
    * and the list of poll records
    */
-  GStaticMutex mutex;
+  GMutex mutex;
   GCond *cond;
   GThread *owner;
   guint owner_count;
@@ -304,8 +309,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)
@@ -374,6 +379,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;
@@ -482,7 +488,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);
@@ -497,6 +503,14 @@ g_main_context_unref (GMainContext *context)
   g_free (context);
 }
 
+#ifdef G_OS_UNIX
+static void
+g_main_context_forked (void)
+{
+  g_main_context_fork_detected = TRUE;
+}
+#endif
+
 /**
  * g_main_context_new:
  * 
@@ -507,26 +521,28 @@ g_main_context_unref (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 (getenv ("G_MAIN_POLL_DEBUG") != NULL)
+        _g_main_poll_debug = TRUE;
+#endif
 
-    if (!beenhere)
-      {
-       if (getenv ("G_MAIN_POLL_DEBUG") != NULL)
-         _g_main_poll_debug = TRUE;
-       beenhere = TRUE;
-      }
-  }
+#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);
 
   context->owner = NULL;
   context->waiters = NULL;
@@ -2499,8 +2515,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)
@@ -2543,7 +2558,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);
@@ -2942,7 +2957,7 @@ g_main_context_iterate (GMainContext *context,
 
       got_ownership = g_main_context_wait (context,
                                           context->cond,
-                                          g_static_mutex_get_mutex (&context->mutex));
+                                          &context->mutex);
 
       if (!got_ownership)
        return FALSE;
@@ -2976,6 +2991,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);
@@ -3152,7 +3168,7 @@ g_main_loop_run (GMainLoop *loop)
       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->mutex);
       
       if (!loop->is_running)
        {
@@ -4011,7 +4027,6 @@ g_child_watch_prepare (GSource *source,
   return FALSE;
 }
 
-
 static gboolean 
 g_child_watch_check (GSource  *source)
 {
@@ -4047,6 +4062,11 @@ g_child_watch_check (GSource  *source)
   return child_exited;
 }
 
+static void
+g_child_watch_finalize (GSource *source)
+{
+}
+
 #else /* G_OS_WIN32 */
 
 static void
@@ -4258,7 +4278,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);
@@ -4266,8 +4286,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)
 {
@@ -4276,6 +4294,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,
@@ -4716,8 +4736,10 @@ 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... */
@@ -4735,7 +4757,7 @@ g_get_worker_context (void)
       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);