OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/common/handle_watcher.h" | 5 #include "mojo/common/handle_watcher.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/atomic_sequence_num.h" | 9 #include "base/atomic_sequence_num.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
12 #include "base/memory/singleton.h" | 12 #include "base/memory/singleton.h" |
13 #include "base/memory/weak_ptr.h" | 13 #include "base/memory/weak_ptr.h" |
14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
15 #include "base/message_loop/message_loop_proxy.h" | 15 #include "base/message_loop/message_loop_proxy.h" |
16 #include "base/synchronization/condition_variable.h" | |
16 #include "base/synchronization/lock.h" | 17 #include "base/synchronization/lock.h" |
17 #include "base/threading/thread.h" | 18 #include "base/threading/thread.h" |
18 #include "base/time/time.h" | 19 #include "base/time/time.h" |
19 #include "mojo/common/message_pump_mojo.h" | 20 #include "mojo/common/message_pump_mojo.h" |
20 #include "mojo/common/message_pump_mojo_handler.h" | 21 #include "mojo/common/message_pump_mojo_handler.h" |
21 #include "mojo/common/time_helper.h" | 22 #include "mojo/common/time_helper.h" |
22 | 23 |
23 namespace mojo { | 24 namespace mojo { |
24 namespace common { | 25 namespace common { |
25 | 26 |
(...skipping 24 matching lines...) Expand all Loading... | |
50 message_loop(NULL) {} | 51 message_loop(NULL) {} |
51 | 52 |
52 WatcherID id; | 53 WatcherID id; |
53 Handle handle; | 54 Handle handle; |
54 MojoHandleSignals handle_signals; | 55 MojoHandleSignals handle_signals; |
55 base::TimeTicks deadline; | 56 base::TimeTicks deadline; |
56 base::Callback<void(MojoResult)> callback; | 57 base::Callback<void(MojoResult)> callback; |
57 scoped_refptr<base::MessageLoopProxy> message_loop; | 58 scoped_refptr<base::MessageLoopProxy> message_loop; |
58 }; | 59 }; |
59 | 60 |
61 // WaitState ------------------------------------------------------------------- | |
62 | |
63 // Used when removing a handle. The main thread blocks until the background | |
64 // thread successfully removes the handle from the set of handles being watched. | |
65 // When the background thread removes the handle it sets |removed| and signals | |
66 // |condition|. | |
67 struct WaitState { | |
darin (slow to review)
2014/07/22 17:42:56
nit: You could also just use base::WaitableEvent h
sky
2014/07/22 18:20:50
I thought there was something like that. Done!
| |
68 WaitState() : condition(&lock), removed(false) {} | |
69 | |
70 base::Lock lock; | |
71 base::ConditionVariable condition; | |
72 bool removed; | |
73 }; | |
74 | |
60 // WatcherBackend -------------------------------------------------------------- | 75 // WatcherBackend -------------------------------------------------------------- |
61 | 76 |
62 // WatcherBackend is responsible for managing the requests and interacting with | 77 // WatcherBackend is responsible for managing the requests and interacting with |
63 // MessagePumpMojo. All access (outside of creation/destruction) is done on the | 78 // MessagePumpMojo. All access (outside of creation/destruction) is done on the |
64 // thread WatcherThreadManager creates. | 79 // thread WatcherThreadManager creates. |
65 class WatcherBackend : public MessagePumpMojoHandler { | 80 class WatcherBackend : public MessagePumpMojoHandler { |
66 public: | 81 public: |
67 WatcherBackend(); | 82 WatcherBackend(); |
68 virtual ~WatcherBackend(); | 83 virtual ~WatcherBackend(); |
69 | 84 |
70 void StartWatching(const WatchData& data); | 85 void StartWatching(const WatchData& data); |
71 void StopWatching(WatcherID watcher_id); | 86 |
87 // Cancels a previously schedule request to start a watch. When done sets | |
88 // |wait_state->removed| and signals the condition. | |
89 void StopWatching(WatcherID watcher_id, WaitState* wait_state); | |
72 | 90 |
73 private: | 91 private: |
74 typedef std::map<Handle, WatchData> HandleToWatchDataMap; | 92 typedef std::map<Handle, WatchData> HandleToWatchDataMap; |
75 | 93 |
76 // Invoked when a handle needs to be removed and notified. | 94 // Invoked when a handle needs to be removed and notified. |
77 void RemoveAndNotify(const Handle& handle, MojoResult result); | 95 void RemoveAndNotify(const Handle& handle, MojoResult result); |
78 | 96 |
79 // Searches through |handle_to_data_| for |watcher_id|. Returns true if found | 97 // Searches through |handle_to_data_| for |watcher_id|. Returns true if found |
80 // and sets |handle| to the Handle. Returns false if not a known id. | 98 // and sets |handle| to the Handle. Returns false if not a known id. |
81 bool GetMojoHandleByWatcherID(WatcherID watcher_id, Handle* handle) const; | 99 bool GetMojoHandleByWatcherID(WatcherID watcher_id, Handle* handle) const; |
(...skipping 18 matching lines...) Expand all Loading... | |
100 RemoveAndNotify(data.handle, MOJO_RESULT_CANCELLED); | 118 RemoveAndNotify(data.handle, MOJO_RESULT_CANCELLED); |
101 | 119 |
102 DCHECK_EQ(0u, handle_to_data_.count(data.handle)); | 120 DCHECK_EQ(0u, handle_to_data_.count(data.handle)); |
103 | 121 |
104 handle_to_data_[data.handle] = data; | 122 handle_to_data_[data.handle] = data; |
105 message_pump_mojo->AddHandler(this, data.handle, | 123 message_pump_mojo->AddHandler(this, data.handle, |
106 data.handle_signals, | 124 data.handle_signals, |
107 data.deadline); | 125 data.deadline); |
108 } | 126 } |
109 | 127 |
110 void WatcherBackend::StopWatching(WatcherID watcher_id) { | 128 void WatcherBackend::StopWatching(WatcherID watcher_id, WaitState* wait_state) { |
111 // Because of the thread hop it is entirely possible to get here and not | 129 // Because of the thread hop it is entirely possible to get here and not |
112 // have a valid handle registered for |watcher_id|. | 130 // have a valid handle registered for |watcher_id|. |
113 Handle handle; | 131 Handle handle; |
114 if (!GetMojoHandleByWatcherID(watcher_id, &handle)) | 132 if (GetMojoHandleByWatcherID(watcher_id, &handle)) { |
115 return; | 133 handle_to_data_.erase(handle); |
116 | 134 message_pump_mojo->RemoveHandler(handle); |
117 handle_to_data_.erase(handle); | 135 } |
118 message_pump_mojo->RemoveHandler(handle); | 136 { |
137 base::AutoLock auto_lock(wait_state->lock); | |
138 wait_state->removed = true; | |
139 wait_state->condition.Signal(); | |
140 } | |
119 } | 141 } |
120 | 142 |
121 void WatcherBackend::RemoveAndNotify(const Handle& handle, | 143 void WatcherBackend::RemoveAndNotify(const Handle& handle, |
122 MojoResult result) { | 144 MojoResult result) { |
123 if (handle_to_data_.count(handle) == 0) | 145 if (handle_to_data_.count(handle) == 0) |
124 return; | 146 return; |
125 | 147 |
126 const WatchData data(handle_to_data_[handle]); | 148 const WatchData data(handle_to_data_[handle]); |
127 handle_to_data_.erase(handle); | 149 handle_to_data_.erase(handle); |
128 message_pump_mojo->RemoveHandler(handle); | 150 message_pump_mojo->RemoveHandler(handle); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
201 const base::Callback<void(MojoResult)>& callback) { | 223 const base::Callback<void(MojoResult)>& callback) { |
202 WatchData data; | 224 WatchData data; |
203 data.id = watcher_id_generator_.GetNext(); | 225 data.id = watcher_id_generator_.GetNext(); |
204 data.handle = handle; | 226 data.handle = handle; |
205 data.callback = callback; | 227 data.callback = callback; |
206 data.handle_signals = handle_signals; | 228 data.handle_signals = handle_signals; |
207 data.deadline = deadline; | 229 data.deadline = deadline; |
208 data.message_loop = base::MessageLoopProxy::current(); | 230 data.message_loop = base::MessageLoopProxy::current(); |
209 DCHECK_NE(static_cast<base::MessageLoopProxy*>(NULL), | 231 DCHECK_NE(static_cast<base::MessageLoopProxy*>(NULL), |
210 data.message_loop.get()); | 232 data.message_loop.get()); |
211 // We outlive |thread_|, so it's safe to use Unretained() here. | 233 // We own |thread_|, so it's safe to use Unretained() here. |
212 thread_.message_loop()->PostTask( | 234 thread_.message_loop()->PostTask( |
213 FROM_HERE, | 235 FROM_HERE, |
214 base::Bind(&WatcherBackend::StartWatching, | 236 base::Bind(&WatcherBackend::StartWatching, |
215 base::Unretained(&backend_), | 237 base::Unretained(&backend_), |
216 data)); | 238 data)); |
217 return data.id; | 239 return data.id; |
218 } | 240 } |
219 | 241 |
220 void WatcherThreadManager::StopWatching(WatcherID watcher_id) { | 242 void WatcherThreadManager::StopWatching(WatcherID watcher_id) { |
221 // We outlive |thread_|, so it's safe to use Unretained() here. | 243 // We own |thread_|, so it's safe to use Unretained() here. |
244 WaitState wait_state; | |
222 thread_.message_loop()->PostTask( | 245 thread_.message_loop()->PostTask( |
223 FROM_HERE, | 246 FROM_HERE, |
224 base::Bind(&WatcherBackend::StopWatching, | 247 base::Bind(&WatcherBackend::StopWatching, |
225 base::Unretained(&backend_), | 248 base::Unretained(&backend_), |
226 watcher_id)); | 249 watcher_id, |
250 &wait_state)); | |
251 | |
252 // We need to block until the handle is actually removed. | |
253 { | |
254 base::AutoLock auto_lock(wait_state.lock); | |
255 while (!wait_state.removed) | |
256 wait_state.condition.Wait(); | |
257 } | |
227 } | 258 } |
228 | 259 |
229 WatcherThreadManager::WatcherThreadManager() | 260 WatcherThreadManager::WatcherThreadManager() |
230 : thread_(kWatcherThreadName) { | 261 : thread_(kWatcherThreadName) { |
231 base::Thread::Options thread_options; | 262 base::Thread::Options thread_options; |
232 thread_options.message_pump_factory = base::Bind(&CreateMessagePumpMojo); | 263 thread_options.message_pump_factory = base::Bind(&CreateMessagePumpMojo); |
233 thread_.StartWithOptions(thread_options); | 264 thread_.StartWithOptions(thread_options); |
234 } | 265 } |
235 | 266 |
236 } // namespace | 267 } // namespace |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
303 | 334 |
304 state_.reset(new State(this, handle, handle_signals, deadline, callback)); | 335 state_.reset(new State(this, handle, handle_signals, deadline, callback)); |
305 } | 336 } |
306 | 337 |
307 void HandleWatcher::Stop() { | 338 void HandleWatcher::Stop() { |
308 state_.reset(); | 339 state_.reset(); |
309 } | 340 } |
310 | 341 |
311 } // namespace common | 342 } // namespace common |
312 } // namespace mojo | 343 } // namespace mojo |
OLD | NEW |