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"
13 typedef HRESULT(WINAPI
* GETTHREADDESCRIPTION
)(HANDLE hThread
,
14 PWSTR
* threadDescription
);
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
) {
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));
35 te32
.dwSize
= sizeof(THREADENTRY32
);
37 // Retrieve information about the first thread,
38 // and exit if unsuccessful
39 if (!Thread32First(hThreadSnap
.get(), &te32
)) {
44 if (te32
.th32OwnerProcessID
== info
->pid
) {
46 OpenThread(THREAD_QUERY_INFORMATION
, TRUE
, te32
.th32ThreadID
));
51 FILETIME createTime
, exitTime
, kernelTime
, userTime
;
52 if (!GetThreadTimes(hThread
.get(), &createTime
, &exitTime
, &kernelTime
,
58 if (getThreadDescription
) {
59 PWSTR threadName
= nullptr;
60 if (getThreadDescription(hThread
.get(), &threadName
) && threadName
) {
61 thread
.name
= 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__
);
81 nsCOMPtr
<nsIEventTarget
> target
=
82 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
, &rv
);
84 NS_WARNING("Failed to get stream transport service");
85 holder
->Reject(rv
, __func__
);
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
));
95 holder
->Reject(NS_ERROR_FAILURE
, __func__
);
99 wchar_t filename
[MAX_PATH
];
100 if (GetProcessImageFileNameW(handle
.get(), filename
, MAX_PATH
) == 0) {
101 holder
->Reject(NS_ERROR_FAILURE
, __func__
);
104 FILETIME createTime
, exitTime
, kernelTime
, userTime
;
105 if (!GetProcessTimes(handle
.get(), &createTime
, &exitTime
, &kernelTime
,
107 holder
->Reject(NS_ERROR_FAILURE
, __func__
);
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__
);
119 info
.childId
= childId
;
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
);
132 NS_WARNING("Failed to dispatch the LoadDataRunnable.");
138 } // namespace mozilla