Commit eb860fd8 authored by Allison Karlitskaya's avatar Allison Karlitskaya

Partially revert "Merge waitpid() from g_spawn_sync into gmain()"

This partially reverts commit ce002293.

It used to be safe to use g_spawn_sync() from processes that had their
own SIGCHLD handler because it simply called wait().  When it was
changed to depend on the GLib child watching infrastructure this meant
that GLib had to own the SIGCHLD handler.

This caused hangs in at least Pidgin.

The patch contained two other improvements to the child watch code which
we want to keep, so only revert the changes to gspawn itself.

https://bugzilla.gnome.org/show_bug.cgi?id=698081
parent c91af2ab
......@@ -47,7 +47,6 @@
#include "genviron.h"
#include "gmem.h"
#include "gmain.h"
#include "gshell.h"
#include "gstring.h"
#include "gstrfuncs.h"
......@@ -207,21 +206,6 @@ read_data (GString *str,
}
}
typedef struct {
GMainLoop *loop;
gint *status_p;
} SyncWaitpidData;
static void
on_sync_waitpid (GPid pid,
gint status,
gpointer user_data)
{
SyncWaitpidData *data = user_data;
*(data->status_p) = status;
g_main_loop_quit (data->loop);
}
/**
* g_spawn_sync:
* @working_directory: (allow-none): child's current working directory, or %NULL to inherit parent's
......@@ -277,7 +261,6 @@ g_spawn_sync (const gchar *working_directory,
GString *errstr = NULL;
gboolean failed;
gint status;
SyncWaitpidData waitpid_data;
g_return_val_if_fail (argv != NULL, FALSE);
g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
......@@ -410,32 +393,45 @@ g_spawn_sync (const gchar *working_directory,
close_and_invalidate (&outpipe);
if (errpipe >= 0)
close_and_invalidate (&errpipe);
/* Now create a temporary main context and loop, with just one
* waitpid source. We used to invoke waitpid() directly here, but
* this way we unify with the worker thread in gmain.c.
/* Wait for child to exit, even if we have
* an error pending.
*/
{
GMainContext *context;
GMainLoop *loop;
GSource *source;
context = g_main_context_new ();
loop = g_main_loop_new (context, TRUE);
again:
ret = waitpid (pid, &status, 0);
waitpid_data.loop = loop;
waitpid_data.status_p = &status;
source = g_child_watch_source_new (pid);
g_source_set_callback (source, (GSourceFunc)on_sync_waitpid, &waitpid_data, NULL);
g_source_attach (source, context);
g_source_unref (source);
g_main_loop_run (loop);
if (ret < 0)
{
if (errno == EINTR)
goto again;
else if (errno == ECHILD)
{
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.");
}
else
{
/* We don't need the exit status. */
}
}
else
{
if (!failed) /* avoid error pileups */
{
int errsv = errno;
g_main_context_unref (context);
g_main_loop_unref (loop);
}
failed = TRUE;
g_set_error (error,
G_SPAWN_ERROR,
G_SPAWN_ERROR_READ,
_("Unexpected error in waitpid() (%s)"),
g_strerror (errsv));
}
}
}
if (failed)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment