180814287SRaphael Isemann //===-- HostProcessWindows.cpp --------------------------------------------===//
24e82ec9cSZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64e82ec9cSZachary Turner //
74e82ec9cSZachary Turner //===----------------------------------------------------------------------===//
84e82ec9cSZachary Turner 
9b9c1b51eSKate Stone #include "lldb/Host/windows/HostProcessWindows.h"
10172d37d3SZachary Turner #include "lldb/Host/HostThread.h"
11172d37d3SZachary Turner #include "lldb/Host/ThreadLauncher.h"
124e82ec9cSZachary Turner #include "lldb/Host/windows/windows.h"
135713a05bSZachary Turner #include "lldb/Utility/FileSpec.h"
144e82ec9cSZachary Turner 
154e82ec9cSZachary Turner #include "llvm/ADT/STLExtras.h"
16190fadcdSZachary Turner #include "llvm/Support/ConvertUTF.h"
17631b5f7dSStella Stamenova #include "llvm/Support/WindowsError.h"
184e82ec9cSZachary Turner 
19f6ee79c9SHafiz Abid Qadeer #include <psapi.h>
20f5e4f37cSZachary Turner 
214e82ec9cSZachary Turner using namespace lldb_private;
224e82ec9cSZachary Turner 
23b9c1b51eSKate Stone namespace {
24b9c1b51eSKate Stone struct MonitorInfo {
25998bdc5bSPavel Labath   Host::MonitorChildProcessCallback callback;
26172d37d3SZachary Turner   HANDLE process_handle;
27172d37d3SZachary Turner };
28172d37d3SZachary Turner }
29172d37d3SZachary Turner 
HostProcessWindows()30c76a4452SZachary Turner HostProcessWindows::HostProcessWindows()
31b9c1b51eSKate Stone     : HostNativeProcessBase(), m_owns_handle(true) {}
32c76a4452SZachary Turner 
HostProcessWindows(lldb::process_t process)33f5e4f37cSZachary Turner HostProcessWindows::HostProcessWindows(lldb::process_t process)
34b9c1b51eSKate Stone     : HostNativeProcessBase(process), m_owns_handle(true) {}
354e82ec9cSZachary Turner 
~HostProcessWindows()36b9c1b51eSKate Stone HostProcessWindows::~HostProcessWindows() { Close(); }
374e82ec9cSZachary Turner 
SetOwnsHandle(bool owns)38b9c1b51eSKate Stone void HostProcessWindows::SetOwnsHandle(bool owns) { m_owns_handle = owns; }
39742346a2SZachary Turner 
Terminate()4097206d57SZachary Turner Status HostProcessWindows::Terminate() {
4197206d57SZachary Turner   Status error;
42f5e4f37cSZachary Turner   if (m_process == nullptr)
434e82ec9cSZachary Turner     error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32);
444e82ec9cSZachary Turner 
454e82ec9cSZachary Turner   if (!::TerminateProcess(m_process, 0))
464e82ec9cSZachary Turner     error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
474e82ec9cSZachary Turner 
484e82ec9cSZachary Turner   return error;
494e82ec9cSZachary Turner }
504e82ec9cSZachary Turner 
GetProcessId() const51b9c1b51eSKate Stone lldb::pid_t HostProcessWindows::GetProcessId() const {
52172d37d3SZachary Turner   return (m_process == LLDB_INVALID_PROCESS) ? -1 : ::GetProcessId(m_process);
534e82ec9cSZachary Turner }
544e82ec9cSZachary Turner 
IsRunning() const55b9c1b51eSKate Stone bool HostProcessWindows::IsRunning() const {
56f5e4f37cSZachary Turner   if (m_process == nullptr)
574e82ec9cSZachary Turner     return false;
584e82ec9cSZachary Turner 
594e82ec9cSZachary Turner   DWORD code = 0;
604e82ec9cSZachary Turner   if (!::GetExitCodeProcess(m_process, &code))
614e82ec9cSZachary Turner     return false;
624e82ec9cSZachary Turner 
634e82ec9cSZachary Turner   return (code == STILL_ACTIVE);
644e82ec9cSZachary Turner }
654e82ec9cSZachary Turner 
6682951cfbSPavel Labath static lldb::thread_result_t
MonitorThread(const Host::MonitorChildProcessCallback & callback,HANDLE process_handle)6782951cfbSPavel Labath MonitorThread(const Host::MonitorChildProcessCallback &callback,
6882951cfbSPavel Labath               HANDLE process_handle) {
6982951cfbSPavel Labath   DWORD exit_code;
7082951cfbSPavel Labath 
7182951cfbSPavel Labath   ::WaitForSingleObject(process_handle, INFINITE);
7282951cfbSPavel Labath   ::GetExitCodeProcess(process_handle, &exit_code);
73*b5eeb887SPavel Labath   callback(::GetProcessId(process_handle), 0, exit_code);
7482951cfbSPavel Labath   ::CloseHandle(process_handle);
7582951cfbSPavel Labath   return {};
7682951cfbSPavel Labath }
7782951cfbSPavel Labath 
StartMonitoring(const Host::MonitorChildProcessCallback & callback)7809923183SJonas Devlieghere llvm::Expected<HostThread> HostProcessWindows::StartMonitoring(
7912c9c4a8SPavel Labath     const Host::MonitorChildProcessCallback &callback) {
8082951cfbSPavel Labath   HANDLE process_handle;
81172d37d3SZachary Turner 
82b9c1b51eSKate Stone   // Since the life of this HostProcessWindows instance and the life of the
8305097246SAdrian Prantl   // process may be different, duplicate the handle so that the monitor thread
8405097246SAdrian Prantl   // can have ownership over its own copy of the handle.
85b9c1b51eSKate Stone   if (::DuplicateHandle(GetCurrentProcess(), m_process, GetCurrentProcess(),
8682951cfbSPavel Labath                         &process_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
8782951cfbSPavel Labath     return ThreadLauncher::LaunchThread(
8882951cfbSPavel Labath         "ChildProcessMonitor", [callback, process_handle] {
8982951cfbSPavel Labath           return MonitorThread(callback, process_handle);
9082951cfbSPavel Labath         });
917f843e22SStella Stamenova   } else {
92631b5f7dSStella Stamenova     return llvm::errorCodeToError(llvm::mapWindowsError(GetLastError()));
937f843e22SStella Stamenova   }
94172d37d3SZachary Turner }
95172d37d3SZachary Turner 
Close()96b9c1b51eSKate Stone void HostProcessWindows::Close() {
97742346a2SZachary Turner   if (m_owns_handle && m_process != LLDB_INVALID_PROCESS)
984e82ec9cSZachary Turner     ::CloseHandle(m_process);
994e82ec9cSZachary Turner   m_process = nullptr;
1004e82ec9cSZachary Turner }
101