diff options
author | Zachary Turner <zturner@google.com> | 2014-10-14 21:55:08 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2014-10-14 21:55:08 +0000 |
commit | 172d37d3b92ca70e65f11f9a7caf7af4c8a5e44f (patch) | |
tree | 0df4532b38c6277c18c69659225f56a8188c6092 /lldb/source/Host | |
parent | 756acbaa0e76c17426983863099d42449b0a6729 (diff) | |
download | bcm5719-llvm-172d37d3b92ca70e65f11f9a7caf7af4c8a5e44f.tar.gz bcm5719-llvm-172d37d3b92ca70e65f11f9a7caf7af4c8a5e44f.zip |
Create a process launcher abstraction.
This implements Host::LaunchProcess for windows, and in doing so
does some minor refactor to move towards a more modular process
launching design.
The original motivation for this is that launching processes on
windows needs some very windows specific code, which would live
most appropriately in source/Host/windows somewhere. However,
there is already some common code that all platforms use when
launching a process before delegating to the platform specific
stuff, which lives in source/Host/common/Host.cpp which would
be nice to reuse without duplicating.
This commonality has been abstracted into MonitoringProcessLauncher,
a class which abstracts out the notion of launching a process using
an arbitrary algorithm, and then monitoring it for state changes.
The windows specific launching code lives in ProcessLauncherWindows,
and the posix specific launching code lives in ProcessLauncherPosix.
When launching a process MonitoringProcessLauncher is created, and
then an appropriate delegate launcher is created and given to the
MonitoringProcessLauncher.
Reviewed by: Greg Clayton
Differential Revision: http://reviews.llvm.org/D5781
llvm-svn: 219731
Diffstat (limited to 'lldb/source/Host')
-rw-r--r-- | lldb/source/Host/CMakeLists.txt | 3 | ||||
-rw-r--r-- | lldb/source/Host/common/Host.cpp | 128 | ||||
-rw-r--r-- | lldb/source/Host/common/HostProcess.cpp | 7 | ||||
-rw-r--r-- | lldb/source/Host/common/MonitoringProcessLauncher.cpp | 102 | ||||
-rw-r--r-- | lldb/source/Host/macosx/Host.mm | 8 | ||||
-rw-r--r-- | lldb/source/Host/posix/HostProcessPosix.cpp | 9 | ||||
-rw-r--r-- | lldb/source/Host/posix/ProcessLauncherPosix.cpp | 33 | ||||
-rw-r--r-- | lldb/source/Host/windows/Host.cpp | 8 | ||||
-rw-r--r-- | lldb/source/Host/windows/HostProcessWindows.cpp | 49 | ||||
-rw-r--r-- | lldb/source/Host/windows/ProcessLauncherWindows.cpp | 94 |
10 files changed, 331 insertions, 110 deletions
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index 73da2a890af..85211f9f017 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -16,6 +16,7 @@ add_host_subdirectory(common common/HostThread.cpp common/IOObject.cpp common/Mutex.cpp + common/MonitoringProcessLauncher.cpp common/NativeBreakpoint.cpp common/NativeBreakpointList.cpp common/NativeProcessProtocol.cpp @@ -48,6 +49,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Windows") windows/HostThreadWindows.cpp windows/Mutex.cpp windows/PipeWindows.cpp + windows/ProcessLauncherWindows.cpp windows/ProcessRunLock.cpp windows/ThisThread.cpp windows/Windows.cpp @@ -59,6 +61,7 @@ else() posix/HostProcessPosix.cpp posix/HostThreadPosix.cpp posix/PipePosix.cpp + posix/ProcessLauncherPosix.cpp ) if (CMAKE_SYSTEM_NAME MATCHES "Darwin") diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 09376d2d443..ee0cb197105 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -71,7 +71,10 @@ #include "lldb/Host/Endian.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/MonitoringProcessLauncher.h" #include "lldb/Host/Mutex.h" +#include "lldb/Host/ProcessLauncher.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/lldb-private-forward.h" #include "lldb/Target/FileAction.h" @@ -86,6 +89,12 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#if defined(_WIN32) +#include "lldb/Host/windows/ProcessLauncherWindows.h" +#else +#include "lldb/Host/posix/ProcessLauncherPosix.h" +#endif + #if defined (__APPLE__) #ifndef _POSIX_SPAWN_DISABLE_ASLR #define _POSIX_SPAWN_DISABLE_ASLR 0x0100 @@ -717,7 +726,7 @@ Host::RunShellCommand (const char *command, // common/Host.cpp. short -Host::GetPosixspawnFlags (ProcessLaunchInfo &launch_info) +Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) { #ifndef __ANDROID__ short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; @@ -769,7 +778,7 @@ Host::GetPosixspawnFlags (ProcessLaunchInfo &launch_info) } Error -Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid) +Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid) { Error error; #ifndef __ANDROID__ @@ -890,6 +899,7 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i #endif } + ::pid_t result_pid = LLDB_INVALID_PROCESS_ID; const size_t num_file_actions = launch_info.GetNumFileActions (); if (num_file_actions > 0) { @@ -914,21 +924,13 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i } } - error.SetError (::posix_spawnp (&pid, - exe_path, - &file_actions, - &attr, - argv, - envp), - eErrorTypePOSIX); + error.SetError(::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), eErrorTypePOSIX); if (error.Fail() || log) { - error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", - pid, exe_path, static_cast<void*>(&file_actions), - static_cast<void*>(&attr), - reinterpret_cast<const void*>(argv), - reinterpret_cast<const void*>(envp)); + error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", result_pid, + exe_path, static_cast<void *>(&file_actions), static_cast<void *>(&attr), reinterpret_cast<const void *>(argv), + reinterpret_cast<const void *>(envp)); if (log) { for (int ii=0; argv[ii]; ++ii) @@ -939,20 +941,13 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i } else { - error.SetError (::posix_spawnp (&pid, - exe_path, - NULL, - &attr, - argv, - envp), - eErrorTypePOSIX); + error.SetError(::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), eErrorTypePOSIX); if (error.Fail() || log) { error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )", - pid, exe_path, static_cast<void*>(&attr), - reinterpret_cast<const void*>(argv), - reinterpret_cast<const void*>(envp)); + result_pid, exe_path, static_cast<void *>(&attr), reinterpret_cast<const void *>(argv), + reinterpret_cast<const void *>(envp)); if (log) { for (int ii=0; argv[ii]; ++ii) @@ -960,6 +955,7 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i } } } + pid = result_pid; if (working_dir) { @@ -1056,86 +1052,28 @@ Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log * #endif // LaunchProcedssPosixSpawn: Apple, Linux, FreeBSD and other GLIBC systems - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || defined(__NetBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || defined(__NetBSD__) || defined(_WIN32) // The functions below implement process launching via posix_spawn() for Linux, // FreeBSD and NetBSD. Error Host::LaunchProcess (ProcessLaunchInfo &launch_info) { - Error error; - char exe_path[PATH_MAX]; - - PlatformSP host_platform_sp (Platform::GetHostPlatform ()); - - const ArchSpec &arch_spec = launch_info.GetArchitecture(); - - FileSpec exe_spec(launch_info.GetExecutableFile()); - - FileSpec::FileType file_type = exe_spec.GetFileType(); - if (file_type != FileSpec::eFileTypeRegular) - { - lldb::ModuleSP exe_module_sp; - error = host_platform_sp->ResolveExecutable (exe_spec, - arch_spec, - exe_module_sp, - NULL); - - if (error.Fail()) - return error; - - if (exe_module_sp) - exe_spec = exe_module_sp->GetFileSpec(); - } - - if (exe_spec.Exists()) - { - exe_spec.GetPath (exe_path, sizeof(exe_path)); - } - else - { - launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path)); - error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path); - return error; - } - - assert(!launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY)); - - ::pid_t pid = LLDB_INVALID_PROCESS_ID; - - error = LaunchProcessPosixSpawn(exe_path, launch_info, pid); + std::unique_ptr<ProcessLauncher> delegate_launcher; +#if defined(_WIN32) + delegate_launcher.reset(new ProcessLauncherWindows()); +#else + delegate_launcher.reset(new ProcessLauncherPosix()); +#endif + MonitoringProcessLauncher launcher(std::move(delegate_launcher)); - if (pid != LLDB_INVALID_PROCESS_ID) - { - // If all went well, then set the process ID into the launch info - launch_info.SetProcessID(pid); + Error error; + HostProcess process = launcher.LaunchProcess(launch_info, error); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + // TODO(zturner): It would be better if the entire HostProcess were returned instead of writing + // it into this structure. + launch_info.SetProcessID(process.GetProcessId()); - // Make sure we reap any processes we spawn or we will have zombies. - if (!launch_info.MonitorProcess()) - { - const bool monitor_signals = false; - StartMonitoringChildProcess (Process::SetProcessExitStatus, - NULL, - pid, - monitor_signals); - if (log) - log->PutCString ("monitored child process with default Process::SetProcessExitStatus."); - } - else - { - if (log) - log->PutCString ("monitored child process with user-specified process monitor."); - } - } - else - { - // Invalid process ID, something didn't go well - if (error.Success()) - error.SetErrorString ("process launch failed for unknown reasons"); - } return error; } diff --git a/lldb/source/Host/common/HostProcess.cpp b/lldb/source/Host/common/HostProcess.cpp index 9339d37b912..58a214693a5 100644 --- a/lldb/source/Host/common/HostProcess.cpp +++ b/lldb/source/Host/common/HostProcess.cpp @@ -9,6 +9,7 @@ #include "lldb/Host/HostNativeProcess.h" #include "lldb/Host/HostProcess.h" +#include "lldb/Host/HostThread.h" using namespace lldb; using namespace lldb_private; @@ -47,6 +48,12 @@ bool HostProcess::IsRunning() const return m_native_process->IsRunning(); } +HostThread +HostProcess::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals) +{ + return m_native_process->StartMonitoring(callback, callback_baton, monitor_signals); +} + HostNativeProcessBase &HostProcess::GetNativeProcess() { return *m_native_process; diff --git a/lldb/source/Host/common/MonitoringProcessLauncher.cpp b/lldb/source/Host/common/MonitoringProcessLauncher.cpp new file mode 100644 index 00000000000..3b0078474b0 --- /dev/null +++ b/lldb/source/Host/common/MonitoringProcessLauncher.cpp @@ -0,0 +1,102 @@ +//===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/MonitoringProcessLauncher.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/ProcessLaunchInfo.h" + +using namespace lldb; +using namespace lldb_private; + +MonitoringProcessLauncher::MonitoringProcessLauncher(std::unique_ptr<ProcessLauncher> delegate_launcher) + : m_delegate_launcher(std::move(delegate_launcher)) +{ +} + +HostProcess +MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) +{ + ProcessLaunchInfo resolved_info(launch_info); + + error.Clear(); + char exe_path[PATH_MAX]; + + PlatformSP host_platform_sp(Platform::GetHostPlatform()); + + const ArchSpec &arch_spec = resolved_info.GetArchitecture(); + + FileSpec exe_spec(resolved_info.GetExecutableFile()); + + FileSpec::FileType file_type = exe_spec.GetFileType(); + if (file_type != FileSpec::eFileTypeRegular) + { + lldb::ModuleSP exe_module_sp; + error = host_platform_sp->ResolveExecutable(exe_spec, arch_spec, exe_module_sp, NULL); + + if (error.Fail()) + return HostProcess(); + + if (exe_module_sp) + exe_spec = exe_module_sp->GetFileSpec(); + } + + if (exe_spec.Exists()) + { + exe_spec.GetPath(exe_path, sizeof(exe_path)); + } + else + { + resolved_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); + error.SetErrorStringWithFormat("executable doesn't exist: '%s'", exe_path); + return HostProcess(); + } + + resolved_info.SetExecutableFile(exe_spec, false); + assert(!resolved_info.GetFlags().Test(eLaunchFlagLaunchInTTY)); + + ::pid_t pid = LLDB_INVALID_PROCESS_ID; + + HostProcess process = m_delegate_launcher->LaunchProcess(resolved_info, error); + + if (process.GetProcessId() != LLDB_INVALID_PROCESS_ID) + { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + Host::MonitorChildProcessCallback callback = launch_info.GetMonitorProcessCallback(); + + void *baton = nullptr; + bool monitor_signals = false; + if (callback) + { + // If the ProcessLaunchInfo specified a callback, use that. + baton = launch_info.GetMonitorProcessBaton(); + monitor_signals = launch_info.GetMonitorSignals(); + } + else + { + callback = Process::SetProcessExitStatus; + } + + process.StartMonitoring(callback, baton, monitor_signals); + if (log) + log->PutCString("started monitoring child process."); + } + else + { + // Invalid process ID, something didn't go well + if (error.Success()) + error.SetErrorString("process launch failed for unknown reasons"); + } + return process; +} diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm index ffa4f849965..228305e0814 100644 --- a/lldb/source/Host/macosx/Host.mm +++ b/lldb/source/Host/macosx/Host.mm @@ -1138,7 +1138,7 @@ getXPCAuthorization (ProcessLaunchInfo &launch_info) #endif static Error -LaunchProcessXPC (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid) +LaunchProcessXPC(const char *exe_path, ProcessLaunchInfo &launch_info, lldb::pid_t &pid) { #if !NO_XPC_SERVICES Error error = getXPCAuthorization(launch_info); @@ -1347,9 +1347,9 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info) return error; #endif } - - ::pid_t pid = LLDB_INVALID_PROCESS_ID; - + + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + if (ShouldLaunchUsingXPC(launch_info)) { error = LaunchProcessXPC(exe_path, launch_info, pid); diff --git a/lldb/source/Host/posix/HostProcessPosix.cpp b/lldb/source/Host/posix/HostProcessPosix.cpp index 0d9f85377dd..8e19add048e 100644 --- a/lldb/source/Host/posix/HostProcessPosix.cpp +++ b/lldb/source/Host/posix/HostProcessPosix.cpp @@ -1,4 +1,4 @@ -//===-- HostProcessWindows.cpp ----------------------------------*- C++ -*-===// +//===-- HostProcessPosix.cpp ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "lldb/Host/Host.h" #include "lldb/Host/posix/HostProcessPosix.h" #include "lldb/Host/FileSystem.h" @@ -107,3 +108,9 @@ bool HostProcessPosix::IsRunning() const Error error = Signal(0); return error.Success(); } + +HostThread +HostProcessPosix::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals) +{ + return Host::StartMonitoringChildProcess(callback, callback_baton, m_process, monitor_signals); +} diff --git a/lldb/source/Host/posix/ProcessLauncherPosix.cpp b/lldb/source/Host/posix/ProcessLauncherPosix.cpp new file mode 100644 index 00000000000..dd5c5121a97 --- /dev/null +++ b/lldb/source/Host/posix/ProcessLauncherPosix.cpp @@ -0,0 +1,33 @@ +//===-- ProcessLauncherPosix.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Host.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/posix/ProcessLauncherPosix.h" + +#include "lldb/Target/ProcessLaunchInfo.h" + +#include <limits.h> + +using namespace lldb; +using namespace lldb_private; + +HostProcess +ProcessLauncherPosix::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) +{ + lldb::pid_t pid; + char exe_path[PATH_MAX]; + + launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); + + // TODO(zturner): Move the code from LaunchProcessPosixSpawn to here, and make MacOSX re-use this + // ProcessLauncher when it wants a posix_spawn launch. + error = Host::LaunchProcessPosixSpawn(exe_path, launch_info, pid); + return HostProcess(pid); +} diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp index 4542025f6ee..4f698df16eb 100644 --- a/lldb/source/Host/windows/Host.cpp +++ b/lldb/source/Host/windows/Host.cpp @@ -96,14 +96,6 @@ namespace } } -Error -Host::LaunchProcess (ProcessLaunchInfo &launch_info) -{ - Error error; - assert(!"Not implemented yet!!!"); - return error; -} - lldb::DataBufferSP Host::GetAuxvData(lldb_private::Process *process) { diff --git a/lldb/source/Host/windows/HostProcessWindows.cpp b/lldb/source/Host/windows/HostProcessWindows.cpp index 447f672ac77..8388e21b853 100644 --- a/lldb/source/Host/windows/HostProcessWindows.cpp +++ b/lldb/source/Host/windows/HostProcessWindows.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/FileSpec.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/windows/windows.h" #include "lldb/Host/windows/HostProcessWindows.h" @@ -17,6 +19,16 @@ using namespace lldb_private; +namespace +{ +struct MonitorInfo +{ + HostProcess::MonitorCallback callback; + void *baton; + HANDLE process_handle; +}; +} + HostProcessWindows::HostProcessWindows() : HostNativeProcessBase() { @@ -61,7 +73,7 @@ Error HostProcessWindows::GetMainModule(FileSpec &file_spec) const lldb::pid_t HostProcessWindows::GetProcessId() const { - return ::GetProcessId(m_process); + return (m_process == LLDB_INVALID_PROCESS) ? -1 : ::GetProcessId(m_process); } bool HostProcessWindows::IsRunning() const @@ -76,9 +88,42 @@ bool HostProcessWindows::IsRunning() const return (code == STILL_ACTIVE); } +HostThread +HostProcessWindows::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals) +{ + HostThread monitor_thread; + MonitorInfo *info = new MonitorInfo; + info->callback = callback; + info->baton = callback_baton; + + // Since the life of this HostProcessWindows instance and the life of the process may be different, duplicate the handle so that + // the monitor thread can have ownership over its own copy of the handle. + HostThread result; + if (::DuplicateHandle(GetCurrentProcess(), m_process, GetCurrentProcess(), &info->process_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + result = ThreadLauncher::LaunchThread("ChildProcessMonitor", HostProcessWindows::MonitorThread, info, nullptr); + return result; +} + +lldb::thread_result_t +HostProcessWindows::MonitorThread(void *thread_arg) +{ + DWORD exit_code; + + MonitorInfo *info = static_cast<MonitorInfo *>(thread_arg); + if (info) + { + DWORD wait_result = ::WaitForSingleObject(info->process_handle, INFINITE); + ::GetExitCodeProcess(info->process_handle, &exit_code); + info->callback(info->baton, ::GetProcessId(info->process_handle), true, 0, exit_code); + + delete (info); + } + return 0; +} + void HostProcessWindows::Close() { - if (m_process != nullptr) + if (m_process != LLDB_INVALID_PROCESS) ::CloseHandle(m_process); m_process = nullptr; } diff --git a/lldb/source/Host/windows/ProcessLauncherWindows.cpp b/lldb/source/Host/windows/ProcessLauncherWindows.cpp new file mode 100644 index 00000000000..7a99e0944e5 --- /dev/null +++ b/lldb/source/Host/windows/ProcessLauncherWindows.cpp @@ -0,0 +1,94 @@ +//===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/windows/ProcessLauncherWindows.h" +#include "lldb/Target/ProcessLaunchInfo.h" + +#include <string> +#include <vector> + +using namespace lldb; +using namespace lldb_private; + +HostProcess +ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) +{ + error.Clear(); + + std::string executable; + std::string commandLine; + std::vector<char> environment; + STARTUPINFO startupinfo = {0}; + PROCESS_INFORMATION pi = {0}; + + HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO); + HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO); + HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO); + + startupinfo.cb = sizeof(startupinfo); + startupinfo.dwFlags |= STARTF_USESTDHANDLES; + startupinfo.hStdError = stderr_handle; + startupinfo.hStdInput = stdin_handle; + startupinfo.hStdOutput = stdout_handle; + + executable = launch_info.GetExecutableFile().GetPath(); + launch_info.GetArguments().GetQuotedCommandString(commandLine); + BOOL result = ::CreateProcessA(executable.c_str(), const_cast<char *>(commandLine.c_str()), NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, + launch_info.GetWorkingDirectory(), &startupinfo, &pi); + if (result) + { + // Do not call CloseHandle on pi.hProcess, since we want to pass that back through the HostProcess. + ::CloseHandle(pi.hThread); + } + + if (stdin_handle) + ::CloseHandle(stdin_handle); + if (stdout_handle) + ::CloseHandle(stdout_handle); + if (stderr_handle) + ::CloseHandle(stderr_handle); + + if (!result) + error.SetError(::GetLastError(), eErrorTypeWin32); + return HostProcess(pi.hProcess); +} + +HANDLE +ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd) +{ + const FileAction *action = launch_info.GetFileActionForFD(fd); + if (action == nullptr) + return NULL; + SECURITY_ATTRIBUTES secattr = {0}; + secattr.nLength = sizeof(SECURITY_ATTRIBUTES); + secattr.bInheritHandle = TRUE; + + const char *path = action->GetPath(); + DWORD access = 0; + DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE; + DWORD create = 0; + DWORD flags = 0; + if (fd == STDIN_FILENO) + { + access = GENERIC_READ; + create = OPEN_EXISTING; + flags = FILE_ATTRIBUTE_READONLY; + } + if (fd == STDOUT_FILENO || fd == STDERR_FILENO) + { + access = GENERIC_WRITE; + create = CREATE_ALWAYS; + if (fd == STDERR_FILENO) + flags = FILE_FLAG_WRITE_THROUGH; + } + + HANDLE result = ::CreateFile(path, access, share, &secattr, create, flags, NULL); + return (result == INVALID_HANDLE_VALUE) ? NULL : result; +} |