mirror of
https://salsa.debian.org/srivasta/make-dfsg.git
synced 2024-12-26 14:00:56 +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
|
||||
#include <signal.h>]])
|
||||
|
||||
AC_FUNC_FORK
|
||||
|
||||
AC_FUNC_SETVBUF_REVERSED
|
||||
|
||||
# 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");
|
||||
return o;
|
||||
}
|
||||
|
||||
#elif defined(WINDOWS32)
|
||||
windows32_openpipe (pipedes, errfd, &pid, command_argv, envp);
|
||||
/* 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");
|
||||
return o;
|
||||
}
|
||||
else
|
||||
|
||||
#else
|
||||
if (pipe (pipedes) < 0)
|
||||
{
|
||||
|
@ -1771,118 +1772,113 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
|||
return o;
|
||||
}
|
||||
|
||||
# ifdef __EMX__
|
||||
/* close some handles that are unnecessary for the child process */
|
||||
/* Close handles that are unnecessary for the child process. */
|
||||
CLOSE_ON_EXEC(pipedes[1]);
|
||||
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__
|
||||
shell_function_completed = 0;
|
||||
shell_function_completed = 0;
|
||||
|
||||
/* Free the storage only the child needed. */
|
||||
free (command_argv[0]);
|
||||
free (command_argv);
|
||||
/* Free the storage only the child needed. */
|
||||
free (command_argv[0]);
|
||||
free (command_argv);
|
||||
|
||||
/* Close the write side of the pipe. We test for -1, since
|
||||
pipedes[1] is -1 on MS-Windows, and some versions of MS
|
||||
libraries barf when 'close' is called with -1. */
|
||||
if (pipedes[1] >= 0)
|
||||
close (pipedes[1]);
|
||||
/* Close the write side of the pipe. We test for -1, since
|
||||
pipedes[1] is -1 on MS-Windows, and some versions of MS
|
||||
libraries barf when 'close' is called with -1. */
|
||||
if (pipedes[1] >= 0)
|
||||
close (pipedes[1]);
|
||||
#endif
|
||||
|
||||
/* Set up and read from the pipe. */
|
||||
/* Set up and read from the pipe. */
|
||||
|
||||
maxlen = 200;
|
||||
buffer = xmalloc (maxlen + 1);
|
||||
maxlen = 200;
|
||||
buffer = xmalloc (maxlen + 1);
|
||||
|
||||
/* Read from the pipe until it gets EOF. */
|
||||
for (i = 0; ; i += cc)
|
||||
{
|
||||
if (i == maxlen)
|
||||
{
|
||||
maxlen += 512;
|
||||
buffer = xrealloc (buffer, maxlen + 1);
|
||||
}
|
||||
/* Read from the pipe until it gets EOF. */
|
||||
for (i = 0; ; i += cc)
|
||||
{
|
||||
if (i == maxlen)
|
||||
{
|
||||
maxlen += 512;
|
||||
buffer = xrealloc (buffer, maxlen + 1);
|
||||
}
|
||||
|
||||
EINTRLOOP (cc, read (pipedes[0], &buffer[i], maxlen - i));
|
||||
if (cc <= 0)
|
||||
break;
|
||||
}
|
||||
buffer[i] = '\0';
|
||||
EINTRLOOP (cc, read (pipedes[0], &buffer[i], maxlen - i));
|
||||
if (cc <= 0)
|
||||
break;
|
||||
}
|
||||
buffer[i] = '\0';
|
||||
|
||||
/* Close the read side of the pipe. */
|
||||
/* Close the read side of the pipe. */
|
||||
#ifdef __MSDOS__
|
||||
if (fpipe)
|
||||
{
|
||||
int st = pclose (fpipe);
|
||||
shell_completed (st, 0);
|
||||
}
|
||||
if (fpipe)
|
||||
{
|
||||
int st = pclose (fpipe);
|
||||
shell_completed (st, 0);
|
||||
}
|
||||
#else
|
||||
(void) close (pipedes[0]);
|
||||
(void) close (pipedes[0]);
|
||||
#endif
|
||||
|
||||
/* Loop until child_handler or reap_children() sets
|
||||
shell_function_completed to the status of our child shell. */
|
||||
while (shell_function_completed == 0)
|
||||
reap_children (1, 0);
|
||||
/* Loop until child_handler or reap_children() sets
|
||||
shell_function_completed to the status of our child shell. */
|
||||
while (shell_function_completed == 0)
|
||||
reap_children (1, 0);
|
||||
|
||||
if (batch_filename)
|
||||
{
|
||||
DB (DB_VERBOSE, (_("Cleaning up temporary batch file %s\n"),
|
||||
batch_filename));
|
||||
remove (batch_filename);
|
||||
free (batch_filename);
|
||||
}
|
||||
shell_function_pid = 0;
|
||||
if (batch_filename)
|
||||
{
|
||||
DB (DB_VERBOSE, (_("Cleaning up temporary batch file %s\n"),
|
||||
batch_filename));
|
||||
remove (batch_filename);
|
||||
free (batch_filename);
|
||||
}
|
||||
shell_function_pid = 0;
|
||||
|
||||
/* 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
|
||||
most likely an exec fail. */
|
||||
/* 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
|
||||
most likely an exec fail. */
|
||||
|
||||
if (shell_function_completed == -1)
|
||||
{
|
||||
/* This likely means that the execvp failed, so we should just
|
||||
write the error message in the pipe from the child. */
|
||||
fputs (buffer, stderr);
|
||||
fflush (stderr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The child finished normally. Replace all newlines in its output
|
||||
with spaces, and put that in the variable output buffer. */
|
||||
fold_newlines (buffer, &i, trim_newlines);
|
||||
o = variable_buffer_output (o, buffer, i);
|
||||
}
|
||||
if (shell_function_completed == -1)
|
||||
{
|
||||
/* This likely means that the execvp failed, so we should just
|
||||
write the error message in the pipe from the child. */
|
||||
fputs (buffer, stderr);
|
||||
fflush (stderr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The child finished normally. Replace all newlines in its output
|
||||
with spaces, and put that in the variable output buffer. */
|
||||
fold_newlines (buffer, &i, trim_newlines);
|
||||
o = variable_buffer_output (o, buffer, i);
|
||||
}
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
free (buffer);
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
|
230
job.c
230
job.c
|
@ -1074,17 +1074,12 @@ unblock_sigs (void)
|
|||
static void
|
||||
start_job_command (struct child *child)
|
||||
{
|
||||
#if !defined(_AMIGA) && !defined(WINDOWS32)
|
||||
static int bad_stdin = -1;
|
||||
#endif
|
||||
int flags;
|
||||
char *p;
|
||||
#ifdef VMS
|
||||
char *argv;
|
||||
#else
|
||||
char **argv;
|
||||
int outfd = FD_STDOUT;
|
||||
int errfd = FD_STDERR;
|
||||
#endif
|
||||
|
||||
/* If we have a completely empty commandset, stop now. */
|
||||
|
@ -1328,32 +1323,6 @@ start_job_command (struct child *child)
|
|||
fflush (stdout);
|
||||
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
|
||||
(one that points to the terminal or whatever), or the 'bad' one
|
||||
that points to the read side of a broken pipe. */
|
||||
|
@ -1362,8 +1331,6 @@ start_job_command (struct child *child)
|
|||
if (child->good_stdin)
|
||||
good_stdin_used = 1;
|
||||
|
||||
#endif /* !VMS */
|
||||
|
||||
child->deleted = 0;
|
||||
|
||||
#ifndef _AMIGA
|
||||
|
@ -1380,7 +1347,7 @@ start_job_command (struct child *child)
|
|||
{
|
||||
int is_remote, id, used_stdin;
|
||||
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))
|
||||
/* Don't give up; remote execution may fail for various reasons. If
|
||||
so, simply run the job locally. */
|
||||
|
@ -1409,7 +1376,7 @@ start_job_command (struct child *child)
|
|||
child->remote = 0;
|
||||
|
||||
#ifdef VMS
|
||||
if (!child_execute_job (argv, child))
|
||||
if (!child_execute_job (child, argv))
|
||||
{
|
||||
/* Fork failed! */
|
||||
perror_with_name ("fork", "");
|
||||
|
@ -1420,68 +1387,20 @@ start_job_command (struct child *child)
|
|||
|
||||
parent_environ = environ;
|
||||
|
||||
#ifndef NO_OUTPUT_SYNC
|
||||
/* 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 ();
|
||||
jobserver_pre_child (flags & COMMANDS_RECURSE);
|
||||
|
||||
/* Never use fork()/exec() here! Use spawn() instead in exec_command() */
|
||||
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;
|
||||
}
|
||||
child->pid = child_execute_job (&child->output, child->good_stdin, argv, child->environment);
|
||||
|
||||
/* 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. */
|
||||
if (child->pid == 0)
|
||||
{
|
||||
/* We are the child side. */
|
||||
unblock_sigs ();
|
||||
jobserver_post_child (flags & COMMANDS_RECURSE);
|
||||
|
||||
/* If we AREN'T running a recursive command and we have a jobserver,
|
||||
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)
|
||||
if (child->pid < 0)
|
||||
{
|
||||
/* Fork failed! */
|
||||
unblock_sigs ();
|
||||
perror_with_name ("fork", "");
|
||||
goto error;
|
||||
}
|
||||
# endif /* !__EMX__ */
|
||||
#endif /* !VMS */
|
||||
}
|
||||
|
||||
|
@ -1557,6 +1476,8 @@ start_job_command (struct child *child)
|
|||
{
|
||||
HANDLE hPID;
|
||||
char* arg0;
|
||||
int outfd = FD_STDOUT;
|
||||
int errfd = FD_STDERR;
|
||||
|
||||
/* make UNC paths safe for CreateProcess -- backslash format */
|
||||
arg0 = argv[0];
|
||||
|
@ -2098,82 +2019,95 @@ start_waiting_jobs (void)
|
|||
/* EMX: Start a child process. This function returns the new pid. */
|
||||
# if defined __EMX__
|
||||
int
|
||||
child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
|
||||
char **argv, char **envp)
|
||||
child_execute_job (struct output *out, int good_stdin, char **argv, char **envp)
|
||||
{
|
||||
int pid;
|
||||
int save_stdin = -1;
|
||||
int save_stdout = -1;
|
||||
int save_stderr = -1;
|
||||
int fdin = good_stdin ? FD_STDIN : get_bad_stdin ();
|
||||
int fdout = FD_STDOUT;
|
||||
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
|
||||
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
|
||||
as close on exec. */
|
||||
if (stdin_fd != FD_STDIN)
|
||||
if (fdin != FD_STDIN)
|
||||
{
|
||||
save_stdin = dup (FD_STDIN);
|
||||
if (save_stdin < 0)
|
||||
save_fdin = dup (FD_STDIN);
|
||||
if (save_fdin < 0)
|
||||
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);
|
||||
CLOSE_ON_EXEC (stdin_fd);
|
||||
dup2 (fdin, FD_STDIN);
|
||||
CLOSE_ON_EXEC (fdin);
|
||||
}
|
||||
|
||||
if (stdout_fd != FD_STDOUT)
|
||||
if (fdout != FD_STDOUT)
|
||||
{
|
||||
save_stdout = dup (FD_STDOUT);
|
||||
if (save_stdout < 0)
|
||||
save_fdout = dup (FD_STDOUT);
|
||||
if (save_fdout < 0)
|
||||
O (fatal, NILF,
|
||||
_("no more file handles: could not duplicate stdout\n"));
|
||||
CLOSE_ON_EXEC (save_stdout);
|
||||
CLOSE_ON_EXEC (save_fdout);
|
||||
|
||||
dup2 (stdout_fd, FD_STDOUT);
|
||||
CLOSE_ON_EXEC (stdout_fd);
|
||||
dup2 (fdout, FD_STDOUT);
|
||||
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);
|
||||
if (save_stderr < 0)
|
||||
save_fderr = dup (FD_STDERR);
|
||||
if (save_fderr < 0)
|
||||
O (fatal, NILF,
|
||||
_("no more file handles: could not duplicate stderr\n"));
|
||||
CLOSE_ON_EXEC (save_stderr);
|
||||
CLOSE_ON_EXEC (save_fderr);
|
||||
}
|
||||
|
||||
dup2 (stderr_fd, FD_STDERR);
|
||||
CLOSE_ON_EXEC (stderr_fd);
|
||||
dup2 (fderr, FD_STDERR);
|
||||
CLOSE_ON_EXEC (fderr);
|
||||
}
|
||||
|
||||
/* Run the command. */
|
||||
pid = exec_command (argv, envp);
|
||||
|
||||
/* 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"));
|
||||
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"));
|
||||
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"));
|
||||
else
|
||||
close (save_stderr);
|
||||
close (save_fderr);
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
/* UNIX:
|
||||
Replace the current process with one 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. This function does not return. */
|
||||
void
|
||||
child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
|
||||
char **argv, char **envp)
|
||||
/* POSIX:
|
||||
Create a child process executing the command in ARGV.
|
||||
ENVP is the environment of the new program. Returns the PID or -1. */
|
||||
int
|
||||
child_execute_job (struct output *out, int good_stdin, char **argv, char **envp)
|
||||
{
|
||||
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. */
|
||||
if (stdin_fd != FD_STDIN)
|
||||
#ifndef NO_OUTPUT_SYNC
|
||||
/* Divert child output if output_sync in use. */
|
||||
if (out && out->syncout)
|
||||
{
|
||||
EINTRLOOP (r, dup2 (stdin_fd, FD_STDIN));
|
||||
close (stdin_fd);
|
||||
if (out->out >= 0)
|
||||
fdout = out->out;
|
||||
if (out->err >= 0)
|
||||
fderr = out->err;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (stdout_fd != FD_STDOUT)
|
||||
EINTRLOOP (r, dup2 (stdout_fd, FD_STDOUT));
|
||||
if (stderr_fd != FD_STDERR)
|
||||
EINTRLOOP (r, dup2 (stderr_fd, FD_STDERR));
|
||||
pid = vfork();
|
||||
if (pid != 0)
|
||||
return pid;
|
||||
|
||||
if (stdout_fd != FD_STDOUT)
|
||||
close (stdout_fd);
|
||||
if (stderr_fd != FD_STDERR && stderr_fd != stdout_fd)
|
||||
close (stderr_fd);
|
||||
/* We are the child. */
|
||||
unblock_sigs ();
|
||||
|
||||
#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. */
|
||||
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. */
|
||||
|
||||
#if !defined F_SETFD
|
||||
#if !defined(F_SETFD) || !defined(F_GETFD)
|
||||
# ifdef WINDOWS32
|
||||
# define CLOSE_ON_EXEC(_d) process_noinherit(_d)
|
||||
# else
|
||||
|
@ -124,20 +124,16 @@ void start_waiting_jobs (void);
|
|||
|
||||
char **construct_command_argv (char *line, char **restp, struct file *file,
|
||||
int cmd_flags, char** batch_file);
|
||||
|
||||
#ifdef VMS
|
||||
int child_execute_job (char *argv, struct child *child);
|
||||
int child_execute_job (struct child *child, char *argv);
|
||||
#else
|
||||
# define FD_STDIN (fileno (stdin))
|
||||
# define FD_STDOUT (fileno (stdout))
|
||||
# define FD_STDERR (fileno (stderr))
|
||||
# if defined(__EMX__)
|
||||
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
|
||||
int child_execute_job (struct output *out, int good_stdin, char **argv, char **envp);
|
||||
#endif
|
||||
|
||||
#ifdef _AMIGA
|
||||
void exec_command (char **argv) __attribute__ ((noreturn));
|
||||
#elif defined(__EMX__)
|
||||
|
|
3
main.c
3
main.c
|
@ -2417,8 +2417,7 @@ main (int argc, char **argv, char **envp)
|
|||
termination. */
|
||||
int pid;
|
||||
int r;
|
||||
pid = child_execute_job (FD_STDIN, FD_STDOUT, FD_STDERR,
|
||||
nargv, environ);
|
||||
pid = child_execute_job (NULL, 1, nargv, environ);
|
||||
|
||||
/* is this loop really necessary? */
|
||||
do {
|
||||
|
|
|
@ -138,6 +138,13 @@ extern int errno;
|
|||
# define SA_RESTART 0
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VFORK_H
|
||||
# include <vfork.h>
|
||||
#endif
|
||||
#if !HAVE_WORKING_VFORK
|
||||
# define vfork fork
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
|
11
os.h
11
os.h
|
@ -69,9 +69,16 @@ int jobserver_acquire (int timeout);
|
|||
#define jobserver_release(_fatal) (void)(0)
|
||||
#define jobserver_acquire_all() (0)
|
||||
#define jobserver_signal() (void)(0)
|
||||
#define jobserver_pre_child() (void)(0)
|
||||
#define jobserver_post_child() (void)(0)
|
||||
#define jobserver_pre_child(_r) (void)(0)
|
||||
#define jobserver_post_child(_r) (void)(0)
|
||||
#define jobserver_pre_acquire() (void)(0)
|
||||
#define jobserver_acquire(_tmout) (0)
|
||||
|
||||
#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.
|
||||
On POSIX we just call jobserver_clear() in the child process. */
|
||||
void jobserver_pre_child ()
|
||||
/* Prepare the jobserver to start a child process. */
|
||||
void jobserver_pre_child (int recursive)
|
||||
{
|
||||
CLOSE_ON_EXEC (job_fds[0]);
|
||||
CLOSE_ON_EXEC (job_fds[1]);
|
||||
/* If it's not a recursive make, avoid polutting the jobserver pipes. */
|
||||
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)
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
int flags;
|
||||
EINTRLOOP (flags, fcntl (job_fds[i], F_GETFD));
|
||||
if (flags >= 0)
|
||||
{
|
||||
int r;
|
||||
EINTRLOOP (r, fcntl (job_fds[i], F_SETFD, flags & ~FD_CLOEXEC));
|
||||
}
|
||||
}
|
||||
if (!recursive && job_fds[0] >= 0)
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
int flags;
|
||||
EINTRLOOP (flags, fcntl (job_fds[i], F_GETFD));
|
||||
if (flags >= 0)
|
||||
{
|
||||
int r;
|
||||
EINTRLOOP (r, fcntl (job_fds[i], F_SETFD, flags & ~FD_CLOEXEC));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -388,3 +392,33 @@ jobserver_acquire (int timeout)
|
|||
#endif
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
pid = fork ();
|
||||
pid = vfork ();
|
||||
if (pid < 0)
|
||||
{
|
||||
/* The fork failed! */
|
||||
|
|
|
@ -803,7 +803,7 @@ build_vms_cmd (char **cmd_tokens,
|
|||
}
|
||||
|
||||
int
|
||||
child_execute_job (char *argv, struct child *child)
|
||||
child_execute_job (struct child *child, char *argv)
|
||||
{
|
||||
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