• 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 #ifndef BASE_TASK_SEQUENCE_MANAGER_ASSOCIATED_THREAD_ID_H_
6 #define BASE_TASK_SEQUENCE_MANAGER_ASSOCIATED_THREAD_ID_H_
7 
8 #include <atomic>
9 #include <memory>
10 
11 #include "base/base_export.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/sequence_checker.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/threading/platform_thread_ref.h"
16 #include "base/threading/thread_checker.h"
17 #include "third_party/abseil-cpp/absl/types/optional.h"
18 
19 namespace base {
20 namespace sequence_manager {
21 namespace internal {
22 
23 // TODO(eseckler): Make this owned by SequenceManager once the TaskQueue
24 // refactor has happened (https://crbug.com/865411).
25 //
26 // This class is thread-safe. But see notes about memory ordering guarantees for
27 // the various methods.
28 class BASE_EXPORT AssociatedThreadId
29     : public base::RefCountedThreadSafe<AssociatedThreadId> {
30  public:
31   AssociatedThreadId();
32 
33   // TODO(eseckler): Replace thread_checker with sequence_checker everywhere.
34   THREAD_CHECKER(thread_checker);
35   SEQUENCE_CHECKER(sequence_checker);
36 
CreateUnbound()37   static scoped_refptr<AssociatedThreadId> CreateUnbound() {
38     return MakeRefCounted<AssociatedThreadId>();
39   }
40 
CreateBound()41   static scoped_refptr<AssociatedThreadId> CreateBound() {
42     auto associated_thread = MakeRefCounted<AssociatedThreadId>();
43     associated_thread->BindToCurrentThread();
44     return associated_thread;
45   }
46 
47   // Rebind the associated thread to the current thread. This allows creating
48   // the SequenceManager and TaskQueues on a different thread/sequence than the
49   // one it will manage.
50   //
51   // Can only be called once.
52   void BindToCurrentThread();
53 
54   // Checks whether this object has already been bound to a thread.
55   //
56   // This method guarantees a happens-before ordering with
57   // BindToCurrentThread(), that is all memory writes that happened-before the
58   // call to BindToCurrentThread() will become visible side-effects in the
59   // current thread.
60   //
61   // Attention: The result might be stale by the time this method returns.
IsBound()62   bool IsBound() const {
63     return !thread_ref_.load(std::memory_order_acquire).is_null();
64   }
65 
66   // Checks whether this object is bound to the current thread. Returns false if
67   // this object is not bound to any thread.
68   //
69   // Note that this method provides no memory ordering guarantees but those are
70   // not really needed. If this method returns true we are on the same thread
71   // that called BindToCurrentThread(). If the method returns false this object
72   // could be unbound, so there is no possible ordering.
73   //
74   // Attention:: The result might be stale by the time this method returns.
IsBoundToCurrentThread()75   bool IsBoundToCurrentThread() const {
76     return thread_ref_.load(std::memory_order_relaxed) ==
77            PlatformThread::CurrentRef();
78   }
79 
80  private:
81   friend class base::RefCountedThreadSafe<AssociatedThreadId>;
82   ~AssociatedThreadId();
83 
84   std::atomic<PlatformThreadRef> thread_ref_{};
85 };
86 
87 }  // namespace internal
88 }  // namespace sequence_manager
89 }  // namespace base
90 
91 #endif  // BASE_TASK_SEQUENCE_MANAGER_ASSOCIATED_THREAD_ID_H_
92