Fix lock order inversion between ManagedStatic and Statistic

Summary:
Statistic and ManagedStatic both use mutexes. There was a lock order
inversion where, during initialization, Statistic's mutex would be
held while taking ManagedStatic's, and in llvm_shutdown,
ManagedStatic's mutex would be held while taking Statistic's
mutex. This change causes Statistic's initialization code to avoid
holding its mutex while calling ManagedStatic's methods, avoiding the
inversion.

Reviewers: dsanders, rtereshin

Reviewed By: dsanders

Subscribers: hiraditya, llvm-commits

Differential Revision: https://reviews.llvm.org/D45398

llvm-svn: 330236
This commit is contained in:
Bob Haarman 2018-04-17 23:37:18 +00:00
parent 3108802f16
commit 37a9269cc7
1 changed files with 13 additions and 2 deletions

View File

@ -94,10 +94,21 @@ static ManagedStatic<sys::SmartMutex<true> > StatLock;
void Statistic::RegisterStatistic() {
// If stats are enabled, inform StatInfo that this statistic should be
// printed.
sys::SmartScopedLock<true> Writer(*StatLock);
// llvm_shutdown calls destructors while holding the ManagedStatic mutex.
// These destructors end up calling PrintStatistics, which takes StatLock.
// Since dereferencing StatInfo and StatLock can require taking the
// ManagedStatic mutex, doing so with StatLock held would lead to a lock
// order inversion. To avoid that, we dereference the ManagedStatics first,
// and only take StatLock afterwards.
if (!Initialized.load(std::memory_order_relaxed)) {
sys::SmartMutex<true> &Lock = *StatLock;
StatisticInfo &SI = *StatInfo;
sys::SmartScopedLock<true> Writer(Lock);
// Check Initialized again after acquiring the lock.
if (Initialized.load(std::memory_order_relaxed))
return;
if (Stats || Enabled)
StatInfo->addStatistic(this);
SI.addStatistic(this);
// Remember we have been registered.
Initialized.store(true, std::memory_order_release);