Bug 1614864 [wpt PR 21746] - [webnfc] Add WPT tests for smart poster, a=testonly
[gecko.git] / widget / windows / ProcInfo.cpp
blobb5bb6bca2ee5e2c2996a71559cce643afc662b5b
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ProcInfo.h"
8 #include "mozilla/ipc/GeckoChildProcessHost.h"
9 #include <windows.h>
10 #include <psapi.h>
11 #include <tlhelp32.h>
13 typedef HRESULT(WINAPI* GETTHREADDESCRIPTION)(HANDLE hThread,
14 PWSTR* threadDescription);
16 namespace mozilla {
18 uint64_t ToNanoSeconds(const FILETIME& aFileTime) {
19 // FILETIME values are 100-nanoseconds units, converting
20 ULARGE_INTEGER usec = {{aFileTime.dwLowDateTime, aFileTime.dwHighDateTime}};
21 return usec.QuadPart * 100;
24 void AppendThreads(ProcInfo* info) {
25 THREADENTRY32 te32;
26 auto getThreadDescription =
27 reinterpret_cast<GETTHREADDESCRIPTION>(::GetProcAddress(
28 ::GetModuleHandleW(L"Kernel32.dll"), "GetThreadDescription"));
30 // Take a snapshot of all running threads, system-wide.
31 nsAutoHandle hThreadSnap(CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0));
32 if (!hThreadSnap) {
33 return;
35 te32.dwSize = sizeof(THREADENTRY32);
37 // Retrieve information about the first thread,
38 // and exit if unsuccessful
39 if (!Thread32First(hThreadSnap.get(), &te32)) {
40 return;
43 do {
44 if (te32.th32OwnerProcessID == info->pid) {
45 nsAutoHandle hThread(
46 OpenThread(THREAD_QUERY_INFORMATION, TRUE, te32.th32ThreadID));
47 if (!hThread) {
48 continue;
51 FILETIME createTime, exitTime, kernelTime, userTime;
52 if (!GetThreadTimes(hThread.get(), &createTime, &exitTime, &kernelTime,
53 &userTime)) {
54 continue;
57 ThreadInfo thread;
58 if (getThreadDescription) {
59 PWSTR threadName = nullptr;
60 if (getThreadDescription(hThread.get(), &threadName) && threadName) {
61 thread.name = threadName;
63 if (threadName) {
64 LocalFree(threadName);
67 thread.tid = te32.th32ThreadID;
68 thread.cpuKernel = ToNanoSeconds(kernelTime);
69 thread.cpuUser = ToNanoSeconds(userTime);
70 info->threads.AppendElement(thread);
72 } while (Thread32Next(hThreadSnap.get(), &te32));
75 RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
76 const ProcType& type) {
77 auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
78 RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);
80 nsresult rv = NS_OK;
81 nsCOMPtr<nsIEventTarget> target =
82 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
83 if (NS_FAILED(rv)) {
84 NS_WARNING("Failed to get stream transport service");
85 holder->Reject(rv, __func__);
86 return promise;
89 RefPtr<nsIRunnable> r = NS_NewRunnableFunction(
90 __func__, [holder = std::move(holder), pid, type, childId]() -> void {
91 nsAutoHandle handle(OpenProcess(
92 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
94 if (!handle) {
95 holder->Reject(NS_ERROR_FAILURE, __func__);
96 return;
99 wchar_t filename[MAX_PATH];
100 if (GetProcessImageFileNameW(handle.get(), filename, MAX_PATH) == 0) {
101 holder->Reject(NS_ERROR_FAILURE, __func__);
102 return;
104 FILETIME createTime, exitTime, kernelTime, userTime;
105 if (!GetProcessTimes(handle.get(), &createTime, &exitTime, &kernelTime,
106 &userTime)) {
107 holder->Reject(NS_ERROR_FAILURE, __func__);
108 return;
110 PROCESS_MEMORY_COUNTERS memoryCounters;
111 if (!GetProcessMemoryInfo(handle.get(),
112 (PPROCESS_MEMORY_COUNTERS)&memoryCounters,
113 sizeof(memoryCounters))) {
114 holder->Reject(NS_ERROR_FAILURE, __func__);
115 return;
117 ProcInfo info;
118 info.pid = pid;
119 info.childId = childId;
120 info.type = type;
121 info.filename.Assign(filename);
122 info.cpuKernel = ToNanoSeconds(kernelTime);
123 info.cpuUser = ToNanoSeconds(userTime);
124 info.residentSetSize = memoryCounters.WorkingSetSize;
125 info.virtualMemorySize = memoryCounters.PagefileUsage;
126 AppendThreads(&info);
127 holder->Resolve(info, __func__);
130 rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
131 if (NS_FAILED(rv)) {
132 NS_WARNING("Failed to dispatch the LoadDataRunnable.");
135 return promise;
138 } // namespace mozilla