Use spawnve on cygwin.
* configure.ac (AC_CHECK_HEADERS): Add process.h. (checkfuncs): Add dup3, spawnve, spawnvpe; sort the list. (AC_CHECK_FUNCS): Add dup3, spawnve, spawnvpe. * configure, config.in: Rebuild. * pex-unix.c [HAVE_SPAWNVE] (pex_unix_exec_child): New function. [HAVE_SPAWNVE] (save_and_install_fd, restore_fd): New functions.
This commit is contained in:
parent
f445451a1f
commit
9c55e06476
5 changed files with 237 additions and 13 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
2010-11-04 Richard Henderson <rth@redhat.com>
|
||||||
|
|
||||||
|
* configure.ac (AC_CHECK_HEADERS): Add process.h.
|
||||||
|
(checkfuncs): Add dup3, spawnve, spawnvpe; sort the list.
|
||||||
|
(AC_CHECK_FUNCS): Add dup3, spawnve, spawnvpe.
|
||||||
|
* configure, config.in: Rebuild.
|
||||||
|
* pex-unix.c [HAVE_SPAWNVE] (pex_unix_exec_child): New function.
|
||||||
|
[HAVE_SPAWNVE] (save_and_install_fd, restore_fd): New functions.
|
||||||
|
|
||||||
2010-11-02 Ian Lance Taylor <iant@google.com>
|
2010-11-02 Ian Lance Taylor <iant@google.com>
|
||||||
Dave Korn <dave.korn.cygwin@gmail.com>
|
Dave Korn <dave.korn.cygwin@gmail.com>
|
||||||
Iain Sandoe <iains@gcc.gnu.org>
|
Iain Sandoe <iains@gcc.gnu.org>
|
||||||
|
|
|
@ -91,6 +91,9 @@
|
||||||
don't. */
|
don't. */
|
||||||
#undef HAVE_DECL_VSNPRINTF
|
#undef HAVE_DECL_VSNPRINTF
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `dup3' function. */
|
||||||
|
#undef HAVE_DUP3
|
||||||
|
|
||||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||||
#undef HAVE_FCNTL_H
|
#undef HAVE_FCNTL_H
|
||||||
|
|
||||||
|
@ -169,6 +172,9 @@
|
||||||
/* Define if you have prctl PR_SET_NAME */
|
/* Define if you have prctl PR_SET_NAME */
|
||||||
#undef HAVE_PRCTL_SET_NAME
|
#undef HAVE_PRCTL_SET_NAME
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <process.h> header file. */
|
||||||
|
#undef HAVE_PROCESS_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `psignal' function. */
|
/* Define to 1 if you have the `psignal' function. */
|
||||||
#undef HAVE_PSIGNAL
|
#undef HAVE_PSIGNAL
|
||||||
|
|
||||||
|
@ -208,6 +214,12 @@
|
||||||
/* Define to 1 if you have the `snprintf' function. */
|
/* Define to 1 if you have the `snprintf' function. */
|
||||||
#undef HAVE_SNPRINTF
|
#undef HAVE_SNPRINTF
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `spawnve' function. */
|
||||||
|
#undef HAVE_SPAWNVE
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `spawnvpe' function. */
|
||||||
|
#undef HAVE_SPAWNVPE
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdint.h> header file. */
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
#undef HAVE_STDINT_H
|
#undef HAVE_STDINT_H
|
||||||
|
|
||||||
|
|
14
libiberty/configure
vendored
14
libiberty/configure
vendored
|
@ -4895,7 +4895,7 @@ host_makefile_frag=${frag}
|
||||||
# It's OK to check for header files. Although the compiler may not be
|
# It's OK to check for header files. Although the compiler may not be
|
||||||
# able to link anything, it had better be able to at least compile
|
# able to link anything, it had better be able to at least compile
|
||||||
# something.
|
# something.
|
||||||
for ac_header in sys/file.h sys/param.h limits.h stdlib.h malloc.h string.h unistd.h strings.h sys/time.h time.h sys/resource.h sys/stat.h sys/mman.h fcntl.h alloca.h sys/pstat.h sys/sysmp.h sys/sysinfo.h machine/hal_sysinfo.h sys/table.h sys/sysctl.h sys/systemcfg.h stdint.h stdio_ext.h
|
for ac_header in sys/file.h sys/param.h limits.h stdlib.h malloc.h string.h unistd.h strings.h sys/time.h time.h sys/resource.h sys/stat.h sys/mman.h fcntl.h alloca.h sys/pstat.h sys/sysmp.h sys/sysinfo.h machine/hal_sysinfo.h sys/table.h sys/sysctl.h sys/systemcfg.h stdint.h stdio_ext.h process.h
|
||||||
do :
|
do :
|
||||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||||
ac_fn_c_check_header_preproc "$LINENO" "$ac_header" "$as_ac_Header"
|
ac_fn_c_check_header_preproc "$LINENO" "$ac_header" "$as_ac_Header"
|
||||||
|
@ -5293,9 +5293,10 @@ funcs="$funcs setproctitle"
|
||||||
|
|
||||||
vars="sys_errlist sys_nerr sys_siglist"
|
vars="sys_errlist sys_nerr sys_siglist"
|
||||||
|
|
||||||
checkfuncs="getrusage on_exit psignal strerror strsignal sysconf times sbrk gettimeofday"
|
checkfuncs="__fsetlocking canonicalize_file_name dup3 getrusage getsysinfo \
|
||||||
checkfuncs="$checkfuncs realpath canonicalize_file_name pstat_getstatic pstat_getdynamic sysmp"
|
gettimeofday on_exit psignal pstat_getdynamic pstat_getstatic realpath \
|
||||||
checkfuncs="$checkfuncs getsysinfo table sysctl wait3 wait4 __fsetlocking"
|
sbrk spawnve spawnvpe strerror strsignal sysconf sysctl sysmp table \
|
||||||
|
times wait3 wait4"
|
||||||
|
|
||||||
# These are neither executed nor required, but they help keep
|
# These are neither executed nor required, but they help keep
|
||||||
# autoheader happy without adding a bunch of text to acconfig.h.
|
# autoheader happy without adding a bunch of text to acconfig.h.
|
||||||
|
@ -5303,6 +5304,7 @@ if test "x" = "y"; then
|
||||||
for ac_func in asprintf atexit \
|
for ac_func in asprintf atexit \
|
||||||
basename bcmp bcopy bsearch bzero \
|
basename bcmp bcopy bsearch bzero \
|
||||||
calloc canonicalize_file_name clock \
|
calloc canonicalize_file_name clock \
|
||||||
|
dup3 \
|
||||||
ffs __fsetlocking \
|
ffs __fsetlocking \
|
||||||
getcwd getpagesize getrusage getsysinfo gettimeofday \
|
getcwd getpagesize getrusage getsysinfo gettimeofday \
|
||||||
index insque \
|
index insque \
|
||||||
|
@ -5310,8 +5312,8 @@ if test "x" = "y"; then
|
||||||
on_exit \
|
on_exit \
|
||||||
psignal pstat_getdynamic pstat_getstatic putenv \
|
psignal pstat_getdynamic pstat_getstatic putenv \
|
||||||
random realpath rename rindex \
|
random realpath rename rindex \
|
||||||
sbrk setenv setproctitle sigsetmask snprintf stpcpy stpncpy strcasecmp strchr \
|
sbrk setenv setproctitle sigsetmask snprintf spawnve spawnvpe \
|
||||||
strdup \
|
stpcpy stpncpy strcasecmp strchr strdup \
|
||||||
strerror strncasecmp strndup strrchr strsignal strstr strtod strtol \
|
strerror strncasecmp strndup strrchr strsignal strstr strtod strtol \
|
||||||
strtoul strverscmp sysconf sysctl sysmp \
|
strtoul strverscmp sysconf sysctl sysmp \
|
||||||
table times tmpnam \
|
table times tmpnam \
|
||||||
|
|
|
@ -246,7 +246,7 @@ AC_SUBST_FILE(host_makefile_frag)
|
||||||
# It's OK to check for header files. Although the compiler may not be
|
# It's OK to check for header files. Although the compiler may not be
|
||||||
# able to link anything, it had better be able to at least compile
|
# able to link anything, it had better be able to at least compile
|
||||||
# something.
|
# something.
|
||||||
AC_CHECK_HEADERS(sys/file.h sys/param.h limits.h stdlib.h malloc.h string.h unistd.h strings.h sys/time.h time.h sys/resource.h sys/stat.h sys/mman.h fcntl.h alloca.h sys/pstat.h sys/sysmp.h sys/sysinfo.h machine/hal_sysinfo.h sys/table.h sys/sysctl.h sys/systemcfg.h stdint.h stdio_ext.h)
|
AC_CHECK_HEADERS(sys/file.h sys/param.h limits.h stdlib.h malloc.h string.h unistd.h strings.h sys/time.h time.h sys/resource.h sys/stat.h sys/mman.h fcntl.h alloca.h sys/pstat.h sys/sysmp.h sys/sysinfo.h machine/hal_sysinfo.h sys/table.h sys/sysctl.h sys/systemcfg.h stdint.h stdio_ext.h process.h)
|
||||||
AC_HEADER_SYS_WAIT
|
AC_HEADER_SYS_WAIT
|
||||||
AC_HEADER_TIME
|
AC_HEADER_TIME
|
||||||
|
|
||||||
|
@ -358,9 +358,10 @@ funcs="$funcs setproctitle"
|
||||||
|
|
||||||
vars="sys_errlist sys_nerr sys_siglist"
|
vars="sys_errlist sys_nerr sys_siglist"
|
||||||
|
|
||||||
checkfuncs="getrusage on_exit psignal strerror strsignal sysconf times sbrk gettimeofday"
|
checkfuncs="__fsetlocking canonicalize_file_name dup3 getrusage getsysinfo \
|
||||||
checkfuncs="$checkfuncs realpath canonicalize_file_name pstat_getstatic pstat_getdynamic sysmp"
|
gettimeofday on_exit psignal pstat_getdynamic pstat_getstatic realpath \
|
||||||
checkfuncs="$checkfuncs getsysinfo table sysctl wait3 wait4 __fsetlocking"
|
sbrk spawnve spawnvpe strerror strsignal sysconf sysctl sysmp table \
|
||||||
|
times wait3 wait4"
|
||||||
|
|
||||||
# These are neither executed nor required, but they help keep
|
# These are neither executed nor required, but they help keep
|
||||||
# autoheader happy without adding a bunch of text to acconfig.h.
|
# autoheader happy without adding a bunch of text to acconfig.h.
|
||||||
|
@ -368,6 +369,7 @@ if test "x" = "y"; then
|
||||||
AC_CHECK_FUNCS(asprintf atexit \
|
AC_CHECK_FUNCS(asprintf atexit \
|
||||||
basename bcmp bcopy bsearch bzero \
|
basename bcmp bcopy bsearch bzero \
|
||||||
calloc canonicalize_file_name clock \
|
calloc canonicalize_file_name clock \
|
||||||
|
dup3 \
|
||||||
ffs __fsetlocking \
|
ffs __fsetlocking \
|
||||||
getcwd getpagesize getrusage getsysinfo gettimeofday \
|
getcwd getpagesize getrusage getsysinfo gettimeofday \
|
||||||
index insque \
|
index insque \
|
||||||
|
@ -375,8 +377,8 @@ if test "x" = "y"; then
|
||||||
on_exit \
|
on_exit \
|
||||||
psignal pstat_getdynamic pstat_getstatic putenv \
|
psignal pstat_getdynamic pstat_getstatic putenv \
|
||||||
random realpath rename rindex \
|
random realpath rename rindex \
|
||||||
sbrk setenv setproctitle sigsetmask snprintf stpcpy stpncpy strcasecmp strchr \
|
sbrk setenv setproctitle sigsetmask snprintf spawnve spawnvpe \
|
||||||
strdup \
|
stpcpy stpncpy strcasecmp strchr strdup \
|
||||||
strerror strncasecmp strndup strrchr strsignal strstr strtod strtol \
|
strerror strncasecmp strndup strrchr strsignal strstr strtod strtol \
|
||||||
strtoul strverscmp sysconf sysctl sysmp \
|
strtoul strverscmp sysconf sysctl sysmp \
|
||||||
table times tmpnam \
|
table times tmpnam \
|
||||||
|
|
|
@ -55,7 +55,9 @@ extern int errno;
|
||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_PROCESS_H
|
||||||
|
#include <process.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef vfork /* Autoconf may define this to fork for us. */
|
#ifdef vfork /* Autoconf may define this to fork for us. */
|
||||||
# define VFORK_STRING "fork"
|
# define VFORK_STRING "fork"
|
||||||
|
@ -387,6 +389,202 @@ pex_child_error (struct pex_obj *obj, const char *executable,
|
||||||
|
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
|
|
||||||
|
#if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE)
|
||||||
|
/* Implementation of pex->exec_child using the Cygwin spawn operation. */
|
||||||
|
|
||||||
|
/* Subroutine of pex_unix_exec_child. Move OLD_FD to a new file descriptor
|
||||||
|
to be stored in *PNEW_FD, save the flags in *PFLAGS, and arrange for the
|
||||||
|
saved copy to be close-on-exec. Move CHILD_FD into OLD_FD. If CHILD_FD
|
||||||
|
is -1, OLD_FD is to be closed. Return -1 on error. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
save_and_install_fd(int *pnew_fd, int *pflags, int old_fd, int child_fd)
|
||||||
|
{
|
||||||
|
int new_fd, flags;
|
||||||
|
|
||||||
|
flags = fcntl (old_fd, F_GETFD);
|
||||||
|
|
||||||
|
/* If we could not retrieve the flags, then OLD_FD was not open. */
|
||||||
|
if (flags < 0)
|
||||||
|
{
|
||||||
|
new_fd = -1, flags = 0;
|
||||||
|
if (child_fd >= 0 && dup2 (child_fd, old_fd) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* If we wish to close OLD_FD, just mark it CLOEXEC. */
|
||||||
|
else if (child_fd == -1)
|
||||||
|
{
|
||||||
|
new_fd = old_fd;
|
||||||
|
if ((flags & FD_CLOEXEC) == 0 && fcntl (old_fd, F_SETFD, FD_CLOEXEC) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Otherwise we need to save a copy of OLD_FD before installing CHILD_FD. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef F_DUPFD_CLOEXEC
|
||||||
|
new_fd = fcntl (old_fd, F_DUPFD_CLOEXEC, 3);
|
||||||
|
if (new_fd < 0)
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
/* Prefer F_DUPFD over dup in order to avoid getting a new fd
|
||||||
|
in the range 0-2, right where a new stderr fd might get put. */
|
||||||
|
new_fd = fcntl (old_fd, F_DUPFD, 3);
|
||||||
|
if (new_fd < 0)
|
||||||
|
return -1;
|
||||||
|
if (fcntl (new_fd, F_SETFD, FD_CLOEXEC) < 0)
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
if (dup2 (child_fd, old_fd) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pflags = flags;
|
||||||
|
if (pnew_fd)
|
||||||
|
*pnew_fd = new_fd;
|
||||||
|
else if (new_fd != old_fd)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subroutine of pex_unix_exec_child. Move SAVE_FD back to OLD_FD
|
||||||
|
restoring FLAGS. If SAVE_FD < 0, OLD_FD is to be closed. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
restore_fd(int old_fd, int save_fd, int flags)
|
||||||
|
{
|
||||||
|
/* For SAVE_FD < 0, all we have to do is restore the
|
||||||
|
"closed-ness" of the original. */
|
||||||
|
if (save_fd < 0)
|
||||||
|
return close (old_fd);
|
||||||
|
|
||||||
|
/* For SAVE_FD == OLD_FD, all we have to do is restore the
|
||||||
|
original setting of the CLOEXEC flag. */
|
||||||
|
if (save_fd == old_fd)
|
||||||
|
{
|
||||||
|
if (flags & FD_CLOEXEC)
|
||||||
|
return 0;
|
||||||
|
return fcntl (old_fd, F_SETFD, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise we have to move the descriptor back, restore the flags,
|
||||||
|
and close the saved copy. */
|
||||||
|
#ifdef HAVE_DUP3
|
||||||
|
if (flags == FD_CLOEXEC)
|
||||||
|
{
|
||||||
|
if (dup3 (save_fd, old_fd, O_CLOEXEC) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (dup2 (save_fd, old_fd) < 0)
|
||||||
|
return -1;
|
||||||
|
if (flags != 0 && fcntl (old_fd, F_SETFD, flags) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return close (save_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pid_t
|
||||||
|
pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED,
|
||||||
|
int flags, const char *executable,
|
||||||
|
char * const * argv, char * const * env,
|
||||||
|
int in, int out, int errdes, int toclose,
|
||||||
|
const char **errmsg, int *err)
|
||||||
|
{
|
||||||
|
int fl_in = 0, fl_out = 0, fl_err = 0, fl_tc = 0;
|
||||||
|
int save_in = -1, save_out = -1, save_err = -1;
|
||||||
|
int max, retries;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
if (flags & PEX_STDERR_TO_STDOUT)
|
||||||
|
errdes = out;
|
||||||
|
|
||||||
|
/* We need the three standard file descriptors to be set up as for
|
||||||
|
the child before we perform the spawn. The file descriptors for
|
||||||
|
the parent need to be moved and marked for close-on-exec. */
|
||||||
|
if (in != STDIN_FILE_NO
|
||||||
|
&& save_and_install_fd (&save_in, &fl_in, STDIN_FILE_NO, in) < 0)
|
||||||
|
goto error_dup2;
|
||||||
|
if (out != STDOUT_FILE_NO
|
||||||
|
&& save_and_install_fd (&save_out, &fl_out, STDOUT_FILE_NO, out) < 0)
|
||||||
|
goto error_dup2;
|
||||||
|
if (errdes != STDERR_FILE_NO
|
||||||
|
&& save_and_install_fd (&save_err, &fl_err, STDERR_FILE_NO, errdes) < 0)
|
||||||
|
goto error_dup2;
|
||||||
|
if (toclose >= 0
|
||||||
|
&& save_and_install_fd (NULL, &fl_tc, toclose, -1) < 0)
|
||||||
|
goto error_dup2;
|
||||||
|
|
||||||
|
/* Now that we've moved the file descriptors for the child into place,
|
||||||
|
close the originals. Be careful not to close any of the standard
|
||||||
|
file descriptors that we just set up. */
|
||||||
|
max = -1;
|
||||||
|
if (errdes >= 0)
|
||||||
|
max = STDERR_FILE_NO;
|
||||||
|
else if (out >= 0)
|
||||||
|
max = STDOUT_FILE_NO;
|
||||||
|
else if (in >= 0)
|
||||||
|
max = STDIN_FILE_NO;
|
||||||
|
if (in > max)
|
||||||
|
close (in);
|
||||||
|
if (out > max)
|
||||||
|
close (out);
|
||||||
|
if (errdes > max && errdes != out)
|
||||||
|
close (errdes);
|
||||||
|
|
||||||
|
/* If we were not given an environment, use the global environment. */
|
||||||
|
if (env == NULL)
|
||||||
|
env = environ;
|
||||||
|
|
||||||
|
/* Launch the program. If we get EAGAIN (normally out of pid's), try
|
||||||
|
again a few times with increasing backoff times. */
|
||||||
|
retries = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
typedef const char * const *cc_cp;
|
||||||
|
|
||||||
|
if (flags & PEX_SEARCH)
|
||||||
|
pid = spawnvpe (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
|
||||||
|
else
|
||||||
|
pid = spawnve (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
|
||||||
|
|
||||||
|
if (pid > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
*err = errno;
|
||||||
|
*errmsg = "spawn";
|
||||||
|
if (errno != EAGAIN || ++retries == 4)
|
||||||
|
return (pid_t) -1;
|
||||||
|
sleep (1 << retries);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success. Restore the parent's file descriptors that we saved above. */
|
||||||
|
if (toclose >= 0
|
||||||
|
&& restore_fd (toclose, toclose, fl_tc) < 0)
|
||||||
|
goto error_dup2;
|
||||||
|
if (in != STDIN_FILE_NO
|
||||||
|
&& restore_fd (STDIN_FILE_NO, save_in, fl_in) < 0)
|
||||||
|
goto error_dup2;
|
||||||
|
if (out != STDOUT_FILE_NO
|
||||||
|
&& restore_fd (STDOUT_FILE_NO, save_out, fl_out) < 0)
|
||||||
|
goto error_dup2;
|
||||||
|
if (errdes != STDERR_FILE_NO
|
||||||
|
&& restore_fd (STDERR_FILE_NO, save_err, fl_err) < 0)
|
||||||
|
goto error_dup2;
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
|
||||||
|
error_dup2:
|
||||||
|
*err = errno;
|
||||||
|
*errmsg = "dup2";
|
||||||
|
return (pid_t) -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* Implementation of pex->exec_child using standard vfork + exec. */
|
||||||
|
|
||||||
static pid_t
|
static pid_t
|
||||||
pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
||||||
char * const * argv, char * const * env,
|
char * const * argv, char * const * env,
|
||||||
|
@ -521,6 +719,7 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* SPAWN */
|
||||||
|
|
||||||
/* Wait for a child process to complete. */
|
/* Wait for a child process to complete. */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue