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