Chromium Code Reviews| Index: tools/win/ShowThreadNames/ShowThreadNames.cc |
| diff --git a/tools/win/ShowThreadNames/ShowThreadNames.cc b/tools/win/ShowThreadNames/ShowThreadNames.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..004e615d22bd14b6664b57b5a5bcbbbfc600d26e |
| --- /dev/null |
| +++ b/tools/win/ShowThreadNames/ShowThreadNames.cc |
| @@ -0,0 +1,126 @@ |
| +// Copyright (c) 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include <windows.h> |
| + |
| +#include <stdio.h> |
| +#include <tchar.h> |
| +#include <tlhelp32.h> |
| + |
| +#include <algorithm> |
| +#include <iostream> |
| +#include <iterator> |
| +#include <map> |
| +#include <sstream> |
| +#include <string> |
| + |
| +// List all threads in a process specified. |
| +BOOL ListProcessThreadNames(DWORD dwOwnerPID); |
| + |
| +// The GetThreadDescription API is available since Windows 10, version 1607. |
|
stanisc
2017/02/23 02:29:59
Perhaps you should mention why you have to bind to
chengx
2017/02/23 03:26:04
Done.
|
| +typedef HRESULT(WINAPI* GETTHREADDESCRIPTION)(HANDLE hThread, |
| + PWSTR* threadDescription); |
| + |
| +template <typename A, typename B> |
| +std::pair<B, A> flip_pair(const std::pair<A, B>& p) { |
| + return std::pair<B, A>(p.second, p.first); |
| +} |
| + |
| +template <typename A, typename B> |
| +std::multimap<B, A> flip_map(const std::map<A, B>& src) { |
| + std::multimap<B, A> dst; |
| + std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()), |
| + flip_pair<A, B>); |
| + return dst; |
| +} |
| + |
| +int main(void) { |
| + unsigned int processId; |
| + std::string user_input; |
| + while (true) { |
| + std::cout |
| + << "\nPlease enter the process Id, or \"quit\" to end the program : "; |
| + std::getline(std::cin, user_input); |
| + std::cout << std::endl; |
| + if (user_input == "quit") |
| + break; |
| + std::stringstream ss(user_input); |
| + if (ss >> processId) { |
| + ListProcessThreadNames(processId); |
| + } else { |
| + std::cout << "input is invalid" << std::endl; |
| + } |
| + std::cout << std::endl; |
| + } |
| + return 0; |
| +} |
| + |
| +BOOL ListProcessThreadNames(DWORD dwOwnerPID) { |
| + HMODULE kernel32dll = ::GetModuleHandle(L"Kernel32.dll"); |
| + |
| + if (!kernel32dll) { |
|
brucedawson
2017/02/23 01:57:26
I'd skip this error checking 'cause kernel32.dll w
chengx
2017/02/23 03:26:04
Done.
|
| + std::cout << "Error: cannot find Kernel32.dll" << std::endl; |
| + return (FALSE); |
| + } |
| + |
| + auto get_thread_description_func = reinterpret_cast<GETTHREADDESCRIPTION>( |
| + ::GetProcAddress(kernel32dll, "GetThreadDescription")); |
| + |
| + if (!get_thread_description_func) { |
| + std::cout << "GetThreadDescription API is not available in current OS" |
| + << std::endl; |
| + return (FALSE); |
| + } |
| + |
| + HANDLE hThreadSnap = INVALID_HANDLE_VALUE; |
|
stanisc
2017/02/23 02:29:59
I'd suggest to not use Hungarian notation i.e. han
chengx
2017/02/23 03:26:03
Changed to threadSnap.
|
| + // Take a snapshot of all running threads |
| + hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); |
| + if (hThreadSnap == INVALID_HANDLE_VALUE) |
| + return (FALSE); |
| + |
| + THREADENTRY32 te32; |
| + te32.dwSize = sizeof(THREADENTRY32); |
| + |
| + // Retrieve information about the first thread, and exit if unsuccessful |
| + if (!Thread32First(hThreadSnap, &te32)) { |
| + std::cout << "Thread32First() call failed" << std::endl; |
| + CloseHandle(hThreadSnap); |
| + return (FALSE); |
| + } |
| + |
| + // Walk the thread list of the system, and display ID and name about each |
| + // thread associated with the process specified. |
| + std::cout << "thread_ID thread_name" << std::endl; |
| + std::map<DWORD, std::wstring> id_name_map; |
| + do { |
| + if (te32.th32OwnerProcessID == dwOwnerPID) { |
| + HANDLE threadHandle = |
| + OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID); |
|
brucedawson
2017/02/23 01:57:26
You can probably use THREAD_QUERY_LIMITED_INFORMAT
chengx
2017/02/23 03:26:03
Done.
|
| + if (threadHandle) { |
| + PWSTR data; |
| + HRESULT hr = get_thread_description_func(threadHandle, &data); |
| + if (SUCCEEDED(hr)) { |
| + std::wstring data_w(data); |
| + id_name_map[te32.th32ThreadID] = data_w; |
| + } else { |
| + std::cout << "GetThreadDescription API call failed" << std::endl; |
| + } |
| + CloseHandle(threadHandle); |
| + } |
| + } |
| + } while (Thread32Next(hThreadSnap, &te32)); |
| + |
| + // reverse the map so now it is sorted by thread name. |
|
stanisc
2017/02/23 02:29:59
Nit: comments are supposed to be complete sentence
chengx
2017/02/23 03:26:04
Done.
|
| + std::multimap<std::wstring, DWORD> name_id_map = flip_map(id_name_map); |
|
brucedawson
2017/02/23 01:57:26
If you're going to put it in a multimap<wstring,DW
chengx
2017/02/23 03:26:03
I will use multimap<wstring,DWORD> directly.
|
| + |
| + // show thread ID and name. |
| + for (auto it = name_id_map.begin(); it != name_id_map.end(); ++it) { |
| + std::cout << it->second << "\t"; |
| + std::wcout << it->first << std::endl; |
| + } |
| + |
| + // clean up the snapshot object. |
| + CloseHandle(hThreadSnap); |
|
brucedawson
2017/02/23 01:57:26
For tidiness consider closing the handle as soon a
chengx
2017/02/23 03:26:04
Done.
|
| + return (TRUE); |
| +} |