mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
151 lines
4.1 KiB
C++
151 lines
4.1 KiB
C++
|
// Copyright 2016 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 "base/win/wait_chain.h"
|
||
|
|
||
|
#include <memory>
|
||
|
|
||
|
#include "base/logging.h"
|
||
|
#include "base/strings/stringprintf.h"
|
||
|
|
||
|
namespace base {
|
||
|
namespace win {
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
// Helper deleter to hold a HWCT into a unique_ptr.
|
||
|
struct WaitChainSessionDeleter {
|
||
|
using pointer = HWCT;
|
||
|
void operator()(HWCT session_handle) const {
|
||
|
::CloseThreadWaitChainSession(session_handle);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
using ScopedWaitChainSessionHandle =
|
||
|
std::unique_ptr<HWCT, WaitChainSessionDeleter>;
|
||
|
|
||
|
const wchar_t* WctObjectTypeToString(WCT_OBJECT_TYPE type) {
|
||
|
switch (type) {
|
||
|
case WctCriticalSectionType:
|
||
|
return L"CriticalSection";
|
||
|
case WctSendMessageType:
|
||
|
return L"SendMessage";
|
||
|
case WctMutexType:
|
||
|
return L"Mutex";
|
||
|
case WctAlpcType:
|
||
|
return L"Alpc";
|
||
|
case WctComType:
|
||
|
return L"Com";
|
||
|
case WctThreadWaitType:
|
||
|
return L"ThreadWait";
|
||
|
case WctProcessWaitType:
|
||
|
return L"ProcessWait";
|
||
|
case WctThreadType:
|
||
|
return L"Thread";
|
||
|
case WctComActivationType:
|
||
|
return L"ComActivation";
|
||
|
case WctUnknownType:
|
||
|
return L"Unknown";
|
||
|
case WctSocketIoType:
|
||
|
return L"SocketIo";
|
||
|
case WctSmbIoType:
|
||
|
return L"SmbIo";
|
||
|
case WctMaxType:
|
||
|
break;
|
||
|
}
|
||
|
NOTREACHED();
|
||
|
return L"";
|
||
|
}
|
||
|
|
||
|
const wchar_t* WctObjectStatusToString(WCT_OBJECT_STATUS status) {
|
||
|
switch (status) {
|
||
|
case WctStatusNoAccess:
|
||
|
return L"NoAccess";
|
||
|
case WctStatusRunning:
|
||
|
return L"Running";
|
||
|
case WctStatusBlocked:
|
||
|
return L"Blocked";
|
||
|
case WctStatusPidOnly:
|
||
|
return L"PidOnly";
|
||
|
case WctStatusPidOnlyRpcss:
|
||
|
return L"PidOnlyRpcss";
|
||
|
case WctStatusOwned:
|
||
|
return L"Owned";
|
||
|
case WctStatusNotOwned:
|
||
|
return L"NotOwned";
|
||
|
case WctStatusAbandoned:
|
||
|
return L"Abandoned";
|
||
|
case WctStatusUnknown:
|
||
|
return L"Unknown";
|
||
|
case WctStatusError:
|
||
|
return L"Error";
|
||
|
case WctStatusMax:
|
||
|
break;
|
||
|
}
|
||
|
NOTREACHED();
|
||
|
return L"";
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
bool GetThreadWaitChain(DWORD thread_id,
|
||
|
WaitChainNodeVector* wait_chain,
|
||
|
bool* is_deadlock,
|
||
|
base::string16* failure_reason,
|
||
|
DWORD* last_error) {
|
||
|
DCHECK(wait_chain);
|
||
|
DCHECK(is_deadlock);
|
||
|
|
||
|
constexpr wchar_t kWaitChainSessionFailureReason[] =
|
||
|
L"OpenThreadWaitChainSession() failed.";
|
||
|
constexpr wchar_t kGetWaitChainFailureReason[] =
|
||
|
L"GetThreadWaitChain() failed.";
|
||
|
|
||
|
// Open a synchronous session.
|
||
|
ScopedWaitChainSessionHandle session_handle(
|
||
|
::OpenThreadWaitChainSession(0, nullptr));
|
||
|
if (!session_handle) {
|
||
|
if (last_error)
|
||
|
*last_error = ::GetLastError();
|
||
|
if (failure_reason)
|
||
|
*failure_reason = kWaitChainSessionFailureReason;
|
||
|
DPLOG(ERROR) << kWaitChainSessionFailureReason;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
DWORD nb_nodes = WCT_MAX_NODE_COUNT;
|
||
|
wait_chain->resize(nb_nodes);
|
||
|
BOOL is_cycle;
|
||
|
if (!::GetThreadWaitChain(session_handle.get(), NULL, 0, thread_id, &nb_nodes,
|
||
|
wait_chain->data(), &is_cycle)) {
|
||
|
if (last_error)
|
||
|
*last_error = ::GetLastError();
|
||
|
if (failure_reason)
|
||
|
*failure_reason = kGetWaitChainFailureReason;
|
||
|
DPLOG(ERROR) << kGetWaitChainFailureReason;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
*is_deadlock = is_cycle ? true : false;
|
||
|
wait_chain->resize(nb_nodes);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
base::string16 WaitChainNodeToString(const WAITCHAIN_NODE_INFO& node) {
|
||
|
if (node.ObjectType == WctThreadType) {
|
||
|
return base::StringPrintf(L"Thread %d in process %d with status %ls",
|
||
|
node.ThreadObject.ThreadId,
|
||
|
node.ThreadObject.ProcessId,
|
||
|
WctObjectStatusToString(node.ObjectStatus));
|
||
|
} else {
|
||
|
return base::StringPrintf(L"Lock of type %ls with status %ls",
|
||
|
WctObjectTypeToString(node.ObjectType),
|
||
|
WctObjectStatusToString(node.ObjectStatus));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace win
|
||
|
} // namespace base
|