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/lock.h" | 16 #include "base/synchronization/lock.h" |
| 17 #include "base/synchronization/waitable_event.h" |
17 #include "base/threading/thread.h" | 18 #include "base/threading/thread.h" |
| 19 #include "base/threading/thread_restrictions.h" |
18 #include "base/time/time.h" | 20 #include "base/time/time.h" |
19 #include "mojo/common/message_pump_mojo.h" | 21 #include "mojo/common/message_pump_mojo.h" |
20 #include "mojo/common/message_pump_mojo_handler.h" | 22 #include "mojo/common/message_pump_mojo_handler.h" |
21 #include "mojo/common/time_helper.h" | 23 #include "mojo/common/time_helper.h" |
22 | 24 |
23 namespace mojo { | 25 namespace mojo { |
24 namespace common { | 26 namespace common { |
25 | 27 |
26 typedef int WatcherID; | 28 typedef int WatcherID; |
27 | 29 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 | 63 |
62 // WatcherBackend is responsible for managing the requests and interacting with | 64 // WatcherBackend is responsible for managing the requests and interacting with |
63 // MessagePumpMojo. All access (outside of creation/destruction) is done on the | 65 // MessagePumpMojo. All access (outside of creation/destruction) is done on the |
64 // thread WatcherThreadManager creates. | 66 // thread WatcherThreadManager creates. |
65 class WatcherBackend : public MessagePumpMojoHandler { | 67 class WatcherBackend : public MessagePumpMojoHandler { |
66 public: | 68 public: |
67 WatcherBackend(); | 69 WatcherBackend(); |
68 virtual ~WatcherBackend(); | 70 virtual ~WatcherBackend(); |
69 | 71 |
70 void StartWatching(const WatchData& data); | 72 void StartWatching(const WatchData& data); |
71 void StopWatching(WatcherID watcher_id); | 73 |
| 74 // Cancels a previously schedule request to start a watch. When done signals |
| 75 // |event|. |
| 76 void StopWatching(WatcherID watcher_id, base::WaitableEvent* event); |
72 | 77 |
73 private: | 78 private: |
74 typedef std::map<Handle, WatchData> HandleToWatchDataMap; | 79 typedef std::map<Handle, WatchData> HandleToWatchDataMap; |
75 | 80 |
76 // Invoked when a handle needs to be removed and notified. | 81 // Invoked when a handle needs to be removed and notified. |
77 void RemoveAndNotify(const Handle& handle, MojoResult result); | 82 void RemoveAndNotify(const Handle& handle, MojoResult result); |
78 | 83 |
79 // Searches through |handle_to_data_| for |watcher_id|. Returns true if found | 84 // 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. | 85 // and sets |handle| to the Handle. Returns false if not a known id. |
81 bool GetMojoHandleByWatcherID(WatcherID watcher_id, Handle* handle) const; | 86 bool GetMojoHandleByWatcherID(WatcherID watcher_id, Handle* handle) const; |
(...skipping 18 matching lines...) Expand all Loading... |
100 RemoveAndNotify(data.handle, MOJO_RESULT_CANCELLED); | 105 RemoveAndNotify(data.handle, MOJO_RESULT_CANCELLED); |
101 | 106 |
102 DCHECK_EQ(0u, handle_to_data_.count(data.handle)); | 107 DCHECK_EQ(0u, handle_to_data_.count(data.handle)); |
103 | 108 |
104 handle_to_data_[data.handle] = data; | 109 handle_to_data_[data.handle] = data; |
105 message_pump_mojo->AddHandler(this, data.handle, | 110 message_pump_mojo->AddHandler(this, data.handle, |
106 data.handle_signals, | 111 data.handle_signals, |
107 data.deadline); | 112 data.deadline); |
108 } | 113 } |
109 | 114 |
110 void WatcherBackend::StopWatching(WatcherID watcher_id) { | 115 void WatcherBackend::StopWatching(WatcherID watcher_id, |
| 116 base::WaitableEvent* event) { |
111 // Because of the thread hop it is entirely possible to get here and not | 117 // Because of the thread hop it is entirely possible to get here and not |
112 // have a valid handle registered for |watcher_id|. | 118 // have a valid handle registered for |watcher_id|. |
113 Handle handle; | 119 Handle handle; |
114 if (!GetMojoHandleByWatcherID(watcher_id, &handle)) | 120 if (GetMojoHandleByWatcherID(watcher_id, &handle)) { |
115 return; | 121 handle_to_data_.erase(handle); |
116 | 122 message_pump_mojo->RemoveHandler(handle); |
117 handle_to_data_.erase(handle); | 123 } |
118 message_pump_mojo->RemoveHandler(handle); | 124 event->Signal(); |
119 } | 125 } |
120 | 126 |
121 void WatcherBackend::RemoveAndNotify(const Handle& handle, | 127 void WatcherBackend::RemoveAndNotify(const Handle& handle, |
122 MojoResult result) { | 128 MojoResult result) { |
123 if (handle_to_data_.count(handle) == 0) | 129 if (handle_to_data_.count(handle) == 0) |
124 return; | 130 return; |
125 | 131 |
126 const WatchData data(handle_to_data_[handle]); | 132 const WatchData data(handle_to_data_[handle]); |
127 handle_to_data_.erase(handle); | 133 handle_to_data_.erase(handle); |
128 message_pump_mojo->RemoveHandler(handle); | 134 message_pump_mojo->RemoveHandler(handle); |
(...skipping 17 matching lines...) Expand all Loading... |
146 } | 152 } |
147 | 153 |
148 void WatcherBackend::OnHandleError(const Handle& handle, MojoResult result) { | 154 void WatcherBackend::OnHandleError(const Handle& handle, MojoResult result) { |
149 RemoveAndNotify(handle, result); | 155 RemoveAndNotify(handle, result); |
150 } | 156 } |
151 | 157 |
152 // WatcherThreadManager -------------------------------------------------------- | 158 // WatcherThreadManager -------------------------------------------------------- |
153 | 159 |
154 // WatcherThreadManager manages the background thread that listens for handles | 160 // WatcherThreadManager manages the background thread that listens for handles |
155 // to be ready. All requests are handled by WatcherBackend. | 161 // to be ready. All requests are handled by WatcherBackend. |
| 162 } // namespace |
| 163 |
156 class WatcherThreadManager { | 164 class WatcherThreadManager { |
157 public: | 165 public: |
158 ~WatcherThreadManager(); | 166 ~WatcherThreadManager(); |
159 | 167 |
160 // Returns the shared instance. | 168 // Returns the shared instance. |
161 static WatcherThreadManager* GetInstance(); | 169 static WatcherThreadManager* GetInstance(); |
162 | 170 |
163 // Starts watching the requested handle. Returns a unique ID that is used to | 171 // Starts watching the requested handle. Returns a unique ID that is used to |
164 // stop watching the handle. When the handle is ready |callback| is notified | 172 // stop watching the handle. When the handle is ready |callback| is notified |
165 // on the thread StartWatching() was invoked on. | 173 // on the thread StartWatching() was invoked on. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 const base::Callback<void(MojoResult)>& callback) { | 209 const base::Callback<void(MojoResult)>& callback) { |
202 WatchData data; | 210 WatchData data; |
203 data.id = watcher_id_generator_.GetNext(); | 211 data.id = watcher_id_generator_.GetNext(); |
204 data.handle = handle; | 212 data.handle = handle; |
205 data.callback = callback; | 213 data.callback = callback; |
206 data.handle_signals = handle_signals; | 214 data.handle_signals = handle_signals; |
207 data.deadline = deadline; | 215 data.deadline = deadline; |
208 data.message_loop = base::MessageLoopProxy::current(); | 216 data.message_loop = base::MessageLoopProxy::current(); |
209 DCHECK_NE(static_cast<base::MessageLoopProxy*>(NULL), | 217 DCHECK_NE(static_cast<base::MessageLoopProxy*>(NULL), |
210 data.message_loop.get()); | 218 data.message_loop.get()); |
211 // We outlive |thread_|, so it's safe to use Unretained() here. | 219 // We own |thread_|, so it's safe to use Unretained() here. |
212 thread_.message_loop()->PostTask( | 220 thread_.message_loop()->PostTask( |
213 FROM_HERE, | 221 FROM_HERE, |
214 base::Bind(&WatcherBackend::StartWatching, | 222 base::Bind(&WatcherBackend::StartWatching, |
215 base::Unretained(&backend_), | 223 base::Unretained(&backend_), |
216 data)); | 224 data)); |
217 return data.id; | 225 return data.id; |
218 } | 226 } |
219 | 227 |
220 void WatcherThreadManager::StopWatching(WatcherID watcher_id) { | 228 void WatcherThreadManager::StopWatching(WatcherID watcher_id) { |
221 // We outlive |thread_|, so it's safe to use Unretained() here. | 229 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 230 base::WaitableEvent event(true, false); |
| 231 // We own |thread_|, so it's safe to use Unretained() here. |
222 thread_.message_loop()->PostTask( | 232 thread_.message_loop()->PostTask( |
223 FROM_HERE, | 233 FROM_HERE, |
224 base::Bind(&WatcherBackend::StopWatching, | 234 base::Bind(&WatcherBackend::StopWatching, |
225 base::Unretained(&backend_), | 235 base::Unretained(&backend_), |
226 watcher_id)); | 236 watcher_id, |
| 237 &event)); |
| 238 |
| 239 // We need to block until the handle is actually removed. |
| 240 event.Wait(); |
227 } | 241 } |
228 | 242 |
229 WatcherThreadManager::WatcherThreadManager() | 243 WatcherThreadManager::WatcherThreadManager() |
230 : thread_(kWatcherThreadName) { | 244 : thread_(kWatcherThreadName) { |
231 base::Thread::Options thread_options; | 245 base::Thread::Options thread_options; |
232 thread_options.message_pump_factory = base::Bind(&CreateMessagePumpMojo); | 246 thread_options.message_pump_factory = base::Bind(&CreateMessagePumpMojo); |
233 thread_.StartWithOptions(thread_options); | 247 thread_.StartWithOptions(thread_options); |
234 } | 248 } |
235 | 249 |
236 } // namespace | |
237 | |
238 // HandleWatcher::State -------------------------------------------------------- | 250 // HandleWatcher::State -------------------------------------------------------- |
239 | 251 |
240 // Represents the state of the HandleWatcher. Owns the user's callback and | 252 // Represents the state of the HandleWatcher. Owns the user's callback and |
241 // monitors the current thread's MessageLoop to know when to force the callback | 253 // monitors the current thread's MessageLoop to know when to force the callback |
242 // to run (with an error) even though the pipe hasn't been signaled yet. | 254 // to run (with an error) even though the pipe hasn't been signaled yet. |
243 class HandleWatcher::State : public base::MessageLoop::DestructionObserver { | 255 class HandleWatcher::State : public base::MessageLoop::DestructionObserver { |
244 public: | 256 public: |
245 State(HandleWatcher* watcher, | 257 State(HandleWatcher* watcher, |
246 const Handle& handle, | 258 const Handle& handle, |
247 MojoHandleSignals handle_signals, | 259 MojoHandleSignals handle_signals, |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 | 315 |
304 state_.reset(new State(this, handle, handle_signals, deadline, callback)); | 316 state_.reset(new State(this, handle, handle_signals, deadline, callback)); |
305 } | 317 } |
306 | 318 |
307 void HandleWatcher::Stop() { | 319 void HandleWatcher::Stop() { |
308 state_.reset(); | 320 state_.reset(); |
309 } | 321 } |
310 | 322 |
311 } // namespace common | 323 } // namespace common |
312 } // namespace mojo | 324 } // namespace mojo |
OLD | NEW |