diff options
Diffstat (limited to 'chromium/base/task/common')
-rw-r--r-- | chromium/base/task/common/checked_lock.h | 20 | ||||
-rw-r--r-- | chromium/base/task/common/checked_lock_impl.cc | 13 | ||||
-rw-r--r-- | chromium/base/task/common/checked_lock_impl.h | 6 | ||||
-rw-r--r-- | chromium/base/task/common/checked_lock_unittest.cc | 72 | ||||
-rw-r--r-- | chromium/base/task/common/task_annotator.cc | 16 |
5 files changed, 109 insertions, 18 deletions
diff --git a/chromium/base/task/common/checked_lock.h b/chromium/base/task/common/checked_lock.h index 29ce5735b61..4399ec477a5 100644 --- a/chromium/base/task/common/checked_lock.h +++ b/chromium/base/task/common/checked_lock.h @@ -31,18 +31,27 @@ namespace internal { // CheckedLock(const CheckedLock* predecessor) // Constructor that specifies an allowed predecessor for that lock. // DCHECKs -// On Construction if |predecessor| forms a predecessor lock cycle. +// On Construction if |predecessor| forms a predecessor lock cycle or +// is a universal successor. // On Acquisition if the previous lock acquired on the thread is not // either |predecessor| or a universal predecessor. Okay if there // was no previous lock acquired. // // CheckedLock(UniversalPredecessor universal_predecessor) // Constructor for a lock that will allow the acquisition of any lock after -// it, without needing to explicitly be named a predecessor. Can only be -// acquired if no locks are currently held by this thread. -// DCHECKs +// it, without needing to explicitly be named a predecessor (e.g. a root in +// a lock chain). Can only be acquired if no locks are currently held by +// this thread. DCHECKs // On Acquisition if any CheckedLock is acquired on this thread. // +// CheckedLock(UniversalSuccessor universal_successor) +// Constructor for a lock that will allow its acquisition after any other +// lock, without needing to explicitly name its predecessor (e.g. a leaf in +// a lock chain). Can not be acquired after another UniversalSuccessor lock. +// DCHECKs +// On Acquisition if there was a previously acquired lock on the thread +// and it was also a universal successor. +// // void Acquire() // Acquires the lock. // @@ -63,6 +72,8 @@ class LOCKABLE CheckedLock : public CheckedLockImpl { : CheckedLockImpl(predecessor) {} explicit CheckedLock(UniversalPredecessor universal_predecessor) : CheckedLockImpl(universal_predecessor) {} + explicit CheckedLock(UniversalSuccessor universal_successor) + : CheckedLockImpl(universal_successor) {} }; #else // DCHECK_IS_ON() class LOCKABLE CheckedLock : public Lock { @@ -70,6 +81,7 @@ class LOCKABLE CheckedLock : public Lock { CheckedLock() = default; explicit CheckedLock(const CheckedLock*) {} explicit CheckedLock(UniversalPredecessor) {} + explicit CheckedLock(UniversalSuccessor) {} static void AssertNoLockHeldOnCurrentThread() {} std::unique_ptr<ConditionVariable> CreateConditionVariable() { diff --git a/chromium/base/task/common/checked_lock_impl.cc b/chromium/base/task/common/checked_lock_impl.cc index 698886e1615..8b41e95cf8c 100644 --- a/chromium/base/task/common/checked_lock_impl.cc +++ b/chromium/base/task/common/checked_lock_impl.cc @@ -81,7 +81,12 @@ class SafeAcquisitionTracker { // Using at() is exception-safe here as |lock| was registered already. const CheckedLockImpl* allowed_predecessor = allowed_predecessor_map_.at(lock); - DCHECK_EQ(previous_lock, allowed_predecessor); + if (lock->is_universal_successor()) { + DCHECK(!previous_lock->is_universal_successor()); + return; + } else { + DCHECK_EQ(previous_lock, allowed_predecessor); + } } // Asserts that |lock|'s registered predecessor is safe. Because @@ -134,12 +139,18 @@ CheckedLockImpl::CheckedLockImpl() : CheckedLockImpl(nullptr) {} CheckedLockImpl::CheckedLockImpl(const CheckedLockImpl* predecessor) : is_universal_predecessor_(false) { + DCHECK(predecessor == nullptr || !predecessor->is_universal_successor_); g_safe_acquisition_tracker.Get().RegisterLock(this, predecessor); } CheckedLockImpl::CheckedLockImpl(UniversalPredecessor) : is_universal_predecessor_(true) {} +CheckedLockImpl::CheckedLockImpl(UniversalSuccessor) + : is_universal_successor_(true) { + g_safe_acquisition_tracker.Get().RegisterLock(this, nullptr); +} + CheckedLockImpl::~CheckedLockImpl() { g_safe_acquisition_tracker.Get().UnregisterLock(this); } diff --git a/chromium/base/task/common/checked_lock_impl.h b/chromium/base/task/common/checked_lock_impl.h index acb1d133753..88aba042aad 100644 --- a/chromium/base/task/common/checked_lock_impl.h +++ b/chromium/base/task/common/checked_lock_impl.h @@ -18,6 +18,7 @@ class ConditionVariable; namespace internal { struct UniversalPredecessor {}; +struct UniversalSuccessor {}; // A regular lock with simple deadlock correctness checking. // This lock tracks all of the available locks to make sure that any locks are @@ -28,6 +29,7 @@ class BASE_EXPORT CheckedLockImpl { CheckedLockImpl(); explicit CheckedLockImpl(const CheckedLockImpl* predecessor); explicit CheckedLockImpl(UniversalPredecessor); + explicit CheckedLockImpl(UniversalSuccessor); ~CheckedLockImpl(); static void AssertNoLockHeldOnCurrentThread(); @@ -40,10 +42,12 @@ class BASE_EXPORT CheckedLockImpl { std::unique_ptr<ConditionVariable> CreateConditionVariable(); bool is_universal_predecessor() const { return is_universal_predecessor_; } + bool is_universal_successor() const { return is_universal_successor_; } private: Lock lock_; - const bool is_universal_predecessor_; + const bool is_universal_predecessor_ = false; + const bool is_universal_successor_ = false; DISALLOW_COPY_AND_ASSIGN(CheckedLockImpl); }; diff --git a/chromium/base/task/common/checked_lock_unittest.cc b/chromium/base/task/common/checked_lock_unittest.cc index 54b74c50391..2e21eace50b 100644 --- a/chromium/base/task/common/checked_lock_unittest.cc +++ b/chromium/base/task/common/checked_lock_unittest.cc @@ -307,7 +307,7 @@ TEST(CheckedLockTest, AcquireMultipleLocksAfterUniversalPredecessor) NO_THREAD_SAFETY_ANALYSIS { // Acquisition of a universal-predecessor lock does not affect acquisition // rules for locks beyond the one acquired directly after it. - CheckedLock universal_predecessor((UniversalPredecessor())); + CheckedLock universal_predecessor{UniversalPredecessor()}; CheckedLock lock; CheckedLock lock2(&lock); CheckedLock lock3; @@ -329,7 +329,7 @@ NO_THREAD_SAFETY_ANALYSIS { TEST(CheckedLockTest, AcquireUniversalPredecessorAfterLock) NO_THREAD_SAFETY_ANALYSIS { // A universal-predecessor lock may not be acquired after any other lock. - CheckedLock universal_predecessor((UniversalPredecessor())); + CheckedLock universal_predecessor{UniversalPredecessor()}; CheckedLock lock; EXPECT_DCHECK_DEATH({ @@ -342,8 +342,8 @@ TEST(CheckedLockTest, AcquireUniversalPredecessorAfterUniversalPredecessor) NO_THREAD_SAFETY_ANALYSIS { // A universal-predecessor lock may not be acquired after any other lock, not // even another universal predecessor. - CheckedLock universal_predecessor((UniversalPredecessor())); - CheckedLock universal_predecessor2((UniversalPredecessor())); + CheckedLock universal_predecessor{UniversalPredecessor()}; + CheckedLock universal_predecessor2{UniversalPredecessor()}; EXPECT_DCHECK_DEATH({ universal_predecessor.Acquire(); @@ -351,6 +351,70 @@ NO_THREAD_SAFETY_ANALYSIS { }); } +TEST(CheckedLockTest, AcquireLockBeforeUniversalSuccessor) { + // Acquisition of a universal-successor lock should be allowed + // after any other acquisition. + CheckedLock universal_successor{UniversalSuccessor()}; + CheckedLock lock; + + lock.Acquire(); + universal_successor.Acquire(); + universal_successor.Release(); + lock.Release(); +} + +TEST(CheckedLockTest, AcquireMultipleLocksBeforeAndAfterUniversalSuccessor) +NO_THREAD_SAFETY_ANALYSIS { + // Acquisition of a universal-successor lock does not affect acquisition + // rules for locks beyond the one acquired directly after it. + CheckedLock lock; + CheckedLock universal_successor{UniversalSuccessor()}; + CheckedLock lock2; + + lock.Acquire(); + universal_successor.Acquire(); + universal_successor.Release(); + lock.Release(); + + EXPECT_DCHECK_DEATH({ + universal_successor.Acquire(); + lock2.Acquire(); + }); +} + +TEST(CheckedLockTest, AcquireUniversalSuccessorBeforeLock) +NO_THREAD_SAFETY_ANALYSIS { + // A universal-successor lock may not be acquired before any other lock. + CheckedLock universal_successor{UniversalSuccessor()}; + CheckedLock lock; + + EXPECT_DCHECK_DEATH({ + universal_successor.Acquire(); + lock.Acquire(); + }); +} + +TEST(CheckedLockTest, AcquireUniversalSuccessorAfterUniversalSuccessor) +NO_THREAD_SAFETY_ANALYSIS { + // A universal-successor lock may not be acquired before any other lock, not + // even another universal successor. + CheckedLock universal_successor{UniversalSuccessor()}; + CheckedLock universal_successor2{UniversalSuccessor()}; + + EXPECT_DCHECK_DEATH({ + universal_successor.Acquire(); + universal_successor2.Acquire(); + }); +} + +TEST(CheckedLockTest, UniversalSuccessorAsPredecessor) +NO_THREAD_SAFETY_ANALYSIS { + // A universal-successor lock cannot be declared as a predecessor to + // any other lock. + CheckedLock universal_successor{UniversalSuccessor()}; + EXPECT_DCHECK_DEATH({ CheckedLock banned_successor(&universal_successor); }); +} + TEST(CheckedLockTest, AssertNoLockHeldOnCurrentThread) { // AssertNoLockHeldOnCurrentThread() shouldn't fail when no lock is acquired. CheckedLock::AssertNoLockHeldOnCurrentThread(); diff --git a/chromium/base/task/common/task_annotator.cc b/chromium/base/task/common/task_annotator.cc index 1001359c712..505a55b0e49 100644 --- a/chromium/base/task/common/task_annotator.cc +++ b/chromium/base/task/common/task_annotator.cc @@ -10,7 +10,7 @@ #include "base/debug/alias.h" #include "base/no_destructor.h" #include "base/threading/thread_local.h" -#include "base/trace_event/trace_event.h" +#include "base/trace_event/base_tracing.h" namespace base { @@ -64,10 +64,10 @@ void TaskAnnotator::WillQueueTask(const char* trace_event_name, DCHECK(trace_event_name); DCHECK(pending_task); DCHECK(task_queue_name); - TRACE_EVENT_WITH_FLOW1( - TRACE_DISABLED_BY_DEFAULT("toplevel.flow"), trace_event_name, - TRACE_ID_LOCAL(GetTaskTraceID(*pending_task)), TRACE_EVENT_FLAG_FLOW_OUT, - "task_queue_name", task_queue_name); + TRACE_EVENT_WITH_FLOW1("toplevel.flow", trace_event_name, + TRACE_ID_LOCAL(GetTaskTraceID(*pending_task)), + TRACE_EVENT_FLAG_FLOW_OUT, "task_queue_name", + task_queue_name); DCHECK(!pending_task->task_backtrace[0]) << "Task backtrace was already set, task posted twice??"; @@ -98,9 +98,9 @@ void TaskAnnotator::RunTask(const char* trace_event_name, TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("toplevel.ipc"), "TaskAnnotator::RunTask", "ipc_hash", pending_task->ipc_hash); - TRACE_EVENT_WITH_FLOW0( - TRACE_DISABLED_BY_DEFAULT("toplevel.flow"), trace_event_name, - TRACE_ID_LOCAL(GetTaskTraceID(*pending_task)), TRACE_EVENT_FLAG_FLOW_IN); + TRACE_EVENT_WITH_FLOW0("toplevel.flow", trace_event_name, + TRACE_ID_LOCAL(GetTaskTraceID(*pending_task)), + TRACE_EVENT_FLAG_FLOW_IN); // Before running the task, store the IPC context and the task backtrace with // the chain of PostTasks that resulted in this call and deliberately alias it |