diff options
| author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2023-07-26 07:15:26 (GMT) |
|---|---|---|
| committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2023-07-26 07:15:26 (GMT) |
| commit | b985fb89654fa2129bfc4cfa20853b10d7cc7184 (patch) | |
| tree | 3818f81aa8ca532e614ccf31af9db7ef9ee0de85 | |
| parent | 4f7e149fb6b4b78d45059bff477ee467f4d6c8b9 (diff) | |
| parent | 004d2e654ffa9506699941289039edae89fcb620 (diff) | |
| download | tcl-b985fb89654fa2129bfc4cfa20853b10d7cc7184.zip tcl-b985fb89654fa2129bfc4cfa20853b10d7cc7184.tar.gz tcl-b985fb89654fa2129bfc4cfa20853b10d7cc7184.tar.bz2 | |
Fix [c54e4a1aeb] (again): High Tcl latencies with fork() in larger systems.
vfork() is now prefered, if available
| -rwxr-xr-x | unix/configure | 107 | ||||
| -rw-r--r-- | unix/tcl.m4 | 4 | ||||
| -rw-r--r-- | unix/tclConfig.h.in | 9 | ||||
| -rw-r--r-- | unix/tclUnixPipe.c | 77 | ||||
| -rw-r--r-- | unix/tclUnixPort.h | 12 |
5 files changed, 178 insertions, 31 deletions
diff --git a/unix/configure b/unix/configure index 108ac04..553fc73 100755 --- a/unix/configure +++ b/unix/configure @@ -8978,7 +8978,112 @@ echo "${ECHO_T}$ac_cv_nolto" >&6 CFLAGS_NOLTO="" fi - #AC_CHECK_FUNCS([posix_spawnp]) + # Check for vfork, posix_spawnp() and friends unconditionally + + + + +for ac_func in vfork posix_spawnp posix_spawn_file_actions_adddup2 posix_spawnattr_setflags +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + # 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/tcl.m4 b/unix/tcl.m4 index d6f1d2b..06d31b8 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 vfork, posix_spawnp() and friends unconditionally + AC_CHECK_FUNCS(vfork 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/tclConfig.h.in b/unix/tclConfig.h.in index 486d8d9..5a64236 100644 --- a/unix/tclConfig.h.in +++ b/unix/tclConfig.h.in @@ -174,9 +174,15 @@ /* Define to 1 if you have the `OSSpinLockLock' function. */ #undef HAVE_OSSPINLOCKLOCK +/* Define to 1 if you have the `posix_spawnattr_setflags' function. */ +#undef HAVE_POSIX_SPAWNATTR_SETFLAGS + /* Define to 1 if you have the `posix_spawnp' function. */ #undef HAVE_POSIX_SPAWNP +/* Define to 1 if you have the `posix_spawn_file_actions_adddup2' function. */ +#undef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2 + /* Define to 1 if you have the `pthread_atfork' function. */ #undef HAVE_PTHREAD_ATFORK @@ -273,6 +279,9 @@ /* Define to 1 if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + /* Define to 1 if you have the `waitpid' function. */ #undef HAVE_WAITPID diff --git a/unix/tclUnixPipe.c b/unix/tclUnixPipe.c index 649fa4d..96ca095 100644 --- a/unix/tclUnixPipe.c +++ b/unix/tclUnixPipe.c @@ -14,10 +14,17 @@ #include "tclInt.h" #ifdef HAVE_POSIX_SPAWNP -# include <spawn.h> +# if defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2) \ + && defined(HAVE_POSIX_SPAWNATTR_SETFLAGS) \ + && !defined(HAVE_VFORK) +# include <unistd.h> +# include <spawn.h> +# else +# undef HAVE_POSIX_SPAWNP +# endif #endif -#ifdef USE_VFORK +#ifdef HAVE_VFORK #define fork vfork #endif @@ -417,6 +424,7 @@ TclpCreateProcess( int pid, i; #if defined(HAVE_POSIX_SPAWNP) int childErrno; + static int use_spawn = -1; #endif errPipeIn = NULL; @@ -446,7 +454,7 @@ TclpCreateProcess( newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]); } -#if defined(USE_VFORK) || defined(HAVE_POSIX_SPAWNP) +#if defined(HAVE_VFORK) || defined(HAVE_POSIX_SPAWNP) /* * 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 @@ -467,28 +475,52 @@ TclpCreateProcess( #endif #ifdef HAVE_POSIX_SPAWNP - { +#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 +530,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(); @@ -558,12 +592,9 @@ TclpCreateProcess( if (pid == -1) { #ifdef HAVE_POSIX_SPAWNP 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; } diff --git a/unix/tclUnixPort.h b/unix/tclUnixPort.h index 711ad4c..486fa23 100644 --- a/unix/tclUnixPort.h +++ b/unix/tclUnixPort.h @@ -636,11 +636,13 @@ extern char ** environ; defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1050 # warning "Weak import of 64-bit CoreFoundation is not supported, will not run on Mac OS X < 10.5." # 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 quite OK. - */ -#undef HAVE_POSIX_SPAWNP + /* + * 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. + */ +# undef HAVE_POSIX_SPAWNP +# undef HAVE_VFORK #endif /* __APPLE__ */ /* |
