I ended up reverting this in r228020, and also helped Delesley repro the problems.
On Tue, Feb 3, 2015 at 10:17 AM, DeLesley Hutchins <[email protected]> wrote: > Author: delesley > Date: Tue Feb 3 12:17:48 2015 > New Revision: 227997 > > URL: http://llvm.org/viewvc/llvm-project?rev=227997&view=rev > Log: > Thread Safety Analysis: add support for before/after annotations on > mutexes. > These checks detect potential deadlocks caused by inconsistent lock > ordering. The checks are implemented under the -Wthread-safety-beta flag. > > Modified: > cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h > cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h > cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > cfe/trunk/include/clang/Sema/Sema.h > cfe/trunk/lib/Analysis/ThreadSafety.cpp > cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp > cfe/trunk/lib/Sema/Sema.cpp > cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp > > Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h?rev=227997&r1=227996&r2=227997&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h (original) > +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h Tue Feb 3 > 12:17:48 2015 > @@ -26,6 +26,8 @@ > namespace clang { > namespace threadSafety { > > +class BeforeSet; > + > /// This enum distinguishes between different kinds of operations that may > /// need to be protected by locks. We use this enum in error handling. > enum ProtectedOperationKind { > @@ -183,6 +185,14 @@ public: > virtual void handleFunExcludesLock(StringRef Kind, Name FunName, > Name LockName, SourceLocation Loc) {} > > + > + /// Warn that L1 cannot be acquired before L2. > + virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name, > + Name L2Name, SourceLocation Loc) > {} > + > + /// Warn that there is a cycle in acquired_before/after dependencies. > + virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) {} > + > /// Called by the analysis when starting analysis of a function. > /// Used to issue suggestions for changes to annotations. > virtual void enterFunction(const FunctionDecl *FD) {} > @@ -203,7 +213,8 @@ private: > /// at the end of each block, and issue warnings for thread safety > violations. > /// Each block in the CFG is traversed exactly once. > void runThreadSafetyAnalysis(AnalysisDeclContext &AC, > - ThreadSafetyHandler &Handler); > + ThreadSafetyHandler &Handler, > + BeforeSet **Bset); > > /// \brief Helper function that returns a LockKind required for the given > level > /// of access. > > Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h?rev=227997&r1=227996&r2=227997&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h > (original) > +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Tue > Feb 3 12:17:48 2015 > @@ -286,6 +286,14 @@ public: > sx::partiallyMatches(CapExpr, other.CapExpr); > } > > + const ValueDecl* valueDecl() const { > + if (Negated) > + return nullptr; > + if (auto *P = dyn_cast<til::Project>(CapExpr)) > + return P->clangDecl(); > + return nullptr; > + } > + > std::string toString() const { > if (Negated) > return "!" + sx::toString(CapExpr); > > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=227997&r1=227996&r2=227997&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Feb 3 > 12:17:48 2015 > @@ -2394,6 +2394,13 @@ def warn_fun_excludes_mutex : Warning< > def warn_cannot_resolve_lock : Warning< > "cannot resolve lock expression">, > InGroup<ThreadSafetyAnalysis>, DefaultIgnore; > +def warn_acquired_before : Warning< > + "%0 '%1' must be acquired before '%2'">, > + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; > +def warn_acquired_before_after_cycle : Warning< > + "Cycle in acquired_before/after dependencies, starting with '%0'">, > + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; > + > > // Thread safety warnings negative capabilities > def warn_acquire_requires_negative_cap : Warning< > > Modified: cfe/trunk/include/clang/Sema/Sema.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=227997&r1=227996&r2=227997&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Sema/Sema.h (original) > +++ cfe/trunk/include/clang/Sema/Sema.h Tue Feb 3 12:17:48 2015 > @@ -199,6 +199,11 @@ namespace sema { > class TemplateDeductionInfo; > } > > +namespace threadSafety { > + class BeforeSet; > + void threadSafetyCleanup(BeforeSet* Cache); > +} > + > // FIXME: No way to easily map from TemplateTypeParmTypes to > // TemplateTypeParmDecls, so we have this horrible PointerUnion. > typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, > NamedDecl*>, > @@ -6708,6 +6713,7 @@ public: > > /// \brief Worker object for performing CFG-based warnings. > sema::AnalysisBasedWarnings AnalysisWarnings; > + threadSafety::BeforeSet *ThreadSafetyDeclCache; > > /// \brief An entity for which implicit template instantiation is > required. > /// > > Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=227997&r1=227996&r2=227997&view=diff > > ============================================================================== > --- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original) > +++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Tue Feb 3 12:17:48 2015 > @@ -101,17 +101,22 @@ private: > LockKind LKind; ///< exclusive or shared > SourceLocation AcquireLoc; ///< where it was acquired. > bool Asserted; ///< true if the lock was asserted > + bool Declared; ///< true if the lock was declared > > public: > FactEntry(const CapabilityExpr &CE, LockKind LK, SourceLocation Loc, > - bool Asrt) > - : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt) {} > + bool Asrt, bool Declrd = false) > + : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt), > + Declared(Declrd) {} > > virtual ~FactEntry() {} > > - LockKind kind() const { return LKind; } > + LockKind kind() const { return LKind; } > SourceLocation loc() const { return AcquireLoc; } > bool asserted() const { return Asserted; } > + bool declared() const { return Declared; } > + > + void setDeclared(bool D) { Declared = D; } > > virtual void > handleRemovalFromIntersection(const FactSet &FSet, FactManager &FactMan, > @@ -231,14 +236,56 @@ public: > > FactEntry *findPartialMatch(FactManager &FM, > const CapabilityExpr &CapE) const { > - auto I = std::find_if(begin(), end(), [&](FactID ID) { > + auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool { > return FM[ID].partiallyMatches(CapE); > }); > return I != end() ? &FM[*I] : nullptr; > } > + > + bool containsMutexDecl(FactManager &FM, const ValueDecl* Vd) const { > + auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool { > + return FM[ID].valueDecl() == Vd; > + }); > + return I != end(); > + } > +}; > + > + > +class ThreadSafetyAnalyzer; > + > + > +class BeforeSet { > +private: > + typedef SmallVector<const ValueDecl*, 4> BeforeVect; > + > + struct BeforeInfo { > + BeforeInfo() : Vect(nullptr), Visited(false) { } > + > + std::unique_ptr<BeforeVect> Vect; > + int Visited; > + }; > + > + typedef llvm::DenseMap<const ValueDecl*, BeforeInfo> BeforeMap; > + typedef llvm::DenseMap<const ValueDecl*, bool> CycleMap; > + > +public: > + BeforeSet() { } > + > + BeforeInfo* insertAttrExprs(const ValueDecl* Vd, > + ThreadSafetyAnalyzer& Analyzer); > + > + void checkBeforeAfter(const ValueDecl* Vd, > + const FactSet& FSet, > + ThreadSafetyAnalyzer& Analyzer, > + SourceLocation Loc, StringRef CapKind); > + > +private: > + BeforeMap BMap; > + CycleMap CycMap; > }; > > > + > typedef llvm::ImmutableMap<const NamedDecl*, unsigned> LocalVarContext; > class LocalVariableMap; > > @@ -853,6 +900,7 @@ public: > /// \brief Class which implements the core thread safety analysis > routines. > class ThreadSafetyAnalyzer { > friend class BuildLockset; > + friend class BeforeSet; > > llvm::BumpPtrAllocator Bpa; > threadSafety::til::MemRegionRef Arena; > @@ -864,9 +912,11 @@ class ThreadSafetyAnalyzer { > FactManager FactMan; > std::vector<CFGBlockInfo> BlockInfo; > > + BeforeSet* GlobalBeforeSet; > + > public: > - ThreadSafetyAnalyzer(ThreadSafetyHandler &H) > - : Arena(&Bpa), SxBuilder(Arena), Handler(H) {} > + ThreadSafetyAnalyzer(ThreadSafetyHandler &H, BeforeSet* Bset) > + : Arena(&Bpa), SxBuilder(Arena), Handler(H), GlobalBeforeSet(Bset) {} > > bool inCurrentScope(const CapabilityExpr &CapE); > > @@ -907,6 +957,136 @@ public: > void runAnalysis(AnalysisDeclContext &AC); > }; > > + > + > +/// Process acquired_before and acquired_after attributes on Vd. > +BeforeSet::BeforeInfo* BeforeSet::insertAttrExprs(const ValueDecl* Vd, > + ThreadSafetyAnalyzer& Analyzer) { > + // Create a new entry for Vd. > + auto& Entry = BMap.FindAndConstruct(Vd); > + BeforeInfo* Info = &Entry.second; > + BeforeVect* Bv = nullptr; > + > + const AttrVec &ArgAttrs = Vd->getAttrs(); > + for (Attr* At : ArgAttrs) { > + switch (At->getKind()) { > + case attr::AcquiredBefore: { > + auto *A = cast<AcquiredBeforeAttr>(At); > + > + // Create a new BeforeVect for Vd if necessary. > + if (!Bv) { > + Bv = new BeforeVect; > + Info->Vect.reset(Bv); > + } > + // Read exprs from the attribute, and add them to BeforeVect. > + for (const auto *Arg : A->args()) { > + CapabilityExpr Cp = > + Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr); > + if (const ValueDecl *Cpvd = Cp.valueDecl()) { > + Bv->push_back(Cpvd); > + auto It = BMap.find(Cpvd); > + if (It == BMap.end()) > + insertAttrExprs(Cpvd, Analyzer); > + } > + } > + break; > + } > + case attr::AcquiredAfter: { > + auto *A = cast<AcquiredAfterAttr>(At); > + > + // Read exprs from the attribute, and add them to BeforeVect. > + for (const auto *Arg : A->args()) { > + CapabilityExpr Cp = > + Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr); > + if (const ValueDecl *ArgVd = Cp.valueDecl()) { > + // Get entry for mutex listed in attribute > + BeforeInfo* ArgInfo; > + auto It = BMap.find(ArgVd); > + if (It == BMap.end()) > + ArgInfo = insertAttrExprs(ArgVd, Analyzer); > + else > + ArgInfo = &It->second; > + > + // Create a new BeforeVect if necessary. > + BeforeVect* ArgBv = ArgInfo->Vect.get(); > + if (!ArgBv) { > + ArgBv = new BeforeVect; > + ArgInfo->Vect.reset(ArgBv); > + } > + ArgBv->push_back(Vd); > + } > + } > + break; > + } > + default: > + break; > + } > + } > + > + return Info; > +} > + > + > +/// Return true if any mutexes in FSet are in the acquired_before set of > Vd. > +void BeforeSet::checkBeforeAfter(const ValueDecl* StartVd, > + const FactSet& FSet, > + ThreadSafetyAnalyzer& Analyzer, > + SourceLocation Loc, StringRef CapKind) { > + SmallVector<BeforeInfo*, 8> InfoVect; > + > + // Do a depth-first traversal of Vd. > + // Return true if there are cycles. > + std::function<bool (const ValueDecl*)> traverse = [&](const ValueDecl* > Vd) { > + if (!Vd) > + return false; > + > + BeforeSet::BeforeInfo* Info; > + auto It = BMap.find(Vd); > + if (It == BMap.end()) > + Info = insertAttrExprs(Vd, Analyzer); > + else > + Info = &It->second; > + > + if (Info->Visited == 1) > + return true; > + > + if (Info->Visited == 2) > + return false; > + > + BeforeVect* Bv = Info->Vect.get(); > + if (!Bv) > + return false; > + > + InfoVect.push_back(Info); > + Info->Visited = 1; > + for (auto *Vdb : *Bv) { > + // Exclude mutexes in our immediate before set. > + if (FSet.containsMutexDecl(Analyzer.FactMan, Vdb)) { > + StringRef L1 = StartVd->getName(); > + StringRef L2 = Vdb->getName(); > + Analyzer.Handler.handleLockAcquiredBefore(CapKind, L1, L2, Loc); > + } > + // Transitively search other before sets, and warn on cycles. > + if (traverse(Vdb)) { > + if (CycMap.find(Vd) == CycMap.end()) { > + CycMap.insert(std::make_pair(Vd, true)); > + StringRef L1 = Vd->getName(); > + Analyzer.Handler.handleBeforeAfterCycle(L1, Vd->getLocation()); > + } > + } > + } > + Info->Visited = 2; > + return false; > + }; > + > + traverse(StartVd); > + > + for (auto* Info : InfoVect) > + Info->Visited = 0; > +} > + > + > + > /// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs. > static const ValueDecl *getValueDecl(const Expr *Exp) { > if (const auto *CE = dyn_cast<ImplicitCastExpr>(Exp)) > @@ -1020,7 +1200,13 @@ void ThreadSafetyAnalyzer::addLock(FactS > } > } > > - // FIXME: deal with acquired before/after annotations. > + // Check before/after constraints > + if (Handler.issueBetaWarnings() && > + !Entry->asserted() && !Entry->declared()) { > + GlobalBeforeSet->checkBeforeAfter(Entry->valueDecl(), FSet, *this, > + Entry->loc(), DiagKind); > + } > + > // FIXME: Don't always warn when we have support for reentrant locks. > if (FSet.findLock(FactMan, *Entry)) { > if (!Entry->asserted()) > @@ -1979,14 +2165,16 @@ void ThreadSafetyAnalyzer::runAnalysis(A > } > > // FIXME -- Loc can be wrong here. > - for (const auto &Mu : ExclusiveLocksToAdd) > - addLock(InitialLockset, > - llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc), > - CapDiagKind, true); > - for (const auto &Mu : SharedLocksToAdd) > - addLock(InitialLockset, > - llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc), > - CapDiagKind, true); > + for (const auto &Mu : ExclusiveLocksToAdd) { > + auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, > Loc); > + Entry->setDeclared(true); > + addLock(InitialLockset, std::move(Entry), CapDiagKind, true); > + } > + for (const auto &Mu : SharedLocksToAdd) { > + auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, > Loc); > + Entry->setDeclared(true); > + addLock(InitialLockset, std::move(Entry), CapDiagKind, true); > + } > } > > for (const auto *CurrBlock : *SortedGraph) { > @@ -2180,11 +2368,20 @@ void ThreadSafetyAnalyzer::runAnalysis(A > /// at the end of each block, and issue warnings for thread safety > violations. > /// Each block in the CFG is traversed exactly once. > void runThreadSafetyAnalysis(AnalysisDeclContext &AC, > - ThreadSafetyHandler &Handler) { > - ThreadSafetyAnalyzer Analyzer(Handler); > + ThreadSafetyHandler &Handler, > + BeforeSet **BSet) { > + if (!*BSet) > + *BSet = new BeforeSet; > + ThreadSafetyAnalyzer Analyzer(Handler, *BSet); > Analyzer.runAnalysis(AC); > } > > + > +void threadSafetyCleanup(BeforeSet* Cache) { > + delete Cache; > +} > + > + > /// \brief Helper function that returns a LockKind required for the given > level > /// of access. > LockKind getLockKindFromAccessKind(AccessKind AK) { > > Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=227997&r1=227996&r2=227997&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original) > +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Tue Feb 3 12:17:48 2015 > @@ -1679,6 +1679,22 @@ class ThreadSafetyReporter : public clan > Warnings.push_back(DelayedDiag(Warning, getNotes())); > } > > + > + virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name, > + Name L2Name, SourceLocation Loc) > + override { > + PartialDiagnosticAt Warning(Loc, > + S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name); > + Warnings.push_back(DelayedDiag(Warning, getNotes())); > + } > + > + virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) > + override { > + PartialDiagnosticAt Warning(Loc, > + S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name); > + Warnings.push_back(DelayedDiag(Warning, getNotes())); > + } > + > void enterFunction(const FunctionDecl* FD) override { > CurrentFunction = FD; > } > @@ -1704,7 +1720,7 @@ class ConsumedWarningsHandler : public C > DiagList Warnings; > > public: > - > + > ConsumedWarningsHandler(Sema &S) : S(S) {} > > void emitDiagnostics() override { > @@ -1981,7 +1997,8 @@ AnalysisBasedWarnings::IssueWarnings(sem > if (!Diags.isIgnored(diag::warn_thread_safety_verbose, > D->getLocStart())) > Reporter.setVerbose(true); > > - threadSafety::runThreadSafetyAnalysis(AC, Reporter); > + threadSafety::runThreadSafetyAnalysis(AC, Reporter, > + &S.ThreadSafetyDeclCache); > Reporter.emitDiagnostics(); > } > > > Modified: cfe/trunk/lib/Sema/Sema.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=227997&r1=227996&r2=227997&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/Sema.cpp (original) > +++ cfe/trunk/lib/Sema/Sema.cpp Tue Feb 3 12:17:48 2015 > @@ -102,7 +102,7 @@ Sema::Sema(Preprocessor &pp, ASTContext > AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), > NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), > CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), > - TyposCorrected(0), AnalysisWarnings(*this), > + TyposCorrected(0), AnalysisWarnings(*this), > ThreadSafetyDeclCache(nullptr), > VarDataSharingAttributesStack(nullptr), CurScope(nullptr), > Ident_super(nullptr), Ident___float128(nullptr) > { > @@ -243,6 +243,8 @@ Sema::~Sema() { > if (isMultiplexExternalSource) > delete ExternalSource; > > + threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache); > + > // Destroys data sharing attributes stack for OpenMP > DestroyDataSharingAttributesStack(); > > > Modified: cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp?rev=227997&r1=227996&r2=227997&view=diff > > ============================================================================== > --- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original) > +++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Tue Feb 3 > 12:17:48 2015 > @@ -4835,7 +4835,7 @@ public: > read2(10, *foosp); // expected-warning {{reading the value > pointed to by 'foosp' requires holding mutex 'mu'}} > destroy(mymove(*foosp)); // expected-warning {{reading the value > pointed to by 'foosp' requires holding mutex 'mu'}} > > - // TODO -- these requires better smart pointer handling. > + // TODO -- these require better smart pointer handling. > copy(*foosp.get()); > write1(*foosp.get()); > write2(10, *foosp.get()); > @@ -4848,3 +4848,213 @@ public: > > } // end namespace PassByRefTest > > + > +namespace AcquiredBeforeAfterText { > + > +class Foo { > + Mutex mu1 ACQUIRED_BEFORE(mu2, mu3); > + Mutex mu2; > + Mutex mu3; > + > + void test1() { > + mu1.Lock(); > + mu2.Lock(); > + mu3.Lock(); > + > + mu3.Unlock(); > + mu2.Unlock(); > + mu1.Unlock(); > + } > + > + void test2() { > + mu2.Lock(); > + mu1.Lock(); // expected-warning {{mutex 'mu1' must be acquired > before 'mu2'}} > + mu1.Unlock(); > + mu2.Unlock(); > + } > + > + void test3() { > + mu3.Lock(); > + mu1.Lock(); // expected-warning {{mutex 'mu1' must be acquired > before 'mu3'}} > + mu1.Unlock(); > + mu3.Unlock(); > + } > + > + void test4() EXCLUSIVE_LOCKS_REQUIRED(mu1) { > + mu2.Lock(); > + mu2.Unlock(); > + } > + > + void test5() EXCLUSIVE_LOCKS_REQUIRED(mu2) { > + mu1.Lock(); // expected-warning {{mutex 'mu1' must be acquired > before 'mu2'}} > + mu1.Unlock(); > + } > + > + void test6() EXCLUSIVE_LOCKS_REQUIRED(mu2) { > + mu1.AssertHeld(); > + } > + > + void test7() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2, mu3) { } > + > + void test8() EXCLUSIVE_LOCKS_REQUIRED(mu3, mu2, mu1) { } > +}; > + > + > +class Foo2 { > + Mutex mu1; > + Mutex mu2 ACQUIRED_AFTER(mu1); > + Mutex mu3 ACQUIRED_AFTER(mu1); > + > + void test1() { > + mu1.Lock(); > + mu2.Lock(); > + mu3.Lock(); > + > + mu3.Unlock(); > + mu2.Unlock(); > + mu1.Unlock(); > + } > + > + void test2() { > + mu2.Lock(); > + mu1.Lock(); // expected-warning {{mutex 'mu1' must be acquired > before 'mu2'}} > + mu1.Unlock(); > + mu2.Unlock(); > + } > + > + void test3() { > + mu3.Lock(); > + mu1.Lock(); // expected-warning {{mutex 'mu1' must be acquired > before 'mu3'}} > + mu1.Unlock(); > + mu3.Unlock(); > + } > +}; > + > + > +class Foo3 { > + Mutex mu1 ACQUIRED_BEFORE(mu2); > + Mutex mu2; > + Mutex mu3 ACQUIRED_AFTER(mu2) ACQUIRED_BEFORE(mu4); > + Mutex mu4; > + > + void test1() { > + mu1.Lock(); > + mu2.Lock(); > + mu3.Lock(); > + mu4.Lock(); > + > + mu4.Unlock(); > + mu3.Unlock(); > + mu2.Unlock(); > + mu1.Unlock(); > + } > + > + void test2() { > + mu4.Lock(); > + mu2.Lock(); // expected-warning {{mutex 'mu2' must be acquired > before 'mu4'}} > + > + mu2.Unlock(); > + mu4.Unlock(); > + } > + > + void test3() { > + mu4.Lock(); > + mu1.Lock(); // expected-warning {{mutex 'mu1' must be acquired > before 'mu4'}} > + > + mu1.Unlock(); > + mu4.Unlock(); > + } > + > + void test4() { > + mu3.Lock(); > + mu1.Lock(); // expected-warning {{mutex 'mu1' must be acquired > before 'mu3'}} > + > + mu1.Unlock(); > + mu3.Unlock(); > + } > +}; > + > + > +// Test transitive DAG traversal with AFTER > +class Foo4 { > + Mutex mu1; > + Mutex mu2 ACQUIRED_AFTER(mu1); > + Mutex mu3 ACQUIRED_AFTER(mu1); > + Mutex mu4 ACQUIRED_AFTER(mu2, mu3); > + Mutex mu5 ACQUIRED_AFTER(mu4); > + Mutex mu6 ACQUIRED_AFTER(mu4); > + Mutex mu7 ACQUIRED_AFTER(mu5, mu6); > + Mutex mu8 ACQUIRED_AFTER(mu7); > + > + void test() { > + mu8.Lock(); > + mu1.Lock(); // expected-warning {{mutex 'mu1' must be acquired > before 'mu8'}} > + mu1.Unlock(); > + mu8.Unlock(); > + } > +}; > + > + > +// Test transitive DAG traversal with BEFORE > +class Foo5 { > + Mutex mu1 ACQUIRED_BEFORE(mu2, mu3); > + Mutex mu2 ACQUIRED_BEFORE(mu4); > + Mutex mu3 ACQUIRED_BEFORE(mu4); > + Mutex mu4 ACQUIRED_BEFORE(mu5, mu6); > + Mutex mu5 ACQUIRED_BEFORE(mu7); > + Mutex mu6 ACQUIRED_BEFORE(mu7); > + Mutex mu7 ACQUIRED_BEFORE(mu8); > + Mutex mu8; > + > + void test() { > + mu8.Lock(); > + mu1.Lock(); // expected-warning {{mutex 'mu1' must be acquired > before 'mu8'}} > + mu1.Unlock(); > + mu8.Unlock(); > + } > +}; > + > + > +class Foo6 { > + Mutex mu1 ACQUIRED_AFTER(mu3); // expected-warning {{Cycle in > acquired_before/after dependencies, starting with 'mu1'}} > + Mutex mu2 ACQUIRED_AFTER(mu1); // expected-warning {{Cycle in > acquired_before/after dependencies, starting with 'mu2'}} > + Mutex mu3 ACQUIRED_AFTER(mu2); // expected-warning {{Cycle in > acquired_before/after dependencies, starting with 'mu3'}} > + > + Mutex mu_b ACQUIRED_BEFORE(mu_b); // expected-warning {{Cycle in > acquired_before/after dependencies, starting with 'mu_b'}} > + Mutex mu_a ACQUIRED_AFTER(mu_a); // expected-warning {{Cycle in > acquired_before/after dependencies, starting with 'mu_a'}} > + > + void test0() { > + mu_a.Lock(); > + mu_b.Lock(); > + mu_b.Unlock(); > + mu_a.Unlock(); > + } > + > + void test1a() { > + mu1.Lock(); > + mu1.Unlock(); > + } > + > + void test1b() { > + mu1.Lock(); > + mu_a.Lock(); > + mu_b.Lock(); > + mu_b.Unlock(); > + mu_a.Unlock(); > + mu1.Unlock(); > + } > + > + void test() { > + mu2.Lock(); > + mu2.Unlock(); > + } > + > + void test3() { > + mu3.Lock(); > + mu3.Unlock(); > + } > +}; > + > + > +} // end namespace AcquiredBeforeAfterTest > + > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
