1dda28197Spatrick //===-- HostProcessWindows.cpp --------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Host/windows/HostProcessWindows.h"
10061da546Spatrick #include "lldb/Host/HostThread.h"
11061da546Spatrick #include "lldb/Host/ThreadLauncher.h"
12061da546Spatrick #include "lldb/Host/windows/windows.h"
13061da546Spatrick #include "lldb/Utility/FileSpec.h"
14061da546Spatrick
15061da546Spatrick #include "llvm/ADT/STLExtras.h"
16061da546Spatrick #include "llvm/Support/ConvertUTF.h"
17061da546Spatrick #include "llvm/Support/WindowsError.h"
18061da546Spatrick
19061da546Spatrick #include <psapi.h>
20061da546Spatrick
21061da546Spatrick using namespace lldb_private;
22061da546Spatrick
23061da546Spatrick namespace {
24061da546Spatrick struct MonitorInfo {
25061da546Spatrick Host::MonitorChildProcessCallback callback;
26061da546Spatrick HANDLE process_handle;
27061da546Spatrick };
28061da546Spatrick }
29061da546Spatrick
HostProcessWindows()30061da546Spatrick HostProcessWindows::HostProcessWindows()
31061da546Spatrick : HostNativeProcessBase(), m_owns_handle(true) {}
32061da546Spatrick
HostProcessWindows(lldb::process_t process)33061da546Spatrick HostProcessWindows::HostProcessWindows(lldb::process_t process)
34061da546Spatrick : HostNativeProcessBase(process), m_owns_handle(true) {}
35061da546Spatrick
~HostProcessWindows()36061da546Spatrick HostProcessWindows::~HostProcessWindows() { Close(); }
37061da546Spatrick
SetOwnsHandle(bool owns)38061da546Spatrick void HostProcessWindows::SetOwnsHandle(bool owns) { m_owns_handle = owns; }
39061da546Spatrick
Terminate()40061da546Spatrick Status HostProcessWindows::Terminate() {
41061da546Spatrick Status error;
42061da546Spatrick if (m_process == nullptr)
43061da546Spatrick error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32);
44061da546Spatrick
45061da546Spatrick if (!::TerminateProcess(m_process, 0))
46061da546Spatrick error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
47061da546Spatrick
48061da546Spatrick return error;
49061da546Spatrick }
50061da546Spatrick
GetProcessId() const51061da546Spatrick lldb::pid_t HostProcessWindows::GetProcessId() const {
52061da546Spatrick return (m_process == LLDB_INVALID_PROCESS) ? -1 : ::GetProcessId(m_process);
53061da546Spatrick }
54061da546Spatrick
IsRunning() const55061da546Spatrick bool HostProcessWindows::IsRunning() const {
56061da546Spatrick if (m_process == nullptr)
57061da546Spatrick return false;
58061da546Spatrick
59061da546Spatrick DWORD code = 0;
60061da546Spatrick if (!::GetExitCodeProcess(m_process, &code))
61061da546Spatrick return false;
62061da546Spatrick
63061da546Spatrick return (code == STILL_ACTIVE);
64061da546Spatrick }
65061da546Spatrick
66*f6aab3d8Srobert static lldb::thread_result_t
MonitorThread(const Host::MonitorChildProcessCallback & callback,HANDLE process_handle)67*f6aab3d8Srobert MonitorThread(const Host::MonitorChildProcessCallback &callback,
68*f6aab3d8Srobert HANDLE process_handle) {
69*f6aab3d8Srobert DWORD exit_code;
70*f6aab3d8Srobert
71*f6aab3d8Srobert ::WaitForSingleObject(process_handle, INFINITE);
72*f6aab3d8Srobert ::GetExitCodeProcess(process_handle, &exit_code);
73*f6aab3d8Srobert callback(::GetProcessId(process_handle), 0, exit_code);
74*f6aab3d8Srobert ::CloseHandle(process_handle);
75*f6aab3d8Srobert return {};
76*f6aab3d8Srobert }
77*f6aab3d8Srobert
StartMonitoring(const Host::MonitorChildProcessCallback & callback)78061da546Spatrick llvm::Expected<HostThread> HostProcessWindows::StartMonitoring(
79*f6aab3d8Srobert const Host::MonitorChildProcessCallback &callback) {
80*f6aab3d8Srobert HANDLE process_handle;
81061da546Spatrick
82061da546Spatrick // Since the life of this HostProcessWindows instance and the life of the
83061da546Spatrick // process may be different, duplicate the handle so that the monitor thread
84061da546Spatrick // can have ownership over its own copy of the handle.
85061da546Spatrick if (::DuplicateHandle(GetCurrentProcess(), m_process, GetCurrentProcess(),
86*f6aab3d8Srobert &process_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
87*f6aab3d8Srobert return ThreadLauncher::LaunchThread(
88*f6aab3d8Srobert "ChildProcessMonitor", [callback, process_handle] {
89*f6aab3d8Srobert return MonitorThread(callback, process_handle);
90*f6aab3d8Srobert });
91061da546Spatrick } else {
92061da546Spatrick return llvm::errorCodeToError(llvm::mapWindowsError(GetLastError()));
93061da546Spatrick }
94061da546Spatrick }
95061da546Spatrick
Close()96061da546Spatrick void HostProcessWindows::Close() {
97061da546Spatrick if (m_owns_handle && m_process != LLDB_INVALID_PROCESS)
98061da546Spatrick ::CloseHandle(m_process);
99061da546Spatrick m_process = nullptr;
100061da546Spatrick }
101