• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/task/sequence_manager/associated_thread_id.h"
6 
7 #include "base/check.h"
8 #include "base/dcheck_is_on.h"
9 
10 namespace base {
11 namespace sequence_manager {
12 namespace internal {
13 
14 AssociatedThreadId::AssociatedThreadId() = default;
15 AssociatedThreadId::~AssociatedThreadId() = default;
16 
BindToCurrentThread()17 void AssociatedThreadId::BindToCurrentThread() {
18 #if DCHECK_IS_ON()
19   const auto prev_thread_ref =
20       bound_thread_ref_.load(std::memory_order_relaxed);
21   DCHECK(prev_thread_ref.is_null() ||
22          prev_thread_ref == PlatformThread::CurrentRef());
23 #endif
24   sequence_token_ = base::internal::SequenceToken::GetForCurrentThread();
25   bound_thread_ref_.store(PlatformThread::CurrentRef(),
26                           std::memory_order_release);
27 
28   // Rebind the thread and sequence checkers to the current thread/sequence.
29   DETACH_FROM_THREAD(thread_checker);
30   DCHECK_CALLED_ON_VALID_THREAD(thread_checker);
31 
32   DETACH_FROM_SEQUENCE(sequence_checker);
33   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker);
34 }
35 
IsBoundToCurrentThread() const36 bool AssociatedThreadId::IsBoundToCurrentThread() const {
37   const PlatformThreadRef bound_thread_ref =
38       bound_thread_ref_.load(std::memory_order_relaxed);
39   const PlatformThreadRef in_sequence_thread_ref =
40       in_sequence_thread_ref_.load(std::memory_order_relaxed);
41   const PlatformThreadRef current_thread_ref = PlatformThread::CurrentRef();
42 
43   if (!in_sequence_thread_ref.is_null()) {
44     // The main thread cannot run when another thread is running "in sequence"
45     // with it.
46     CHECK_NE(current_thread_ref, bound_thread_ref);
47   }
48 
49   return bound_thread_ref == current_thread_ref;
50 }
51 
AssertInSequenceWithCurrentThread() const52 void AssociatedThreadId::AssertInSequenceWithCurrentThread() const {
53   const PlatformThreadRef in_sequence_thread_ref =
54       in_sequence_thread_ref_.load(std::memory_order_relaxed);
55 
56   if (!in_sequence_thread_ref.is_null()) {
57     CHECK_EQ(in_sequence_thread_ref, PlatformThread::CurrentRef());
58     return;
59   }
60 
61 #if DCHECK_IS_ON()
62   const PlatformThreadRef bound_thread_ref =
63       bound_thread_ref_.load(std::memory_order_relaxed);
64   if (!bound_thread_ref.is_null()) {
65     CHECK_EQ(bound_thread_ref, PlatformThread::CurrentRef());
66     return;
67   }
68 
69   DCHECK_CALLED_ON_VALID_THREAD(thread_checker);
70 #endif  // DCHECK_IS_ON()
71 }
72 
StartInSequenceWithCurrentThread()73 void AssociatedThreadId::StartInSequenceWithCurrentThread() {
74   PlatformThreadRef expected = PlatformThreadRef();
75   bool succeeded = in_sequence_thread_ref_.compare_exchange_strong(
76       expected, PlatformThread::CurrentRef(), std::memory_order_relaxed);
77   CHECK(succeeded);
78 }
79 
StopInSequenceWithCurrentThread()80 void AssociatedThreadId::StopInSequenceWithCurrentThread() {
81   PlatformThreadRef expected = PlatformThread::CurrentRef();
82   bool succeeded = in_sequence_thread_ref_.compare_exchange_strong(
83       expected, PlatformThreadRef(), std::memory_order_relaxed);
84   CHECK(succeeded);
85 }
86 
87 }  // namespace internal
88 }  // namespace sequence_manager
89 }  // namespace base
90