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

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: Addressed comments/questions 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
« no previous file with comments | « chrome/chrome_watcher/chrome_watcher.gypi ('k') | chrome/chrome_watcher/wait_chain_util_win.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..25c337b2b5769d17e8f6bf40120fe284d1733d65 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,19 @@ void GetKaskoCrashReportsBaseDir(const base::char16* browser_data_directory,
}
}
+void AddCrashKey(const wchar_t* key,
+ const wchar_t* value,
+ std::vector<kasko::api::CrashKey>* crash_keys) {
+ DCHECK(key);
+ DCHECK(value);
+ DCHECK(crash_keys);
+
+ kasko::api::CrashKey crash_key;
+ std::wcsncpy(crash_key.name, key, kasko::api::CrashKey::kNameMaxLength);
manzagop (departed) 2016/03/31 20:24:45 Do you need a -1 to for \0?
Patrick Monette 2016/04/05 19:03:12 I'm not sure but I've gone for the safe way and ad
+ 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 +256,35 @@ 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(L"hung-process", L"1", &annotations);
+
+ // 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)) {
manzagop (departed) 2016/03/29 13:57:48 IIUC this can cross process boundaries and the cha
Sigurður Ásgeirsson 2016/03/29 16:57:32 oh - interesting - this is true.
Patrick Monette 2016/04/05 19:03:12 Done.
+ // The last thread in the wait chain is nominated as the hung thread.
+ DCHECK(wait_chain.back().ObjectType == WctThreadType);
manzagop (departed) 2016/03/29 13:57:48 How sure are we the last element is a thread? I gu
Patrick Monette 2016/04/05 19:03:12 Done. In some cases, it's possible that the last e
+ hung_thread_id = wait_chain.back().ThreadObject.ThreadId;
+
+ // The entire wait chain is added to the crash report via crash keys.
+ //
+ // As an example (key : value):
+ // hung-process-is-deadlock : false
+ // hung-process-wait-chain-00 : Thread #10242 with status Blocked
+ // hung-process-wait-chain-01 : Lock of type ThreadWait with status Owned
+ // hung-process-wait-chain-02 : Thread #77221 with status Blocked
+ //
+ AddCrashKey(L"hung-process-is-deadlock", is_deadlock ? L"true" : L"false",
+ &annotations);
+ for (size_t i = 0; i < wait_chain.size(); i++) {
+ AddCrashKey(
+ base::StringPrintf(L"hung-process-wait-chain-%02zu", i).c_str(),
+ WaitChainNodeToString(wait_chain[i]).c_str(), &annotations);
+ }
+ }
std::vector<const base::char16*> key_buffers;
std::vector<const base::char16*> value_buffers;
@@ -252,7 +295,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 +303,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,
« no previous file with comments | « chrome/chrome_watcher/chrome_watcher.gypi ('k') | chrome/chrome_watcher/wait_chain_util_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698