Index: include/lldb/Host/HostNativeProcessBase.h =================================================================== --- include/lldb/Host/HostNativeProcessBase.h +++ include/lldb/Host/HostNativeProcessBase.h @@ -34,6 +34,12 @@ {} virtual ~HostNativeProcessBase() {} + lldb::process_t + GetProcess() const + { + return m_process; + } + virtual Error Terminate() = 0; virtual Error GetMainModule(FileSpec &file_spec) const = 0; Index: include/lldb/Host/HostProcess.h =================================================================== --- include/lldb/Host/HostProcess.h +++ include/lldb/Host/HostProcess.h @@ -46,6 +46,7 @@ Error Terminate(); Error GetMainModule(FileSpec &file_spec) const; + lldb::process_t GetProcess() const; lldb::pid_t GetProcessId() const; bool IsRunning() const; Index: include/lldb/Host/MonitoringProcessLauncher.h =================================================================== --- include/lldb/Host/MonitoringProcessLauncher.h +++ include/lldb/Host/MonitoringProcessLauncher.h @@ -15,15 +15,18 @@ namespace lldb_private { +class ProcessStatusMonitor; + class MonitoringProcessLauncher : public ProcessLauncher { public: - explicit MonitoringProcessLauncher(std::unique_ptr delegate_launcher); + explicit MonitoringProcessLauncher(lldb::ProcessStatusMonitorSP monitor, lldb::ProcessLauncherUP delegate_launcher); virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error); private: - std::unique_ptr m_delegate_launcher; + lldb::ProcessStatusMonitorSP m_monitor; + lldb::ProcessLauncherUP m_delegate_launcher; }; } Index: include/lldb/Host/ProcessStatusMonitor.h =================================================================== --- /dev/null +++ include/lldb/Host/ProcessStatusMonitor.h @@ -0,0 +1,58 @@ +//===-- ProcessStatusMonitor.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_ProcessStatusMonitor_H_ +#define liblldb_Host_ProcessStatusMonitor_H_ + +#include "lldb/Core/Error.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/lldb-types.h" + +#include +#include + +namespace lldb_private +{ +typedef bool (*ProcessStatusMonitorCallback)(void *baton, lldb::pid_t pid, bool exited, + int signal, // Zero for no signal + int status); // Exit value of process if signal is zero + +typedef std::pair ProcessStatusMonitorCallbackEntry; +typedef std::list ProcessStatusMonitorCallbackList; +typedef std::unique_ptr ProcessStatusMonitorCallbackListUP; + +//---------------------------------------------------------------------- +// ProcessStatusMonitor +// +// ProcessStatusMonitor accepts callback registrations and provides an interface +// for implementors to initiate the monitoring of a given process. This allows, +// for example, an implementation that launches one thread per process, or another +// implementation that can monitor many processes on the same thread. +//---------------------------------------------------------------------- +class ProcessStatusMonitor +{ + public: + struct MonitorData + { + ProcessStatusMonitorCallbackListUP m_callbacks; + HostProcess m_process; + }; + + ProcessStatusMonitor(); + virtual ~ProcessStatusMonitor() {} + + void AddProcessEventCallback(ProcessStatusMonitorCallback callback, void *baton); + virtual void StartMonitoring(const HostProcess &process) = 0; + + protected: + ProcessStatusMonitorCallbackListUP m_callbacks; +}; +} + +#endif Index: include/lldb/Host/windows/ExitStatusMonitorWindows.h =================================================================== --- /dev/null +++ include/lldb/Host/windows/ExitStatusMonitorWindows.h @@ -0,0 +1,35 @@ +//===-- ExitStatusMonitor.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_windows_ExitStatusMonitor_H_ +#define liblldb_Host_windows_ExitStatusMonitor_H_ + +#include "lldb/Host/ProcessStatusMonitor.h" + +namespace lldb_private +{ +//---------------------------------------------------------------------- +// ExitStatusMonitor +// +// An simple process status monitor that initiates monitoring on a new thread +// for every process, and notifies callbacks when a process exits. +//---------------------------------------------------------------------- +class ExitStatusMonitor : public ProcessStatusMonitor +{ + public: + virtual ~ExitStatusMonitor() {} + + virtual void StartMonitoring(const HostProcess &process); + + private: + static lldb::thread_result_t MonitorThread(void *thread_data); +}; +} + +#endif Index: include/lldb/Host/windows/HostProcessWindows.h =================================================================== --- include/lldb/Host/windows/HostProcessWindows.h +++ include/lldb/Host/windows/HostProcessWindows.h @@ -34,7 +34,6 @@ virtual HostThread StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals); private: - static lldb::thread_result_t MonitorThread(void *thread_arg); void Close(); }; Index: include/lldb/lldb-forward.h =================================================================== --- include/lldb/lldb-forward.h +++ include/lldb/lldb-forward.h @@ -161,7 +161,10 @@ class ProcessInstanceInfo; class ProcessInstanceInfoList; class ProcessInstanceInfoMatch; +class ProcessLauncher; class ProcessLaunchInfo; +class ProcessStatusMonitor; +class ProcessStatusMonitorImpl; class Property; struct PropertyDefinition; class PythonArray; @@ -349,6 +352,9 @@ typedef std::shared_ptr OptionValueUUIDSP; typedef std::shared_ptr PlatformSP; typedef std::shared_ptr ProcessSP; + typedef std::unique_ptr ProcessLauncherUP; + typedef std::shared_ptr ProcessStatusMonitorSP; + typedef std::unique_ptr ProcessStatusMonitorImplUP; typedef std::shared_ptr ProcessAttachInfoSP; typedef std::shared_ptr ProcessLaunchInfoSP; typedef std::weak_ptr ProcessWP; Index: source/Host/CMakeLists.txt =================================================================== --- source/Host/CMakeLists.txt +++ source/Host/CMakeLists.txt @@ -22,6 +22,7 @@ common/NativeProcessProtocol.cpp common/NativeThreadProtocol.cpp common/OptionParser.cpp + common/ProcessStatusMonitor.cpp common/ProcessRunLock.cpp common/Socket.cpp common/SocketAddress.cpp @@ -51,6 +52,7 @@ windows/PipeWindows.cpp windows/ProcessLauncherWindows.cpp windows/ProcessRunLock.cpp + windows/ExitStatusMonitorWindows.cpp windows/ThisThread.cpp windows/Windows.cpp ) Index: source/Host/common/Host.cpp =================================================================== --- source/Host/common/Host.cpp +++ source/Host/common/Host.cpp @@ -64,6 +64,7 @@ #if defined(_WIN32) #include "lldb/Host/windows/ProcessLauncherWindows.h" +#include "lldb/Host/windows/ExitStatusMonitorWindows.h" #else #include "lldb/Host/posix/ProcessLauncherPosix.h" #endif @@ -1033,12 +1034,14 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info) { std::unique_ptr delegate_launcher; + ProcessStatusMonitorSP delegate_monitor; #if defined(_WIN32) delegate_launcher.reset(new ProcessLauncherWindows()); + delegate_monitor.reset(new ExitStatusMonitor()); #else delegate_launcher.reset(new ProcessLauncherPosix()); #endif - MonitoringProcessLauncher launcher(std::move(delegate_launcher)); + MonitoringProcessLauncher launcher(delegate_monitor, std::move(delegate_launcher)); Error error; HostProcess process = launcher.LaunchProcess(launch_info, error); Index: source/Host/common/HostProcess.cpp =================================================================== --- source/Host/common/HostProcess.cpp +++ source/Host/common/HostProcess.cpp @@ -38,6 +38,12 @@ return m_native_process->GetMainModule(file_spec); } +lldb::process_t +HostProcess::GetProcess() const +{ + return m_native_process->GetProcess(); +} + lldb::pid_t HostProcess::GetProcessId() const { return m_native_process->GetProcessId(); Index: source/Host/common/MonitoringProcessLauncher.cpp =================================================================== --- source/Host/common/MonitoringProcessLauncher.cpp +++ source/Host/common/MonitoringProcessLauncher.cpp @@ -12,6 +12,7 @@ #include "lldb/Core/Module.h" #include "lldb/Host/HostProcess.h" #include "lldb/Host/MonitoringProcessLauncher.h" +#include "lldb/Host/ProcessStatusMonitor.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessLaunchInfo.h" @@ -19,8 +20,9 @@ using namespace lldb; using namespace lldb_private; -MonitoringProcessLauncher::MonitoringProcessLauncher(std::unique_ptr delegate_launcher) - : m_delegate_launcher(std::move(delegate_launcher)) +MonitoringProcessLauncher::MonitoringProcessLauncher(ProcessStatusMonitorSP monitor, ProcessLauncherUP delegate_launcher) + : m_monitor(monitor) + , m_delegate_launcher(std::move(delegate_launcher)) { } @@ -86,7 +88,21 @@ callback = Process::SetProcessExitStatus; } - process.StartMonitoring(callback, baton, monitor_signals); + if (m_monitor) + { + // If the ProcessLaunchInfo specified a callback, make sure it's registered in + // addition to anything else that may have been registered by the creator of the + // status monitor. + m_monitor->AddProcessEventCallback(callback, baton); + m_monitor->StartMonitoring(process); + } + else + { + // FIXME: This branch should go away if everything used a ProcessStatusMonitor and we + // could assume that m_monitor was non-null. + process.StartMonitoring(callback, baton, monitor_signals); + } + if (log) log->PutCString("started monitoring child process."); } Index: source/Host/common/ProcessStatusMonitor.cpp =================================================================== --- /dev/null +++ source/Host/common/ProcessStatusMonitor.cpp @@ -0,0 +1,24 @@ +//===-- ProcessStatusMonitor.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/ProcessStatusMonitor.h" + +using namespace lldb; +using namespace lldb_private; + +ProcessStatusMonitor::ProcessStatusMonitor() + : m_callbacks(new ProcessStatusMonitorCallbackList()) +{ +} + +void +ProcessStatusMonitor::AddProcessEventCallback(ProcessStatusMonitorCallback callback, void *baton) +{ + m_callbacks->push_back(std::make_pair(callback, baton)); +} Index: source/Host/windows/ExitStatusMonitorWindows.cpp =================================================================== --- /dev/null +++ source/Host/windows/ExitStatusMonitorWindows.cpp @@ -0,0 +1,47 @@ +//===-- ExitStatusMonitorWindows.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/ThreadLauncher.h" +#include "lldb/Host/windows/ExitStatusMonitorWindows.h" +#include "lldb/Host/windows/windows.h" + +using namespace lldb; +using namespace lldb_private; + +void +ExitStatusMonitor::StartMonitoring(const HostProcess &process) +{ + if (!m_callbacks) + return; + + MonitorData *thread_data = new MonitorData(); + thread_data->m_callbacks = std::move(m_callbacks); + thread_data->m_process = process; + ThreadLauncher::LaunchThread("ExitStatusMonitorThread", MonitorThread, thread_data, nullptr); +} + +lldb::thread_result_t +ExitStatusMonitor::MonitorThread(void *data) +{ + MonitorData *thread_data = static_cast(data); + HostProcess process(thread_data->m_process); + std::unique_ptr callbacks(std::move(thread_data->m_callbacks)); + + DWORD exit_code = 0; + DWORD wait_result = ::WaitForSingleObject(process.GetProcess(), INFINITE); + ::GetExitCodeProcess(process.GetProcess(), &exit_code); + + for (const auto &entry : *callbacks) + entry.first(entry.second, process.GetProcessId(), true, 0, exit_code); + + delete thread_data; + + return 0; +} Index: source/Host/windows/HostProcessWindows.cpp =================================================================== --- source/Host/windows/HostProcessWindows.cpp +++ source/Host/windows/HostProcessWindows.cpp @@ -9,9 +9,11 @@ #include "lldb/Host/FileSpec.h" #include "lldb/Host/HostThread.h" +#include "lldb/Host/ProcessStatusMonitor.h" #include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/windows/windows.h" +#include "lldb/Host/windows/ExitStatusMonitorWindows.h" #include "lldb/Host/windows/HostProcessWindows.h" +#include "lldb/Host/windows/windows.h" #include "llvm/ADT/STLExtras.h" @@ -19,16 +21,6 @@ using namespace lldb_private; -namespace -{ -struct MonitorInfo -{ - HostProcess::MonitorCallback callback; - void *baton; - HANDLE process_handle; -}; -} - HostProcessWindows::HostProcessWindows() : HostNativeProcessBase() { @@ -91,34 +83,8 @@ 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(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); - ::CloseHandle(info->process_handle); - delete (info); - } - return 0; + // Not implemented. Remove this after converting to ProcessStatusMonitor. + return HostThread(); } void HostProcessWindows::Close() Index: source/Host/windows/ProcessLauncherWindows.cpp =================================================================== --- source/Host/windows/ProcessLauncherWindows.cpp +++ source/Host/windows/ProcessLauncherWindows.cpp @@ -38,9 +38,13 @@ startupinfo.hStdInput = stdin_handle; startupinfo.hStdOutput = stdout_handle; + DWORD flags = CREATE_NEW_CONSOLE; + if (launch_info.GetFlags().Test(eLaunchFlagDebug)) + flags |= DEBUG_ONLY_THIS_PROCESS; + executable = launch_info.GetExecutableFile().GetPath(); launch_info.GetArguments().GetQuotedCommandString(commandLine); - BOOL result = ::CreateProcessA(executable.c_str(), const_cast(commandLine.c_str()), NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, + BOOL result = ::CreateProcessA(executable.c_str(), const_cast(commandLine.c_str()), NULL, NULL, TRUE, flags, NULL, launch_info.GetWorkingDirectory(), &startupinfo, &pi); if (result) {