OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/edk/system/wait_set_dispatcher.h" | 5 #include "mojo/edk/system/wait_set_dispatcher.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <utility> | 10 #include <utility> |
(...skipping 21 matching lines...) Expand all Loading... | |
32 WaitSetDispatcher* const dispatcher_; | 32 WaitSetDispatcher* const dispatcher_; |
33 }; | 33 }; |
34 | 34 |
35 WaitSetDispatcher::WaitState::WaitState() {} | 35 WaitSetDispatcher::WaitState::WaitState() {} |
36 | 36 |
37 WaitSetDispatcher::WaitState::~WaitState() {} | 37 WaitSetDispatcher::WaitState::~WaitState() {} |
38 | 38 |
39 WaitSetDispatcher::WaitSetDispatcher() | 39 WaitSetDispatcher::WaitSetDispatcher() |
40 : waiter_(new WaitSetDispatcher::Waiter(this)) {} | 40 : waiter_(new WaitSetDispatcher::Waiter(this)) {} |
41 | 41 |
42 WaitSetDispatcher::~WaitSetDispatcher() { | |
43 DCHECK(waiting_dispatchers_.empty()); | |
44 DCHECK(awoken_queue_.empty()); | |
45 DCHECK(processed_dispatchers_.empty()); | |
46 } | |
47 | |
48 Dispatcher::Type WaitSetDispatcher::GetType() const { | 42 Dispatcher::Type WaitSetDispatcher::GetType() const { |
49 return Type::WAIT_SET; | 43 return Type::WAIT_SET; |
50 } | 44 } |
51 | 45 |
52 void WaitSetDispatcher::CloseImplNoLock() { | 46 MojoResult WaitSetDispatcher::Close() { |
53 lock().AssertAcquired(); | 47 { |
54 for (const auto& entry : waiting_dispatchers_) | 48 base::AutoLock lock(lock_); |
Anand Mistry (off Chromium)
2016/01/28 02:26:25
Why not just hold lock_ for the entire function. I
| |
55 entry.second.dispatcher->RemoveAwakable(waiter_.get(), nullptr); | 49 if (is_closed_) |
56 waiting_dispatchers_.clear(); | 50 return MOJO_RESULT_INVALID_ARGUMENT; |
51 is_closed_ = true; | |
52 } | |
53 | |
54 { | |
55 base::AutoLock locker(awakable_lock_); | |
56 awakable_list_.CancelAll(); | |
57 } | |
58 | |
59 { | |
60 base::AutoLock lock(lock_); | |
61 for (const auto& entry : waiting_dispatchers_) | |
62 entry.second.dispatcher->RemoveAwakable(waiter_.get(), nullptr); | |
63 waiting_dispatchers_.clear(); | |
64 } | |
57 | 65 |
58 base::AutoLock locker(awoken_lock_); | 66 base::AutoLock locker(awoken_lock_); |
59 awoken_queue_.clear(); | 67 awoken_queue_.clear(); |
60 processed_dispatchers_.clear(); | 68 processed_dispatchers_.clear(); |
69 | |
70 return MOJO_RESULT_OK; | |
61 } | 71 } |
62 | 72 |
63 MojoResult WaitSetDispatcher::AddWaitingDispatcherImplNoLock( | 73 MojoResult WaitSetDispatcher::AddWaitingDispatcher( |
64 const scoped_refptr<Dispatcher>& dispatcher, | 74 const scoped_refptr<Dispatcher>& dispatcher, |
65 MojoHandleSignals signals, | 75 MojoHandleSignals signals, |
66 uintptr_t context) { | 76 uintptr_t context) { |
67 lock().AssertAcquired(); | |
68 if (dispatcher == this) | 77 if (dispatcher == this) |
69 return MOJO_RESULT_INVALID_ARGUMENT; | 78 return MOJO_RESULT_INVALID_ARGUMENT; |
70 | 79 |
80 base::AutoLock lock(lock_); | |
81 | |
82 if (is_closed_) | |
83 return MOJO_RESULT_INVALID_ARGUMENT; | |
84 | |
71 uintptr_t dispatcher_handle = reinterpret_cast<uintptr_t>(dispatcher.get()); | 85 uintptr_t dispatcher_handle = reinterpret_cast<uintptr_t>(dispatcher.get()); |
72 auto it = waiting_dispatchers_.find(dispatcher_handle); | 86 auto it = waiting_dispatchers_.find(dispatcher_handle); |
73 if (it != waiting_dispatchers_.end()) { | 87 if (it != waiting_dispatchers_.end()) { |
74 return MOJO_RESULT_ALREADY_EXISTS; | 88 return MOJO_RESULT_ALREADY_EXISTS; |
75 } | 89 } |
76 | 90 |
77 const MojoResult result = dispatcher->AddAwakable(waiter_.get(), signals, | 91 const MojoResult result = dispatcher->AddAwakable(waiter_.get(), signals, |
78 dispatcher_handle, nullptr); | 92 dispatcher_handle, nullptr); |
79 if (result == MOJO_RESULT_INVALID_ARGUMENT) { | 93 if (result == MOJO_RESULT_INVALID_ARGUMENT) { |
80 // Dispatcher is closed. | 94 // Dispatcher is closed. |
81 return result; | 95 return result; |
82 } else if (result != MOJO_RESULT_OK) { | 96 } else if (result != MOJO_RESULT_OK) { |
83 WakeDispatcher(result, dispatcher_handle); | 97 WakeDispatcher(result, dispatcher_handle); |
84 } | 98 } |
85 | 99 |
86 WaitState state; | 100 WaitState state; |
87 state.dispatcher = dispatcher; | 101 state.dispatcher = dispatcher; |
88 state.context = context; | 102 state.context = context; |
89 state.signals = signals; | 103 state.signals = signals; |
90 bool inserted = waiting_dispatchers_.insert( | 104 bool inserted = waiting_dispatchers_.insert( |
91 std::make_pair(dispatcher_handle, state)).second; | 105 std::make_pair(dispatcher_handle, state)).second; |
92 DCHECK(inserted); | 106 DCHECK(inserted); |
93 | 107 |
94 return MOJO_RESULT_OK; | 108 return MOJO_RESULT_OK; |
95 } | 109 } |
96 | 110 |
97 MojoResult WaitSetDispatcher::RemoveWaitingDispatcherImplNoLock( | 111 MojoResult WaitSetDispatcher::RemoveWaitingDispatcher( |
98 const scoped_refptr<Dispatcher>& dispatcher) { | 112 const scoped_refptr<Dispatcher>& dispatcher) { |
99 lock().AssertAcquired(); | |
100 uintptr_t dispatcher_handle = reinterpret_cast<uintptr_t>(dispatcher.get()); | 113 uintptr_t dispatcher_handle = reinterpret_cast<uintptr_t>(dispatcher.get()); |
101 auto it = waiting_dispatchers_.find(dispatcher_handle); | 114 { |
102 if (it == waiting_dispatchers_.end()) | 115 base::AutoLock lock(lock_); |
Anand Mistry (off Chromium)
2016/01/28 02:26:25
Need to handle the closed state. This can return "
| |
103 return MOJO_RESULT_NOT_FOUND; | 116 auto it = waiting_dispatchers_.find(dispatcher_handle); |
117 if (it == waiting_dispatchers_.end()) | |
118 return MOJO_RESULT_NOT_FOUND; | |
104 | 119 |
105 dispatcher->RemoveAwakable(waiter_.get(), nullptr); | 120 dispatcher->RemoveAwakable(waiter_.get(), nullptr); |
106 // At this point, it should not be possible for |waiter_| to be woken with | 121 // At this point, it should not be possible for |waiter_| to be woken with |
107 // |dispatcher|. | 122 // |dispatcher|. |
108 waiting_dispatchers_.erase(it); | 123 waiting_dispatchers_.erase(it); |
124 } | |
109 | 125 |
110 base::AutoLock locker(awoken_lock_); | 126 base::AutoLock locker(awoken_lock_); |
111 int num_erased = 0; | 127 int num_erased = 0; |
112 for (auto it = awoken_queue_.begin(); it != awoken_queue_.end();) { | 128 for (auto it = awoken_queue_.begin(); it != awoken_queue_.end();) { |
113 if (it->first == dispatcher_handle) { | 129 if (it->first == dispatcher_handle) { |
114 it = awoken_queue_.erase(it); | 130 it = awoken_queue_.erase(it); |
115 num_erased++; | 131 num_erased++; |
116 } else { | 132 } else { |
117 ++it; | 133 ++it; |
118 } | 134 } |
119 } | 135 } |
120 // The dispatcher should only exist in the queue once. | 136 // The dispatcher should only exist in the queue once. |
121 DCHECK_LE(num_erased, 1); | 137 DCHECK_LE(num_erased, 1); |
122 processed_dispatchers_.erase( | 138 processed_dispatchers_.erase( |
123 std::remove(processed_dispatchers_.begin(), processed_dispatchers_.end(), | 139 std::remove(processed_dispatchers_.begin(), processed_dispatchers_.end(), |
124 dispatcher_handle), | 140 dispatcher_handle), |
125 processed_dispatchers_.end()); | 141 processed_dispatchers_.end()); |
126 | 142 |
127 return MOJO_RESULT_OK; | 143 return MOJO_RESULT_OK; |
128 } | 144 } |
129 | 145 |
130 MojoResult WaitSetDispatcher::GetReadyDispatchersImplNoLock( | 146 MojoResult WaitSetDispatcher::GetReadyDispatchers( |
131 uint32_t* count, | 147 uint32_t* count, |
132 DispatcherVector* dispatchers, | 148 DispatcherVector* dispatchers, |
133 MojoResult* results, | 149 MojoResult* results, |
134 uintptr_t* contexts) { | 150 uintptr_t* contexts) { |
135 lock().AssertAcquired(); | 151 base::AutoLock lock(lock_); |
152 | |
136 dispatchers->clear(); | 153 dispatchers->clear(); |
137 | 154 |
138 // Re-queue any already retrieved dispatchers. These should be the dispatchers | 155 // Re-queue any already retrieved dispatchers. These should be the dispatchers |
139 // that were returned on the last call to this function. This loop is | 156 // that were returned on the last call to this function. This loop is |
140 // necessary to preserve the logically level-triggering behaviour of waiting | 157 // necessary to preserve the logically level-triggering behaviour of waiting |
141 // in Mojo. In particular, if no action is taken on a signal, that signal | 158 // in Mojo. In particular, if no action is taken on a signal, that signal |
142 // continues to be satisfied, and therefore a |MojoWait()| on that | 159 // continues to be satisfied, and therefore a |MojoWait()| on that |
143 // handle/signal continues to return immediately. | 160 // handle/signal continues to return immediately. |
144 std::deque<uintptr_t> pending; | 161 std::deque<uintptr_t> pending; |
145 { | 162 { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 num_woken++; | 215 num_woken++; |
199 } | 216 } |
200 | 217 |
201 *count = num_woken; | 218 *count = num_woken; |
202 if (!num_woken) | 219 if (!num_woken) |
203 return MOJO_RESULT_SHOULD_WAIT; | 220 return MOJO_RESULT_SHOULD_WAIT; |
204 | 221 |
205 return MOJO_RESULT_OK; | 222 return MOJO_RESULT_OK; |
206 } | 223 } |
207 | 224 |
208 void WaitSetDispatcher::CancelAllAwakablesNoLock() { | 225 HandleSignalsState WaitSetDispatcher::GetHandleSignalsState() const { |
Anand Mistry (off Chromium)
2016/01/28 02:26:25
Need to handle the closed state. Without it, it's
| |
209 lock().AssertAcquired(); | 226 HandleSignalsState rv; |
210 base::AutoLock locker(awakable_lock_); | 227 rv.satisfiable_signals = MOJO_HANDLE_SIGNAL_READABLE; |
211 awakable_list_.CancelAll(); | 228 base::AutoLock locker(awoken_lock_); |
229 if (!awoken_queue_.empty() || !processed_dispatchers_.empty()) | |
230 rv.satisfied_signals = MOJO_HANDLE_SIGNAL_READABLE; | |
231 return rv; | |
212 } | 232 } |
213 | 233 |
214 MojoResult WaitSetDispatcher::AddAwakableImplNoLock( | 234 MojoResult WaitSetDispatcher::AddAwakable(Awakable* awakable, |
215 Awakable* awakable, | 235 MojoHandleSignals signals, |
216 MojoHandleSignals signals, | 236 uintptr_t context, |
217 uintptr_t context, | 237 HandleSignalsState* signals_state) { |
218 HandleSignalsState* signals_state) { | 238 HandleSignalsState state(GetHandleSignalsState()); |
219 lock().AssertAcquired(); | |
220 | |
221 HandleSignalsState state(GetHandleSignalsStateImplNoLock()); | |
222 if (state.satisfies(signals)) { | 239 if (state.satisfies(signals)) { |
223 if (signals_state) | 240 if (signals_state) |
224 *signals_state = state; | 241 *signals_state = state; |
225 return MOJO_RESULT_ALREADY_EXISTS; | 242 return MOJO_RESULT_ALREADY_EXISTS; |
226 } | 243 } |
227 if (!state.can_satisfy(signals)) { | 244 if (!state.can_satisfy(signals)) { |
228 if (signals_state) | 245 if (signals_state) |
229 *signals_state = state; | 246 *signals_state = state; |
230 return MOJO_RESULT_FAILED_PRECONDITION; | 247 return MOJO_RESULT_FAILED_PRECONDITION; |
231 } | 248 } |
232 | 249 |
233 base::AutoLock locker(awakable_lock_); | 250 base::AutoLock locker(awakable_lock_); |
234 awakable_list_.Add(awakable, signals, context); | 251 awakable_list_.Add(awakable, signals, context); |
235 return MOJO_RESULT_OK; | 252 return MOJO_RESULT_OK; |
236 } | 253 } |
237 | 254 |
238 void WaitSetDispatcher::RemoveAwakableImplNoLock( | 255 void WaitSetDispatcher::RemoveAwakable(Awakable* awakable, |
239 Awakable* awakable, | 256 HandleSignalsState* signals_state) { |
240 HandleSignalsState* signals_state) { | |
241 lock().AssertAcquired(); | |
242 base::AutoLock locker(awakable_lock_); | 257 base::AutoLock locker(awakable_lock_); |
243 awakable_list_.Remove(awakable); | 258 awakable_list_.Remove(awakable); |
244 if (signals_state) | 259 if (signals_state) |
245 *signals_state = GetHandleSignalsStateImplNoLock(); | 260 *signals_state = GetHandleSignalsState(); |
246 } | 261 } |
247 | 262 |
248 HandleSignalsState WaitSetDispatcher::GetHandleSignalsStateImplNoLock() const { | 263 bool WaitSetDispatcher::BeginTransit() { |
249 lock().AssertAcquired(); | 264 // You can't transfer wait sets! |
250 HandleSignalsState rv; | 265 return false; |
251 rv.satisfiable_signals = MOJO_HANDLE_SIGNAL_READABLE; | |
252 base::AutoLock locker(awoken_lock_); | |
253 if (!awoken_queue_.empty() || !processed_dispatchers_.empty()) | |
254 rv.satisfied_signals = MOJO_HANDLE_SIGNAL_READABLE; | |
255 return rv; | |
256 } | 266 } |
257 | 267 |
258 scoped_refptr<Dispatcher> | 268 WaitSetDispatcher::~WaitSetDispatcher() { |
259 WaitSetDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() { | 269 DCHECK(waiting_dispatchers_.empty()); |
260 lock().AssertAcquired(); | 270 DCHECK(awoken_queue_.empty()); |
261 LOG(ERROR) << "Attempting to serialize WaitSet"; | 271 DCHECK(processed_dispatchers_.empty()); |
262 CloseImplNoLock(); | |
263 return new WaitSetDispatcher(); | |
264 } | 272 } |
265 | 273 |
266 void WaitSetDispatcher::WakeDispatcher(MojoResult result, uintptr_t context) { | 274 void WaitSetDispatcher::WakeDispatcher(MojoResult result, uintptr_t context) { |
267 { | 275 { |
268 base::AutoLock locker(awoken_lock_); | 276 base::AutoLock locker(awoken_lock_); |
269 | 277 |
270 if (result == MOJO_RESULT_ALREADY_EXISTS) | 278 if (result == MOJO_RESULT_ALREADY_EXISTS) |
271 result = MOJO_RESULT_OK; | 279 result = MOJO_RESULT_OK; |
272 | 280 |
273 awoken_queue_.push_back(std::make_pair(context, result)); | 281 awoken_queue_.push_back(std::make_pair(context, result)); |
274 } | 282 } |
275 | 283 |
276 base::AutoLock locker(awakable_lock_); | 284 base::AutoLock locker(awakable_lock_); |
277 HandleSignalsState signals_state; | 285 HandleSignalsState signals_state; |
278 signals_state.satisfiable_signals = MOJO_HANDLE_SIGNAL_READABLE; | 286 signals_state.satisfiable_signals = MOJO_HANDLE_SIGNAL_READABLE; |
279 signals_state.satisfied_signals = MOJO_HANDLE_SIGNAL_READABLE; | 287 signals_state.satisfied_signals = MOJO_HANDLE_SIGNAL_READABLE; |
280 awakable_list_.AwakeForStateChange(signals_state); | 288 awakable_list_.AwakeForStateChange(signals_state); |
281 } | 289 } |
282 | 290 |
283 } // namespace edk | 291 } // namespace edk |
284 } // namespace mojo | 292 } // namespace mojo |
OLD | NEW |