When possible, manage without the helper process. (Part of the

2003-07-31  Tor Lillqvist  <tml@iki.fi>

	* glib/gspawn-win32.c: When possible, manage without the helper
	process. (Part of the enhancements outlined in #98737.) Speeds up
	GIMP 1.3's first-time-run plug-in query phase a lot.

	Plug a file descriptor (and thus Win32 handle) leak: close the
	read end of the child error report pipe after use.
This commit is contained in:
Tor Lillqvist 2003-07-31 01:25:19 +00:00 committed by Tor Lillqvist
parent 82911ba375
commit cdf72b09e6
7 changed files with 149 additions and 18 deletions

View File

@ -1,3 +1,12 @@
2003-07-31 Tor Lillqvist <tml@iki.fi>
* glib/gspawn-win32.c: When possible, manage without the helper
process. (Part of the enhancements outlined in #98737.) Speeds up
GIMP 1.3's first-time-run plug-in query phase a lot.
Plug a file descriptor (and thus Win32 handle) leak: close the
read end of the child error report pipe after use.
2003-07-30 Matthias Clasen <maclas@gmx.de> 2003-07-30 Matthias Clasen <maclas@gmx.de>
* glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc. * glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc.

View File

@ -1,3 +1,12 @@
2003-07-31 Tor Lillqvist <tml@iki.fi>
* glib/gspawn-win32.c: When possible, manage without the helper
process. (Part of the enhancements outlined in #98737.) Speeds up
GIMP 1.3's first-time-run plug-in query phase a lot.
Plug a file descriptor (and thus Win32 handle) leak: close the
read end of the child error report pipe after use.
2003-07-30 Matthias Clasen <maclas@gmx.de> 2003-07-30 Matthias Clasen <maclas@gmx.de>
* glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc. * glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc.

View File

@ -1,3 +1,12 @@
2003-07-31 Tor Lillqvist <tml@iki.fi>
* glib/gspawn-win32.c: When possible, manage without the helper
process. (Part of the enhancements outlined in #98737.) Speeds up
GIMP 1.3's first-time-run plug-in query phase a lot.
Plug a file descriptor (and thus Win32 handle) leak: close the
read end of the child error report pipe after use.
2003-07-30 Matthias Clasen <maclas@gmx.de> 2003-07-30 Matthias Clasen <maclas@gmx.de>
* glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc. * glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc.

View File

@ -1,3 +1,12 @@
2003-07-31 Tor Lillqvist <tml@iki.fi>
* glib/gspawn-win32.c: When possible, manage without the helper
process. (Part of the enhancements outlined in #98737.) Speeds up
GIMP 1.3's first-time-run plug-in query phase a lot.
Plug a file descriptor (and thus Win32 handle) leak: close the
read end of the child error report pipe after use.
2003-07-30 Matthias Clasen <maclas@gmx.de> 2003-07-30 Matthias Clasen <maclas@gmx.de>
* glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc. * glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc.

View File

@ -1,3 +1,12 @@
2003-07-31 Tor Lillqvist <tml@iki.fi>
* glib/gspawn-win32.c: When possible, manage without the helper
process. (Part of the enhancements outlined in #98737.) Speeds up
GIMP 1.3's first-time-run plug-in query phase a lot.
Plug a file descriptor (and thus Win32 handle) leak: close the
read end of the child error report pipe after use.
2003-07-30 Matthias Clasen <maclas@gmx.de> 2003-07-30 Matthias Clasen <maclas@gmx.de>
* glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc. * glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc.

View File

@ -1,3 +1,12 @@
2003-07-31 Tor Lillqvist <tml@iki.fi>
* glib/gspawn-win32.c: When possible, manage without the helper
process. (Part of the enhancements outlined in #98737.) Speeds up
GIMP 1.3's first-time-run plug-in query phase a lot.
Plug a file descriptor (and thus Win32 handle) leak: close the
read end of the child error report pipe after use.
2003-07-30 Matthias Clasen <maclas@gmx.de> 2003-07-30 Matthias Clasen <maclas@gmx.de>
* glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc. * glib/gutils.c (g_unsetenv): Use same argument name as in header, to pacify gtk-doc.

View File

@ -1,6 +1,7 @@
/* gspawn-win32.c - Process launching on Win32 /* gspawn-win32.c - Process launching on Win32
* *
* Copyright 2000 Red Hat, Inc. * Copyright 2000 Red Hat, Inc.
* Copyright 2003 Tor Lillqvist
* *
* GLib is free software; you can redistribute it and/or * GLib is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as * modify it under the terms of the GNU Lesser General Public License as
@ -30,17 +31,21 @@
* running, and the current directory is common for all threads.) * running, and the current directory is common for all threads.)
* *
* Thus, we must in most cases use a helper program to handle closing * Thus, we must in most cases use a helper program to handle closing
* of (inherited) file descriptors and changing of directory. In fact, * of (inherited) file descriptors and changing of directory. The
* we do it all the time. * helper process is also needed if the standard input, standard
* output, or standard error of the process to be run are supposed to
* be redirected somewhere.
*
* The structure of the source code in this file is a mess, I know.
*/ */
/* FIXME: Actually implement G_SPAWN_FILE_AND_ARGV_ZERO */
/* Define this to get some logging all the time */ /* Define this to get some logging all the time */
/* #define G_SPAWN_WIN32_DEBUG */ /* #define G_SPAWN_WIN32_DEBUG */
#include <config.h> #include <config.h>
#include "config.h"
#include "glib.h" #include "glib.h"
#include "gprintfint.h" #include "gprintfint.h"
@ -97,6 +102,11 @@ enum {
ARG_COUNT = ARG_PROGRAM ARG_COUNT = ARG_PROGRAM
}; };
/* Return codes from do_spawn() */
#define DO_SPAWN_ERROR_HELPER -1
#define DO_SPAWN_OK_NO_HELPER -2
#define DO_SPAWN_ERROR_NO_HELPER -3
static gint static gint
protect_argv (gchar **argv, protect_argv (gchar **argv,
gchar ***new_argv) gchar ***new_argv)
@ -189,9 +199,10 @@ static gboolean do_spawn_with_pipes (gboolean dont_wait,
gboolean stdout_to_null, gboolean stdout_to_null,
gboolean stderr_to_null, gboolean stderr_to_null,
gboolean child_inherits_stdin, gboolean child_inherits_stdin,
gboolean file_and_argv_zero,
GSpawnChildSetupFunc child_setup, GSpawnChildSetupFunc child_setup,
gpointer user_data, gpointer user_data,
gint *child_pid, gint *child_handle,
gint *standard_input, gint *standard_input,
gint *standard_output, gint *standard_output,
gint *standard_error, gint *standard_error,
@ -214,7 +225,7 @@ g_spawn_async (const gchar *working_directory,
GSpawnFlags flags, GSpawnFlags flags,
GSpawnChildSetupFunc child_setup, GSpawnChildSetupFunc child_setup,
gpointer user_data, gpointer user_data,
gint *child_pid, gint *child_handle,
GError **error) GError **error)
{ {
g_return_val_if_fail (argv != NULL, FALSE); g_return_val_if_fail (argv != NULL, FALSE);
@ -224,7 +235,7 @@ g_spawn_async (const gchar *working_directory,
flags, flags,
child_setup, child_setup,
user_data, user_data,
child_pid, child_handle,
NULL, NULL, NULL, NULL, NULL, NULL,
error); error);
} }
@ -345,6 +356,7 @@ g_spawn_sync (const gchar *working_directory,
(flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0, (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
(flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0, (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
(flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0, (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
(flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0,
child_setup, child_setup,
user_data, user_data,
&pid, &pid,
@ -511,7 +523,7 @@ g_spawn_async_with_pipes (const gchar *working_directory,
GSpawnFlags flags, GSpawnFlags flags,
GSpawnChildSetupFunc child_setup, GSpawnChildSetupFunc child_setup,
gpointer user_data, gpointer user_data,
gint *child_pid, gint *child_handle,
gint *standard_input, gint *standard_input,
gint *standard_output, gint *standard_output,
gint *standard_error, gint *standard_error,
@ -536,9 +548,10 @@ g_spawn_async_with_pipes (const gchar *working_directory,
(flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0, (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
(flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0, (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
(flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0, (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
(flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0,
child_setup, child_setup,
user_data, user_data,
child_pid, child_handle,
standard_input, standard_input,
standard_output, standard_output,
standard_error, standard_error,
@ -605,6 +618,14 @@ g_spawn_command_line_async (const gchar *command_line,
return retval; return retval;
} }
/* This stinks, code reorg needed. Presumably do_spawn() should be
* inserted into its only caller, do_spawn_with_pipes(), and then code
* snippets from that function should be split out to separate
* functions if necessary.
*/
static gint shortcut_spawn_retval;
static gint static gint
do_spawn (gboolean dont_wait, do_spawn (gboolean dont_wait,
gint child_err_report_fd, gint child_err_report_fd,
@ -619,6 +640,7 @@ do_spawn (gboolean dont_wait,
gboolean stdout_to_null, gboolean stdout_to_null,
gboolean stderr_to_null, gboolean stderr_to_null,
gboolean child_inherits_stdin, gboolean child_inherits_stdin,
gboolean file_and_argv_zero,
GSpawnChildSetupFunc child_setup, GSpawnChildSetupFunc child_setup,
gpointer user_data) gpointer user_data)
{ {
@ -630,6 +652,34 @@ do_spawn (gboolean dont_wait,
SETUP_DEBUG(); SETUP_DEBUG();
if (stdin_fd == -1 && stdout_fd == -1 && stderr_fd == -1 &&
(working_directory == NULL || !*working_directory) &&
!close_descriptors &&
!stdout_to_null && !stderr_to_null &&
child_inherits_stdin)
{
/* We can do without the helper process */
int mode = dont_wait ? P_NOWAIT : P_WAIT;
if (debug)
g_print ("doing without gspawn-win32-helper\n");
if (search_path)
rc = spawnvp (mode, argv[0], argv);
else
rc = spawnv (mode, argv[0], argv);
if (rc == -1)
{
return DO_SPAWN_ERROR_NO_HELPER;
}
else
{
shortcut_spawn_retval = rc;
return DO_SPAWN_OK_NO_HELPER;
}
}
while (argv[argc]) while (argv[argc])
++argc; ++argc;
@ -808,9 +858,10 @@ do_spawn_with_pipes (gboolean dont_wait,
gboolean stdout_to_null, gboolean stdout_to_null,
gboolean stderr_to_null, gboolean stderr_to_null,
gboolean child_inherits_stdin, gboolean child_inherits_stdin,
gboolean file_and_argv_zero,
GSpawnChildSetupFunc child_setup, GSpawnChildSetupFunc child_setup,
gpointer user_data, gpointer user_data,
gint *child_pid, gint *child_handle,
gint *standard_input, gint *standard_input,
gint *standard_output, gint *standard_output,
gint *standard_error, gint *standard_error,
@ -855,6 +906,7 @@ do_spawn_with_pipes (gboolean dont_wait,
stdout_to_null, stdout_to_null,
stderr_to_null, stderr_to_null,
child_inherits_stdin, child_inherits_stdin,
file_and_argv_zero,
child_setup, child_setup,
user_data); user_data);
@ -862,8 +914,8 @@ do_spawn_with_pipes (gboolean dont_wait,
g_free (new_argv[i]); g_free (new_argv[i]);
g_free (new_argv); g_free (new_argv);
/* do_spawn() returns -1 if gspawn-win32-helper couldn't be run */ /* Check if gspawn-win32-helper couldn't be run */
if (helper == -1) if (helper == DO_SPAWN_ERROR_HELPER)
{ {
g_set_error (error, g_set_error (error,
G_SPAWN_ERROR, G_SPAWN_ERROR,
@ -872,6 +924,29 @@ do_spawn_with_pipes (gboolean dont_wait,
goto cleanup_and_fail; goto cleanup_and_fail;
} }
else if (helper == DO_SPAWN_OK_NO_HELPER)
{
if (child_handle && dont_wait && !dont_return_handle)
*child_handle = shortcut_spawn_retval;
else if (!dont_wait && exit_status)
*exit_status = shortcut_spawn_retval;
close_and_invalidate (&child_err_report_pipe[0]);
close_and_invalidate (&child_err_report_pipe[1]);
return TRUE;
}
else if (helper == DO_SPAWN_ERROR_NO_HELPER)
{
g_set_error (error,
G_SPAWN_ERROR,
G_SPAWN_ERROR_FAILED,
_("Failed to execute child process (%s)"),
g_strerror (errno));
helper = -1;
goto cleanup_and_fail;
}
if (!read_ints (child_err_report_pipe[0], if (!read_ints (child_err_report_pipe[0],
buf, 2, &n_ints, buf, 2, &n_ints,
error) || error) ||
@ -882,19 +957,19 @@ do_spawn_with_pipes (gboolean dont_wait,
switch (buf[0]) switch (buf[0])
{ {
case CHILD_NO_ERROR: case CHILD_NO_ERROR:
if (child_pid && dont_wait && !dont_return_handle) if (child_handle && dont_wait && !dont_return_handle)
{ {
/* helper is our HANDLE for gspawn-win32-helper. It has /* helper is our HANDLE for gspawn-win32-helper. It has
* told us the HANDLE of its child. Duplicate that into * told us the HANDLE of its child. Duplicate that into
* a HANDLE valid in this process. * a HANDLE valid in this process.
*/ */
if (!DuplicateHandle ((HANDLE) helper, (HANDLE) buf[1], if (!DuplicateHandle ((HANDLE) helper, (HANDLE) buf[1],
GetCurrentProcess (), (LPHANDLE) child_pid, GetCurrentProcess (), (LPHANDLE) child_handle,
0, TRUE, DUPLICATE_SAME_ACCESS)) 0, TRUE, DUPLICATE_SAME_ACCESS))
*child_pid = 0; *child_handle = 0;
} }
else if (child_pid) else if (child_handle)
*child_pid = 0; *child_handle = 0;
break; break;
case CHILD_CHDIR_FAILED: case CHILD_CHDIR_FAILED:
@ -927,6 +1002,8 @@ do_spawn_with_pipes (gboolean dont_wait,
*exit_status = buf[1]; *exit_status = buf[1];
CloseHandle ((HANDLE) helper); CloseHandle ((HANDLE) helper);
close_and_invalidate (&child_err_report_pipe[0]);
return TRUE; return TRUE;
cleanup_and_fail: cleanup_and_fail: