blob: 157a43c1977fc9b1baf6bce0c2bc722c92571ea8 [file] [log] [blame]
Eric Seckler34f0ed042018-07-26 07:55:161// Copyright 2018 The Chromium Authors. All rights reserved.
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
Carlos Caballero7162ac52018-11-30 09:46:538#include <atomic>
Eric Seckler34f0ed042018-07-26 07:55:169#include <memory>
10
11#include "base/macros.h"
12#include "base/memory/ref_counted.h"
Carlos Caballero7162ac52018-11-30 09:46:5313#include "base/optional.h"
Eric Seckler34f0ed042018-07-26 07:55:1614#include "base/sequence_checker.h"
15#include "base/threading/platform_thread.h"
16#include "base/threading/thread_checker.h"
17
18namespace base {
19namespace sequence_manager {
20namespace internal {
21
22// TODO(eseckler): Make this owned by SequenceManager once the TaskQueue
23// refactor has happened (https://crbug.com/865411).
Carlos Caballero7162ac52018-11-30 09:46:5324//
25// This class is thread-safe. But see notes about memory ordering guarantees for
26// the various methods.
27class BASE_EXPORT AssociatedThreadId
Eric Seckler34f0ed042018-07-26 07:55:1628 : public base::RefCountedThreadSafe<AssociatedThreadId> {
29 public:
Carlos Caballero7162ac52018-11-30 09:46:5330 AssociatedThreadId();
31
Eric Seckler34f0ed042018-07-26 07:55:1632 // TODO(eseckler): Replace thread_checker with sequence_checker everywhere.
33 THREAD_CHECKER(thread_checker);
34 SEQUENCE_CHECKER(sequence_checker);
35
36 static scoped_refptr<AssociatedThreadId> CreateUnbound() {
37 return MakeRefCounted<AssociatedThreadId>();
38 }
39
40 static scoped_refptr<AssociatedThreadId> CreateBound() {
41 auto associated_thread = MakeRefCounted<AssociatedThreadId>();
42 associated_thread->BindToCurrentThread();
43 return associated_thread;
44 }
45
46 // Rebind the associated thread to the current thread. This allows creating
47 // the SequenceManager and TaskQueues on a different thread/sequence than the
Carlos Caballero7162ac52018-11-30 09:46:5348 // one it will manage.
49 //
50 // Can only be called once.
51 void BindToCurrentThread();
Eric Seckler34f0ed042018-07-26 07:55:1652
Carlos Caballero7162ac52018-11-30 09:46:5353 // Returns the id of the thread bound to this object via a previous call to
54 // BindToCurrentThread(), nullopt if no thread was bound yet.
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.
62 Optional<PlatformThreadId> GetBoundThreadId() const {
63 auto thread_id = thread_id_.load(std::memory_order_acquire);
64 if (thread_id == kInvalidThreadId) {
65 return nullopt;
66 } else {
67 return thread_id;
68 }
69 }
Eric Seckler34f0ed042018-07-26 07:55:1670
Carlos Caballero7162ac52018-11-30 09:46:5371 // Checks whether this object has already been bound to a thread.
72 //
73 // This method guarantees a happens-before ordering with
74 // BindToCurrentThread(), that is all memory writes that happened-before the
75 // call to BindToCurrentThread() will become visible side-effects in the
76 // current thread.
77 //
78 // Attention: The result might be stale by the time this method returns.
79 bool IsBound() const {
80 return thread_id_.load(std::memory_order_acquire) != kInvalidThreadId;
81 }
82
83 // Checks whether this object is bound to the current thread. Returns false if
84 // this object is not bound to any thread.
85 //
86 // Note that this method provides no memory ordering guarantees but those are
87 // not really needed. If this method returns true we are on the same thread
88 // that called BindToCurrentThread(). If the method returns false this object
89 // could be unbound, so there is no possible ordering.
90 //
91 // Attention:: The result might be stale by the time this method returns.
92 bool IsBoundToCurrentThread() const {
93 return thread_id_.load(std::memory_order_relaxed) ==
94 PlatformThread::CurrentId();
Eric Seckler34f0ed042018-07-26 07:55:1695 }
96
97 // TODO(eseckler): Add a method that checks that we are either bound already
98 // or on the thread which created us and use it in any_thread() accessors.
99
100 private:
101 friend class base::RefCountedThreadSafe<AssociatedThreadId>;
Carlos Caballero7162ac52018-11-30 09:46:53102 ~AssociatedThreadId();
103
104 // All access to this member can be std::memory_order_relaxed as this class
105 // provides no ordering guarantees.
106 std::atomic<PlatformThreadId> thread_id_{kInvalidThreadId};
Eric Seckler34f0ed042018-07-26 07:55:16107};
108
109} // namespace internal
110} // namespace sequence_manager
111} // namespace base
112
113#endif // BASE_TASK_SEQUENCE_MANAGER_ASSOCIATED_THREAD_ID_H_