• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "mojo/system/core.h"
6 
7 #include <vector>
8 
9 #include "base/logging.h"
10 #include "base/time/time.h"
11 #include "mojo/public/c/system/macros.h"
12 #include "mojo/system/constants.h"
13 #include "mojo/system/data_pipe.h"
14 #include "mojo/system/data_pipe_consumer_dispatcher.h"
15 #include "mojo/system/data_pipe_producer_dispatcher.h"
16 #include "mojo/system/dispatcher.h"
17 #include "mojo/system/local_data_pipe.h"
18 #include "mojo/system/memory.h"
19 #include "mojo/system/message_pipe.h"
20 #include "mojo/system/message_pipe_dispatcher.h"
21 #include "mojo/system/raw_shared_buffer.h"
22 #include "mojo/system/shared_buffer_dispatcher.h"
23 #include "mojo/system/waiter.h"
24 
25 namespace mojo {
26 namespace system {
27 
28 // Implementation notes
29 //
30 // Mojo primitives are implemented by the singleton |Core| object. Most calls
31 // are for a "primary" handle (the first argument). |Core::GetDispatcher()| is
32 // used to look up a |Dispatcher| object for a given handle. That object
33 // implements most primitives for that object. The wait primitives are not
34 // attached to objects and are implemented by |Core| itself.
35 //
36 // Some objects have multiple handles associated to them, e.g., message pipes
37 // (which have two). In such a case, there is still a |Dispatcher| (e.g.,
38 // |MessagePipeDispatcher|) for each handle, with each handle having a strong
39 // reference to the common "secondary" object (e.g., |MessagePipe|). This
40 // secondary object does NOT have any references to the |Dispatcher|s (even if
41 // it did, it wouldn't be able to do anything with them due to lock order
42 // requirements -- see below).
43 //
44 // Waiting is implemented by having the thread that wants to wait call the
45 // |Dispatcher|s for the handles that it wants to wait on with a |Waiter|
46 // object; this |Waiter| object may be created on the stack of that thread or be
47 // kept in thread local storage for that thread (TODO(vtl): future improvement).
48 // The |Dispatcher| then adds the |Waiter| to a |WaiterList| that's either owned
49 // by that |Dispatcher| (see |SimpleDispatcher|) or by a secondary object (e.g.,
50 // |MessagePipe|). To signal/wake a |Waiter|, the object in question -- either a
51 // |SimpleDispatcher| or a secondary object -- talks to its |WaiterList|.
52 
53 // Thread-safety notes
54 //
55 // Mojo primitives calls are thread-safe. We achieve this with relatively
56 // fine-grained locking. There is a global handle table lock. This lock should
57 // be held as briefly as possible (TODO(vtl): a future improvement would be to
58 // switch it to a reader-writer lock). Each |Dispatcher| object then has a lock
59 // (which subclasses can use to protect their data).
60 //
61 // The lock ordering is as follows:
62 //   1. global handle table lock, global mapping table lock
63 //   2. |Dispatcher| locks
64 //   3. secondary object locks
65 //   ...
66 //   INF. |Waiter| locks
67 //
68 // Notes:
69 //    - While holding a |Dispatcher| lock, you may not unconditionally attempt
70 //      to take another |Dispatcher| lock. (This has consequences on the
71 //      concurrency semantics of |MojoWriteMessage()| when passing handles.)
72 //      Doing so would lead to deadlock.
73 //    - Locks at the "INF" level may not have any locks taken while they are
74 //      held.
75 
Core()76 Core::Core() {
77 }
78 
~Core()79 Core::~Core() {
80 }
81 
AddDispatcher(const scoped_refptr<Dispatcher> & dispatcher)82 MojoHandle Core::AddDispatcher(
83     const scoped_refptr<Dispatcher>& dispatcher) {
84   base::AutoLock locker(handle_table_lock_);
85   return handle_table_.AddDispatcher(dispatcher);
86 }
87 
GetDispatcher(MojoHandle handle)88 scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) {
89   if (handle == MOJO_HANDLE_INVALID)
90     return NULL;
91 
92   base::AutoLock locker(handle_table_lock_);
93   return handle_table_.GetDispatcher(handle);
94 }
95 
GetTimeTicksNow()96 MojoTimeTicks Core::GetTimeTicksNow() {
97   return base::TimeTicks::Now().ToInternalValue();
98 }
99 
Close(MojoHandle handle)100 MojoResult Core::Close(MojoHandle handle) {
101   if (handle == MOJO_HANDLE_INVALID)
102     return MOJO_RESULT_INVALID_ARGUMENT;
103 
104   scoped_refptr<Dispatcher> dispatcher;
105   {
106     base::AutoLock locker(handle_table_lock_);
107     MojoResult result = handle_table_.GetAndRemoveDispatcher(handle,
108                                                              &dispatcher);
109     if (result != MOJO_RESULT_OK)
110       return result;
111   }
112 
113   // The dispatcher doesn't have a say in being closed, but gets notified of it.
114   // Note: This is done outside of |handle_table_lock_|. As a result, there's a
115   // race condition that the dispatcher must handle; see the comment in
116   // |Dispatcher| in dispatcher.h.
117   return dispatcher->Close();
118 }
119 
Wait(MojoHandle handle,MojoHandleSignals signals,MojoDeadline deadline)120 MojoResult Core::Wait(MojoHandle handle,
121                       MojoHandleSignals signals,
122                       MojoDeadline deadline) {
123   return WaitManyInternal(&handle, &signals, 1, deadline);
124 }
125 
WaitMany(const MojoHandle * handles,const MojoHandleSignals * signals,uint32_t num_handles,MojoDeadline deadline)126 MojoResult Core::WaitMany(const MojoHandle* handles,
127                           const MojoHandleSignals* signals,
128                           uint32_t num_handles,
129                           MojoDeadline deadline) {
130   if (!VerifyUserPointerWithCount<MojoHandle>(handles, num_handles))
131     return MOJO_RESULT_INVALID_ARGUMENT;
132   if (!VerifyUserPointerWithCount<MojoHandleSignals>(signals, num_handles))
133     return MOJO_RESULT_INVALID_ARGUMENT;
134   if (num_handles < 1)
135     return MOJO_RESULT_INVALID_ARGUMENT;
136   if (num_handles > kMaxWaitManyNumHandles)
137     return MOJO_RESULT_RESOURCE_EXHAUSTED;
138   return WaitManyInternal(handles, signals, num_handles, deadline);
139 }
140 
CreateMessagePipe(const MojoCreateMessagePipeOptions * options,MojoHandle * message_pipe_handle0,MojoHandle * message_pipe_handle1)141 MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
142                                    MojoHandle* message_pipe_handle0,
143                                    MojoHandle* message_pipe_handle1) {
144   MojoCreateMessagePipeOptions validated_options = {};
145   // This will verify the |options| pointer.
146   MojoResult result = MessagePipeDispatcher::ValidateCreateOptions(
147       options, &validated_options);
148   if (result != MOJO_RESULT_OK)
149     return result;
150   if (!VerifyUserPointer<MojoHandle>(message_pipe_handle0))
151     return MOJO_RESULT_INVALID_ARGUMENT;
152   if (!VerifyUserPointer<MojoHandle>(message_pipe_handle1))
153     return MOJO_RESULT_INVALID_ARGUMENT;
154 
155   scoped_refptr<MessagePipeDispatcher> dispatcher0(
156       new MessagePipeDispatcher(validated_options));
157   scoped_refptr<MessagePipeDispatcher> dispatcher1(
158       new MessagePipeDispatcher(validated_options));
159 
160   std::pair<MojoHandle, MojoHandle> handle_pair;
161   {
162     base::AutoLock locker(handle_table_lock_);
163     handle_pair = handle_table_.AddDispatcherPair(dispatcher0, dispatcher1);
164   }
165   if (handle_pair.first == MOJO_HANDLE_INVALID) {
166     DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID);
167     LOG(ERROR) << "Handle table full";
168     dispatcher0->Close();
169     dispatcher1->Close();
170     return MOJO_RESULT_RESOURCE_EXHAUSTED;
171   }
172 
173   scoped_refptr<MessagePipe> message_pipe(new MessagePipe());
174   dispatcher0->Init(message_pipe, 0);
175   dispatcher1->Init(message_pipe, 1);
176 
177   *message_pipe_handle0 = handle_pair.first;
178   *message_pipe_handle1 = handle_pair.second;
179   return MOJO_RESULT_OK;
180 }
181 
182 // Implementation note: To properly cancel waiters and avoid other races, this
183 // does not transfer dispatchers from one handle to another, even when sending a
184 // message in-process. Instead, it must transfer the "contents" of the
185 // dispatcher to a new dispatcher, and then close the old dispatcher. If this
186 // isn't done, in the in-process case, calls on the old handle may complete
187 // after the the message has been received and a new handle created (and
188 // possibly even after calls have been made on the new handle).
WriteMessage(MojoHandle message_pipe_handle,const void * bytes,uint32_t num_bytes,const MojoHandle * handles,uint32_t num_handles,MojoWriteMessageFlags flags)189 MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
190                               const void* bytes,
191                               uint32_t num_bytes,
192                               const MojoHandle* handles,
193                               uint32_t num_handles,
194                               MojoWriteMessageFlags flags) {
195   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle));
196   if (!dispatcher)
197     return MOJO_RESULT_INVALID_ARGUMENT;
198 
199   // Easy case: not sending any handles.
200   if (num_handles == 0)
201     return dispatcher->WriteMessage(bytes, num_bytes, NULL, flags);
202 
203   // We have to handle |handles| here, since we have to mark them busy in the
204   // global handle table. We can't delegate this to the dispatcher, since the
205   // handle table lock must be acquired before the dispatcher lock.
206   //
207   // (This leads to an oddity: |handles|/|num_handles| are always verified for
208   // validity, even for dispatchers that don't support |WriteMessage()| and will
209   // simply return failure unconditionally. It also breaks the usual
210   // left-to-right verification order of arguments.)
211   if (!VerifyUserPointerWithCount<MojoHandle>(handles, num_handles))
212     return MOJO_RESULT_INVALID_ARGUMENT;
213   if (num_handles > kMaxMessageNumHandles)
214     return MOJO_RESULT_RESOURCE_EXHAUSTED;
215 
216   // We'll need to hold on to the dispatchers so that we can pass them on to
217   // |WriteMessage()| and also so that we can unlock their locks afterwards
218   // without accessing the handle table. These can be dumb pointers, since their
219   // entries in the handle table won't get removed (since they'll be marked as
220   // busy).
221   std::vector<DispatcherTransport> transports(num_handles);
222 
223   // When we pass handles, we have to try to take all their dispatchers' locks
224   // and mark the handles as busy. If the call succeeds, we then remove the
225   // handles from the handle table.
226   {
227     base::AutoLock locker(handle_table_lock_);
228     MojoResult result = handle_table_.MarkBusyAndStartTransport(
229         message_pipe_handle, handles, num_handles, &transports);
230     if (result != MOJO_RESULT_OK)
231       return result;
232   }
233 
234   MojoResult rv = dispatcher->WriteMessage(bytes, num_bytes, &transports,
235                                            flags);
236 
237   // We need to release the dispatcher locks before we take the handle table
238   // lock.
239   for (uint32_t i = 0; i < num_handles; i++)
240     transports[i].End();
241 
242   {
243     base::AutoLock locker(handle_table_lock_);
244     if (rv == MOJO_RESULT_OK)
245       handle_table_.RemoveBusyHandles(handles, num_handles);
246     else
247       handle_table_.RestoreBusyHandles(handles, num_handles);
248   }
249 
250   return rv;
251 }
252 
ReadMessage(MojoHandle message_pipe_handle,void * bytes,uint32_t * num_bytes,MojoHandle * handles,uint32_t * num_handles,MojoReadMessageFlags flags)253 MojoResult Core::ReadMessage(MojoHandle message_pipe_handle,
254                              void* bytes,
255                              uint32_t* num_bytes,
256                              MojoHandle* handles,
257                              uint32_t* num_handles,
258                              MojoReadMessageFlags flags) {
259   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle));
260   if (!dispatcher)
261     return MOJO_RESULT_INVALID_ARGUMENT;
262 
263   if (num_handles) {
264     if (!VerifyUserPointer<uint32_t>(num_handles))
265       return MOJO_RESULT_INVALID_ARGUMENT;
266     if (!VerifyUserPointerWithCount<MojoHandle>(handles, *num_handles))
267       return MOJO_RESULT_INVALID_ARGUMENT;
268   }
269 
270   // Easy case: won't receive any handles.
271   if (!num_handles || *num_handles == 0)
272     return dispatcher->ReadMessage(bytes, num_bytes, NULL, num_handles, flags);
273 
274   DispatcherVector dispatchers;
275   MojoResult rv = dispatcher->ReadMessage(bytes, num_bytes,
276                                           &dispatchers, num_handles,
277                                           flags);
278   if (!dispatchers.empty()) {
279     DCHECK_EQ(rv, MOJO_RESULT_OK);
280     DCHECK(num_handles);
281     DCHECK_LE(dispatchers.size(), static_cast<size_t>(*num_handles));
282 
283     bool success;
284     {
285       base::AutoLock locker(handle_table_lock_);
286       success = handle_table_.AddDispatcherVector(dispatchers, handles);
287     }
288     if (!success) {
289       LOG(ERROR) << "Received message with " << dispatchers.size()
290                  << " handles, but handle table full";
291       // Close dispatchers (outside the lock).
292       for (size_t i = 0; i < dispatchers.size(); i++) {
293         if (dispatchers[i])
294           dispatchers[i]->Close();
295       }
296     }
297   }
298 
299   return rv;
300 }
301 
CreateDataPipe(const MojoCreateDataPipeOptions * options,MojoHandle * data_pipe_producer_handle,MojoHandle * data_pipe_consumer_handle)302 MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options,
303                                 MojoHandle* data_pipe_producer_handle,
304                                 MojoHandle* data_pipe_consumer_handle) {
305   MojoCreateDataPipeOptions validated_options = {};
306   // This will verify the |options| pointer.
307   MojoResult result = DataPipe::ValidateCreateOptions(options,
308                                                       &validated_options);
309   if (result != MOJO_RESULT_OK)
310     return result;
311   if (!VerifyUserPointer<MojoHandle>(data_pipe_producer_handle))
312     return MOJO_RESULT_INVALID_ARGUMENT;
313   if (!VerifyUserPointer<MojoHandle>(data_pipe_consumer_handle))
314     return MOJO_RESULT_INVALID_ARGUMENT;
315 
316   scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher(
317       new DataPipeProducerDispatcher());
318   scoped_refptr<DataPipeConsumerDispatcher> consumer_dispatcher(
319       new DataPipeConsumerDispatcher());
320 
321   std::pair<MojoHandle, MojoHandle> handle_pair;
322   {
323     base::AutoLock locker(handle_table_lock_);
324     handle_pair = handle_table_.AddDispatcherPair(producer_dispatcher,
325                                                   consumer_dispatcher);
326   }
327   if (handle_pair.first == MOJO_HANDLE_INVALID) {
328     DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID);
329     LOG(ERROR) << "Handle table full";
330     producer_dispatcher->Close();
331     consumer_dispatcher->Close();
332     return MOJO_RESULT_RESOURCE_EXHAUSTED;
333   }
334   DCHECK_NE(handle_pair.second, MOJO_HANDLE_INVALID);
335 
336   scoped_refptr<DataPipe> data_pipe(new LocalDataPipe(validated_options));
337   producer_dispatcher->Init(data_pipe);
338   consumer_dispatcher->Init(data_pipe);
339 
340   *data_pipe_producer_handle = handle_pair.first;
341   *data_pipe_consumer_handle = handle_pair.second;
342   return MOJO_RESULT_OK;
343 }
344 
WriteData(MojoHandle data_pipe_producer_handle,const void * elements,uint32_t * num_bytes,MojoWriteDataFlags flags)345 MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle,
346                            const void* elements,
347                            uint32_t* num_bytes,
348                            MojoWriteDataFlags flags) {
349   scoped_refptr<Dispatcher> dispatcher(
350       GetDispatcher(data_pipe_producer_handle));
351   if (!dispatcher)
352     return MOJO_RESULT_INVALID_ARGUMENT;
353 
354   return dispatcher->WriteData(elements, num_bytes, flags);
355 }
356 
BeginWriteData(MojoHandle data_pipe_producer_handle,void ** buffer,uint32_t * buffer_num_bytes,MojoWriteDataFlags flags)357 MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle,
358                                 void** buffer,
359                                 uint32_t* buffer_num_bytes,
360                                 MojoWriteDataFlags flags) {
361   scoped_refptr<Dispatcher> dispatcher(
362       GetDispatcher(data_pipe_producer_handle));
363   if (!dispatcher)
364     return MOJO_RESULT_INVALID_ARGUMENT;
365 
366   return dispatcher->BeginWriteData(buffer, buffer_num_bytes, flags);
367 }
368 
EndWriteData(MojoHandle data_pipe_producer_handle,uint32_t num_bytes_written)369 MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle,
370                               uint32_t num_bytes_written) {
371   scoped_refptr<Dispatcher> dispatcher(
372       GetDispatcher(data_pipe_producer_handle));
373   if (!dispatcher)
374     return MOJO_RESULT_INVALID_ARGUMENT;
375 
376   return dispatcher->EndWriteData(num_bytes_written);
377 }
378 
ReadData(MojoHandle data_pipe_consumer_handle,void * elements,uint32_t * num_bytes,MojoReadDataFlags flags)379 MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle,
380                           void* elements,
381                           uint32_t* num_bytes,
382                           MojoReadDataFlags flags) {
383   scoped_refptr<Dispatcher> dispatcher(
384       GetDispatcher(data_pipe_consumer_handle));
385   if (!dispatcher)
386     return MOJO_RESULT_INVALID_ARGUMENT;
387 
388   return dispatcher->ReadData(elements, num_bytes, flags);
389 }
390 
BeginReadData(MojoHandle data_pipe_consumer_handle,const void ** buffer,uint32_t * buffer_num_bytes,MojoReadDataFlags flags)391 MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle,
392                                const void** buffer,
393                                uint32_t* buffer_num_bytes,
394                                MojoReadDataFlags flags) {
395   scoped_refptr<Dispatcher> dispatcher(
396       GetDispatcher(data_pipe_consumer_handle));
397   if (!dispatcher)
398     return MOJO_RESULT_INVALID_ARGUMENT;
399 
400   return dispatcher->BeginReadData(buffer, buffer_num_bytes, flags);
401 }
402 
EndReadData(MojoHandle data_pipe_consumer_handle,uint32_t num_bytes_read)403 MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle,
404                              uint32_t num_bytes_read) {
405   scoped_refptr<Dispatcher> dispatcher(
406       GetDispatcher(data_pipe_consumer_handle));
407   if (!dispatcher)
408     return MOJO_RESULT_INVALID_ARGUMENT;
409 
410   return dispatcher->EndReadData(num_bytes_read);
411 }
412 
CreateSharedBuffer(const MojoCreateSharedBufferOptions * options,uint64_t num_bytes,MojoHandle * shared_buffer_handle)413 MojoResult Core::CreateSharedBuffer(
414     const MojoCreateSharedBufferOptions* options,
415     uint64_t num_bytes,
416     MojoHandle* shared_buffer_handle) {
417   MojoCreateSharedBufferOptions validated_options = {};
418   // This will verify the |options| pointer.
419   MojoResult result =
420       SharedBufferDispatcher::ValidateCreateOptions(options,
421                                                     &validated_options);
422   if (result != MOJO_RESULT_OK)
423     return result;
424   if (!VerifyUserPointer<MojoHandle>(shared_buffer_handle))
425     return MOJO_RESULT_INVALID_ARGUMENT;
426 
427   scoped_refptr<SharedBufferDispatcher> dispatcher;
428   result = SharedBufferDispatcher::Create(validated_options, num_bytes,
429                                           &dispatcher);
430   if (result != MOJO_RESULT_OK) {
431     DCHECK(!dispatcher);
432     return result;
433   }
434 
435   MojoHandle h = AddDispatcher(dispatcher);
436   if (h == MOJO_HANDLE_INVALID) {
437     LOG(ERROR) << "Handle table full";
438     dispatcher->Close();
439     return MOJO_RESULT_RESOURCE_EXHAUSTED;
440   }
441 
442   *shared_buffer_handle = h;
443   return MOJO_RESULT_OK;
444 }
445 
DuplicateBufferHandle(MojoHandle buffer_handle,const MojoDuplicateBufferHandleOptions * options,MojoHandle * new_buffer_handle)446 MojoResult Core::DuplicateBufferHandle(
447     MojoHandle buffer_handle,
448     const MojoDuplicateBufferHandleOptions* options,
449     MojoHandle* new_buffer_handle) {
450   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
451   if (!dispatcher)
452     return MOJO_RESULT_INVALID_ARGUMENT;
453 
454   // Don't verify |options| here; that's the dispatcher's job.
455   if (!VerifyUserPointer<MojoHandle>(new_buffer_handle))
456     return MOJO_RESULT_INVALID_ARGUMENT;
457 
458   scoped_refptr<Dispatcher> new_dispatcher;
459   MojoResult result = dispatcher->DuplicateBufferHandle(options,
460                                                         &new_dispatcher);
461   if (result != MOJO_RESULT_OK)
462     return result;
463 
464   MojoHandle new_handle = AddDispatcher(new_dispatcher);
465   if (new_handle == MOJO_HANDLE_INVALID) {
466     LOG(ERROR) << "Handle table full";
467     dispatcher->Close();
468     return MOJO_RESULT_RESOURCE_EXHAUSTED;
469   }
470 
471   *new_buffer_handle = new_handle;
472   return MOJO_RESULT_OK;
473 }
474 
MapBuffer(MojoHandle buffer_handle,uint64_t offset,uint64_t num_bytes,void ** buffer,MojoMapBufferFlags flags)475 MojoResult Core::MapBuffer(MojoHandle buffer_handle,
476                            uint64_t offset,
477                            uint64_t num_bytes,
478                            void** buffer,
479                            MojoMapBufferFlags flags) {
480   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
481   if (!dispatcher)
482     return MOJO_RESULT_INVALID_ARGUMENT;
483 
484   if (!VerifyUserPointerWithCount<void*>(buffer, 1))
485     return MOJO_RESULT_INVALID_ARGUMENT;
486 
487   scoped_ptr<RawSharedBufferMapping> mapping;
488   MojoResult result = dispatcher->MapBuffer(offset, num_bytes, flags, &mapping);
489   if (result != MOJO_RESULT_OK)
490     return result;
491 
492   DCHECK(mapping);
493   void* address = mapping->base();
494   {
495     base::AutoLock locker(mapping_table_lock_);
496     result = mapping_table_.AddMapping(mapping.Pass());
497   }
498   if (result != MOJO_RESULT_OK)
499     return result;
500 
501   *buffer = address;
502   return MOJO_RESULT_OK;
503 }
504 
UnmapBuffer(void * buffer)505 MojoResult Core::UnmapBuffer(void* buffer) {
506   base::AutoLock locker(mapping_table_lock_);
507   return mapping_table_.RemoveMapping(buffer);
508 }
509 
510 // Note: We allow |handles| to repeat the same handle multiple times, since
511 // different flags may be specified.
512 // TODO(vtl): This incurs a performance cost in |RemoveWaiter()|. Analyze this
513 // more carefully and address it if necessary.
WaitManyInternal(const MojoHandle * handles,const MojoHandleSignals * signals,uint32_t num_handles,MojoDeadline deadline)514 MojoResult Core::WaitManyInternal(const MojoHandle* handles,
515                                   const MojoHandleSignals* signals,
516                                   uint32_t num_handles,
517                                   MojoDeadline deadline) {
518   DCHECK_GT(num_handles, 0u);
519 
520   DispatcherVector dispatchers;
521   dispatchers.reserve(num_handles);
522   for (uint32_t i = 0; i < num_handles; i++) {
523     scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handles[i]);
524     if (!dispatcher)
525       return MOJO_RESULT_INVALID_ARGUMENT;
526     dispatchers.push_back(dispatcher);
527   }
528 
529   // TODO(vtl): Should make the waiter live (permanently) in TLS.
530   Waiter waiter;
531   waiter.Init();
532 
533   uint32_t i;
534   MojoResult rv = MOJO_RESULT_OK;
535   for (i = 0; i < num_handles; i++) {
536     rv = dispatchers[i]->AddWaiter(&waiter, signals[i], i);
537     if (rv != MOJO_RESULT_OK)
538       break;
539   }
540   uint32_t num_added = i;
541 
542   if (rv == MOJO_RESULT_ALREADY_EXISTS) {
543     rv = static_cast<MojoResult>(i);  // The i-th one is already "triggered".
544   } else if (rv == MOJO_RESULT_OK) {
545     uint32_t context = static_cast<uint32_t>(-1);
546     rv = waiter.Wait(deadline, &context);
547     if (rv == MOJO_RESULT_OK)
548       rv = static_cast<MojoResult>(context);
549   }
550 
551   // Make sure no other dispatchers try to wake |waiter| for the current
552   // |Wait()|/|WaitMany()| call. (Only after doing this can |waiter| be
553   // destroyed, but this would still be required if the waiter were in TLS.)
554   for (i = 0; i < num_added; i++)
555     dispatchers[i]->RemoveWaiter(&waiter);
556 
557   return rv;
558 }
559 
560 }  // namespace system
561 }  // namespace mojo
562