Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: mojo/public/cpp/bindings/lib/sync_handle_registry.cc

Issue 2664483002: Support sync mojo IPCs to and from bindings running on a sequence.
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "mojo/public/cpp/bindings/sync_handle_registry.h" 5 #include "mojo/public/cpp/bindings/sync_handle_registry.h"
6 6
7 #include <unordered_map>
8
7 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
8 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/sequence_token.h"
12 #include "base/sequenced_task_runner.h"
9 #include "base/stl_util.h" 13 #include "base/stl_util.h"
10 #include "base/threading/thread_local.h" 14 #include "base/threading/thread_local.h"
15 #include "base/threading/thread_task_runner_handle.h"
11 #include "mojo/public/c/system/core.h" 16 #include "mojo/public/c/system/core.h"
12 17
13 namespace mojo { 18 namespace mojo {
14 namespace { 19 namespace {
15 20
16 base::LazyInstance<base::ThreadLocalPointer<SyncHandleRegistry>>::Leaky 21 struct WorkerPoolSequenceTokenHasher {
17 g_current_sync_handle_watcher = LAZY_INSTANCE_INITIALIZER; 22 size_t operator()(
23 const base::SequencedWorkerPool::SequenceToken& value) const {
24 return std::hash<std::string>()(value.ToString());
25 }
26 };
27
28 struct WorkerPoolSequenceTokenEquals {
29 size_t operator()(const base::SequencedWorkerPool::SequenceToken& a,
30 const base::SequencedWorkerPool::SequenceToken& b) const {
31 return a.Equals(b);
32 }
33 };
34
35 struct SequenceTokenHasher {
36 size_t operator()(const base::SequenceToken& value) const {
37 return std::hash<decltype(value.ToInternalValue())>()(
38 value.ToInternalValue());
39 }
40 };
41
42 // Provides access to a sequence-local SyncHandleRegistry pointer. For
43 // standalone threads, thread-local storage is used. Otherwise, global maps
44 // keyed by SequenceToken are used if one is set for the current thread. Note
45 // that both types of SequenceToken are used: base::SequenceToken and
46 // base::SequencedWorkerPool::SequenceToken, in that order.
47 class SequenceLocalPointer {
48 public:
49 template <typename Factory>
50 scoped_refptr<SyncHandleRegistry> GetOrCreate(const Factory& create) {
51 SyncHandleRegistry** registry_pointer_storage = GetRegistryPointerStorage();
52 if (!registry_pointer_storage) {
53 scoped_refptr<SyncHandleRegistry> registry(thread_local_storage_.Get());
54 if (registry)
55 return registry;
56
57 registry = create();
58 thread_local_storage_.Set(registry.get());
59 return registry;
60 }
61
62 scoped_refptr<SyncHandleRegistry> registry(*registry_pointer_storage);
63 if (!registry) {
64 registry = create();
65 *registry_pointer_storage = registry.get();
66 }
67 return registry;
68 }
69
70 void Clear() {
71 auto sequence_token = base::SequenceToken::GetForCurrentThread();
72 if (sequence_token.IsValid()) {
73 base::AutoLock l(lock_);
74 size_t erased = sequence_to_registry_map_.erase(sequence_token);
75 DCHECK(erased);
76 return;
77 }
78 auto worker_pool_sequence_token =
79 base::SequencedWorkerPool::GetSequenceTokenForCurrentThread();
80 if (worker_pool_sequence_token.IsValid()) {
81 base::AutoLock l(lock_);
82 size_t erased = worker_pool_sequence_to_registry_map_.erase(
83 worker_pool_sequence_token);
84 DCHECK(erased);
85 return;
86 }
87 thread_local_storage_.Set(nullptr);
88 return;
89 }
90
91 private:
92 // Returns a pointer to the storage for a |SyncHandleRegistry*| for the
93 // current sequence. Note that the returned pointer may be safely read and
94 // written without |lock_| held since this entry in the map is only accessed
95 // on the current sequence.
96 SyncHandleRegistry** GetRegistryPointerStorage() {
97 auto sequence_token = base::SequenceToken::GetForCurrentThread();
98 if (sequence_token.IsValid()) {
99 base::AutoLock l(lock_);
100 return &sequence_to_registry_map_[sequence_token];
101 }
102 auto worker_pool_sequence_token =
103 base::SequencedWorkerPool::GetSequenceTokenForCurrentThread();
104 if (worker_pool_sequence_token.IsValid()) {
105 base::AutoLock l(lock_);
106 return &worker_pool_sequence_to_registry_map_[worker_pool_sequence_token];
107 }
108 return nullptr;
109 }
110
111 base::ThreadLocalPointer<SyncHandleRegistry> thread_local_storage_;
112
113 // Guards |sequence_to_registry_map_| and
114 // |worker_pool_sequence_to_registry_map_|.
115 base::Lock lock_;
116
117 std::unordered_map<base::SequenceToken,
118 SyncHandleRegistry*,
119 SequenceTokenHasher>
120 sequence_to_registry_map_;
121
122 // TODO(sammc): Remove this once base::SequenceToken is used everywhere.
123 std::unordered_map<base::SequencedWorkerPool::SequenceToken,
124 SyncHandleRegistry*,
125 WorkerPoolSequenceTokenHasher,
126 WorkerPoolSequenceTokenEquals>
127 worker_pool_sequence_to_registry_map_;
128 };
129
130 base::LazyInstance<SequenceLocalPointer>::Leaky g_current_sync_handle_registry =
131 LAZY_INSTANCE_INITIALIZER;
18 132
19 } // namespace 133 } // namespace
20 134
21 // static 135 // static
22 scoped_refptr<SyncHandleRegistry> SyncHandleRegistry::current() { 136 scoped_refptr<SyncHandleRegistry> SyncHandleRegistry::current() {
23 scoped_refptr<SyncHandleRegistry> result( 137 return g_current_sync_handle_registry.Pointer()->GetOrCreate(
24 g_current_sync_handle_watcher.Pointer()->Get()); 138 []() { return make_scoped_refptr(new SyncHandleRegistry()); });
25 if (!result) {
26 result = new SyncHandleRegistry();
27 DCHECK_EQ(result.get(), g_current_sync_handle_watcher.Pointer()->Get());
28 }
29 return result;
30 } 139 }
31 140
32 bool SyncHandleRegistry::RegisterHandle(const Handle& handle, 141 bool SyncHandleRegistry::RegisterHandle(const Handle& handle,
33 MojoHandleSignals handle_signals, 142 MojoHandleSignals handle_signals,
34 const HandleCallback& callback) { 143 const HandleCallback& callback) {
35 DCHECK(thread_checker_.CalledOnValidThread()); 144 DCHECK(sequence_checker_.CalledOnValidSequence());
36 145
37 if (base::ContainsKey(handles_, handle)) 146 if (base::ContainsKey(handles_, handle))
38 return false; 147 return false;
39 148
40 MojoResult result = MojoAddHandle(wait_set_handle_.get().value(), 149 MojoResult result = MojoAddHandle(wait_set_handle_.get().value(),
41 handle.value(), handle_signals); 150 handle.value(), handle_signals);
42 if (result != MOJO_RESULT_OK) 151 if (result != MOJO_RESULT_OK)
43 return false; 152 return false;
44 153
45 handles_[handle] = callback; 154 handles_[handle] = callback;
46 return true; 155 return true;
47 } 156 }
48 157
49 void SyncHandleRegistry::UnregisterHandle(const Handle& handle) { 158 void SyncHandleRegistry::UnregisterHandle(const Handle& handle) {
50 DCHECK(thread_checker_.CalledOnValidThread()); 159 DCHECK(sequence_checker_.CalledOnValidSequence());
51 if (!base::ContainsKey(handles_, handle)) 160 if (!base::ContainsKey(handles_, handle))
52 return; 161 return;
53 162
54 MojoResult result = 163 MojoResult result =
55 MojoRemoveHandle(wait_set_handle_.get().value(), handle.value()); 164 MojoRemoveHandle(wait_set_handle_.get().value(), handle.value());
56 DCHECK_EQ(MOJO_RESULT_OK, result); 165 DCHECK_EQ(MOJO_RESULT_OK, result);
57 handles_.erase(handle); 166 handles_.erase(handle);
58 } 167 }
59 168
60 bool SyncHandleRegistry::WatchAllHandles(const bool* should_stop[], 169 bool SyncHandleRegistry::WatchAllHandles(const bool* should_stop[],
61 size_t count) { 170 size_t count) {
62 DCHECK(thread_checker_.CalledOnValidThread()); 171 DCHECK(sequence_checker_.CalledOnValidSequence());
63 172
64 MojoResult result; 173 MojoResult result;
65 uint32_t num_ready_handles; 174 uint32_t num_ready_handles;
66 MojoHandle ready_handle; 175 MojoHandle ready_handle;
67 MojoResult ready_handle_result; 176 MojoResult ready_handle_result;
68 177
69 scoped_refptr<SyncHandleRegistry> preserver(this); 178 scoped_refptr<SyncHandleRegistry> preserver(this);
70 while (true) { 179 while (true) {
71 for (size_t i = 0; i < count; ++i) 180 for (size_t i = 0; i < count; ++i)
72 if (*should_stop[i]) 181 if (*should_stop[i])
(...skipping 20 matching lines...) Expand all
93 202
94 return false; 203 return false;
95 } 204 }
96 205
97 SyncHandleRegistry::SyncHandleRegistry() { 206 SyncHandleRegistry::SyncHandleRegistry() {
98 MojoHandle handle; 207 MojoHandle handle;
99 MojoResult result = MojoCreateWaitSet(&handle); 208 MojoResult result = MojoCreateWaitSet(&handle);
100 CHECK_EQ(MOJO_RESULT_OK, result); 209 CHECK_EQ(MOJO_RESULT_OK, result);
101 wait_set_handle_.reset(Handle(handle)); 210 wait_set_handle_.reset(Handle(handle));
102 CHECK(wait_set_handle_.is_valid()); 211 CHECK(wait_set_handle_.is_valid());
103
104 DCHECK(!g_current_sync_handle_watcher.Pointer()->Get());
105 g_current_sync_handle_watcher.Pointer()->Set(this);
106 } 212 }
107 213
108 SyncHandleRegistry::~SyncHandleRegistry() { 214 SyncHandleRegistry::~SyncHandleRegistry() {
109 DCHECK(thread_checker_.CalledOnValidThread()); 215 DCHECK(sequence_checker_.CalledOnValidSequence());
110 216 g_current_sync_handle_registry.Pointer()->Clear();
111 // This object may be destructed after the thread local storage slot used by
112 // |g_current_sync_handle_watcher| is reset during thread shutdown.
113 // For example, another slot in the thread local storage holds a referrence to
114 // this object, and that slot is cleaned up after
115 // |g_current_sync_handle_watcher|.
116 if (!g_current_sync_handle_watcher.Pointer()->Get())
117 return;
118
119 // If this breaks, it is likely that the global variable is bulit into and
120 // accessed from multiple modules.
121 DCHECK_EQ(this, g_current_sync_handle_watcher.Pointer()->Get());
122
123 g_current_sync_handle_watcher.Pointer()->Set(nullptr);
124 } 217 }
125 218
126 } // namespace mojo 219 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/lib/multiplex_router.cc ('k') | mojo/public/cpp/bindings/lib/sync_handle_watcher.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698