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
This commit is contained in:
Simon McVittie 2017-10-11 13:55:41 +01:00
parent 65e443da65
commit 6e480634c6
2 changed files with 25 additions and 10 deletions

View File

@ -5080,7 +5080,7 @@ dispatch_unix_signals_unlocked (void)
} }
else if (pid == -1 && errno == ECHILD) 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_exited = TRUE;
source->child_status = 0; source->child_status = 0;
wake_source ((GSource *) source); wake_source ((GSource *) source);
@ -5321,14 +5321,24 @@ g_unix_signal_handler (int signum)
* source is still active. Typically, you will want to call * source is still active. Typically, you will want to call
* g_spawn_close_pid() in the callback function for the source. * g_spawn_close_pid() in the callback function for the source.
* *
* Note further that using g_child_watch_source_new() is not * On POSIX platforms, the following restrictions apply to this API
* compatible with calling `waitpid` with a nonpositive first * due to limitations in POSIX process interfaces:
* argument in the application. Calling waitpid() for individual
* pids will still work fine.
* *
* Similarly, on POSIX platforms, the @pid passed to this function must * * @pid must be a child of this process
* be greater than 0 (i.e. this function must wait for a specific child, * * @pid must be positive
* and cannot wait for one of many children by using a nonpositive argument). * * 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 * 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. * in the callback function for the source.
* *
* GLib supports only a single callback per process id. * 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 * This internally creates a main loop source using
* g_child_watch_source_new() and attaches it to the main loop context * 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. * g_spawn_close_pid() in the callback function for the source.
* *
* GLib supports only a single callback per process id. * 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 * This internally creates a main loop source using
* g_child_watch_source_new() and attaches it to the main loop context * g_child_watch_source_new() and attaches it to the main loop context

View File

@ -277,7 +277,8 @@ read_data (GString *str,
* the child is stored there; see the documentation of * the child is stored there; see the documentation of
* g_spawn_check_exit_status() for how to use and interpret this. * 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 * 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, * If an error occurs, no data is returned in @standard_output,
* @standard_error, or @exit_status. * @standard_error, or @exit_status.
@ -458,7 +459,7 @@ g_spawn_sync (const gchar *working_directory,
{ {
if (exit_status) 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 else
{ {