#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#ifdef HAVE_POSIX_SPAWN
+#include <spawn.h>
+#if !defined(__APPLE__)
+ extern char **environ;
+#else
+#include <crt_externs.h> // _NSGetEnviron
+#endif
+#endif
namespace llvm {
using namespace sys;
}
static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) {
- if (Path == 0)
- // Noop
+ if (Path == 0) // Noop
return false;
- std::string File;
+ const char *File;
if (Path->isEmpty())
// Redirect empty paths to /dev/null
File = "/dev/null";
else
- File = Path->str();
+ File = Path->c_str();
// Open the file
- int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
+ int InFD = open(File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
if (InFD == -1) {
- MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for "
+ MakeErrMsg(ErrMsg, "Cannot open file '" + std::string(File) + "' for "
+ (FD == 0 ? "input" : "output"));
return true;
}
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;
+ const char *File;
+ if (Path->isEmpty())
+ // Redirect empty paths to /dev/null
+ File = "/dev/null";
+ else
+ File = Path->c_str();
+
+ if (int Err = posix_spawn_file_actions_addopen(&FileActions, FD,
+ File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666))
+ return MakeErrMsg(ErrMsg, "Cannot dup2", Err);
+ return false;
+}
+#endif
+
static void TimeOutHandler(int Sig) {
}
}
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);
+ }
+ }
+
+ if (!envp)
+#if !defined(__APPLE__)
+ envp = (const char**)environ;
+#else
+ envp = (const char**)*_NSGetEnviron(); // environ is missing in dylibs.
+#endif
+
+ 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";