[glib] mainloop: detect fork() and abort



commit 01ed78d525cf2f8769022e27cc2573ec7ba123b3
Author: Ryan Lortie <desrt desrt ca>
Date:   Tue Sep 13 19:56:22 2011 -0400

    mainloop: detect fork() and abort
    
    Abort if the child process returns to the mainloop after a fork().
    
    https://bugzilla.gnome.org/show_bug.cgi?id=658999

 glib/gmain.c |   39 ++++++++++++++++++++++++++++-----------
 1 files changed, 28 insertions(+), 11 deletions(-)
---
diff --git a/glib/gmain.c b/glib/gmain.c
index 855e63a..aa2877e 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -49,6 +49,7 @@
 
 #ifdef G_OS_UNIX
 #include "glib-unix.h"
+#include <pthread.h>
 #ifdef HAVE_EVENTFD
 #include <sys/eventfd.h>
 #endif
@@ -174,6 +175,10 @@
  * <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 */
@@ -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;
@@ -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,25 +521,27 @@ 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_once_init_leave (&initialised, TRUE);
+    }
+
+  context = g_new0 (GMainContext, 1);
+
   g_static_mutex_init (&context->mutex);
 
   context->owner = NULL;
@@ -2976,6 +2992,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);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]