summaryrefslogtreecommitdiff
path: root/chromium/base/task/common
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/base/task/common')
-rw-r--r--chromium/base/task/common/checked_lock.h20
-rw-r--r--chromium/base/task/common/checked_lock_impl.cc13
-rw-r--r--chromium/base/task/common/checked_lock_impl.h6
-rw-r--r--chromium/base/task/common/checked_lock_unittest.cc72
-rw-r--r--chromium/base/task/common/task_annotator.cc16
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