mirror of
https://salsa.debian.org/srivasta/make-dfsg.git
synced 2024-12-27 06:27:57 +00:00
[SV 44555] Use vfork() instead of fork() where available.
Testing has shown that vfork() is actually significantly more efficient on systems where it's supported, even for copy-on-write implementations. If make is big enough, duplicating the page tables is significant overhead. * configure.ac: Check for fork/vfork. * makeint.h: Include vfork.h and set up #define for it. * os.h, posixos.c (get_bad_stdin): For children who can't use the normal stdin file descriptor, get a broken one. * job.c (start_job_command): Avoid so many ifdefs and simplify the invocation of child_execute_job() (child_execute_job): move the fork operation here so it can return early for the parent process. Switch to use vfork(). * function.c (func_shell_base): Use new child_execute_job() and simplify ifdefs. * job.h, main.c, remote-cstms.c, vmsjobs.c, w32os.c: Update declarations and calls.
This commit is contained in:
parent
14b2d7effb
commit
fd1dd7c398
11 changed files with 258 additions and 265 deletions
|
@ -144,6 +144,8 @@ AC_CHECK_FUNCS([strdup strndup mkstemp mktemp fdopen fileno \
|
||||||
AC_CHECK_DECLS([bsd_signal], [], [], [[#define _GNU_SOURCE 1
|
AC_CHECK_DECLS([bsd_signal], [], [], [[#define _GNU_SOURCE 1
|
||||||
#include <signal.h>]])
|
#include <signal.h>]])
|
||||||
|
|
||||||
|
AC_FUNC_FORK
|
||||||
|
|
||||||
AC_FUNC_SETVBUF_REVERSED
|
AC_FUNC_SETVBUF_REVERSED
|
||||||
|
|
||||||
# Rumor has it that strcasecmp lives in -lresolv on some odd systems.
|
# Rumor has it that strcasecmp lives in -lresolv on some odd systems.
|
||||||
|
|
182
function.c
182
function.c
|
@ -1751,6 +1751,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||||
perror_with_name (error_prefix, "pipe");
|
perror_with_name (error_prefix, "pipe");
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(WINDOWS32)
|
#elif defined(WINDOWS32)
|
||||||
windows32_openpipe (pipedes, errfd, &pid, command_argv, envp);
|
windows32_openpipe (pipedes, errfd, &pid, command_argv, envp);
|
||||||
/* Restore the value of just_print_flag. */
|
/* Restore the value of just_print_flag. */
|
||||||
|
@ -1763,7 +1764,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||||
perror_with_name (error_prefix, "pipe");
|
perror_with_name (error_prefix, "pipe");
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
#else
|
#else
|
||||||
if (pipe (pipedes) < 0)
|
if (pipe (pipedes) < 0)
|
||||||
{
|
{
|
||||||
|
@ -1771,118 +1772,113 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef __EMX__
|
/* Close handles that are unnecessary for the child process. */
|
||||||
/* close some handles that are unnecessary for the child process */
|
|
||||||
CLOSE_ON_EXEC(pipedes[1]);
|
CLOSE_ON_EXEC(pipedes[1]);
|
||||||
CLOSE_ON_EXEC(pipedes[0]);
|
CLOSE_ON_EXEC(pipedes[0]);
|
||||||
/* Never use fork()/exec() here! Use spawn() instead in exec_command() */
|
|
||||||
pid = child_execute_job (FD_STDIN, pipedes[1], errfd, command_argv, envp);
|
|
||||||
if (pid < 0)
|
|
||||||
perror_with_name (error_prefix, "spawn");
|
|
||||||
# else /* ! __EMX__ */
|
|
||||||
pid = fork ();
|
|
||||||
if (pid < 0)
|
|
||||||
perror_with_name (error_prefix, "fork");
|
|
||||||
else if (pid == 0)
|
|
||||||
{
|
|
||||||
# ifdef SET_STACK_SIZE
|
|
||||||
/* Reset limits, if necessary. */
|
|
||||||
if (stack_limit.rlim_cur)
|
|
||||||
setrlimit (RLIMIT_STACK, &stack_limit);
|
|
||||||
# endif
|
|
||||||
child_execute_job (FD_STDIN, pipedes[1], errfd, command_argv, envp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
/* We are the parent. */
|
|
||||||
char *buffer;
|
|
||||||
unsigned int maxlen, i;
|
|
||||||
int cc;
|
|
||||||
|
|
||||||
/* Record the PID for reap_children. */
|
{
|
||||||
shell_function_pid = pid;
|
struct output out;
|
||||||
|
out.syncout = 1;
|
||||||
|
out.out = pipedes[1];
|
||||||
|
out.err = errfd;
|
||||||
|
|
||||||
|
pid = child_execute_job (&out, 1, command_argv, envp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid < 0)
|
||||||
|
{
|
||||||
|
perror_with_name (error_prefix, "fork");
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
unsigned int maxlen, i;
|
||||||
|
int cc;
|
||||||
|
|
||||||
|
/* Record the PID for reap_children. */
|
||||||
|
shell_function_pid = pid;
|
||||||
#ifndef __MSDOS__
|
#ifndef __MSDOS__
|
||||||
shell_function_completed = 0;
|
shell_function_completed = 0;
|
||||||
|
|
||||||
/* Free the storage only the child needed. */
|
/* Free the storage only the child needed. */
|
||||||
free (command_argv[0]);
|
free (command_argv[0]);
|
||||||
free (command_argv);
|
free (command_argv);
|
||||||
|
|
||||||
/* Close the write side of the pipe. We test for -1, since
|
/* Close the write side of the pipe. We test for -1, since
|
||||||
pipedes[1] is -1 on MS-Windows, and some versions of MS
|
pipedes[1] is -1 on MS-Windows, and some versions of MS
|
||||||
libraries barf when 'close' is called with -1. */
|
libraries barf when 'close' is called with -1. */
|
||||||
if (pipedes[1] >= 0)
|
if (pipedes[1] >= 0)
|
||||||
close (pipedes[1]);
|
close (pipedes[1]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Set up and read from the pipe. */
|
/* Set up and read from the pipe. */
|
||||||
|
|
||||||
maxlen = 200;
|
maxlen = 200;
|
||||||
buffer = xmalloc (maxlen + 1);
|
buffer = xmalloc (maxlen + 1);
|
||||||
|
|
||||||
/* Read from the pipe until it gets EOF. */
|
/* Read from the pipe until it gets EOF. */
|
||||||
for (i = 0; ; i += cc)
|
for (i = 0; ; i += cc)
|
||||||
{
|
{
|
||||||
if (i == maxlen)
|
if (i == maxlen)
|
||||||
{
|
{
|
||||||
maxlen += 512;
|
maxlen += 512;
|
||||||
buffer = xrealloc (buffer, maxlen + 1);
|
buffer = xrealloc (buffer, maxlen + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
EINTRLOOP (cc, read (pipedes[0], &buffer[i], maxlen - i));
|
EINTRLOOP (cc, read (pipedes[0], &buffer[i], maxlen - i));
|
||||||
if (cc <= 0)
|
if (cc <= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
buffer[i] = '\0';
|
buffer[i] = '\0';
|
||||||
|
|
||||||
/* Close the read side of the pipe. */
|
/* Close the read side of the pipe. */
|
||||||
#ifdef __MSDOS__
|
#ifdef __MSDOS__
|
||||||
if (fpipe)
|
if (fpipe)
|
||||||
{
|
{
|
||||||
int st = pclose (fpipe);
|
int st = pclose (fpipe);
|
||||||
shell_completed (st, 0);
|
shell_completed (st, 0);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void) close (pipedes[0]);
|
(void) close (pipedes[0]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Loop until child_handler or reap_children() sets
|
/* Loop until child_handler or reap_children() sets
|
||||||
shell_function_completed to the status of our child shell. */
|
shell_function_completed to the status of our child shell. */
|
||||||
while (shell_function_completed == 0)
|
while (shell_function_completed == 0)
|
||||||
reap_children (1, 0);
|
reap_children (1, 0);
|
||||||
|
|
||||||
if (batch_filename)
|
if (batch_filename)
|
||||||
{
|
{
|
||||||
DB (DB_VERBOSE, (_("Cleaning up temporary batch file %s\n"),
|
DB (DB_VERBOSE, (_("Cleaning up temporary batch file %s\n"),
|
||||||
batch_filename));
|
batch_filename));
|
||||||
remove (batch_filename);
|
remove (batch_filename);
|
||||||
free (batch_filename);
|
free (batch_filename);
|
||||||
}
|
}
|
||||||
shell_function_pid = 0;
|
shell_function_pid = 0;
|
||||||
|
|
||||||
/* shell_completed() will set shell_function_completed to 1 when the
|
/* shell_completed() will set shell_function_completed to 1 when the
|
||||||
child dies normally, or to -1 if it dies with status 127, which is
|
child dies normally, or to -1 if it dies with status 127, which is
|
||||||
most likely an exec fail. */
|
most likely an exec fail. */
|
||||||
|
|
||||||
if (shell_function_completed == -1)
|
if (shell_function_completed == -1)
|
||||||
{
|
{
|
||||||
/* This likely means that the execvp failed, so we should just
|
/* This likely means that the execvp failed, so we should just
|
||||||
write the error message in the pipe from the child. */
|
write the error message in the pipe from the child. */
|
||||||
fputs (buffer, stderr);
|
fputs (buffer, stderr);
|
||||||
fflush (stderr);
|
fflush (stderr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The child finished normally. Replace all newlines in its output
|
/* The child finished normally. Replace all newlines in its output
|
||||||
with spaces, and put that in the variable output buffer. */
|
with spaces, and put that in the variable output buffer. */
|
||||||
fold_newlines (buffer, &i, trim_newlines);
|
fold_newlines (buffer, &i, trim_newlines);
|
||||||
o = variable_buffer_output (o, buffer, i);
|
o = variable_buffer_output (o, buffer, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
free (buffer);
|
free (buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
230
job.c
230
job.c
|
@ -1074,17 +1074,12 @@ unblock_sigs (void)
|
||||||
static void
|
static void
|
||||||
start_job_command (struct child *child)
|
start_job_command (struct child *child)
|
||||||
{
|
{
|
||||||
#if !defined(_AMIGA) && !defined(WINDOWS32)
|
|
||||||
static int bad_stdin = -1;
|
|
||||||
#endif
|
|
||||||
int flags;
|
int flags;
|
||||||
char *p;
|
char *p;
|
||||||
#ifdef VMS
|
#ifdef VMS
|
||||||
char *argv;
|
char *argv;
|
||||||
#else
|
#else
|
||||||
char **argv;
|
char **argv;
|
||||||
int outfd = FD_STDOUT;
|
|
||||||
int errfd = FD_STDERR;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If we have a completely empty commandset, stop now. */
|
/* If we have a completely empty commandset, stop now. */
|
||||||
|
@ -1328,32 +1323,6 @@ start_job_command (struct child *child)
|
||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
fflush (stderr);
|
fflush (stderr);
|
||||||
|
|
||||||
#ifndef VMS
|
|
||||||
#if !defined(WINDOWS32) && !defined(_AMIGA) && !defined(__MSDOS__)
|
|
||||||
|
|
||||||
/* Set up a bad standard input that reads from a broken pipe. */
|
|
||||||
|
|
||||||
if (bad_stdin == -1)
|
|
||||||
{
|
|
||||||
/* Make a file descriptor that is the read end of a broken pipe.
|
|
||||||
This will be used for some children's standard inputs. */
|
|
||||||
int pd[2];
|
|
||||||
if (pipe (pd) == 0)
|
|
||||||
{
|
|
||||||
/* Close the write side. */
|
|
||||||
(void) close (pd[1]);
|
|
||||||
/* Save the read side. */
|
|
||||||
bad_stdin = pd[0];
|
|
||||||
|
|
||||||
/* Set the descriptor to close on exec, so it does not litter any
|
|
||||||
child's descriptor table. When it is dup2'd onto descriptor 0,
|
|
||||||
that descriptor will not close on exec. */
|
|
||||||
CLOSE_ON_EXEC (bad_stdin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !WINDOWS32 && !_AMIGA && !__MSDOS__ */
|
|
||||||
|
|
||||||
/* Decide whether to give this child the 'good' standard input
|
/* Decide whether to give this child the 'good' standard input
|
||||||
(one that points to the terminal or whatever), or the 'bad' one
|
(one that points to the terminal or whatever), or the 'bad' one
|
||||||
that points to the read side of a broken pipe. */
|
that points to the read side of a broken pipe. */
|
||||||
|
@ -1362,8 +1331,6 @@ start_job_command (struct child *child)
|
||||||
if (child->good_stdin)
|
if (child->good_stdin)
|
||||||
good_stdin_used = 1;
|
good_stdin_used = 1;
|
||||||
|
|
||||||
#endif /* !VMS */
|
|
||||||
|
|
||||||
child->deleted = 0;
|
child->deleted = 0;
|
||||||
|
|
||||||
#ifndef _AMIGA
|
#ifndef _AMIGA
|
||||||
|
@ -1380,7 +1347,7 @@ start_job_command (struct child *child)
|
||||||
{
|
{
|
||||||
int is_remote, id, used_stdin;
|
int is_remote, id, used_stdin;
|
||||||
if (start_remote_job (argv, child->environment,
|
if (start_remote_job (argv, child->environment,
|
||||||
child->good_stdin ? 0 : bad_stdin,
|
child->good_stdin ? 0 : get_bad_stdin (),
|
||||||
&is_remote, &id, &used_stdin))
|
&is_remote, &id, &used_stdin))
|
||||||
/* Don't give up; remote execution may fail for various reasons. If
|
/* Don't give up; remote execution may fail for various reasons. If
|
||||||
so, simply run the job locally. */
|
so, simply run the job locally. */
|
||||||
|
@ -1409,7 +1376,7 @@ start_job_command (struct child *child)
|
||||||
child->remote = 0;
|
child->remote = 0;
|
||||||
|
|
||||||
#ifdef VMS
|
#ifdef VMS
|
||||||
if (!child_execute_job (argv, child))
|
if (!child_execute_job (child, argv))
|
||||||
{
|
{
|
||||||
/* Fork failed! */
|
/* Fork failed! */
|
||||||
perror_with_name ("fork", "");
|
perror_with_name ("fork", "");
|
||||||
|
@ -1420,68 +1387,20 @@ start_job_command (struct child *child)
|
||||||
|
|
||||||
parent_environ = environ;
|
parent_environ = environ;
|
||||||
|
|
||||||
#ifndef NO_OUTPUT_SYNC
|
jobserver_pre_child (flags & COMMANDS_RECURSE);
|
||||||
/* Divert child output if output_sync in use. */
|
|
||||||
if (child->output.syncout)
|
|
||||||
{
|
|
||||||
if (child->output.out >= 0)
|
|
||||||
outfd = child->output.out;
|
|
||||||
if (child->output.err >= 0)
|
|
||||||
errfd = child->output.err;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
# ifdef __EMX__
|
|
||||||
/* If we aren't running a recursive command and we have a jobserver
|
|
||||||
pipe, close it before exec'ing. */
|
|
||||||
if (!(flags & COMMANDS_RECURSE) && jobserver_enabled ())
|
|
||||||
jobserver_pre_child ();
|
|
||||||
|
|
||||||
/* Never use fork()/exec() here! Use spawn() instead in exec_command() */
|
child->pid = child_execute_job (&child->output, child->good_stdin, argv, child->environment);
|
||||||
child->pid = child_execute_job (child->good_stdin ? FD_STDIN : bad_stdin,
|
|
||||||
outfd, errfd,
|
|
||||||
argv, child->environment);
|
|
||||||
if (child->pid < 0)
|
|
||||||
{
|
|
||||||
/* spawn failed! */
|
|
||||||
unblock_sigs ();
|
|
||||||
perror_with_name ("spawn", "");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* undo CLOSE_ON_EXEC() after the child process has been started */
|
|
||||||
if (!(flags & COMMANDS_RECURSE) && jobserver_enabled ())
|
|
||||||
jobserver_post_child ();
|
|
||||||
|
|
||||||
#else /* !__EMX__ */
|
|
||||||
|
|
||||||
child->pid = fork ();
|
|
||||||
environ = parent_environ; /* Restore value child may have clobbered. */
|
environ = parent_environ; /* Restore value child may have clobbered. */
|
||||||
if (child->pid == 0)
|
jobserver_post_child (flags & COMMANDS_RECURSE);
|
||||||
{
|
|
||||||
/* We are the child side. */
|
|
||||||
unblock_sigs ();
|
|
||||||
|
|
||||||
/* If we AREN'T running a recursive command and we have a jobserver,
|
if (child->pid < 0)
|
||||||
clear it before exec'ing. */
|
|
||||||
if (!(flags & COMMANDS_RECURSE) && jobserver_enabled ())
|
|
||||||
jobserver_clear ();
|
|
||||||
|
|
||||||
#ifdef SET_STACK_SIZE
|
|
||||||
/* Reset limits, if necessary. */
|
|
||||||
if (stack_limit.rlim_cur)
|
|
||||||
setrlimit (RLIMIT_STACK, &stack_limit);
|
|
||||||
#endif
|
|
||||||
child_execute_job (child->good_stdin ? FD_STDIN : bad_stdin,
|
|
||||||
outfd, errfd, argv, child->environment);
|
|
||||||
}
|
|
||||||
else if (child->pid < 0)
|
|
||||||
{
|
{
|
||||||
/* Fork failed! */
|
/* Fork failed! */
|
||||||
unblock_sigs ();
|
unblock_sigs ();
|
||||||
perror_with_name ("fork", "");
|
perror_with_name ("fork", "");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
# endif /* !__EMX__ */
|
|
||||||
#endif /* !VMS */
|
#endif /* !VMS */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1557,6 +1476,8 @@ start_job_command (struct child *child)
|
||||||
{
|
{
|
||||||
HANDLE hPID;
|
HANDLE hPID;
|
||||||
char* arg0;
|
char* arg0;
|
||||||
|
int outfd = FD_STDOUT;
|
||||||
|
int errfd = FD_STDERR;
|
||||||
|
|
||||||
/* make UNC paths safe for CreateProcess -- backslash format */
|
/* make UNC paths safe for CreateProcess -- backslash format */
|
||||||
arg0 = argv[0];
|
arg0 = argv[0];
|
||||||
|
@ -2098,82 +2019,95 @@ start_waiting_jobs (void)
|
||||||
/* EMX: Start a child process. This function returns the new pid. */
|
/* EMX: Start a child process. This function returns the new pid. */
|
||||||
# if defined __EMX__
|
# if defined __EMX__
|
||||||
int
|
int
|
||||||
child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
|
child_execute_job (struct output *out, int good_stdin, char **argv, char **envp)
|
||||||
char **argv, char **envp)
|
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
int save_stdin = -1;
|
int fdin = good_stdin ? FD_STDIN : get_bad_stdin ();
|
||||||
int save_stdout = -1;
|
int fdout = FD_STDOUT;
|
||||||
int save_stderr = -1;
|
int fderr = FD_STDERR;
|
||||||
|
int save_fdin = -1;
|
||||||
|
int save_fdout = -1;
|
||||||
|
int save_fderr = -1;
|
||||||
|
|
||||||
|
#ifndef NO_OUTPUT_SYNC
|
||||||
|
/* Divert child output if output_sync in use. */
|
||||||
|
if (out && out->syncout)
|
||||||
|
{
|
||||||
|
if (out->out >= 0)
|
||||||
|
fdout = out->out;
|
||||||
|
if (out->err >= 0)
|
||||||
|
fderr = out->err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* For each FD which needs to be redirected first make a dup of the standard
|
/* For each FD which needs to be redirected first make a dup of the standard
|
||||||
FD to save and mark it close on exec so our child won't see it. Then
|
FD to save and mark it close on exec so our child won't see it. Then
|
||||||
dup2() the standard FD to the redirect FD, and also mark the redirect FD
|
dup2() the standard FD to the redirect FD, and also mark the redirect FD
|
||||||
as close on exec. */
|
as close on exec. */
|
||||||
if (stdin_fd != FD_STDIN)
|
if (fdin != FD_STDIN)
|
||||||
{
|
{
|
||||||
save_stdin = dup (FD_STDIN);
|
save_fdin = dup (FD_STDIN);
|
||||||
if (save_stdin < 0)
|
if (save_fdin < 0)
|
||||||
O (fatal, NILF, _("no more file handles: could not duplicate stdin\n"));
|
O (fatal, NILF, _("no more file handles: could not duplicate stdin\n"));
|
||||||
CLOSE_ON_EXEC (save_stdin);
|
CLOSE_ON_EXEC (save_fdin);
|
||||||
|
|
||||||
dup2 (stdin_fd, FD_STDIN);
|
dup2 (fdin, FD_STDIN);
|
||||||
CLOSE_ON_EXEC (stdin_fd);
|
CLOSE_ON_EXEC (fdin);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stdout_fd != FD_STDOUT)
|
if (fdout != FD_STDOUT)
|
||||||
{
|
{
|
||||||
save_stdout = dup (FD_STDOUT);
|
save_fdout = dup (FD_STDOUT);
|
||||||
if (save_stdout < 0)
|
if (save_fdout < 0)
|
||||||
O (fatal, NILF,
|
O (fatal, NILF,
|
||||||
_("no more file handles: could not duplicate stdout\n"));
|
_("no more file handles: could not duplicate stdout\n"));
|
||||||
CLOSE_ON_EXEC (save_stdout);
|
CLOSE_ON_EXEC (save_fdout);
|
||||||
|
|
||||||
dup2 (stdout_fd, FD_STDOUT);
|
dup2 (fdout, FD_STDOUT);
|
||||||
CLOSE_ON_EXEC (stdout_fd);
|
CLOSE_ON_EXEC (fdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stderr_fd != FD_STDERR)
|
if (fderr != FD_STDERR)
|
||||||
{
|
{
|
||||||
if (stderr_fd != stdout_fd)
|
if (fderr != fdout)
|
||||||
{
|
{
|
||||||
save_stderr = dup (FD_STDERR);
|
save_fderr = dup (FD_STDERR);
|
||||||
if (save_stderr < 0)
|
if (save_fderr < 0)
|
||||||
O (fatal, NILF,
|
O (fatal, NILF,
|
||||||
_("no more file handles: could not duplicate stderr\n"));
|
_("no more file handles: could not duplicate stderr\n"));
|
||||||
CLOSE_ON_EXEC (save_stderr);
|
CLOSE_ON_EXEC (save_fderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
dup2 (stderr_fd, FD_STDERR);
|
dup2 (fderr, FD_STDERR);
|
||||||
CLOSE_ON_EXEC (stderr_fd);
|
CLOSE_ON_EXEC (fderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run the command. */
|
/* Run the command. */
|
||||||
pid = exec_command (argv, envp);
|
pid = exec_command (argv, envp);
|
||||||
|
|
||||||
/* Restore stdout/stdin/stderr of the parent and close temporary FDs. */
|
/* Restore stdout/stdin/stderr of the parent and close temporary FDs. */
|
||||||
if (save_stdin >= 0)
|
if (save_fdin >= 0)
|
||||||
{
|
{
|
||||||
if (dup2 (save_stdin, FD_STDIN) != FD_STDIN)
|
if (dup2 (save_fdin, FD_STDIN) != FD_STDIN)
|
||||||
O (fatal, NILF, _("Could not restore stdin\n"));
|
O (fatal, NILF, _("Could not restore stdin\n"));
|
||||||
else
|
else
|
||||||
close (save_stdin);
|
close (save_fdin);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (save_stdout >= 0)
|
if (save_fdout >= 0)
|
||||||
{
|
{
|
||||||
if (dup2 (save_stdout, FD_STDOUT) != FD_STDOUT)
|
if (dup2 (save_fdout, FD_STDOUT) != FD_STDOUT)
|
||||||
O (fatal, NILF, _("Could not restore stdout\n"));
|
O (fatal, NILF, _("Could not restore stdout\n"));
|
||||||
else
|
else
|
||||||
close (save_stdout);
|
close (save_fdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (save_stderr >= 0)
|
if (save_fderr >= 0)
|
||||||
{
|
{
|
||||||
if (dup2 (save_stderr, FD_STDERR) != FD_STDERR)
|
if (dup2 (save_fderr, FD_STDERR) != FD_STDERR)
|
||||||
O (fatal, NILF, _("Could not restore stderr\n"));
|
O (fatal, NILF, _("Could not restore stderr\n"));
|
||||||
else
|
else
|
||||||
close (save_stderr);
|
close (save_fderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
|
@ -2181,32 +2115,50 @@ child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
|
||||||
|
|
||||||
#elif !defined (_AMIGA) && !defined (__MSDOS__) && !defined (VMS)
|
#elif !defined (_AMIGA) && !defined (__MSDOS__) && !defined (VMS)
|
||||||
|
|
||||||
/* UNIX:
|
/* POSIX:
|
||||||
Replace the current process with one executing the command in ARGV.
|
Create a child process executing the command in ARGV.
|
||||||
STDIN_FD/STDOUT_FD/STDERR_FD are used as the process's stdin/stdout/stderr;
|
ENVP is the environment of the new program. Returns the PID or -1. */
|
||||||
ENVP is the environment of the new program. This function does not return. */
|
int
|
||||||
void
|
child_execute_job (struct output *out, int good_stdin, char **argv, char **envp)
|
||||||
child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
|
|
||||||
char **argv, char **envp)
|
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
int pid;
|
||||||
|
int fdin = good_stdin ? FD_STDIN : get_bad_stdin ();
|
||||||
|
int fdout = FD_STDOUT;
|
||||||
|
int fderr = FD_STDERR;
|
||||||
|
|
||||||
/* For any redirected FD, dup2() it to the standard FD then close it. */
|
#ifndef NO_OUTPUT_SYNC
|
||||||
if (stdin_fd != FD_STDIN)
|
/* Divert child output if output_sync in use. */
|
||||||
|
if (out && out->syncout)
|
||||||
{
|
{
|
||||||
EINTRLOOP (r, dup2 (stdin_fd, FD_STDIN));
|
if (out->out >= 0)
|
||||||
close (stdin_fd);
|
fdout = out->out;
|
||||||
|
if (out->err >= 0)
|
||||||
|
fderr = out->err;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (stdout_fd != FD_STDOUT)
|
pid = vfork();
|
||||||
EINTRLOOP (r, dup2 (stdout_fd, FD_STDOUT));
|
if (pid != 0)
|
||||||
if (stderr_fd != FD_STDERR)
|
return pid;
|
||||||
EINTRLOOP (r, dup2 (stderr_fd, FD_STDERR));
|
|
||||||
|
|
||||||
if (stdout_fd != FD_STDOUT)
|
/* We are the child. */
|
||||||
close (stdout_fd);
|
unblock_sigs ();
|
||||||
if (stderr_fd != FD_STDERR && stderr_fd != stdout_fd)
|
|
||||||
close (stderr_fd);
|
#ifdef SET_STACK_SIZE
|
||||||
|
/* Reset limits, if necessary. */
|
||||||
|
if (stack_limit.rlim_cur)
|
||||||
|
setrlimit (RLIMIT_STACK, &stack_limit);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* For any redirected FD, dup2() it to the standard FD.
|
||||||
|
They are all marked close-on-exec already. */
|
||||||
|
if (fdin != FD_STDIN)
|
||||||
|
EINTRLOOP (r, dup2 (fdin, FD_STDIN));
|
||||||
|
if (fdout != FD_STDOUT)
|
||||||
|
EINTRLOOP (r, dup2 (fdout, FD_STDOUT));
|
||||||
|
if (fderr != FD_STDERR)
|
||||||
|
EINTRLOOP (r, dup2 (fderr, FD_STDERR));
|
||||||
|
|
||||||
/* Run the command. */
|
/* Run the command. */
|
||||||
exec_command (argv, envp);
|
exec_command (argv, envp);
|
||||||
|
|
14
job.h
14
job.h
|
@ -24,7 +24,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
/* How to set close-on-exec for a file descriptor. */
|
/* How to set close-on-exec for a file descriptor. */
|
||||||
|
|
||||||
#if !defined F_SETFD
|
#if !defined(F_SETFD) || !defined(F_GETFD)
|
||||||
# ifdef WINDOWS32
|
# ifdef WINDOWS32
|
||||||
# define CLOSE_ON_EXEC(_d) process_noinherit(_d)
|
# define CLOSE_ON_EXEC(_d) process_noinherit(_d)
|
||||||
# else
|
# else
|
||||||
|
@ -124,20 +124,16 @@ void start_waiting_jobs (void);
|
||||||
|
|
||||||
char **construct_command_argv (char *line, char **restp, struct file *file,
|
char **construct_command_argv (char *line, char **restp, struct file *file,
|
||||||
int cmd_flags, char** batch_file);
|
int cmd_flags, char** batch_file);
|
||||||
|
|
||||||
#ifdef VMS
|
#ifdef VMS
|
||||||
int child_execute_job (char *argv, struct child *child);
|
int child_execute_job (struct child *child, char *argv);
|
||||||
#else
|
#else
|
||||||
# define FD_STDIN (fileno (stdin))
|
# define FD_STDIN (fileno (stdin))
|
||||||
# define FD_STDOUT (fileno (stdout))
|
# define FD_STDOUT (fileno (stdout))
|
||||||
# define FD_STDERR (fileno (stderr))
|
# define FD_STDERR (fileno (stderr))
|
||||||
# if defined(__EMX__)
|
int child_execute_job (struct output *out, int good_stdin, char **argv, char **envp);
|
||||||
int child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
|
|
||||||
char **argv, char **envp);
|
|
||||||
# else
|
|
||||||
void child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
|
|
||||||
char **argv, char **envp) __attribute__ ((noreturn));
|
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _AMIGA
|
#ifdef _AMIGA
|
||||||
void exec_command (char **argv) __attribute__ ((noreturn));
|
void exec_command (char **argv) __attribute__ ((noreturn));
|
||||||
#elif defined(__EMX__)
|
#elif defined(__EMX__)
|
||||||
|
|
3
main.c
3
main.c
|
@ -2417,8 +2417,7 @@ main (int argc, char **argv, char **envp)
|
||||||
termination. */
|
termination. */
|
||||||
int pid;
|
int pid;
|
||||||
int r;
|
int r;
|
||||||
pid = child_execute_job (FD_STDIN, FD_STDOUT, FD_STDERR,
|
pid = child_execute_job (NULL, 1, nargv, environ);
|
||||||
nargv, environ);
|
|
||||||
|
|
||||||
/* is this loop really necessary? */
|
/* is this loop really necessary? */
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -138,6 +138,13 @@ extern int errno;
|
||||||
# define SA_RESTART 0
|
# define SA_RESTART 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_VFORK_H
|
||||||
|
# include <vfork.h>
|
||||||
|
#endif
|
||||||
|
#if !HAVE_WORKING_VFORK
|
||||||
|
# define vfork fork
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIMITS_H
|
#ifdef HAVE_LIMITS_H
|
||||||
# include <limits.h>
|
# include <limits.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
11
os.h
11
os.h
|
@ -69,9 +69,16 @@ int jobserver_acquire (int timeout);
|
||||||
#define jobserver_release(_fatal) (void)(0)
|
#define jobserver_release(_fatal) (void)(0)
|
||||||
#define jobserver_acquire_all() (0)
|
#define jobserver_acquire_all() (0)
|
||||||
#define jobserver_signal() (void)(0)
|
#define jobserver_signal() (void)(0)
|
||||||
#define jobserver_pre_child() (void)(0)
|
#define jobserver_pre_child(_r) (void)(0)
|
||||||
#define jobserver_post_child() (void)(0)
|
#define jobserver_post_child(_r) (void)(0)
|
||||||
#define jobserver_pre_acquire() (void)(0)
|
#define jobserver_pre_acquire() (void)(0)
|
||||||
#define jobserver_acquire(_tmout) (0)
|
#define jobserver_acquire(_tmout) (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Create a "bad" file descriptor for stdin when parallel jobs are run. */
|
||||||
|
#if !defined(VMD) && !defined(WINDOWS32) && !defined(_AMIGA) && !defined(__MSDOS__)
|
||||||
|
int get_bad_stdin ();
|
||||||
|
#else
|
||||||
|
# define get_bad_stdin() (-1)
|
||||||
|
#endif
|
||||||
|
|
66
posixos.c
66
posixos.c
|
@ -174,27 +174,31 @@ jobserver_acquire_all ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is really only invoked on OS/2.
|
/* Prepare the jobserver to start a child process. */
|
||||||
On POSIX we just call jobserver_clear() in the child process. */
|
void jobserver_pre_child (int recursive)
|
||||||
void jobserver_pre_child ()
|
|
||||||
{
|
{
|
||||||
CLOSE_ON_EXEC (job_fds[0]);
|
/* If it's not a recursive make, avoid polutting the jobserver pipes. */
|
||||||
CLOSE_ON_EXEC (job_fds[1]);
|
if (!recursive && job_fds[0] >= 0)
|
||||||
|
{
|
||||||
|
CLOSE_ON_EXEC (job_fds[0]);
|
||||||
|
CLOSE_ON_EXEC (job_fds[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void jobserver_post_child ()
|
void jobserver_post_child (int recursive)
|
||||||
{
|
{
|
||||||
#if defined(F_GETFD) && defined(F_SETFD)
|
#if defined(F_GETFD) && defined(F_SETFD)
|
||||||
for (int i = 0; i < 2; ++i)
|
if (!recursive && job_fds[0] >= 0)
|
||||||
{
|
for (int i = 0; i < 2; ++i)
|
||||||
int flags;
|
{
|
||||||
EINTRLOOP (flags, fcntl (job_fds[i], F_GETFD));
|
int flags;
|
||||||
if (flags >= 0)
|
EINTRLOOP (flags, fcntl (job_fds[i], F_GETFD));
|
||||||
{
|
if (flags >= 0)
|
||||||
int r;
|
{
|
||||||
EINTRLOOP (r, fcntl (job_fds[i], F_SETFD, flags & ~FD_CLOEXEC));
|
int r;
|
||||||
}
|
EINTRLOOP (r, fcntl (job_fds[i], F_SETFD, flags & ~FD_CLOEXEC));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,3 +392,33 @@ jobserver_acquire (int timeout)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* MAKE_JOBSERVER */
|
#endif /* MAKE_JOBSERVER */
|
||||||
|
|
||||||
|
/* Create a "bad" file descriptor for stdin when parallel jobs are run. */
|
||||||
|
int
|
||||||
|
get_bad_stdin ()
|
||||||
|
{
|
||||||
|
static int bad_stdin = -1;
|
||||||
|
|
||||||
|
/* Set up a bad standard input that reads from a broken pipe. */
|
||||||
|
|
||||||
|
if (bad_stdin == -1)
|
||||||
|
{
|
||||||
|
/* Make a file descriptor that is the read end of a broken pipe.
|
||||||
|
This will be used for some children's standard inputs. */
|
||||||
|
int pd[2];
|
||||||
|
if (pipe (pd) == 0)
|
||||||
|
{
|
||||||
|
/* Close the write side. */
|
||||||
|
(void) close (pd[1]);
|
||||||
|
/* Save the read side. */
|
||||||
|
bad_stdin = pd[0];
|
||||||
|
|
||||||
|
/* Set the descriptor to close on exec, so it does not litter any
|
||||||
|
child's descriptor table. When it is dup2'd onto descriptor 0,
|
||||||
|
that descriptor will not close on exec. */
|
||||||
|
CLOSE_ON_EXEC (bad_stdin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bad_stdin;
|
||||||
|
}
|
||||||
|
|
|
@ -222,7 +222,7 @@ start_remote_job (char **argv, char **envp, int stdin_fd,
|
||||||
fflush (stderr);
|
fflush (stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
pid = fork ();
|
pid = vfork ();
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
/* The fork failed! */
|
/* The fork failed! */
|
||||||
|
|
|
@ -803,7 +803,7 @@ build_vms_cmd (char **cmd_tokens,
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
child_execute_job (char *argv, struct child *child)
|
child_execute_job (struct child *child, char *argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
|
@ -148,11 +148,11 @@ jobserver_signal ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void jobserver_pre_child ()
|
void jobserver_pre_child (int recursive)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void jobserver_post_child ()
|
void jobserver_post_child (int recursive)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue