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

Unified Diff: chrome/chrome_watcher/chrome_watcher_main.cc

Issue 1834463002: Identify the hung thread using the Wait Chain Traversal API (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 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
Index: chrome/chrome_watcher/chrome_watcher_main.cc
diff --git a/chrome/chrome_watcher/chrome_watcher_main.cc b/chrome/chrome_watcher/chrome_watcher_main.cc
index 1976c7ae099e09150b70fcb2ba2f9a86afdb4df5..e8b7a9e758ff053c313a3317a10620b5d4d8fa4c 100644
--- a/chrome/chrome_watcher/chrome_watcher_main.cc
+++ b/chrome/chrome_watcher/chrome_watcher_main.cc
@@ -25,6 +25,7 @@
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/thread_task_runner_handle.h"
@@ -41,6 +42,7 @@
#include "third_party/kasko/kasko_features.h"
#if BUILDFLAG(ENABLE_KASKO)
+#include "chrome/chrome_watcher/wait_chain_util_win.h"
#include "components/crash/content/app/crashpad.h"
#include "syzygy/kasko/api/reporter.h"
#endif
@@ -232,6 +234,17 @@ void GetKaskoCrashReportsBaseDir(const base::char16* browser_data_directory,
}
}
+void AddCrashKey(std::vector<kasko::api::CrashKey>* crash_keys,
Sigurður Ásgeirsson 2016/03/24 19:30:18 nit: crash_keys is an out param, by convention put
Patrick Monette 2016/03/24 23:21:03 Done.
+ const wchar_t* key,
+ const wchar_t* value) {
+ DCHECK(crash_keys);
manzagop (departed) 2016/03/24 19:36:36 DCHECK the others as well?
Patrick Monette 2016/03/24 23:21:03 Done.
+
+ kasko::api::CrashKey crash_key;
+ std::wcsncpy(crash_key.name, key, kasko::api::CrashKey::kNameMaxLength);
+ std::wcsncpy(crash_key.value, value, kasko::api::CrashKey::kValueMaxLength);
+ crash_keys->push_back(crash_key);
+}
+
void DumpHungBrowserProcess(DWORD main_thread_id,
const base::string16& channel,
const base::Process& process) {
@@ -241,7 +254,28 @@ void DumpHungBrowserProcess(DWORD main_thread_id,
// Add a special crash key to distinguish reports generated for a hung
// process.
- annotations.push_back(kasko::api::CrashKey{L"hung-process", L"1"});
+ AddCrashKey(&annotations, L"hung-process", L"1");
+
+ // Use the Wait Chain Traversal API to determine the hung thread. Defaults to
+ // UI thread on error.
+ std::vector<WAITCHAIN_NODE_INFO> wait_chain;
+ bool is_deadlock = false;
+
+ DWORD hung_thread_id = main_thread_id;
+ if (GetThreadWaitChain(main_thread_id, &wait_chain, &is_deadlock)) {
+ // The last thread in the wait chain is nominated as the hung thread.
+ DCHECK(wait_chain.back().ObjectType == WctThreadType);
+ hung_thread_id = wait_chain.back().ThreadObject.ThreadId;
+
+ AddCrashKey(&annotations, L"hung-process-is-deadlock",
+ is_deadlock ? L"true" : L"false");
+
+ for (size_t i = 0; i < wait_chain.size(); i++) {
Sigurður Ásgeirsson 2016/03/24 19:30:18 Some running commentary here on what you expect th
Patrick Monette 2016/03/24 23:21:03 Done.
+ AddCrashKey(&annotations,
+ base::StringPrintf(L"hung-process-wait-chain-%zu", i).c_str(),
manzagop (departed) 2016/03/24 19:36:36 Since the chain can contain up to 16 things, perha
Patrick Monette 2016/03/24 23:21:03 Done.
+ WaitChainNodeToString(wait_chain[i]).c_str());
+ }
+ }
std::vector<const base::char16*> key_buffers;
std::vector<const base::char16*> value_buffers;
@@ -252,7 +286,7 @@ void DumpHungBrowserProcess(DWORD main_thread_id,
key_buffers.push_back(nullptr);
value_buffers.push_back(nullptr);
- // Synthesize an exception for the main thread. Populate the record with the
+ // Synthesize an exception for the hung thread. Populate the record with the
// current context of the thread to get the stack trace bucketed on the crash
// backend.
CONTEXT thread_context = {};
@@ -260,29 +294,29 @@ void DumpHungBrowserProcess(DWORD main_thread_id,
exception_record.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
EXCEPTION_POINTERS exception_pointers = {&exception_record, &thread_context};
- base::win::ScopedHandle main_thread(::OpenThread(
+ base::win::ScopedHandle hung_thread(::OpenThread(
THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
- FALSE, main_thread_id));
+ FALSE, hung_thread_id));
bool have_context = false;
- if (main_thread.IsValid()) {
- DWORD suspend_count = ::SuspendThread(main_thread.Get());
+ if (hung_thread.IsValid()) {
+ DWORD suspend_count = ::SuspendThread(hung_thread.Get());
const DWORD kSuspendFailed = static_cast<DWORD>(-1);
if (suspend_count != kSuspendFailed) {
// Best effort capture of the context.
thread_context.ContextFlags = CONTEXT_FLOATING_POINT | CONTEXT_SEGMENTS |
CONTEXT_INTEGER | CONTEXT_CONTROL;
- if (::GetThreadContext(main_thread.Get(), &thread_context) == TRUE)
+ if (::GetThreadContext(hung_thread.Get(), &thread_context) == TRUE)
have_context = true;
- ::ResumeThread(main_thread.Get());
+ ::ResumeThread(hung_thread.Get());
}
}
// TODO(erikwright): Make the dump-type channel-dependent.
if (have_context) {
kasko::api::SendReportForProcess(
- process.Handle(), main_thread_id, &exception_pointers,
+ process.Handle(), hung_thread_id, &exception_pointers,
kasko::api::LARGER_DUMP_TYPE, key_buffers.data(), value_buffers.data());
} else {
kasko::api::SendReportForProcess(process.Handle(), 0, nullptr,

Powered by Google App Engine
This is Rietveld 408576698