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

Side by Side Diff: mojo/edk/system/core.cc

Issue 1350023003: Add a Mojo EDK for Chrome that uses one OS pipe per message pipe. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: more cleanup Created 5 years, 2 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 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 "third_party/mojo/src/mojo/edk/system/core.h" 5 #include "mojo/edk/system/core.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/time/time.h" 10 #include "base/time/time.h"
11 #include "mojo/edk/embedder/platform_channel_pair.h"
12 #include "mojo/edk/embedder/platform_shared_buffer.h"
13 #include "mojo/edk/embedder/platform_support.h"
14 #include "mojo/edk/system/async_waiter.h"
15 #include "mojo/edk/system/configuration.h"
16 #include "mojo/edk/system/data_pipe.h"
17 #include "mojo/edk/system/data_pipe_consumer_dispatcher.h"
18 #include "mojo/edk/system/data_pipe_producer_dispatcher.h"
19 #include "mojo/edk/system/dispatcher.h"
20 #include "mojo/edk/system/handle_signals_state.h"
21 #include "mojo/edk/system/message_pipe_dispatcher.h"
22 #include "mojo/edk/system/shared_buffer_dispatcher.h"
23 #include "mojo/edk/system/waiter.h"
11 #include "mojo/public/c/system/macros.h" 24 #include "mojo/public/c/system/macros.h"
12 #include "mojo/public/cpp/system/macros.h" 25 #include "mojo/public/cpp/system/macros.h"
13 #include "third_party/mojo/src/mojo/edk/embedder/platform_shared_buffer.h"
14 #include "third_party/mojo/src/mojo/edk/embedder/platform_support.h"
15 #include "third_party/mojo/src/mojo/edk/system/async_waiter.h"
16 #include "third_party/mojo/src/mojo/edk/system/configuration.h"
17 #include "third_party/mojo/src/mojo/edk/system/data_pipe.h"
18 #include "third_party/mojo/src/mojo/edk/system/data_pipe_consumer_dispatcher.h"
19 #include "third_party/mojo/src/mojo/edk/system/data_pipe_producer_dispatcher.h"
20 #include "third_party/mojo/src/mojo/edk/system/dispatcher.h"
21 #include "third_party/mojo/src/mojo/edk/system/handle_signals_state.h"
22 #include "third_party/mojo/src/mojo/edk/system/memory.h"
23 #include "third_party/mojo/src/mojo/edk/system/message_pipe.h"
24 #include "third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher.h"
25 #include "third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.h"
26 #include "third_party/mojo/src/mojo/edk/system/waiter.h"
27 26
28 namespace mojo { 27 namespace mojo {
29 namespace system { 28 namespace edk {
30 29
31 // Implementation notes 30 // Implementation notes
32 // 31 //
33 // Mojo primitives are implemented by the singleton |Core| object. Most calls 32 // Mojo primitives are implemented by the singleton |Core| object. Most calls
34 // are for a "primary" handle (the first argument). |Core::GetDispatcher()| is 33 // are for a "primary" handle (the first argument). |Core::GetDispatcher()| is
35 // used to look up a |Dispatcher| object for a given handle. That object 34 // used to look up a |Dispatcher| object for a given handle. That object
36 // implements most primitives for that object. The wait primitives are not 35 // implements most primitives for that object. The wait primitives are not
37 // attached to objects and are implemented by |Core| itself. 36 // attached to objects and are implemented by |Core| itself.
38 // 37 //
39 // Some objects have multiple handles associated to them, e.g., message pipes 38 // Some objects have multiple handles associated to them, e.g., message pipes
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 // 70 //
72 // Notes: 71 // Notes:
73 // - While holding a |Dispatcher| lock, you may not unconditionally attempt 72 // - While holding a |Dispatcher| lock, you may not unconditionally attempt
74 // to take another |Dispatcher| lock. (This has consequences on the 73 // to take another |Dispatcher| lock. (This has consequences on the
75 // concurrency semantics of |MojoWriteMessage()| when passing handles.) 74 // concurrency semantics of |MojoWriteMessage()| when passing handles.)
76 // Doing so would lead to deadlock. 75 // Doing so would lead to deadlock.
77 // - Locks at the "INF" level may not have any locks taken while they are 76 // - Locks at the "INF" level may not have any locks taken while they are
78 // held. 77 // held.
79 78
80 // TODO(vtl): This should take a |scoped_ptr<PlatformSupport>| as a parameter. 79 // TODO(vtl): This should take a |scoped_ptr<PlatformSupport>| as a parameter.
81 Core::Core(embedder::PlatformSupport* platform_support) 80 Core::Core(PlatformSupport* platform_support)
82 : platform_support_(platform_support) { 81 : platform_support_(platform_support) {
83 } 82 }
84 83
85 Core::~Core() { 84 Core::~Core() {
86 } 85 }
87 86
88 MojoHandle Core::AddDispatcher(const scoped_refptr<Dispatcher>& dispatcher) { 87 MojoHandle Core::AddDispatcher(const scoped_refptr<Dispatcher>& dispatcher) {
89 MutexLocker locker(&handle_table_mutex_); 88 base::AutoLock locker(handle_table_lock_);
90 return handle_table_.AddDispatcher(dispatcher); 89 return handle_table_.AddDispatcher(dispatcher);
91 } 90 }
92 91
93 scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) { 92 scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) {
94 if (handle == MOJO_HANDLE_INVALID) 93 if (handle == MOJO_HANDLE_INVALID)
95 return nullptr; 94 return nullptr;
96 95
97 MutexLocker locker(&handle_table_mutex_); 96 base::AutoLock locker(handle_table_lock_);
98 return handle_table_.GetDispatcher(handle); 97 return handle_table_.GetDispatcher(handle);
99 } 98 }
100 99
101 MojoResult Core::GetAndRemoveDispatcher(MojoHandle handle, 100 MojoResult Core::GetAndRemoveDispatcher(MojoHandle handle,
102 scoped_refptr<Dispatcher>* dispatcher) { 101 scoped_refptr<Dispatcher>* dispatcher) {
103 if (handle == MOJO_HANDLE_INVALID) 102 if (handle == MOJO_HANDLE_INVALID)
104 return MOJO_RESULT_INVALID_ARGUMENT; 103 return MOJO_RESULT_INVALID_ARGUMENT;
105 104
106 MutexLocker locker(&handle_table_mutex_); 105 base::AutoLock locker(handle_table_lock_);
107 return handle_table_.GetAndRemoveDispatcher(handle, dispatcher); 106 return handle_table_.GetAndRemoveDispatcher(handle, dispatcher);
108 } 107 }
109 108
110 MojoResult Core::AsyncWait(MojoHandle handle, 109 MojoResult Core::AsyncWait(MojoHandle handle,
111 MojoHandleSignals signals, 110 MojoHandleSignals signals,
112 const base::Callback<void(MojoResult)>& callback) { 111 const base::Callback<void(MojoResult)>& callback) {
113 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle); 112 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle);
114 DCHECK(dispatcher); 113 DCHECK(dispatcher);
115 114
116 scoped_ptr<AsyncWaiter> waiter = make_scoped_ptr(new AsyncWaiter(callback)); 115 scoped_ptr<AsyncWaiter> waiter = make_scoped_ptr(new AsyncWaiter(callback));
117 MojoResult rv = dispatcher->AddAwakable(waiter.get(), signals, 0, nullptr); 116 MojoResult rv = dispatcher->AddAwakable(waiter.get(), signals, 0, nullptr);
118 if (rv == MOJO_RESULT_OK) 117 if (rv == MOJO_RESULT_OK)
119 ignore_result(waiter.release()); 118 ignore_result(waiter.release());
120 return rv; 119 return rv;
121 } 120 }
122 121
123 MojoTimeTicks Core::GetTimeTicksNow() { 122 MojoTimeTicks Core::GetTimeTicksNow() {
124 return base::TimeTicks::Now().ToInternalValue(); 123 return base::TimeTicks::Now().ToInternalValue();
125 } 124 }
126 125
127 MojoResult Core::Close(MojoHandle handle) { 126 MojoResult Core::Close(MojoHandle handle) {
128 if (handle == MOJO_HANDLE_INVALID) 127 if (handle == MOJO_HANDLE_INVALID)
129 return MOJO_RESULT_INVALID_ARGUMENT; 128 return MOJO_RESULT_INVALID_ARGUMENT;
130 129
131 scoped_refptr<Dispatcher> dispatcher; 130 scoped_refptr<Dispatcher> dispatcher;
132 { 131 {
133 MutexLocker locker(&handle_table_mutex_); 132 base::AutoLock locker(handle_table_lock_);
134 MojoResult result = 133 MojoResult result =
135 handle_table_.GetAndRemoveDispatcher(handle, &dispatcher); 134 handle_table_.GetAndRemoveDispatcher(handle, &dispatcher);
136 if (result != MOJO_RESULT_OK) 135 if (result != MOJO_RESULT_OK)
137 return result; 136 return result;
138 } 137 }
139 138
140 // The dispatcher doesn't have a say in being closed, but gets notified of it. 139 // The dispatcher doesn't have a say in being closed, but gets notified of it.
141 // Note: This is done outside of |handle_table_mutex_|. As a result, there's a 140 // Note: This is done outside of |handle_table_lock_|. As a result, there's a
142 // race condition that the dispatcher must handle; see the comment in 141 // race condition that the dispatcher must handle; see the comment in
143 // |Dispatcher| in dispatcher.h. 142 // |Dispatcher| in dispatcher.h.
144 return dispatcher->Close(); 143 return dispatcher->Close();
145 } 144 }
146 145
147 MojoResult Core::Wait(MojoHandle handle, 146 MojoResult Core::Wait(MojoHandle handle,
148 MojoHandleSignals signals, 147 MojoHandleSignals signals,
149 MojoDeadline deadline, 148 MojoDeadline deadline,
150 UserPointer<MojoHandleSignalsState> signals_state) { 149 MojoHandleSignalsState* signals_state) {
151 uint32_t unused = static_cast<uint32_t>(-1); 150 uint32_t unused = static_cast<uint32_t>(-1);
152 HandleSignalsState hss; 151 HandleSignalsState hss;
153 MojoResult rv = WaitManyInternal(&handle, &signals, 1, deadline, &unused, 152 MojoResult rv = WaitManyInternal(&handle, &signals, 1, deadline, &unused,
154 signals_state.IsNull() ? nullptr : &hss); 153 signals_state ? &hss : nullptr);
155 if (rv != MOJO_RESULT_INVALID_ARGUMENT && !signals_state.IsNull()) 154 if (rv != MOJO_RESULT_INVALID_ARGUMENT && signals_state)
156 signals_state.Put(hss); 155 *signals_state = hss;
157 return rv; 156 return rv;
158 } 157 }
159 158
160 MojoResult Core::WaitMany(UserPointer<const MojoHandle> handles, 159 MojoResult Core::WaitMany(const MojoHandle* handles,
161 UserPointer<const MojoHandleSignals> signals, 160 const MojoHandleSignals* signals,
162 uint32_t num_handles, 161 uint32_t num_handles,
163 MojoDeadline deadline, 162 MojoDeadline deadline,
164 UserPointer<uint32_t> result_index, 163 uint32_t* result_index,
165 UserPointer<MojoHandleSignalsState> signals_states) { 164 MojoHandleSignalsState* signals_state) {
166 if (num_handles < 1) 165 if (num_handles < 1)
167 return MOJO_RESULT_INVALID_ARGUMENT; 166 return MOJO_RESULT_INVALID_ARGUMENT;
168 if (num_handles > GetConfiguration().max_wait_many_num_handles) 167 if (num_handles > GetConfiguration().max_wait_many_num_handles)
169 return MOJO_RESULT_RESOURCE_EXHAUSTED; 168 return MOJO_RESULT_RESOURCE_EXHAUSTED;
170 169
171 UserPointer<const MojoHandle>::Reader handles_reader(handles, num_handles);
172 UserPointer<const MojoHandleSignals>::Reader signals_reader(signals,
173 num_handles);
174 uint32_t index = static_cast<uint32_t>(-1); 170 uint32_t index = static_cast<uint32_t>(-1);
175 MojoResult rv; 171 MojoResult rv;
176 if (signals_states.IsNull()) { 172 if (!signals_state) {
177 rv = WaitManyInternal(handles_reader.GetPointer(), 173 rv = WaitManyInternal(handles, signals, num_handles, deadline, &index,
178 signals_reader.GetPointer(), num_handles, deadline, 174 nullptr);
179 &index, nullptr);
180 } else { 175 } else {
181 UserPointer<MojoHandleSignalsState>::Writer signals_states_writer(
182 signals_states, num_handles);
183 // Note: The |reinterpret_cast| is safe, since |HandleSignalsState| is a 176 // Note: The |reinterpret_cast| is safe, since |HandleSignalsState| is a
184 // subclass of |MojoHandleSignalsState| that doesn't add any data members. 177 // subclass of |MojoHandleSignalsState| that doesn't add any data members.
185 rv = WaitManyInternal(handles_reader.GetPointer(), 178 rv = WaitManyInternal(handles, signals, num_handles, deadline, &index,
186 signals_reader.GetPointer(), num_handles, deadline, 179 reinterpret_cast<HandleSignalsState*>(signals_state));
187 &index, reinterpret_cast<HandleSignalsState*>(
188 signals_states_writer.GetPointer()));
189 if (rv != MOJO_RESULT_INVALID_ARGUMENT)
190 signals_states_writer.Commit();
191 } 180 }
192 if (index != static_cast<uint32_t>(-1) && !result_index.IsNull()) 181 if (index != static_cast<uint32_t>(-1) && result_index)
193 result_index.Put(index); 182 *result_index = index;
194 return rv; 183 return rv;
195 } 184 }
196 185
197 MojoResult Core::CreateMessagePipe( 186 MojoResult Core::CreateMessagePipe(
198 UserPointer<const MojoCreateMessagePipeOptions> options, 187 const MojoCreateMessagePipeOptions* options,
199 UserPointer<MojoHandle> message_pipe_handle0, 188 MojoHandle* message_pipe_handle0,
200 UserPointer<MojoHandle> message_pipe_handle1) { 189 MojoHandle* message_pipe_handle1) {
190 CHECK(message_pipe_handle0);
191 CHECK(message_pipe_handle1);
201 MojoCreateMessagePipeOptions validated_options = {}; 192 MojoCreateMessagePipeOptions validated_options = {};
202 MojoResult result = 193 MojoResult result =
203 MessagePipeDispatcher::ValidateCreateOptions(options, &validated_options); 194 MessagePipeDispatcher::ValidateCreateOptions(options, &validated_options);
204 if (result != MOJO_RESULT_OK) 195 if (result != MOJO_RESULT_OK)
205 return result; 196 return result;
206 197
207 scoped_refptr<MessagePipeDispatcher> dispatcher0 = 198 scoped_refptr<MessagePipeDispatcher> dispatcher0 =
208 MessagePipeDispatcher::Create(validated_options); 199 MessagePipeDispatcher::Create(validated_options);
209 scoped_refptr<MessagePipeDispatcher> dispatcher1 = 200 scoped_refptr<MessagePipeDispatcher> dispatcher1 =
210 MessagePipeDispatcher::Create(validated_options); 201 MessagePipeDispatcher::Create(validated_options);
211 202
212 std::pair<MojoHandle, MojoHandle> handle_pair; 203 std::pair<MojoHandle, MojoHandle> handle_pair;
213 { 204 {
214 MutexLocker locker(&handle_table_mutex_); 205 base::AutoLock locker(handle_table_lock_);
215 handle_pair = handle_table_.AddDispatcherPair(dispatcher0, dispatcher1); 206 handle_pair = handle_table_.AddDispatcherPair(dispatcher0, dispatcher1);
216 } 207 }
217 if (handle_pair.first == MOJO_HANDLE_INVALID) { 208 if (handle_pair.first == MOJO_HANDLE_INVALID) {
218 DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID); 209 DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID);
219 LOG(ERROR) << "Handle table full"; 210 LOG(ERROR) << "Handle table full";
220 dispatcher0->Close(); 211 dispatcher0->Close();
221 dispatcher1->Close(); 212 dispatcher1->Close();
222 return MOJO_RESULT_RESOURCE_EXHAUSTED; 213 return MOJO_RESULT_RESOURCE_EXHAUSTED;
223 } 214 }
224 215
225 scoped_refptr<MessagePipe> message_pipe(MessagePipe::CreateLocalLocal()); 216 PlatformChannelPair channel_pair;
226 dispatcher0->Init(message_pipe, 0); 217 dispatcher0->Init(channel_pair.PassServerHandle());
227 dispatcher1->Init(message_pipe, 1); 218 dispatcher1->Init(channel_pair.PassClientHandle());
228 219
229 message_pipe_handle0.Put(handle_pair.first); 220 *message_pipe_handle0 = handle_pair.first;
230 message_pipe_handle1.Put(handle_pair.second); 221 *message_pipe_handle1 = handle_pair.second;
231 return MOJO_RESULT_OK; 222 return MOJO_RESULT_OK;
232 } 223 }
233 224
234 // Implementation note: To properly cancel waiters and avoid other races, this 225 // Implementation note: To properly cancel waiters and avoid other races, this
235 // does not transfer dispatchers from one handle to another, even when sending a 226 // does not transfer dispatchers from one handle to another, even when sending a
236 // message in-process. Instead, it must transfer the "contents" of the 227 // message in-process. Instead, it must transfer the "contents" of the
237 // dispatcher to a new dispatcher, and then close the old dispatcher. If this 228 // dispatcher to a new dispatcher, and then close the old dispatcher. If this
238 // isn't done, in the in-process case, calls on the old handle may complete 229 // isn't done, in the in-process case, calls on the old handle may complete
239 // after the the message has been received and a new handle created (and 230 // after the the message has been received and a new handle created (and
240 // possibly even after calls have been made on the new handle). 231 // possibly even after calls have been made on the new handle).
241 MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, 232 MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
242 UserPointer<const void> bytes, 233 const void* bytes,
243 uint32_t num_bytes, 234 uint32_t num_bytes,
244 UserPointer<const MojoHandle> handles, 235 const MojoHandle* handles,
245 uint32_t num_handles, 236 uint32_t num_handles,
246 MojoWriteMessageFlags flags) { 237 MojoWriteMessageFlags flags) {
247 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle)); 238 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle));
248 if (!dispatcher) 239 if (!dispatcher)
249 return MOJO_RESULT_INVALID_ARGUMENT; 240 return MOJO_RESULT_INVALID_ARGUMENT;
250 241
251 // Easy case: not sending any handles. 242 // Easy case: not sending any handles.
252 if (num_handles == 0) 243 if (num_handles == 0)
253 return dispatcher->WriteMessage(bytes, num_bytes, nullptr, flags); 244 return dispatcher->WriteMessage(bytes, num_bytes, nullptr, flags);
254 245
255 // We have to handle |handles| here, since we have to mark them busy in the 246 // We have to handle |handles| here, since we have to mark them busy in the
256 // global handle table. We can't delegate this to the dispatcher, since the 247 // global handle table. We can't delegate this to the dispatcher, since the
257 // handle table lock must be acquired before the dispatcher lock. 248 // handle table lock must be acquired before the dispatcher lock.
258 // 249 //
259 // (This leads to an oddity: |handles|/|num_handles| are always verified for 250 // (This leads to an oddity: |handles|/|num_handles| are always verified for
260 // validity, even for dispatchers that don't support |WriteMessage()| and will 251 // validity, even for dispatchers that don't support |WriteMessage()| and will
261 // simply return failure unconditionally. It also breaks the usual 252 // simply return failure unconditionally. It also breaks the usual
262 // left-to-right verification order of arguments.) 253 // left-to-right verification order of arguments.)
263 if (num_handles > GetConfiguration().max_message_num_handles) 254 if (num_handles > GetConfiguration().max_message_num_handles)
264 return MOJO_RESULT_RESOURCE_EXHAUSTED; 255 return MOJO_RESULT_RESOURCE_EXHAUSTED;
265 256
266 UserPointer<const MojoHandle>::Reader handles_reader(handles, num_handles);
267
268 // We'll need to hold on to the dispatchers so that we can pass them on to 257 // We'll need to hold on to the dispatchers so that we can pass them on to
269 // |WriteMessage()| and also so that we can unlock their locks afterwards 258 // |WriteMessage()| and also so that we can unlock their locks afterwards
270 // without accessing the handle table. These can be dumb pointers, since their 259 // without accessing the handle table. These can be dumb pointers, since their
271 // entries in the handle table won't get removed (since they'll be marked as 260 // entries in the handle table won't get removed (since they'll be marked as
272 // busy). 261 // busy).
273 std::vector<DispatcherTransport> transports(num_handles); 262 std::vector<DispatcherTransport> transports(num_handles);
274 263
275 // When we pass handles, we have to try to take all their dispatchers' locks 264 // When we pass handles, we have to try to take all their dispatchers' locks
276 // and mark the handles as busy. If the call succeeds, we then remove the 265 // and mark the handles as busy. If the call succeeds, we then remove the
277 // handles from the handle table. 266 // handles from the handle table.
278 { 267 {
279 MutexLocker locker(&handle_table_mutex_); 268 base::AutoLock locker(handle_table_lock_);
280 MojoResult result = handle_table_.MarkBusyAndStartTransport( 269 MojoResult result = handle_table_.MarkBusyAndStartTransport(
281 message_pipe_handle, handles_reader.GetPointer(), num_handles, 270 message_pipe_handle, handles, num_handles, &transports);
282 &transports);
283 if (result != MOJO_RESULT_OK) 271 if (result != MOJO_RESULT_OK)
284 return result; 272 return result;
285 } 273 }
286 274
287 MojoResult rv = 275 MojoResult rv =
288 dispatcher->WriteMessage(bytes, num_bytes, &transports, flags); 276 dispatcher->WriteMessage(bytes, num_bytes, &transports, flags);
289 277
290 // We need to release the dispatcher locks before we take the handle table 278 // We need to release the dispatcher locks before we take the handle table
291 // lock. 279 // lock.
292 for (uint32_t i = 0; i < num_handles; i++) 280 for (uint32_t i = 0; i < num_handles; i++)
293 transports[i].End(); 281 transports[i].End();
294 282
295 { 283 {
296 MutexLocker locker(&handle_table_mutex_); 284 base::AutoLock locker(handle_table_lock_);
297 if (rv == MOJO_RESULT_OK) { 285 if (rv == MOJO_RESULT_OK) {
298 handle_table_.RemoveBusyHandles(handles_reader.GetPointer(), num_handles); 286 handle_table_.RemoveBusyHandles(handles, num_handles);
299 } else { 287 } else {
300 handle_table_.RestoreBusyHandles(handles_reader.GetPointer(), 288 handle_table_.RestoreBusyHandles(handles, num_handles);
301 num_handles);
302 } 289 }
303 } 290 }
304 291
305 return rv; 292 return rv;
306 } 293 }
307 294
308 MojoResult Core::ReadMessage(MojoHandle message_pipe_handle, 295 MojoResult Core::ReadMessage(MojoHandle message_pipe_handle,
309 UserPointer<void> bytes, 296 void* bytes,
310 UserPointer<uint32_t> num_bytes, 297 uint32_t* num_bytes,
311 UserPointer<MojoHandle> handles, 298 MojoHandle* handles,
312 UserPointer<uint32_t> num_handles, 299 uint32_t* num_handles,
313 MojoReadMessageFlags flags) { 300 MojoReadMessageFlags flags) {
314 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle)); 301 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle));
315 if (!dispatcher) 302 if (!dispatcher)
316 return MOJO_RESULT_INVALID_ARGUMENT; 303 return MOJO_RESULT_INVALID_ARGUMENT;
317 304
318 uint32_t num_handles_value = num_handles.IsNull() ? 0 : num_handles.Get();
319
320 MojoResult rv; 305 MojoResult rv;
306 uint32_t num_handles_value = num_handles ? *num_handles : 0;
321 if (num_handles_value == 0) { 307 if (num_handles_value == 0) {
322 // Easy case: won't receive any handles. 308 // Easy case: won't receive any handles.
323 rv = dispatcher->ReadMessage(bytes, num_bytes, nullptr, &num_handles_value, 309 rv = dispatcher->ReadMessage(bytes, num_bytes, nullptr, &num_handles_value,
324 flags); 310 flags);
325 } else { 311 } else {
326 DispatcherVector dispatchers; 312 DispatcherVector dispatchers;
327 rv = dispatcher->ReadMessage(bytes, num_bytes, &dispatchers, 313 rv = dispatcher->ReadMessage(bytes, num_bytes, &dispatchers,
328 &num_handles_value, flags); 314 &num_handles_value, flags);
329 if (!dispatchers.empty()) { 315 if (!dispatchers.empty()) {
330 DCHECK_EQ(rv, MOJO_RESULT_OK); 316 DCHECK_EQ(rv, MOJO_RESULT_OK);
331 DCHECK(!num_handles.IsNull()); 317 DCHECK(num_handles);
332 DCHECK_LE(dispatchers.size(), static_cast<size_t>(num_handles_value)); 318 DCHECK_LE(dispatchers.size(), static_cast<size_t>(num_handles_value));
333 319
334 bool success; 320 bool success;
335 UserPointer<MojoHandle>::Writer handles_writer(handles,
336 dispatchers.size());
337 { 321 {
338 MutexLocker locker(&handle_table_mutex_); 322 base::AutoLock locker(handle_table_lock_);
339 success = handle_table_.AddDispatcherVector( 323 success = handle_table_.AddDispatcherVector(dispatchers, handles);
340 dispatchers, handles_writer.GetPointer());
341 } 324 }
342 if (success) { 325 if (!success) {
343 handles_writer.Commit();
344 } else {
345 LOG(ERROR) << "Received message with " << dispatchers.size() 326 LOG(ERROR) << "Received message with " << dispatchers.size()
346 << " handles, but handle table full"; 327 << " handles, but handle table full";
347 // Close dispatchers (outside the lock). 328 // Close dispatchers (outside the lock).
348 for (size_t i = 0; i < dispatchers.size(); i++) { 329 for (size_t i = 0; i < dispatchers.size(); i++) {
349 if (dispatchers[i]) 330 if (dispatchers[i])
350 dispatchers[i]->Close(); 331 dispatchers[i]->Close();
351 } 332 }
352 if (rv == MOJO_RESULT_OK) 333 if (rv == MOJO_RESULT_OK)
353 rv = MOJO_RESULT_RESOURCE_EXHAUSTED; 334 rv = MOJO_RESULT_RESOURCE_EXHAUSTED;
354 } 335 }
355 } 336 }
356 } 337 }
357 338
358 if (!num_handles.IsNull()) 339 if (num_handles)
359 num_handles.Put(num_handles_value); 340 *num_handles = num_handles_value;
360 return rv; 341 return rv;
361 } 342 }
362 343
363 MojoResult Core::CreateDataPipe( 344 MojoResult Core::CreateDataPipe(
364 UserPointer<const MojoCreateDataPipeOptions> options, 345 const MojoCreateDataPipeOptions* options,
365 UserPointer<MojoHandle> data_pipe_producer_handle, 346 MojoHandle* data_pipe_producer_handle,
366 UserPointer<MojoHandle> data_pipe_consumer_handle) { 347 MojoHandle* data_pipe_consumer_handle) {
367 MojoCreateDataPipeOptions validated_options = {}; 348 MojoCreateDataPipeOptions validated_options = {};
368 MojoResult result = 349 MojoResult result =
369 DataPipe::ValidateCreateOptions(options, &validated_options); 350 DataPipe::ValidateCreateOptions(options, &validated_options);
370 if (result != MOJO_RESULT_OK) 351 if (result != MOJO_RESULT_OK)
371 return result; 352 return result;
372 353
373 scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher = 354 scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher =
374 DataPipeProducerDispatcher::Create(); 355 DataPipeProducerDispatcher::Create(validated_options);
375 scoped_refptr<DataPipeConsumerDispatcher> consumer_dispatcher = 356 scoped_refptr<DataPipeConsumerDispatcher> consumer_dispatcher =
376 DataPipeConsumerDispatcher::Create(); 357 DataPipeConsumerDispatcher::Create(validated_options);
377 358
378 std::pair<MojoHandle, MojoHandle> handle_pair; 359 std::pair<MojoHandle, MojoHandle> handle_pair;
379 { 360 {
380 MutexLocker locker(&handle_table_mutex_); 361 base::AutoLock locker(handle_table_lock_);
381 handle_pair = handle_table_.AddDispatcherPair(producer_dispatcher, 362 handle_pair = handle_table_.AddDispatcherPair(producer_dispatcher,
382 consumer_dispatcher); 363 consumer_dispatcher);
383 } 364 }
384 if (handle_pair.first == MOJO_HANDLE_INVALID) { 365 if (handle_pair.first == MOJO_HANDLE_INVALID) {
385 DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID); 366 DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID);
386 LOG(ERROR) << "Handle table full"; 367 LOG(ERROR) << "Handle table full";
387 producer_dispatcher->Close(); 368 producer_dispatcher->Close();
388 consumer_dispatcher->Close(); 369 consumer_dispatcher->Close();
389 return MOJO_RESULT_RESOURCE_EXHAUSTED; 370 return MOJO_RESULT_RESOURCE_EXHAUSTED;
390 } 371 }
391 DCHECK_NE(handle_pair.second, MOJO_HANDLE_INVALID); 372 DCHECK_NE(handle_pair.second, MOJO_HANDLE_INVALID);
392 373
393 scoped_refptr<DataPipe> data_pipe(DataPipe::CreateLocal(validated_options)); 374 PlatformChannelPair channel_pair;
394 producer_dispatcher->Init(data_pipe); 375 producer_dispatcher->Init(channel_pair.PassServerHandle());
395 consumer_dispatcher->Init(data_pipe); 376 consumer_dispatcher->Init(channel_pair.PassClientHandle());
396 377
397 data_pipe_producer_handle.Put(handle_pair.first); 378 *data_pipe_producer_handle = handle_pair.first;
398 data_pipe_consumer_handle.Put(handle_pair.second); 379 *data_pipe_consumer_handle = handle_pair.second;
399 return MOJO_RESULT_OK; 380 return MOJO_RESULT_OK;
400 } 381 }
401 382
402 MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle, 383 MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle,
403 UserPointer<const void> elements, 384 const void* elements,
404 UserPointer<uint32_t> num_bytes, 385 uint32_t* num_bytes,
405 MojoWriteDataFlags flags) { 386 MojoWriteDataFlags flags) {
406 scoped_refptr<Dispatcher> dispatcher( 387 scoped_refptr<Dispatcher> dispatcher(
407 GetDispatcher(data_pipe_producer_handle)); 388 GetDispatcher(data_pipe_producer_handle));
408 if (!dispatcher) 389 if (!dispatcher)
409 return MOJO_RESULT_INVALID_ARGUMENT; 390 return MOJO_RESULT_INVALID_ARGUMENT;
410 391
411 return dispatcher->WriteData(elements, num_bytes, flags); 392 return dispatcher->WriteData(elements, num_bytes, flags);
412 } 393 }
413 394
414 MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle, 395 MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle,
415 UserPointer<void*> buffer, 396 void** buffer,
416 UserPointer<uint32_t> buffer_num_bytes, 397 uint32_t* buffer_num_bytes,
417 MojoWriteDataFlags flags) { 398 MojoWriteDataFlags flags) {
418 scoped_refptr<Dispatcher> dispatcher( 399 scoped_refptr<Dispatcher> dispatcher(
419 GetDispatcher(data_pipe_producer_handle)); 400 GetDispatcher(data_pipe_producer_handle));
420 if (!dispatcher) 401 if (!dispatcher)
421 return MOJO_RESULT_INVALID_ARGUMENT; 402 return MOJO_RESULT_INVALID_ARGUMENT;
422 403
423 return dispatcher->BeginWriteData(buffer, buffer_num_bytes, flags); 404 return dispatcher->BeginWriteData(buffer, buffer_num_bytes, flags);
424 } 405 }
425 406
426 MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle, 407 MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle,
427 uint32_t num_bytes_written) { 408 uint32_t num_bytes_written) {
428 scoped_refptr<Dispatcher> dispatcher( 409 scoped_refptr<Dispatcher> dispatcher(
429 GetDispatcher(data_pipe_producer_handle)); 410 GetDispatcher(data_pipe_producer_handle));
430 if (!dispatcher) 411 if (!dispatcher)
431 return MOJO_RESULT_INVALID_ARGUMENT; 412 return MOJO_RESULT_INVALID_ARGUMENT;
432 413
433 return dispatcher->EndWriteData(num_bytes_written); 414 return dispatcher->EndWriteData(num_bytes_written);
434 } 415 }
435 416
436 MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle, 417 MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle,
437 UserPointer<void> elements, 418 void* elements,
438 UserPointer<uint32_t> num_bytes, 419 uint32_t* num_bytes,
439 MojoReadDataFlags flags) { 420 MojoReadDataFlags flags) {
440 scoped_refptr<Dispatcher> dispatcher( 421 scoped_refptr<Dispatcher> dispatcher(
441 GetDispatcher(data_pipe_consumer_handle)); 422 GetDispatcher(data_pipe_consumer_handle));
442 if (!dispatcher) 423 if (!dispatcher)
443 return MOJO_RESULT_INVALID_ARGUMENT; 424 return MOJO_RESULT_INVALID_ARGUMENT;
444 425
445 return dispatcher->ReadData(elements, num_bytes, flags); 426 return dispatcher->ReadData(elements, num_bytes, flags);
446 } 427 }
447 428
448 MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle, 429 MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle,
449 UserPointer<const void*> buffer, 430 const void** buffer,
450 UserPointer<uint32_t> buffer_num_bytes, 431 uint32_t* buffer_num_bytes,
451 MojoReadDataFlags flags) { 432 MojoReadDataFlags flags) {
452 scoped_refptr<Dispatcher> dispatcher( 433 scoped_refptr<Dispatcher> dispatcher(
453 GetDispatcher(data_pipe_consumer_handle)); 434 GetDispatcher(data_pipe_consumer_handle));
454 if (!dispatcher) 435 if (!dispatcher)
455 return MOJO_RESULT_INVALID_ARGUMENT; 436 return MOJO_RESULT_INVALID_ARGUMENT;
456 437
457 return dispatcher->BeginReadData(buffer, buffer_num_bytes, flags); 438 return dispatcher->BeginReadData(buffer, buffer_num_bytes, flags);
458 } 439 }
459 440
460 MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle, 441 MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle,
461 uint32_t num_bytes_read) { 442 uint32_t num_bytes_read) {
462 scoped_refptr<Dispatcher> dispatcher( 443 scoped_refptr<Dispatcher> dispatcher(
463 GetDispatcher(data_pipe_consumer_handle)); 444 GetDispatcher(data_pipe_consumer_handle));
464 if (!dispatcher) 445 if (!dispatcher)
465 return MOJO_RESULT_INVALID_ARGUMENT; 446 return MOJO_RESULT_INVALID_ARGUMENT;
466 447
467 return dispatcher->EndReadData(num_bytes_read); 448 return dispatcher->EndReadData(num_bytes_read);
468 } 449 }
469 450
470 MojoResult Core::CreateSharedBuffer( 451 MojoResult Core::CreateSharedBuffer(
471 UserPointer<const MojoCreateSharedBufferOptions> options, 452 const MojoCreateSharedBufferOptions* options,
472 uint64_t num_bytes, 453 uint64_t num_bytes,
473 UserPointer<MojoHandle> shared_buffer_handle) { 454 MojoHandle* shared_buffer_handle) {
474 MojoCreateSharedBufferOptions validated_options = {}; 455 MojoCreateSharedBufferOptions validated_options = {};
475 MojoResult result = SharedBufferDispatcher::ValidateCreateOptions( 456 MojoResult result = SharedBufferDispatcher::ValidateCreateOptions(
476 options, &validated_options); 457 options, &validated_options);
477 if (result != MOJO_RESULT_OK) 458 if (result != MOJO_RESULT_OK)
478 return result; 459 return result;
479 460
480 scoped_refptr<SharedBufferDispatcher> dispatcher; 461 scoped_refptr<SharedBufferDispatcher> dispatcher;
481 result = SharedBufferDispatcher::Create(platform_support_, validated_options, 462 result = SharedBufferDispatcher::Create(platform_support_, validated_options,
482 num_bytes, &dispatcher); 463 num_bytes, &dispatcher);
483 if (result != MOJO_RESULT_OK) { 464 if (result != MOJO_RESULT_OK) {
484 DCHECK(!dispatcher); 465 DCHECK(!dispatcher);
485 return result; 466 return result;
486 } 467 }
487 468
488 MojoHandle h = AddDispatcher(dispatcher); 469 *shared_buffer_handle = AddDispatcher(dispatcher);
489 if (h == MOJO_HANDLE_INVALID) { 470 if (*shared_buffer_handle == MOJO_HANDLE_INVALID) {
490 LOG(ERROR) << "Handle table full"; 471 LOG(ERROR) << "Handle table full";
491 dispatcher->Close(); 472 dispatcher->Close();
492 return MOJO_RESULT_RESOURCE_EXHAUSTED; 473 return MOJO_RESULT_RESOURCE_EXHAUSTED;
493 } 474 }
494 475
495 shared_buffer_handle.Put(h);
496 return MOJO_RESULT_OK; 476 return MOJO_RESULT_OK;
497 } 477 }
498 478
499 MojoResult Core::DuplicateBufferHandle( 479 MojoResult Core::DuplicateBufferHandle(
500 MojoHandle buffer_handle, 480 MojoHandle buffer_handle,
501 UserPointer<const MojoDuplicateBufferHandleOptions> options, 481 const MojoDuplicateBufferHandleOptions* options,
502 UserPointer<MojoHandle> new_buffer_handle) { 482 MojoHandle* new_buffer_handle) {
503 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); 483 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
504 if (!dispatcher) 484 if (!dispatcher)
505 return MOJO_RESULT_INVALID_ARGUMENT; 485 return MOJO_RESULT_INVALID_ARGUMENT;
506 486
507 // Don't verify |options| here; that's the dispatcher's job. 487 // Don't verify |options| here; that's the dispatcher's job.
508 scoped_refptr<Dispatcher> new_dispatcher; 488 scoped_refptr<Dispatcher> new_dispatcher;
509 MojoResult result = 489 MojoResult result =
510 dispatcher->DuplicateBufferHandle(options, &new_dispatcher); 490 dispatcher->DuplicateBufferHandle(options, &new_dispatcher);
511 if (result != MOJO_RESULT_OK) 491 if (result != MOJO_RESULT_OK)
512 return result; 492 return result;
513 493
514 MojoHandle new_handle = AddDispatcher(new_dispatcher); 494 *new_buffer_handle = AddDispatcher(new_dispatcher);
515 if (new_handle == MOJO_HANDLE_INVALID) { 495 if (*new_buffer_handle == MOJO_HANDLE_INVALID) {
516 LOG(ERROR) << "Handle table full"; 496 LOG(ERROR) << "Handle table full";
517 dispatcher->Close(); 497 dispatcher->Close();
518 return MOJO_RESULT_RESOURCE_EXHAUSTED; 498 return MOJO_RESULT_RESOURCE_EXHAUSTED;
519 } 499 }
520 500
521 new_buffer_handle.Put(new_handle);
522 return MOJO_RESULT_OK; 501 return MOJO_RESULT_OK;
523 } 502 }
524 503
525 MojoResult Core::MapBuffer(MojoHandle buffer_handle, 504 MojoResult Core::MapBuffer(MojoHandle buffer_handle,
526 uint64_t offset, 505 uint64_t offset,
527 uint64_t num_bytes, 506 uint64_t num_bytes,
528 UserPointer<void*> buffer, 507 void** buffer,
529 MojoMapBufferFlags flags) { 508 MojoMapBufferFlags flags) {
530 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); 509 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
531 if (!dispatcher) 510 if (!dispatcher)
532 return MOJO_RESULT_INVALID_ARGUMENT; 511 return MOJO_RESULT_INVALID_ARGUMENT;
533 512
534 scoped_ptr<embedder::PlatformSharedBufferMapping> mapping; 513 scoped_ptr<PlatformSharedBufferMapping> mapping;
535 MojoResult result = dispatcher->MapBuffer(offset, num_bytes, flags, &mapping); 514 MojoResult result = dispatcher->MapBuffer(offset, num_bytes, flags, &mapping);
536 if (result != MOJO_RESULT_OK) 515 if (result != MOJO_RESULT_OK)
537 return result; 516 return result;
538 517
539 DCHECK(mapping); 518 DCHECK(mapping);
540 void* address = mapping->GetBase(); 519 void* address = mapping->GetBase();
541 { 520 {
542 MutexLocker locker(&mapping_table_mutex_); 521 base::AutoLock locker(mapping_table_lock_);
543 result = mapping_table_.AddMapping(mapping.Pass()); 522 result = mapping_table_.AddMapping(mapping.Pass());
544 } 523 }
545 if (result != MOJO_RESULT_OK) 524 if (result != MOJO_RESULT_OK)
546 return result; 525 return result;
547 526
548 buffer.Put(address); 527 *buffer = address;
549 return MOJO_RESULT_OK; 528 return MOJO_RESULT_OK;
550 } 529 }
551 530
552 MojoResult Core::UnmapBuffer(UserPointer<void> buffer) { 531 MojoResult Core::UnmapBuffer(void* buffer) {
553 MutexLocker locker(&mapping_table_mutex_); 532 base::AutoLock locker(mapping_table_lock_);
554 return mapping_table_.RemoveMapping(buffer.GetPointerValue()); 533 return mapping_table_.RemoveMapping(buffer);
555 } 534 }
556 535
557 // Note: We allow |handles| to repeat the same handle multiple times, since 536 // Note: We allow |handles| to repeat the same handle multiple times, since
558 // different flags may be specified. 537 // different flags may be specified.
559 // TODO(vtl): This incurs a performance cost in |Remove()|. Analyze this 538 // TODO(vtl): This incurs a performance cost in |Remove()|. Analyze this
560 // more carefully and address it if necessary. 539 // more carefully and address it if necessary.
561 MojoResult Core::WaitManyInternal(const MojoHandle* handles, 540 MojoResult Core::WaitManyInternal(const MojoHandle* handles,
562 const MojoHandleSignals* signals, 541 const MojoHandleSignals* signals,
563 uint32_t num_handles, 542 uint32_t num_handles,
564 MojoDeadline deadline, 543 MojoDeadline deadline,
565 uint32_t* result_index, 544 uint32_t* result_index,
566 HandleSignalsState* signals_states) { 545 HandleSignalsState* signals_states) {
546 CHECK(handles);
547 CHECK(signals);
567 DCHECK_GT(num_handles, 0u); 548 DCHECK_GT(num_handles, 0u);
568 DCHECK_EQ(*result_index, static_cast<uint32_t>(-1)); 549 if (result_index) {
550 DCHECK_EQ(*result_index, static_cast<uint32_t>(-1));
551 }
569 552
570 DispatcherVector dispatchers; 553 DispatcherVector dispatchers;
571 dispatchers.reserve(num_handles); 554 dispatchers.reserve(num_handles);
572 for (uint32_t i = 0; i < num_handles; i++) { 555 for (uint32_t i = 0; i < num_handles; i++) {
573 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handles[i]); 556 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handles[i]);
574 if (!dispatcher) { 557 if (!dispatcher) {
575 *result_index = i; 558 if (result_index && result_index)
brucedawson 2015/10/05 16:50:26 The /analyze builder points out that this line of
559 *result_index = i;
576 return MOJO_RESULT_INVALID_ARGUMENT; 560 return MOJO_RESULT_INVALID_ARGUMENT;
577 } 561 }
578 dispatchers.push_back(dispatcher); 562 dispatchers.push_back(dispatcher);
579 } 563 }
580 564
581 // TODO(vtl): Should make the waiter live (permanently) in TLS. 565 // TODO(vtl): Should make the waiter live (permanently) in TLS.
582 Waiter waiter; 566 Waiter waiter;
583 waiter.Init(); 567 waiter.Init();
584 568
585 uint32_t i; 569 uint32_t i;
586 MojoResult rv = MOJO_RESULT_OK; 570 MojoResult rv = MOJO_RESULT_OK;
587 for (i = 0; i < num_handles; i++) { 571 for (i = 0; i < num_handles; i++) {
588 rv = dispatchers[i]->AddAwakable( 572 rv = dispatchers[i]->AddAwakable(
589 &waiter, signals[i], i, signals_states ? &signals_states[i] : nullptr); 573 &waiter, signals[i], i, signals_states ? &signals_states[i] : nullptr);
590 if (rv != MOJO_RESULT_OK) { 574 if (rv != MOJO_RESULT_OK) {
591 *result_index = i; 575 if (result_index)
576 *result_index = i;
592 break; 577 break;
593 } 578 }
594 } 579 }
595 uint32_t num_added = i; 580 uint32_t num_added = i;
596 581
597 if (rv == MOJO_RESULT_ALREADY_EXISTS) 582 if (rv == MOJO_RESULT_ALREADY_EXISTS)
598 rv = MOJO_RESULT_OK; // The i-th one is already "triggered". 583 rv = MOJO_RESULT_OK; // The i-th one is already "triggered".
599 else if (rv == MOJO_RESULT_OK) 584 else if (rv == MOJO_RESULT_OK)
600 rv = waiter.Wait(deadline, result_index); 585 rv = waiter.Wait(deadline, result_index);
601 586
602 // Make sure no other dispatchers try to wake |waiter| for the current 587 // Make sure no other dispatchers try to wake |waiter| for the current
603 // |Wait()|/|WaitMany()| call. (Only after doing this can |waiter| be 588 // |Wait()|/|WaitMany()| call. (Only after doing this can |waiter| be
604 // destroyed, but this would still be required if the waiter were in TLS.) 589 // destroyed, but this would still be required if the waiter were in TLS.)
605 for (i = 0; i < num_added; i++) { 590 for (i = 0; i < num_added; i++) {
606 dispatchers[i]->RemoveAwakable( 591 dispatchers[i]->RemoveAwakable(
607 &waiter, signals_states ? &signals_states[i] : nullptr); 592 &waiter, signals_states ? &signals_states[i] : nullptr);
608 } 593 }
609 if (signals_states) { 594 if (signals_states) {
610 for (; i < num_handles; i++) 595 for (; i < num_handles; i++)
611 signals_states[i] = dispatchers[i]->GetHandleSignalsState(); 596 signals_states[i] = dispatchers[i]->GetHandleSignalsState();
612 } 597 }
613 598
614 return rv; 599 return rv;
615 } 600 }
616 601
617 } // namespace system 602 } // namespace edk
618 } // namespace mojo 603 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698