Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2002)

Unified Diff: tools/win/ShowThreadNames/ShowThreadNames.cc

Issue 2713773002: ShowThreadNames tool to get thread ID/name pairs in a Chrome process (Closed)
Patch Set: Fix nits. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/win/ShowThreadNames/ReadMe.txt ('k') | tools/win/ShowThreadNames/ShowThreadNames.sln » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..b083f2feef8a0d7875adb05f99c343c38a81eca7
--- /dev/null
+++ b/tools/win/ShowThreadNames/ShowThreadNames.cc
@@ -0,0 +1,142 @@
+// 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 thread names in a process specified.
+BOOL ListProcessThreadNames(DWORD owner_pid);
+// Print the error message.
+void printError(TCHAR* msg);
+
+// The GetThreadDescription API is available since Windows 10, version 1607.
+// The reason why this API is bound in this way rather than just using the
+// Windows SDK, is that this API isn't yet available in the SDK that Chrome
+// builds with.
+// Binding SetThreadDescription API in Chrome can only be done by
+// GetProcAddress, rather than the import library.
+typedef HRESULT(WINAPI* GETTHREADDESCRIPTION)(HANDLE hThread,
+ PWSTR* threadDescription);
+
+int main(void) {
+ DWORD process_Id;
+ 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);
+ // Convert the user input to lower case.
+ std::transform(user_input.begin(), user_input.end(), user_input.begin(),
+ ::tolower);
+ if (user_input == "quit")
+ break;
+ std::cout << std::endl;
+ std::stringstream ss(user_input);
+ if (ss >> process_Id) {
+ ListProcessThreadNames(process_Id);
+ } else {
+ std::cout << "Input is invalid" << std::endl;
+ }
+ std::cout << std::endl;
+ }
+ return 0;
+}
+
+BOOL ListProcessThreadNames(DWORD owner_pid) {
+ auto get_thread_description_func =
+ reinterpret_cast<GETTHREADDESCRIPTION>(::GetProcAddress(
+ ::GetModuleHandle(L"Kernel32.dll"), "GetThreadDescription"));
+
+ if (!get_thread_description_func) {
+ printError(TEXT("GetThreadDescription"));
+ return (FALSE);
+ }
+
+ HANDLE thread_snapshot = INVALID_HANDLE_VALUE;
+ // Take a snapshot of all running threads.
+ thread_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+ if (thread_snapshot == INVALID_HANDLE_VALUE) {
+ printError(TEXT("CreateToolhelp32Snapshot"));
+ return (FALSE);
+ }
+
+ THREADENTRY32 te32;
+ te32.dwSize = sizeof(THREADENTRY32);
+
+ // Retrieve information about the first thread, and exit if unsuccessful.
+ if (!Thread32First(thread_snapshot, &te32)) {
+ printError(TEXT("Thread32First"));
+ CloseHandle(thread_snapshot);
+ 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::multimap<std::wstring, DWORD> name_id_map;
+ do {
+ if (te32.th32OwnerProcessID == owner_pid) {
+ HANDLE thread_handle =
+ OpenThread(THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID);
+ if (thread_handle) {
+ PWSTR data;
+ HRESULT hr = get_thread_description_func(thread_handle, &data);
+ if (SUCCEEDED(hr)) {
+ std::wstring thread_name(data);
+ LocalFree(data);
+ name_id_map.insert(std::make_pair(thread_name, te32.th32ThreadID));
+ } else {
+ printError(TEXT("GetThreadDescription"));
+ }
+ CloseHandle(thread_handle);
+ } else {
+ printError(TEXT("OpenThread"));
+ }
+ }
+ } while (Thread32Next(thread_snapshot, &te32));
+
+ // Clean up the snapshot object.
+ CloseHandle(thread_snapshot);
+
+ // Show all thread ID/name pairs.
+ for (auto name_id_pair : name_id_map) {
+ std::cout << name_id_pair.second << "\t";
+ std::wcout << name_id_pair.first << std::endl;
+ }
+
+ return (TRUE);
+}
+
+void printError(TCHAR* msg) {
+ DWORD eNum;
+ TCHAR sysMsg[256];
+ TCHAR* p;
+
+ eNum = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, eNum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), sysMsg,
+ 256, NULL);
+
+ // Trim the end of the line and terminate it with a null.
+ p = sysMsg;
+ while ((*p > 31) || (*p == 9))
+ ++p;
+ do {
+ *p-- = 0;
+ } while ((p >= sysMsg) && ((*p == '.') || (*p < 33)));
+
+ // Display the message.
+ _tprintf(TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum,
+ sysMsg);
+}
« no previous file with comments | « tools/win/ShowThreadNames/ReadMe.txt ('k') | tools/win/ShowThreadNames/ShowThreadNames.sln » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698