From d1e8fbba7f28a9a803e818990bc86a1ae2756b2e Mon Sep 17 00:00:00 2001 From: FuzzTest Team Date: Wed, 15 Apr 2026 13:34:31 -0700 Subject: [PATCH] No public description PiperOrigin-RevId: 900320823 --- centipede/rusage_profiler.cc | 8 ++++---- centipede/rusage_profiler.h | 10 ++++++---- centipede/rusage_profiler_test.cc | 20 ++++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/centipede/rusage_profiler.cc b/centipede/rusage_profiler.cc index 5e41de5d7..540855b72 100644 --- a/centipede/rusage_profiler.cc +++ b/centipede/rusage_profiler.cc @@ -372,7 +372,7 @@ const RUsageProfiler::Snapshot& RUsageProfiler::TakeSnapshot( // return kEmpty; } - absl::WriterMutexLock lock{mutex_}; + absl::WriterMutexLock lock{snapshots_mutex_}; RUsageTiming snap_timing = RUsageTiming::Zero(); RUsageTiming delta_timing = RUsageTiming::Zero(); @@ -420,7 +420,7 @@ void RUsageProfiler::StartTimelapse( // absl::Duration interval, // bool also_log, // std::string title) { - absl::WriterMutexLock lock{mutex_}; + absl::WriterMutexLock lock{recorder_mutex_}; FUZZTEST_CHECK(!timelapse_recorder_) << "StopTimelapse() wasn't called"; timelapse_recorder_ = std::make_unique( [this, loc = std::move(loc), title = std::move(title), also_log]() { @@ -431,7 +431,7 @@ void RUsageProfiler::StartTimelapse( // } void RUsageProfiler::StopTimelapse() { - absl::WriterMutexLock lock{mutex_}; + absl::WriterMutexLock lock{recorder_mutex_}; FUZZTEST_CHECK(timelapse_recorder_) << "StartTimelapse() wasn't called"; timelapse_recorder_.reset(); } @@ -483,7 +483,7 @@ void RUsageProfiler::PrintReport( // void RUsageProfiler::GenerateReport( ReportSink* absl_nonnull report_sink) const { - absl::ReaderMutexLock lock{mutex_}; + absl::ReaderMutexLock lock{snapshots_mutex_}; // Prevent interleaved reports from multiple concurrent RUsageProfilers. ABSL_CONST_INIT static absl::Mutex report_generation_mutex_{absl::kConstInit}; absl::WriterMutexLock logging_lock{report_generation_mutex_}; diff --git a/centipede/rusage_profiler.h b/centipede/rusage_profiler.h index 756ebb56e..1fcd0c7cb 100644 --- a/centipede/rusage_profiler.h +++ b/centipede/rusage_profiler.h @@ -427,17 +427,19 @@ class RUsageProfiler { // The sequential ID of this profiler. Used to annotate all log const int id_; - // Mutex for the mutable data further below. - mutable absl::Mutex mutex_; + // Mutexes for the mutable data further below. + mutable absl::Mutex snapshots_mutex_; + mutable absl::Mutex recorder_mutex_; // Chronological snapshots. Using std::deque gives a better-than-vector // average insertion speed, preserves iterators across insertions, and strikes // a balance between vector's and list's additional storage. - std::deque snapshots_ ABSL_GUARDED_BY(mutex_); + std::deque snapshots_ ABSL_GUARDED_BY(snapshots_mutex_); // A temporarily lived periodic action that records and optionally logs // timelapse snapshots. (Re)created by each new call to StartTimelapse() and // terminated by StopTimelapse() or the dtor, whichever comes first. - std::unique_ptr timelapse_recorder_ ABSL_GUARDED_BY(mutex_); + std::unique_ptr timelapse_recorder_ + ABSL_GUARDED_BY(recorder_mutex_); // An auto-starting timer passed to RUsageTiming::Snapshot() in order to track // this RUsageProfiler object's lifetime stats rather than the process's diff --git a/centipede/rusage_profiler_test.cc b/centipede/rusage_profiler_test.cc index c8c0b9f78..1ad46eb3d 100644 --- a/centipede/rusage_profiler_test.cc +++ b/centipede/rusage_profiler_test.cc @@ -245,4 +245,24 @@ TEST(RUsageProfilerTest, ValidateReport) { rprof.GenerateReport(&report_capture); } +TEST(RUsageProfilerTest, DeadlockReproduction) { + const auto rusage_scope = RUsageScope::ThisProcess(); + for (int i = 0; i < 1000; ++i) { + RUsageProfiler rprof{rusage_scope, + RUsageProfiler::kAllMetrics, + RUsageProfiler::kRaiiOff, + {__FILE__, __LINE__}}; + // Use a tiny interval to trigger frequent snapshots + rprof.StartTimelapse({__FILE__, __LINE__}, absl::Microseconds(10), + /*also_log=*/false, "Timelapse"); + + // Briefly wait to ensure the background thread starts running + absl::SleepFor(absl::Microseconds(10)); + + // This call frequently deadlocks because it holds the mutex while + // waiting for the background thread to finish its TakeSnapshot() call. + rprof.StopTimelapse(); + } +} + } // namespace fuzztest::internal