make Program::Execute use posix_spawn on systems that support it,
as it is more efficient than fork/exec.
Thanks to Eric for adding the autoconf check. It would be nice if
a cmake guru could add a cmake check for posix_spawn as well.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@101693 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/System/Unix/Program.inc b/lib/System/Unix/Program.inc
index bad4837..44e831f 100644
--- a/lib/System/Unix/Program.inc
+++ b/lib/System/Unix/Program.inc
@@ -30,6 +30,9 @@
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#ifdef HAVE_POSIX_SPAWN
+#include <spawn.h>
+#endif
namespace llvm {
using namespace sys;
@@ -94,8 +97,7 @@
}
static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) {
- if (Path == 0)
- // Noop
+ if (Path == 0) // Noop
return false;
std::string File;
if (Path->isEmpty())
@@ -122,6 +124,25 @@
return false;
}
+#ifdef HAVE_POSIX_SPAWN
+static bool RedirectIO_PS(const Path *Path, int FD, std::string *ErrMsg,
+ posix_spawn_file_actions_t &FileActions) {
+ if (Path == 0) // Noop
+ return false;
+ std::string File;
+ if (Path->isEmpty())
+ // Redirect empty paths to /dev/null
+ File = "/dev/null";
+ else
+ File = Path->str();
+
+ if (int Err = posix_spawn_file_actions_addopen(&FileActions, FD,
+ File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666))
+ return MakeErrMsg(ErrMsg, "Cannot dup2", Err);
+ return false;
+}
+#endif
+
static void TimeOutHandler(int Sig) {
}
@@ -151,13 +172,47 @@
}
bool
-Program::Execute(const Path& path,
- const char** args,
- const char** envp,
- const Path** redirects,
- unsigned memoryLimit,
- std::string* ErrMsg)
-{
+Program::Execute(const Path &path, const char **args, const char **envp,
+ const Path **redirects, unsigned memoryLimit,
+ std::string *ErrMsg) {
+ // If this OS has posix_spawn and there is no memory limit being implied, use
+ // posix_spawn. It is more efficient than fork/exec.
+#ifdef HAVE_POSIX_SPAWN
+ if (memoryLimit == 0) {
+ posix_spawn_file_actions_t FileActions;
+ posix_spawn_file_actions_init(&FileActions);
+
+ if (redirects) {
+ // Redirect stdin/stdout.
+ if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) ||
+ RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions))
+ return false;
+ if (redirects[1] == 0 || redirects[2] == 0 ||
+ *redirects[1] != *redirects[2]) {
+ // Just redirect stderr
+ if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false;
+ } else {
+ // If stdout and stderr should go to the same place, redirect stderr
+ // to the FD already open for stdout.
+ if (int Err = posix_spawn_file_actions_adddup2(&FileActions, 1, 2))
+ return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err);
+ }
+ }
+
+ pid_t PID;
+ int Err = posix_spawn(&PID, path.c_str(), &FileActions,
+ /*attrp*/0, (char**)args, (char**)envp);
+
+ posix_spawn_file_actions_destroy(&FileActions);
+
+ if (Err)
+ return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
+
+ Data_ = reinterpret_cast<void*>(PID);
+ return true;
+ }
+#endif
+
if (!path.canExecute()) {
if (ErrMsg)
*ErrMsg = path.str() + " is not executable";