diff options
-rw-r--r-- | unix/tcl.m4 | 4 | ||||
-rw-r--r-- | unix/tclUnixPipe.c | 90 |
2 files changed, 67 insertions, 27 deletions
diff --git a/unix/tcl.m4 b/unix/tcl.m4 index add827f..dfa812b 100644 --- a/unix/tcl.m4 +++ b/unix/tcl.m4 @@ -590,7 +590,6 @@ AC_DEFUN([SC_ENABLE_FRAMEWORK], [ # TCL_THREADS # _REENTRANT # _THREAD_SAFE -# #------------------------------------------------------------------------ AC_DEFUN([SC_ENABLE_THREADS], [ @@ -2068,7 +2067,8 @@ dnl # preprocessing tests use only CPPFLAGS. CFLAGS_NOLTO="" fi - AC_CHECK_FUNCS([posix_spawnp]) + # Check for posix_spawnp() and friends unconditionally + AC_CHECK_FUNCS(posix_spawnp posix_spawn_file_actions_adddup2 posix_spawnattr_setflags) # FIXME: This subst was left in only because the TCL_DL_LIBS # entry in tclConfig.sh uses it. It is not clear why someone diff --git a/unix/tclUnixPipe.c b/unix/tclUnixPipe.c index 649fa4d..0c9f543 100644 --- a/unix/tclUnixPipe.c +++ b/unix/tclUnixPipe.c @@ -14,7 +14,13 @@ #include "tclInt.h" #ifdef HAVE_POSIX_SPAWNP -# include <spawn.h> +#ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2 +#ifdef HAVE_POSIX_SPAWNATTR_SETFLAGS +#include <unistd.h> +#include <spawn.h> +#define USE_POSIX_SPAWN 1 +#endif +#endif #endif #ifdef USE_VFORK @@ -22,6 +28,16 @@ #endif /* + * For now, test exec-17.1 fails (I/O setup after closing stdout) with + * posix_spawnp(), but the classic implementation (based on fork()+execvp()) + * works well under macOS. + */ + +#ifdef __APPLE__ +#undef USE_POSIX_SPAWN +#endif + +/* * The following macros convert between TclFile's and fd's. The conversion * simple involves shifting fd's up by one to ensure that no valid fd is ever * the same as NULL. @@ -415,8 +431,9 @@ TclpCreateProcess( Tcl_DString *dsArray; char **newArgv; int pid, i; -#if defined(HAVE_POSIX_SPAWNP) +#if defined(USE_POSIX_SPAWN) int childErrno; + int use_spawn = -1; #endif errPipeIn = NULL; @@ -446,7 +463,7 @@ TclpCreateProcess( newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]); } -#if defined(USE_VFORK) || defined(HAVE_POSIX_SPAWNP) +#if defined(USE_VFORK) || defined(USE_POSIX_SPAWN) /* * After vfork(), do not call code in the child that changes global state, * because it is using the parent's memory space at that point and writes @@ -466,29 +483,53 @@ TclpCreateProcess( } #endif -#ifdef HAVE_POSIX_SPAWNP - { +#ifdef USE_POSIX_SPAWN +#ifdef _CS_GNU_LIBC_VERSION + if (use_spawn < 0) { + char conf[32], *p; + int major = 0, minor = 0; + + use_spawn = 0; + memset(conf, 0, sizeof(conf)); + confstr(_CS_GNU_LIBC_VERSION, conf, sizeof(conf)); + p = strchr(conf, ' '); /* skip "glibc" */ + if (p != NULL) { + ++p; + if (sscanf(p, "%d.%d", &major, &minor) > 1) { + if ((major > 2) || ((major == 2) && (minor >= 24))) { + use_spawn = 1; + } + } + } + } +#endif + status = -1; + if (use_spawn) { posix_spawn_file_actions_t actions; posix_spawnattr_t attr; + sigset_t sigs; posix_spawn_file_actions_init(&actions); posix_spawnattr_init(&attr); - - posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF| -# ifdef POSIX_SPAWN_USEVFORK - POSIX_SPAWN_USEVFORK -# else - 0 -# endif - ); + sigfillset(&sigs); + sigdelset(&sigs, SIGKILL); + sigdelset(&sigs, SIGSTOP); + + posix_spawnattr_setflags(&attr, + POSIX_SPAWN_SETSIGDEF +#ifdef POSIX_SPAWN_USEVFORK + | POSIX_SPAWN_USEVFORK +#endif + ); + posix_spawnattr_setsigdefault(&attr, &sigs); posix_spawn_file_actions_adddup2(&actions, GetFd(inputFile), 0); posix_spawn_file_actions_adddup2(&actions, GetFd(outputFile), 1); posix_spawn_file_actions_adddup2(&actions, GetFd(errorFile), 2); - status = posix_spawnp(&pid, newArgv[0], &actions, &attr, newArgv, environ); - childErrno = status; - + status = posix_spawnp(&pid, newArgv[0], &actions, &attr, + newArgv, environ); + childErrno = errno; posix_spawn_file_actions_destroy(&actions); posix_spawnattr_destroy(&attr); @@ -498,11 +539,13 @@ TclpCreateProcess( * - pid == -1: error * - pid > 0: parent process * - * Mimic fork semantics to minimize changes below + * Mimic fork semantics to minimize changes below, + * but retry with fork() as last ressort. */ - if (status != 0) { - pid = -1; - } + } + if (status != 0) { + pid = fork(); + childErrno = errno; } #else pid = fork(); @@ -556,14 +599,11 @@ TclpCreateProcess( TclStackFree(interp, dsArray); if (pid == -1) { -#ifdef HAVE_POSIX_SPAWNP +#ifdef USE_POSIX_SPAWN errno = childErrno; - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "couldn't execute \"%s\": %s", argv[0], Tcl_PosixError(interp))); -#else +#endif Tcl_SetObjResult(interp, Tcl_ObjPrintf( "couldn't fork child process: %s", Tcl_PosixError(interp))); -#endif goto error; } |