[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:
Paul Smith 2016-03-13 01:12:07 -05:00
parent 14b2d7effb
commit fd1dd7c398
11 changed files with 258 additions and 265 deletions

View file

@ -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.

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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 {

View file

@ -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
View file

@ -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

View file

@ -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;
}

View file

@ -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! */

View file

@ -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;

View file

@ -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)
{ {
} }