[glib] g_child_watch_source_new: Document restrictions for POSIX platforms



commit 6e480634c6d55972fe0a6cfb7f5ab2a518078e23
Author: Simon McVittie <smcv collabora com>
Date:   Wed Oct 11 13:55:41 2017 +0100

    g_child_watch_source_new: Document restrictions for POSIX platforms
    
    The warnings issued when dealing with waitpid() raising ECHILD are
    somewhat misleading: there are lots of reasons why waitpid() might
    fail in this way, and we can't tell which one has happened.
    In particular, passing a non-child or a non-pid, waiting for the same
    pid elsewhere, or creating a duplicate watch for the same pid would
    all fail in the same way.
    
    Consolidate the restrictions into one place, and change all the other
    places they were (or should have been!) mentioned to point to
    that one place.
    
    Signed-off-by: Simon McVittie <smcv collabora com>
    Reviewed-by: Philip Withnall <withnall endlessm com>
    Bug: https://bugzilla.gnome.org/show_bug.cgi?id=723743

 glib/gmain.c  |   30 ++++++++++++++++++++++--------
 glib/gspawn.c |    5 +++--
 2 files changed, 25 insertions(+), 10 deletions(-)
---
diff --git a/glib/gmain.c b/glib/gmain.c
index a0330c3..3be0afc 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -5080,7 +5080,7 @@ dispatch_unix_signals_unlocked (void)
                     }
                   else if (pid == -1 && errno == ECHILD)
                     {
-                      g_warning ("GChildWatchSource: Exit status of a child process was requested but ECHILD 
was received by waitpid(). Most likely the process is ignoring SIGCHLD, or some other thread is invoking 
waitpid() with a nonpositive first argument; either behavior can break applications that use 
g_child_watch_add()/g_spawn_sync() either directly or indirectly.");
+                      g_warning ("GChildWatchSource: Exit status of a child process was requested but ECHILD 
was received by waitpid(). See the documentation of g_child_watch_source_new() for possible causes.");
                       source->child_exited = TRUE;
                       source->child_status = 0;
                       wake_source ((GSource *) source);
@@ -5321,14 +5321,24 @@ g_unix_signal_handler (int signum)
  * source is still active. Typically, you will want to call
  * g_spawn_close_pid() in the callback function for the source.
  *
- * Note further that using g_child_watch_source_new() is not
- * compatible with calling `waitpid` with a nonpositive first
- * argument in the application. Calling waitpid() for individual
- * pids will still work fine.
+ * On POSIX platforms, the following restrictions apply to this API
+ * due to limitations in POSIX process interfaces:
  *
- * Similarly, on POSIX platforms, the @pid passed to this function must
- * be greater than 0 (i.e. this function must wait for a specific child,
- * and cannot wait for one of many children by using a nonpositive argument).
+ * * @pid must be a child of this process
+ * * @pid must be positive
+ * * the application must not call `waitpid` with a non-positive
+ *   first argument, for instance in another thread
+ * * the application must not wait for @pid to exit by any other
+ *   mechanism, including `waitpid(pid, ...)` or a second child-watch
+ *   source for the same @pid
+ * * the application must not ignore SIGCHILD
+ *
+ * If any of those conditions are not met, this and related APIs will
+ * not work correctly. This can often be diagnosed via a GLib warning
+ * stating that `ECHILD` was received by `waitpid`.
+ *
+ * Calling `waitpid` for specific processes other than @pid remains a
+ * valid thing to do.
  *
  * Returns: the newly-created child watch source
  *
@@ -5393,6 +5403,8 @@ g_child_watch_source_new (GPid pid)
  * in the callback function for the source.
  * 
  * GLib supports only a single callback per process id.
+ * On POSIX platforms, the same restrictions mentioned for
+ * g_child_watch_source_new() apply to this function.
  *
  * This internally creates a main loop source using 
  * g_child_watch_source_new() and attaches it to the main loop context 
@@ -5451,6 +5463,8 @@ g_child_watch_add_full (gint            priority,
  * g_spawn_close_pid() in the callback function for the source.
  *
  * GLib supports only a single callback per process id.
+ * On POSIX platforms, the same restrictions mentioned for
+ * g_child_watch_source_new() apply to this function.
  *
  * This internally creates a main loop source using 
  * g_child_watch_source_new() and attaches it to the main loop context 
diff --git a/glib/gspawn.c b/glib/gspawn.c
index 85da03d..b1ee3ea 100644
--- a/glib/gspawn.c
+++ b/glib/gspawn.c
@@ -277,7 +277,8 @@ read_data (GString *str,
  * the child is stored there; see the documentation of
  * g_spawn_check_exit_status() for how to use and interpret this.
  * Note that it is invalid to pass %G_SPAWN_DO_NOT_REAP_CHILD in
- * @flags.
+ * @flags, and on POSIX platforms, the same restrictions as for
+ * g_child_watch_source_new() apply.
  *
  * If an error occurs, no data is returned in @standard_output,
  * @standard_error, or @exit_status.
@@ -458,7 +459,7 @@ g_spawn_sync (const gchar          *working_directory,
         {
           if (exit_status)
             {
-              g_warning ("In call to g_spawn_sync(), exit status of a child process was requested but ECHILD 
was received by waitpid(). Most likely the process is ignoring SIGCHLD, or some other thread is invoking 
waitpid() with a nonpositive first argument; either behavior can break applications that use g_spawn_sync 
either directly or indirectly.");
+              g_warning ("In call to g_spawn_sync(), exit status of a child process was requested but ECHILD 
was received by waitpid(). See the documentation of g_child_watch_source_new() for possible causes.");
             }
           else
             {


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