chromium/base/threading/hang_watcher.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/threading/hang_watcher.h"

#include <atomic>
#include <utility>

#include "base/containers/flat_map.h"
#include "base/debug/alias.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/debug/leak_annotations.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/power_monitor/power_monitor.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_checker.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/threading_features.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "base/trace_event/base_tracing.h"
#include "build/build_config.h"
#include "third_party/abseil-cpp/absl/base/attributes.h"

namespace base {

namespace {

// Defines how much logging happens when the HangWatcher monitors the threads.
// Logging levels are set per thread type through Finch. It's important that
// the order of the enum members stay the same and that their numerical
// values be in increasing order. The implementation of
// ThreadTypeLoggingLevelGreaterOrEqual() depends on it.
enum class LoggingLevel {};

HangWatcher* g_instance =;
ABSL_CONST_INIT thread_local internal::HangWatchState* hang_watch_state =;
std::atomic<bool> g_use_hang_watcher{};
std::atomic<HangWatcher::ProcessType> g_hang_watcher_process_type{};

std::atomic<LoggingLevel> g_threadpool_log_level{};
std::atomic<LoggingLevel> g_io_thread_log_level{};
std::atomic<LoggingLevel> g_main_thread_log_level{};

// Indicates whether HangWatcher::Run() should return after the next monitoring.
std::atomic<bool> g_keep_monitoring{};

// If true, indicates that this process's shutdown sequence has started. Once
// flipped to true, cannot be un-flipped.
std::atomic<bool> g_shutting_down{};

// Emits the hung thread count histogram. |count| is the number of threads
// of type |thread_type| that were hung or became hung during the last
// monitoring window. This function should be invoked for each thread type
// encountered on each call to Monitor(). `sample_ticks` is the time at which
// the sample was taken and `monitoring_period` is the interval being sampled.
void LogStatusHistogram(HangWatcher::ThreadType thread_type,
                        int count,
                        TimeTicks sample_ticks,
                        TimeDelta monitoring_period) {}

// Returns true if |thread_type| was configured through Finch to have a logging
// level that is equal to or exceeds |logging_level|.
bool ThreadTypeLoggingLevelGreaterOrEqual(HangWatcher::ThreadType thread_type,
                                          LoggingLevel logging_level) {}

}  // namespace

// Determines if the HangWatcher is activated. When false the HangWatcher
// thread never started.
BASE_FEATURE();

BASE_FEATURE();

// Browser process.
constexpr base::FeatureParam<int> kIOThreadLogLevel{};
constexpr base::FeatureParam<int> kUIThreadLogLevel{};
constexpr base::FeatureParam<int> kThreadPoolLogLevel{};

// GPU process.
constexpr base::FeatureParam<int> kGPUProcessIOThreadLogLevel{};
constexpr base::FeatureParam<int> kGPUProcessMainThreadLogLevel{};
constexpr base::FeatureParam<int> kGPUProcessThreadPoolLogLevel{};

// Renderer process.
constexpr base::FeatureParam<int> kRendererProcessIOThreadLogLevel{};
constexpr base::FeatureParam<int> kRendererProcessMainThreadLogLevel{};
constexpr base::FeatureParam<int> kRendererProcessThreadPoolLogLevel{};

// Utility process.
constexpr base::FeatureParam<int> kUtilityProcessIOThreadLogLevel{};
constexpr base::FeatureParam<int> kUtilityProcessMainThreadLogLevel{};
constexpr base::FeatureParam<int> kUtilityProcessThreadPoolLogLevel{};

constexpr const char* kThreadName =;

// The time that the HangWatcher thread will sleep for between calls to
// Monitor(). Increasing or decreasing this does not modify the type of hangs
// that can be detected. It instead increases the probability that a call to
// Monitor() will happen at the right time to catch a hang. This has to be
// balanced with power/cpu use concerns as busy looping would catch amost all
// hangs but present unacceptable overhead. NOTE: If this period is ever changed
// then all metrics that depend on it like
// HangWatcher.IsThreadHung need to be updated.
constexpr auto kMonitoringPeriod =;

WatchHangsInScope::WatchHangsInScope(TimeDelta timeout) {}

WatchHangsInScope::~WatchHangsInScope() {}

// static
void HangWatcher::InitializeOnMainThread(ProcessType process_type,
                                         bool is_zygote_child,
                                         bool emit_crashes) {}

void HangWatcher::UnitializeOnMainThreadForTesting() {}

// static
bool HangWatcher::IsEnabled() {}

// static
bool HangWatcher::IsThreadPoolHangWatchingEnabled() {}

// static
bool HangWatcher::IsIOThreadHangWatchingEnabled() {}

// static
bool HangWatcher::IsCrashReportingEnabled() {}

// static
void HangWatcher::InvalidateActiveExpectations() {}

// static
void HangWatcher::SetShuttingDown() {}

HangWatcher::HangWatcher()
    :{}

// static
void HangWatcher::CreateHangWatcherInstance() {}

#if !BUILDFLAG(IS_NACL)
debug::ScopedCrashKeyString
HangWatcher::GetTimeSinceLastCriticalMemoryPressureCrashKey() {}
#endif

std::string HangWatcher::GetTimeSinceLastSystemPowerResumeCrashKeyValue()
    const {}

void HangWatcher::OnMemoryPressure(
    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {}

HangWatcher::~HangWatcher() {}

void HangWatcher::Start() {}

void HangWatcher::Stop() {}

bool HangWatcher::IsWatchListEmpty() {}

void HangWatcher::Wait() {}

void HangWatcher::Run() {}

// static
HangWatcher* HangWatcher::GetInstance() {}

// static
void HangWatcher::RecordHang() {}

ScopedClosureRunner HangWatcher::RegisterThreadInternal(
    ThreadType thread_type) {}

// static
ScopedClosureRunner HangWatcher::RegisterThread(ThreadType thread_type) {}

base::TimeTicks HangWatcher::WatchStateSnapShot::GetHighestDeadline() const {}

HangWatcher::WatchStateSnapShot::WatchStateSnapShot() = default;

void HangWatcher::WatchStateSnapShot::Init(
    const HangWatchStates& watch_states,
    base::TimeTicks deadline_ignore_threshold,
    base::TimeDelta monitoring_period) {}

void HangWatcher::WatchStateSnapShot::Clear() {}

HangWatcher::WatchStateSnapShot::WatchStateSnapShot(
    const WatchStateSnapShot& other) = default;

HangWatcher::WatchStateSnapShot::~WatchStateSnapShot() = default;

std::string HangWatcher::WatchStateSnapShot::PrepareHungThreadListCrashKey()
    const {}

bool HangWatcher::WatchStateSnapShot::IsActionable() const {}

HangWatcher::WatchStateSnapShot HangWatcher::GrabWatchStateSnapshotForTesting()
    const {}

void HangWatcher::Monitor() {}

void HangWatcher::DoDumpWithoutCrashing(
    const WatchStateSnapShot& watch_state_snapshot) {}

void HangWatcher::SetAfterMonitorClosureForTesting(
    base::RepeatingClosure closure) {}

void HangWatcher::SetOnHangClosureForTesting(base::RepeatingClosure closure) {}

void HangWatcher::SetMonitoringPeriodForTesting(base::TimeDelta period) {}

void HangWatcher::SetAfterWaitCallbackForTesting(
    RepeatingCallback<void(TimeTicks)> callback) {}

void HangWatcher::SignalMonitorEventForTesting() {}

// static
void HangWatcher::StopMonitoringForTesting() {}

void HangWatcher::SetTickClockForTesting(const base::TickClock* tick_clock) {}

void HangWatcher::BlockIfCaptureInProgress() {}

void HangWatcher::UnregisterThread() {}

namespace internal {
namespace {

constexpr uint64_t kOnlyDeadlineMask =;
constexpr uint64_t kOnlyFlagsMask =;
constexpr uint64_t kMaximumFlag =;

// Use as a mask to keep persistent flags and the deadline.
constexpr uint64_t kPersistentFlagsAndDeadlineMask =;
}  // namespace

// Flag binary representation assertions.
static_assert;
static_assert;

HangWatchDeadline::HangWatchDeadline() = default;
HangWatchDeadline::~HangWatchDeadline() = default;

std::pair<uint64_t, TimeTicks> HangWatchDeadline::GetFlagsAndDeadline() const {}

TimeTicks HangWatchDeadline::GetDeadline() const {}

// static
TimeTicks HangWatchDeadline::Max() {}

// static
bool HangWatchDeadline::IsFlagSet(Flag flag, uint64_t flags) {}

void HangWatchDeadline::SetDeadline(TimeTicks new_deadline) {}

// TODO(crbug.com/40132796): Add flag DCHECKs here.
bool HangWatchDeadline::SetShouldBlockOnHang(uint64_t old_flags,
                                             TimeTicks old_deadline) {}

void HangWatchDeadline::SetIgnoreCurrentWatchHangsInScope() {}

void HangWatchDeadline::UnsetIgnoreCurrentWatchHangsInScope() {}

void HangWatchDeadline::SetPersistentFlag(Flag flag) {}

void HangWatchDeadline::ClearPersistentFlag(Flag flag) {}

// static
uint64_t HangWatchDeadline::ExtractFlags(uint64_t bits) {}

// static
uint64_t HangWatchDeadline::ExtractDeadline(uint64_t bits) {}

// static
TimeTicks HangWatchDeadline::DeadlineFromBits(uint64_t bits) {}

bool HangWatchDeadline::IsFlagSet(Flag flag) const {}

void HangWatchDeadline::SetSwitchBitsClosureForTesting(
    RepeatingCallback<uint64_t(void)> closure) {}

void HangWatchDeadline::ResetSwitchBitsClosureForTesting() {}

uint64_t HangWatchDeadline::SwitchBitsForTesting() {}

HangWatchState::HangWatchState(HangWatcher::ThreadType thread_type)
    :{}

HangWatchState::~HangWatchState() {}

// static
std::unique_ptr<HangWatchState>
HangWatchState::CreateHangWatchStateForCurrentThread(
    HangWatcher::ThreadType thread_type) {}

TimeTicks HangWatchState::GetDeadline() const {}

std::pair<uint64_t, TimeTicks> HangWatchState::GetFlagsAndDeadline() const {}

void HangWatchState::SetDeadline(TimeTicks deadline) {}

bool HangWatchState::IsOverDeadline() const {}

void HangWatchState::SetIgnoreCurrentWatchHangsInScope() {}

void HangWatchState::UnsetIgnoreCurrentWatchHangsInScope() {}

bool HangWatchState::SetShouldBlockOnHang(uint64_t old_flags,
                                          TimeTicks old_deadline) {}

bool HangWatchState::IsFlagSet(HangWatchDeadline::Flag flag) {}

#if DCHECK_IS_ON()
void HangWatchState::SetCurrentWatchHangsInScope(
    WatchHangsInScope* current_hang_watch_scope_enable) {}

WatchHangsInScope* HangWatchState::GetCurrentWatchHangsInScope() {}
#endif

HangWatchDeadline* HangWatchState::GetHangWatchDeadlineForTesting() {}

void HangWatchState::IncrementNestingLevel() {}

void HangWatchState::DecrementNestingLevel() {}

// static
HangWatchState* HangWatchState::GetHangWatchStateForCurrentThread() {}

PlatformThreadId HangWatchState::GetThreadID() const {}

}  // namespace internal

}  // namespace base