No public description PiperOrigin-RevId: 900320823
diff --git a/centipede/rusage_profiler.cc b/centipede/rusage_profiler.cc index 5e41de5..540855b 100644 --- a/centipede/rusage_profiler.cc +++ b/centipede/rusage_profiler.cc
@@ -372,7 +372,7 @@ 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 @@ 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<PeriodicAction>( [this, loc = std::move(loc), title = std::move(title), also_log]() { @@ -431,7 +431,7 @@ } 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::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 756ebb5..1fcd0c7 100644 --- a/centipede/rusage_profiler.h +++ b/centipede/rusage_profiler.h
@@ -427,17 +427,19 @@ // 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<Snapshot> snapshots_ ABSL_GUARDED_BY(mutex_); + std::deque<Snapshot> 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<PeriodicAction> timelapse_recorder_ ABSL_GUARDED_BY(mutex_); + std::unique_ptr<PeriodicAction> 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 c8c0b9f..1ad46eb 100644 --- a/centipede/rusage_profiler_test.cc +++ b/centipede/rusage_profiler_test.cc
@@ -245,4 +245,24 @@ 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