summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixPipe.c
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2023-07-24 11:13:58 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2023-07-24 11:13:58 (GMT)
commit399309020d7f8caf7b710a6a41601159cdc32e30 (patch)
treed057fc8c94b4680c01d3b31e85be1b69913fff2e /unix/tclUnixPipe.c
parent7caf2af1db913adaf775172aaa508e3b98274967 (diff)
parent03b881a299157cbb9681157c7842b5d33a6a2e40 (diff)
downloadtcl-399309020d7f8caf7b710a6a41601159cdc32e30.zip
tcl-399309020d7f8caf7b710a6a41601159cdc32e30.tar.gz
tcl-399309020d7f8caf7b710a6a41601159cdc32e30.tar.bz2
Merge 8.6
Diffstat (limited to 'unix/tclUnixPipe.c')
-rw-r--r--unix/tclUnixPipe.c59
1 files changed, 56 insertions, 3 deletions
diff --git a/unix/tclUnixPipe.c b/unix/tclUnixPipe.c
index a7ad056..dd477cc 100644
--- a/unix/tclUnixPipe.c
+++ b/unix/tclUnixPipe.c
@@ -13,6 +13,10 @@
#include "tclInt.h"
+#ifdef HAVE_POSIX_SPAWNP
+# include <spawn.h>
+#endif
+
#ifdef USE_VFORK
#define fork vfork
#endif
@@ -411,6 +415,9 @@ TclpCreateProcess(
Tcl_DString *dsArray;
char **newArgv;
int pid, i;
+#if defined(HAVE_POSIX_SPAWNP)
+ int childErrno;
+#endif
errPipeIn = NULL;
errPipeOut = NULL;
@@ -439,7 +446,7 @@ TclpCreateProcess(
newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], TCL_INDEX_NONE, &dsArray[i]);
}
-#ifdef USE_VFORK
+#if defined(USE_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
@@ -452,14 +459,54 @@ TclpCreateProcess(
Tcl_GetStdChannel(TCL_STDIN);
}
if (!outputFile) {
- Tcl_GetStdChannel(TCL_STDOUT);
+ Tcl_GetStdChannel(TCL_STDOUT);
}
if (!errorFile) {
- Tcl_GetStdChannel(TCL_STDERR);
+ Tcl_GetStdChannel(TCL_STDERR);
}
#endif
+#ifdef HAVE_POSIX_SPAWNP
+ {
+ posix_spawn_file_actions_t actions;
+ posix_spawnattr_t attr;
+
+ 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
+ );
+
+ 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;
+
+ posix_spawn_file_actions_destroy(&actions);
+ posix_spawnattr_destroy(&attr);
+
+ /*
+ * Fork semantics:
+ * - pid == 0: child process
+ * - pid == -1: error
+ * - pid > 0: parent process
+ *
+ * Mimic fork semantics to minimize changes below
+ */
+ if (status != 0) {
+ pid = -1;
+ }
+ }
+#else
pid = fork();
+#endif
if (pid == 0) {
size_t len;
int joinThisError = errorFile && (errorFile == outputFile);
@@ -509,8 +556,14 @@ TclpCreateProcess(
TclStackFree(interp, dsArray);
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
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"couldn't fork child process: %s", Tcl_PosixError(interp)));
+#endif
goto error;
}