Chromium Code Reviews| 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 |