Home | History | Annotate | Download | only in system
      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/edk/system/core.h"
      6 
      7 #include <string.h>
      8 
      9 #include <utility>
     10 
     11 #include "base/bind.h"
     12 #include "base/containers/stack_container.h"
     13 #include "base/location.h"
     14 #include "base/logging.h"
     15 #include "base/macros.h"
     16 #include "base/memory/ptr_util.h"
     17 #include "base/message_loop/message_loop.h"
     18 #include "base/rand_util.h"
     19 #include "base/threading/thread_task_runner_handle.h"
     20 #include "base/time/time.h"
     21 #include "mojo/edk/embedder/embedder.h"
     22 #include "mojo/edk/embedder/embedder_internal.h"
     23 #include "mojo/edk/embedder/platform_shared_buffer.h"
     24 #include "mojo/edk/system/channel.h"
     25 #include "mojo/edk/system/configuration.h"
     26 #include "mojo/edk/system/data_pipe_consumer_dispatcher.h"
     27 #include "mojo/edk/system/data_pipe_producer_dispatcher.h"
     28 #include "mojo/edk/system/handle_signals_state.h"
     29 #include "mojo/edk/system/message_for_transit.h"
     30 #include "mojo/edk/system/message_pipe_dispatcher.h"
     31 #include "mojo/edk/system/platform_handle_dispatcher.h"
     32 #include "mojo/edk/system/ports/name.h"
     33 #include "mojo/edk/system/ports/node.h"
     34 #include "mojo/edk/system/request_context.h"
     35 #include "mojo/edk/system/shared_buffer_dispatcher.h"
     36 #include "mojo/edk/system/wait_set_dispatcher.h"
     37 #include "mojo/edk/system/waiter.h"
     38 
     39 namespace mojo {
     40 namespace edk {
     41 
     42 namespace {
     43 
     44 // This is an unnecessarily large limit that is relatively easy to enforce.
     45 const uint32_t kMaxHandlesPerMessage = 1024 * 1024;
     46 
     47 // TODO(rockot): Maybe we could negotiate a debugging pipe ID for cross-process
     48 // pipes too; for now we just use a constant. This only affects bootstrap pipes.
     49 const uint64_t kUnknownPipeIdForDebug = 0x7f7f7f7f7f7f7f7fUL;
     50 
     51 void CallWatchCallback(MojoWatchCallback callback,
     52                        uintptr_t context,
     53                        MojoResult result,
     54                        const HandleSignalsState& signals_state,
     55                        MojoWatchNotificationFlags flags) {
     56   callback(context, result, static_cast<MojoHandleSignalsState>(signals_state),
     57       flags);
     58 }
     59 
     60 MojoResult MojoPlatformHandleToScopedPlatformHandle(
     61     const MojoPlatformHandle* platform_handle,
     62     ScopedPlatformHandle* out_handle) {
     63   if (platform_handle->struct_size != sizeof(MojoPlatformHandle))
     64     return MOJO_RESULT_INVALID_ARGUMENT;
     65 
     66   if (platform_handle->type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) {
     67     out_handle->reset();
     68     return MOJO_RESULT_OK;
     69   }
     70 
     71   PlatformHandle handle;
     72   switch (platform_handle->type) {
     73 #if defined(OS_POSIX)
     74     case MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR:
     75       handle.handle = static_cast<int>(platform_handle->value);
     76       break;
     77 #endif
     78 
     79 #if defined(OS_MACOSX) && !defined(OS_IOS)
     80     case MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT:
     81       handle.type = PlatformHandle::Type::MACH;
     82       handle.port = static_cast<mach_port_t>(platform_handle->value);
     83       break;
     84 #endif
     85 
     86 #if defined(OS_WIN)
     87     case MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE:
     88       handle.handle = reinterpret_cast<HANDLE>(platform_handle->value);
     89       break;
     90 #endif
     91 
     92     default:
     93       return MOJO_RESULT_INVALID_ARGUMENT;
     94   }
     95 
     96   out_handle->reset(handle);
     97   return MOJO_RESULT_OK;
     98 }
     99 
    100 MojoResult ScopedPlatformHandleToMojoPlatformHandle(
    101     ScopedPlatformHandle handle,
    102     MojoPlatformHandle* platform_handle) {
    103   if (platform_handle->struct_size != sizeof(MojoPlatformHandle))
    104     return MOJO_RESULT_INVALID_ARGUMENT;
    105 
    106   if (!handle.is_valid()) {
    107     platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_INVALID;
    108     return MOJO_RESULT_OK;
    109   }
    110 
    111 #if defined(OS_POSIX)
    112   switch (handle.get().type) {
    113     case PlatformHandle::Type::POSIX:
    114       platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
    115       platform_handle->value = static_cast<uint64_t>(handle.release().handle);
    116       break;
    117 
    118 #if defined(OS_MACOSX) && !defined(OS_IOS)
    119     case PlatformHandle::Type::MACH:
    120       platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT;
    121       platform_handle->value = static_cast<uint64_t>(handle.release().port);
    122       break;
    123 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    124 
    125     default:
    126       return MOJO_RESULT_INVALID_ARGUMENT;
    127   }
    128 #elif defined(OS_WIN)
    129   platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE;
    130   platform_handle->value = reinterpret_cast<uint64_t>(handle.release().handle);
    131 #endif  // defined(OS_WIN)
    132 
    133   return MOJO_RESULT_OK;
    134 }
    135 
    136 }  // namespace
    137 
    138 Core::Core() {}
    139 
    140 Core::~Core() {
    141   if (node_controller_ && node_controller_->io_task_runner()) {
    142     // If this races with IO thread shutdown the callback will be dropped and
    143     // the NodeController will be shutdown on this thread anyway, which is also
    144     // just fine.
    145     scoped_refptr<base::TaskRunner> io_task_runner =
    146         node_controller_->io_task_runner();
    147     io_task_runner->PostTask(FROM_HERE,
    148                              base::Bind(&Core::PassNodeControllerToIOThread,
    149                                         base::Passed(&node_controller_)));
    150   }
    151 }
    152 
    153 void Core::SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner) {
    154   GetNodeController()->SetIOTaskRunner(io_task_runner);
    155 }
    156 
    157 NodeController* Core::GetNodeController() {
    158   base::AutoLock lock(node_controller_lock_);
    159   if (!node_controller_)
    160     node_controller_.reset(new NodeController(this));
    161   return node_controller_.get();
    162 }
    163 
    164 scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) {
    165   base::AutoLock lock(handles_lock_);
    166   return handles_.GetDispatcher(handle);
    167 }
    168 
    169 void Core::SetDefaultProcessErrorCallback(
    170     const ProcessErrorCallback& callback) {
    171   default_process_error_callback_ = callback;
    172 }
    173 
    174 void Core::AddChild(base::ProcessHandle process_handle,
    175                     ConnectionParams connection_params,
    176                     const std::string& child_token,
    177                     const ProcessErrorCallback& process_error_callback) {
    178   GetNodeController()->ConnectToChild(process_handle,
    179                                       std::move(connection_params), child_token,
    180                                       process_error_callback);
    181 }
    182 
    183 void Core::ChildLaunchFailed(const std::string& child_token) {
    184   RequestContext request_context;
    185   GetNodeController()->CloseChildPorts(child_token);
    186 }
    187 
    188 ScopedMessagePipeHandle Core::ConnectToPeerProcess(
    189     ScopedPlatformHandle pipe_handle,
    190     const std::string& peer_token) {
    191   RequestContext request_context;
    192   ports::PortRef port0, port1;
    193   GetNodeController()->node()->CreatePortPair(&port0, &port1);
    194   MojoHandle handle = AddDispatcher(new MessagePipeDispatcher(
    195       GetNodeController(), port0, kUnknownPipeIdForDebug, 0));
    196   ConnectionParams connection_params(std::move(pipe_handle));
    197   GetNodeController()->ConnectToPeer(std::move(connection_params), port1,
    198                                      peer_token);
    199   return ScopedMessagePipeHandle(MessagePipeHandle(handle));
    200 }
    201 
    202 void Core::ClosePeerConnection(const std::string& peer_token) {
    203   GetNodeController()->ClosePeerConnection(peer_token);
    204 }
    205 
    206 void Core::InitChild(ConnectionParams connection_params) {
    207   GetNodeController()->ConnectToParent(std::move(connection_params));
    208 }
    209 
    210 void Core::SetMachPortProvider(base::PortProvider* port_provider) {
    211 #if defined(OS_MACOSX) && !defined(OS_IOS)
    212   GetNodeController()->CreateMachPortRelay(port_provider);
    213 #endif
    214 }
    215 
    216 MojoHandle Core::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
    217   base::AutoLock lock(handles_lock_);
    218   return handles_.AddDispatcher(dispatcher);
    219 }
    220 
    221 bool Core::AddDispatchersFromTransit(
    222     const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
    223     MojoHandle* handles) {
    224   bool failed = false;
    225   {
    226     base::AutoLock lock(handles_lock_);
    227     if (!handles_.AddDispatchersFromTransit(dispatchers, handles))
    228       failed = true;
    229   }
    230   if (failed) {
    231     for (auto d : dispatchers)
    232       d.dispatcher->Close();
    233     return false;
    234   }
    235   return true;
    236 }
    237 
    238 MojoResult Core::CreatePlatformHandleWrapper(
    239     ScopedPlatformHandle platform_handle,
    240     MojoHandle* wrapper_handle) {
    241   MojoHandle h = AddDispatcher(
    242       PlatformHandleDispatcher::Create(std::move(platform_handle)));
    243   if (h == MOJO_HANDLE_INVALID)
    244     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    245   *wrapper_handle = h;
    246   return MOJO_RESULT_OK;
    247 }
    248 
    249 MojoResult Core::PassWrappedPlatformHandle(
    250     MojoHandle wrapper_handle,
    251     ScopedPlatformHandle* platform_handle) {
    252   base::AutoLock lock(handles_lock_);
    253   scoped_refptr<Dispatcher> d;
    254   MojoResult result = handles_.GetAndRemoveDispatcher(wrapper_handle, &d);
    255   if (result != MOJO_RESULT_OK)
    256     return result;
    257   if (d->GetType() == Dispatcher::Type::PLATFORM_HANDLE) {
    258     PlatformHandleDispatcher* phd =
    259         static_cast<PlatformHandleDispatcher*>(d.get());
    260     *platform_handle = phd->PassPlatformHandle();
    261   } else {
    262     result = MOJO_RESULT_INVALID_ARGUMENT;
    263   }
    264   d->Close();
    265   return result;
    266 }
    267 
    268 MojoResult Core::CreateSharedBufferWrapper(
    269     base::SharedMemoryHandle shared_memory_handle,
    270     size_t num_bytes,
    271     bool read_only,
    272     MojoHandle* mojo_wrapper_handle) {
    273   DCHECK(num_bytes);
    274   scoped_refptr<PlatformSharedBuffer> platform_buffer =
    275       PlatformSharedBuffer::CreateFromSharedMemoryHandle(num_bytes, read_only,
    276                                                          shared_memory_handle);
    277   if (!platform_buffer)
    278     return MOJO_RESULT_UNKNOWN;
    279 
    280   scoped_refptr<SharedBufferDispatcher> dispatcher;
    281   MojoResult result = SharedBufferDispatcher::CreateFromPlatformSharedBuffer(
    282       platform_buffer, &dispatcher);
    283   if (result != MOJO_RESULT_OK)
    284     return result;
    285   MojoHandle h = AddDispatcher(dispatcher);
    286   if (h == MOJO_HANDLE_INVALID)
    287     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    288   *mojo_wrapper_handle = h;
    289   return MOJO_RESULT_OK;
    290 }
    291 
    292 MojoResult Core::PassSharedMemoryHandle(
    293     MojoHandle mojo_handle,
    294     base::SharedMemoryHandle* shared_memory_handle,
    295     size_t* num_bytes,
    296     bool* read_only) {
    297   if (!shared_memory_handle)
    298     return MOJO_RESULT_INVALID_ARGUMENT;
    299 
    300   scoped_refptr<Dispatcher> dispatcher;
    301   MojoResult result = MOJO_RESULT_OK;
    302   {
    303     base::AutoLock lock(handles_lock_);
    304     // Get the dispatcher and check it before removing it from the handle table
    305     // to ensure that the dispatcher is of the correct type. This ensures we
    306     // don't close and remove the wrong type of dispatcher.
    307     dispatcher = handles_.GetDispatcher(mojo_handle);
    308     if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER)
    309       return MOJO_RESULT_INVALID_ARGUMENT;
    310 
    311     result = handles_.GetAndRemoveDispatcher(mojo_handle, &dispatcher);
    312     if (result != MOJO_RESULT_OK)
    313       return result;
    314   }
    315 
    316   SharedBufferDispatcher* shm_dispatcher =
    317       static_cast<SharedBufferDispatcher*>(dispatcher.get());
    318   scoped_refptr<PlatformSharedBuffer> platform_shared_buffer =
    319       shm_dispatcher->PassPlatformSharedBuffer();
    320 
    321   if (!platform_shared_buffer)
    322     return MOJO_RESULT_INVALID_ARGUMENT;
    323 
    324   if (num_bytes)
    325     *num_bytes = platform_shared_buffer->GetNumBytes();
    326   if (read_only)
    327     *read_only = platform_shared_buffer->IsReadOnly();
    328   *shared_memory_handle = platform_shared_buffer->DuplicateSharedMemoryHandle();
    329 
    330   shm_dispatcher->Close();
    331   return result;
    332 }
    333 
    334 void Core::RequestShutdown(const base::Closure& callback) {
    335   GetNodeController()->RequestShutdown(callback);
    336 }
    337 
    338 ScopedMessagePipeHandle Core::CreateParentMessagePipe(
    339     const std::string& token, const std::string& child_token) {
    340   RequestContext request_context;
    341   ports::PortRef port0, port1;
    342   GetNodeController()->node()->CreatePortPair(&port0, &port1);
    343   MojoHandle handle = AddDispatcher(
    344       new MessagePipeDispatcher(GetNodeController(), port0,
    345                                 kUnknownPipeIdForDebug, 0));
    346   GetNodeController()->ReservePort(token, port1, child_token);
    347   return ScopedMessagePipeHandle(MessagePipeHandle(handle));
    348 }
    349 
    350 ScopedMessagePipeHandle Core::CreateChildMessagePipe(const std::string& token) {
    351   RequestContext request_context;
    352   ports::PortRef port0, port1;
    353   GetNodeController()->node()->CreatePortPair(&port0, &port1);
    354   MojoHandle handle = AddDispatcher(
    355       new MessagePipeDispatcher(GetNodeController(), port0,
    356                                 kUnknownPipeIdForDebug, 1));
    357   GetNodeController()->MergePortIntoParent(token, port1);
    358   return ScopedMessagePipeHandle(MessagePipeHandle(handle));
    359 }
    360 
    361 MojoResult Core::SetProperty(MojoPropertyType type, const void* value) {
    362   base::AutoLock locker(property_lock_);
    363   switch (type) {
    364     case MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED:
    365       property_sync_call_allowed_ = *static_cast<const bool*>(value);
    366       return MOJO_RESULT_OK;
    367     default:
    368       return MOJO_RESULT_INVALID_ARGUMENT;
    369   }
    370 }
    371 
    372 MojoTimeTicks Core::GetTimeTicksNow() {
    373   return base::TimeTicks::Now().ToInternalValue();
    374 }
    375 
    376 MojoResult Core::Close(MojoHandle handle) {
    377   RequestContext request_context;
    378   scoped_refptr<Dispatcher> dispatcher;
    379   {
    380     base::AutoLock lock(handles_lock_);
    381     MojoResult rv = handles_.GetAndRemoveDispatcher(handle, &dispatcher);
    382     if (rv != MOJO_RESULT_OK)
    383       return rv;
    384   }
    385   dispatcher->Close();
    386   return MOJO_RESULT_OK;
    387 }
    388 
    389 MojoResult Core::Wait(MojoHandle handle,
    390                       MojoHandleSignals signals,
    391                       MojoDeadline deadline,
    392                       MojoHandleSignalsState* signals_state) {
    393   RequestContext request_context;
    394   uint32_t unused = static_cast<uint32_t>(-1);
    395   HandleSignalsState hss;
    396   MojoResult rv = WaitManyInternal(&handle, &signals, 1, deadline, &unused,
    397                                    signals_state ? &hss : nullptr);
    398   if (rv != MOJO_RESULT_INVALID_ARGUMENT && signals_state)
    399     *signals_state = hss;
    400   return rv;
    401 }
    402 
    403 MojoResult Core::WaitMany(const MojoHandle* handles,
    404                           const MojoHandleSignals* signals,
    405                           uint32_t num_handles,
    406                           MojoDeadline deadline,
    407                           uint32_t* result_index,
    408                           MojoHandleSignalsState* signals_state) {
    409   RequestContext request_context;
    410   if (num_handles < 1)
    411     return MOJO_RESULT_INVALID_ARGUMENT;
    412   if (num_handles > GetConfiguration().max_wait_many_num_handles)
    413     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    414 
    415   uint32_t index = static_cast<uint32_t>(-1);
    416   MojoResult rv;
    417   if (!signals_state) {
    418     rv = WaitManyInternal(handles, signals, num_handles, deadline, &index,
    419                           nullptr);
    420   } else {
    421     // Note: The |reinterpret_cast| is safe, since |HandleSignalsState| is a
    422     // subclass of |MojoHandleSignalsState| that doesn't add any data members.
    423     rv = WaitManyInternal(handles, signals, num_handles, deadline, &index,
    424                           reinterpret_cast<HandleSignalsState*>(signals_state));
    425   }
    426   if (index != static_cast<uint32_t>(-1) && result_index)
    427     *result_index = index;
    428   return rv;
    429 }
    430 
    431 MojoResult Core::Watch(MojoHandle handle,
    432                        MojoHandleSignals signals,
    433                        MojoWatchCallback callback,
    434                        uintptr_t context) {
    435   RequestContext request_context;
    436   scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle);
    437   if (!dispatcher)
    438     return MOJO_RESULT_INVALID_ARGUMENT;
    439   return dispatcher->Watch(
    440       signals, base::Bind(&CallWatchCallback, callback, context), context);
    441 }
    442 
    443 MojoResult Core::CancelWatch(MojoHandle handle, uintptr_t context) {
    444   RequestContext request_context;
    445   scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle);
    446   if (!dispatcher)
    447     return MOJO_RESULT_INVALID_ARGUMENT;
    448   return dispatcher->CancelWatch(context);
    449 }
    450 
    451 MojoResult Core::AllocMessage(uint32_t num_bytes,
    452                               const MojoHandle* handles,
    453                               uint32_t num_handles,
    454                               MojoAllocMessageFlags flags,
    455                               MojoMessageHandle* message) {
    456   if (!message)
    457     return MOJO_RESULT_INVALID_ARGUMENT;
    458 
    459   if (num_handles == 0) {  // Fast path: no handles.
    460     std::unique_ptr<MessageForTransit> msg;
    461     MojoResult rv = MessageForTransit::Create(&msg, num_bytes, nullptr, 0);
    462     if (rv != MOJO_RESULT_OK)
    463       return rv;
    464 
    465     *message = reinterpret_cast<MojoMessageHandle>(msg.release());
    466     return MOJO_RESULT_OK;
    467   }
    468 
    469   if (!handles)
    470     return MOJO_RESULT_INVALID_ARGUMENT;
    471 
    472   if (num_handles > kMaxHandlesPerMessage)
    473     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    474 
    475   std::vector<Dispatcher::DispatcherInTransit> dispatchers;
    476   {
    477     base::AutoLock lock(handles_lock_);
    478     MojoResult rv = handles_.BeginTransit(handles, num_handles, &dispatchers);
    479     if (rv != MOJO_RESULT_OK) {
    480       handles_.CancelTransit(dispatchers);
    481       return rv;
    482     }
    483   }
    484   DCHECK_EQ(num_handles, dispatchers.size());
    485 
    486   std::unique_ptr<MessageForTransit> msg;
    487   MojoResult rv = MessageForTransit::Create(
    488       &msg, num_bytes, dispatchers.data(), num_handles);
    489 
    490   {
    491     base::AutoLock lock(handles_lock_);
    492     if (rv == MOJO_RESULT_OK) {
    493       handles_.CompleteTransitAndClose(dispatchers);
    494       *message = reinterpret_cast<MojoMessageHandle>(msg.release());
    495     } else {
    496       handles_.CancelTransit(dispatchers);
    497     }
    498   }
    499 
    500   return rv;
    501 }
    502 
    503 MojoResult Core::FreeMessage(MojoMessageHandle message) {
    504   if (!message)
    505     return MOJO_RESULT_INVALID_ARGUMENT;
    506 
    507   delete reinterpret_cast<MessageForTransit*>(message);
    508 
    509   return MOJO_RESULT_OK;
    510 }
    511 
    512 MojoResult Core::GetMessageBuffer(MojoMessageHandle message, void** buffer) {
    513   if (!message)
    514     return MOJO_RESULT_INVALID_ARGUMENT;
    515 
    516   *buffer = reinterpret_cast<MessageForTransit*>(message)->mutable_bytes();
    517 
    518   return MOJO_RESULT_OK;
    519 }
    520 
    521 MojoResult Core::GetProperty(MojoPropertyType type, void* value) {
    522   base::AutoLock locker(property_lock_);
    523   switch (type) {
    524     case MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED:
    525       *static_cast<bool*>(value) = property_sync_call_allowed_;
    526       return MOJO_RESULT_OK;
    527     default:
    528       return MOJO_RESULT_INVALID_ARGUMENT;
    529   }
    530 }
    531 
    532 MojoResult Core::CreateWaitSet(MojoHandle* wait_set_handle) {
    533   RequestContext request_context;
    534   if (!wait_set_handle)
    535     return MOJO_RESULT_INVALID_ARGUMENT;
    536 
    537   scoped_refptr<WaitSetDispatcher> dispatcher = new WaitSetDispatcher();
    538   MojoHandle h = AddDispatcher(dispatcher);
    539   if (h == MOJO_HANDLE_INVALID) {
    540     LOG(ERROR) << "Handle table full";
    541     dispatcher->Close();
    542     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    543   }
    544 
    545   *wait_set_handle = h;
    546   return MOJO_RESULT_OK;
    547 }
    548 
    549 MojoResult Core::AddHandle(MojoHandle wait_set_handle,
    550                            MojoHandle handle,
    551                            MojoHandleSignals signals) {
    552   RequestContext request_context;
    553   scoped_refptr<Dispatcher> wait_set_dispatcher(GetDispatcher(wait_set_handle));
    554   if (!wait_set_dispatcher)
    555     return MOJO_RESULT_INVALID_ARGUMENT;
    556 
    557   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(handle));
    558   if (!dispatcher)
    559     return MOJO_RESULT_INVALID_ARGUMENT;
    560 
    561   return wait_set_dispatcher->AddWaitingDispatcher(dispatcher, signals, handle);
    562 }
    563 
    564 MojoResult Core::RemoveHandle(MojoHandle wait_set_handle,
    565                               MojoHandle handle) {
    566   RequestContext request_context;
    567   scoped_refptr<Dispatcher> wait_set_dispatcher(GetDispatcher(wait_set_handle));
    568   if (!wait_set_dispatcher)
    569     return MOJO_RESULT_INVALID_ARGUMENT;
    570 
    571   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(handle));
    572   if (!dispatcher)
    573     return MOJO_RESULT_INVALID_ARGUMENT;
    574 
    575   return wait_set_dispatcher->RemoveWaitingDispatcher(dispatcher);
    576 }
    577 
    578 MojoResult Core::GetReadyHandles(MojoHandle wait_set_handle,
    579                                  uint32_t* count,
    580                                  MojoHandle* handles,
    581                                  MojoResult* results,
    582                                  MojoHandleSignalsState* signals_states) {
    583   RequestContext request_context;
    584   if (!handles || !count || !(*count) || !results)
    585     return MOJO_RESULT_INVALID_ARGUMENT;
    586 
    587   scoped_refptr<Dispatcher> wait_set_dispatcher(GetDispatcher(wait_set_handle));
    588   if (!wait_set_dispatcher)
    589     return MOJO_RESULT_INVALID_ARGUMENT;
    590 
    591   DispatcherVector awoken_dispatchers;
    592   base::StackVector<uintptr_t, 16> contexts;
    593   contexts->assign(*count, MOJO_HANDLE_INVALID);
    594 
    595   MojoResult result = wait_set_dispatcher->GetReadyDispatchers(
    596       count, &awoken_dispatchers, results, contexts->data());
    597 
    598   if (result == MOJO_RESULT_OK) {
    599     for (size_t i = 0; i < *count; i++) {
    600       handles[i] = static_cast<MojoHandle>(contexts[i]);
    601       if (signals_states)
    602         signals_states[i] = awoken_dispatchers[i]->GetHandleSignalsState();
    603     }
    604   }
    605 
    606   return result;
    607 }
    608 
    609 MojoResult Core::CreateMessagePipe(
    610     const MojoCreateMessagePipeOptions* options,
    611     MojoHandle* message_pipe_handle0,
    612     MojoHandle* message_pipe_handle1) {
    613   RequestContext request_context;
    614   ports::PortRef port0, port1;
    615   GetNodeController()->node()->CreatePortPair(&port0, &port1);
    616 
    617   CHECK(message_pipe_handle0);
    618   CHECK(message_pipe_handle1);
    619 
    620   uint64_t pipe_id = base::RandUint64();
    621 
    622   *message_pipe_handle0 = AddDispatcher(
    623       new MessagePipeDispatcher(GetNodeController(), port0, pipe_id, 0));
    624   if (*message_pipe_handle0 == MOJO_HANDLE_INVALID)
    625     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    626 
    627   *message_pipe_handle1 = AddDispatcher(
    628       new MessagePipeDispatcher(GetNodeController(), port1, pipe_id, 1));
    629   if (*message_pipe_handle1 == MOJO_HANDLE_INVALID) {
    630     scoped_refptr<Dispatcher> unused;
    631     unused->Close();
    632 
    633     base::AutoLock lock(handles_lock_);
    634     handles_.GetAndRemoveDispatcher(*message_pipe_handle0, &unused);
    635     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    636   }
    637 
    638   return MOJO_RESULT_OK;
    639 }
    640 
    641 MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
    642                               const void* bytes,
    643                               uint32_t num_bytes,
    644                               const MojoHandle* handles,
    645                               uint32_t num_handles,
    646                               MojoWriteMessageFlags flags) {
    647   if (num_bytes && !bytes)
    648     return MOJO_RESULT_INVALID_ARGUMENT;
    649 
    650   MojoMessageHandle message;
    651   MojoResult rv = AllocMessage(num_bytes, handles, num_handles,
    652                                MOJO_ALLOC_MESSAGE_FLAG_NONE, &message);
    653   if (rv != MOJO_RESULT_OK)
    654     return rv;
    655 
    656   if (num_bytes) {
    657     void* buffer = nullptr;
    658     rv = GetMessageBuffer(message, &buffer);
    659     DCHECK_EQ(rv, MOJO_RESULT_OK);
    660     memcpy(buffer, bytes, num_bytes);
    661   }
    662 
    663   return WriteMessageNew(message_pipe_handle, message, flags);
    664 }
    665 
    666 MojoResult Core::WriteMessageNew(MojoHandle message_pipe_handle,
    667                                  MojoMessageHandle message,
    668                                  MojoWriteMessageFlags flags) {
    669   RequestContext request_context;
    670   std::unique_ptr<MessageForTransit> message_for_transit(
    671       reinterpret_cast<MessageForTransit*>(message));
    672   auto dispatcher = GetDispatcher(message_pipe_handle);
    673   if (!dispatcher)
    674     return MOJO_RESULT_INVALID_ARGUMENT;
    675 
    676   return dispatcher->WriteMessage(std::move(message_for_transit), flags);
    677 }
    678 
    679 MojoResult Core::ReadMessage(MojoHandle message_pipe_handle,
    680                              void* bytes,
    681                              uint32_t* num_bytes,
    682                              MojoHandle* handles,
    683                              uint32_t* num_handles,
    684                              MojoReadMessageFlags flags) {
    685   CHECK((!num_handles || !*num_handles || handles) &&
    686         (!num_bytes || !*num_bytes || bytes));
    687   RequestContext request_context;
    688   auto dispatcher = GetDispatcher(message_pipe_handle);
    689   if (!dispatcher)
    690     return MOJO_RESULT_INVALID_ARGUMENT;
    691   std::unique_ptr<MessageForTransit> message;
    692   MojoResult rv =
    693       dispatcher->ReadMessage(&message, num_bytes, handles, num_handles, flags,
    694                               false /* ignore_num_bytes */);
    695   if (rv != MOJO_RESULT_OK)
    696     return rv;
    697 
    698   if (message && message->num_bytes())
    699     memcpy(bytes, message->bytes(), message->num_bytes());
    700 
    701   return MOJO_RESULT_OK;
    702 }
    703 
    704 MojoResult Core::ReadMessageNew(MojoHandle message_pipe_handle,
    705                                 MojoMessageHandle* message,
    706                                 uint32_t* num_bytes,
    707                                 MojoHandle* handles,
    708                                 uint32_t* num_handles,
    709                                 MojoReadMessageFlags flags) {
    710   CHECK(message);
    711   CHECK(!num_handles || !*num_handles || handles);
    712   RequestContext request_context;
    713   auto dispatcher = GetDispatcher(message_pipe_handle);
    714   if (!dispatcher)
    715     return MOJO_RESULT_INVALID_ARGUMENT;
    716   std::unique_ptr<MessageForTransit> msg;
    717   MojoResult rv =
    718       dispatcher->ReadMessage(&msg, num_bytes, handles, num_handles, flags,
    719                               true /* ignore_num_bytes */);
    720   if (rv != MOJO_RESULT_OK)
    721     return rv;
    722   *message = reinterpret_cast<MojoMessageHandle>(msg.release());
    723   return MOJO_RESULT_OK;
    724 }
    725 
    726 MojoResult Core::FuseMessagePipes(MojoHandle handle0, MojoHandle handle1) {
    727   RequestContext request_context;
    728   scoped_refptr<Dispatcher> dispatcher0;
    729   scoped_refptr<Dispatcher> dispatcher1;
    730 
    731   bool valid_handles = true;
    732   {
    733     base::AutoLock lock(handles_lock_);
    734     MojoResult result0 = handles_.GetAndRemoveDispatcher(handle0, &dispatcher0);
    735     MojoResult result1 = handles_.GetAndRemoveDispatcher(handle1, &dispatcher1);
    736     if (result0 != MOJO_RESULT_OK || result1 != MOJO_RESULT_OK ||
    737         dispatcher0->GetType() != Dispatcher::Type::MESSAGE_PIPE ||
    738         dispatcher1->GetType() != Dispatcher::Type::MESSAGE_PIPE)
    739       valid_handles = false;
    740   }
    741 
    742   if (!valid_handles) {
    743     if (dispatcher0)
    744       dispatcher0->Close();
    745     if (dispatcher1)
    746       dispatcher1->Close();
    747     return MOJO_RESULT_INVALID_ARGUMENT;
    748   }
    749 
    750   MessagePipeDispatcher* mpd0 =
    751       static_cast<MessagePipeDispatcher*>(dispatcher0.get());
    752   MessagePipeDispatcher* mpd1 =
    753       static_cast<MessagePipeDispatcher*>(dispatcher1.get());
    754 
    755   if (!mpd0->Fuse(mpd1))
    756     return MOJO_RESULT_FAILED_PRECONDITION;
    757 
    758   return MOJO_RESULT_OK;
    759 }
    760 
    761 MojoResult Core::NotifyBadMessage(MojoMessageHandle message,
    762                                   const char* error,
    763                                   size_t error_num_bytes) {
    764   if (!message)
    765     return MOJO_RESULT_INVALID_ARGUMENT;
    766 
    767   const PortsMessage& ports_message =
    768       reinterpret_cast<MessageForTransit*>(message)->ports_message();
    769   if (ports_message.source_node() == ports::kInvalidNodeName) {
    770     DVLOG(1) << "Received invalid message from unknown node.";
    771     if (!default_process_error_callback_.is_null())
    772       default_process_error_callback_.Run(std::string(error, error_num_bytes));
    773     return MOJO_RESULT_OK;
    774   }
    775 
    776   GetNodeController()->NotifyBadMessageFrom(
    777       ports_message.source_node(), std::string(error, error_num_bytes));
    778   return MOJO_RESULT_OK;
    779 }
    780 
    781 MojoResult Core::CreateDataPipe(
    782     const MojoCreateDataPipeOptions* options,
    783     MojoHandle* data_pipe_producer_handle,
    784     MojoHandle* data_pipe_consumer_handle) {
    785   RequestContext request_context;
    786   if (options && options->struct_size != sizeof(MojoCreateDataPipeOptions))
    787     return MOJO_RESULT_INVALID_ARGUMENT;
    788 
    789   MojoCreateDataPipeOptions create_options;
    790   create_options.struct_size = sizeof(MojoCreateDataPipeOptions);
    791   create_options.flags = options ? options->flags : 0;
    792   create_options.element_num_bytes = options ? options->element_num_bytes : 1;
    793   // TODO(rockot): Use Configuration to get default data pipe capacity.
    794   create_options.capacity_num_bytes =
    795       options && options->capacity_num_bytes ? options->capacity_num_bytes
    796                                              : 64 * 1024;
    797 
    798   // TODO(rockot): Broker through the parent when necessary.
    799   scoped_refptr<PlatformSharedBuffer> ring_buffer =
    800       GetNodeController()->CreateSharedBuffer(
    801           create_options.capacity_num_bytes);
    802   if (!ring_buffer)
    803     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    804 
    805   ports::PortRef port0, port1;
    806   GetNodeController()->node()->CreatePortPair(&port0, &port1);
    807 
    808   CHECK(data_pipe_producer_handle);
    809   CHECK(data_pipe_consumer_handle);
    810 
    811   uint64_t pipe_id = base::RandUint64();
    812 
    813   scoped_refptr<Dispatcher> producer = new DataPipeProducerDispatcher(
    814       GetNodeController(), port0, ring_buffer, create_options,
    815       true /* initialized */, pipe_id);
    816   scoped_refptr<Dispatcher> consumer = new DataPipeConsumerDispatcher(
    817       GetNodeController(), port1, ring_buffer, create_options,
    818       true /* initialized */, pipe_id);
    819 
    820   *data_pipe_producer_handle = AddDispatcher(producer);
    821   *data_pipe_consumer_handle = AddDispatcher(consumer);
    822   if (*data_pipe_producer_handle == MOJO_HANDLE_INVALID ||
    823       *data_pipe_consumer_handle == MOJO_HANDLE_INVALID) {
    824     if (*data_pipe_producer_handle != MOJO_HANDLE_INVALID) {
    825       scoped_refptr<Dispatcher> unused;
    826       base::AutoLock lock(handles_lock_);
    827       handles_.GetAndRemoveDispatcher(*data_pipe_producer_handle, &unused);
    828     }
    829     producer->Close();
    830     consumer->Close();
    831     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    832   }
    833 
    834   return MOJO_RESULT_OK;
    835 }
    836 
    837 MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle,
    838                            const void* elements,
    839                            uint32_t* num_bytes,
    840                            MojoWriteDataFlags flags) {
    841   RequestContext request_context;
    842   scoped_refptr<Dispatcher> dispatcher(
    843       GetDispatcher(data_pipe_producer_handle));
    844   if (!dispatcher)
    845     return MOJO_RESULT_INVALID_ARGUMENT;
    846 
    847   return dispatcher->WriteData(elements, num_bytes, flags);
    848 }
    849 
    850 MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle,
    851                                 void** buffer,
    852                                 uint32_t* buffer_num_bytes,
    853                                 MojoWriteDataFlags flags) {
    854   RequestContext request_context;
    855   scoped_refptr<Dispatcher> dispatcher(
    856       GetDispatcher(data_pipe_producer_handle));
    857   if (!dispatcher)
    858     return MOJO_RESULT_INVALID_ARGUMENT;
    859 
    860   return dispatcher->BeginWriteData(buffer, buffer_num_bytes, flags);
    861 }
    862 
    863 MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle,
    864                               uint32_t num_bytes_written) {
    865   RequestContext request_context;
    866   scoped_refptr<Dispatcher> dispatcher(
    867       GetDispatcher(data_pipe_producer_handle));
    868   if (!dispatcher)
    869     return MOJO_RESULT_INVALID_ARGUMENT;
    870 
    871   return dispatcher->EndWriteData(num_bytes_written);
    872 }
    873 
    874 MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle,
    875                           void* elements,
    876                           uint32_t* num_bytes,
    877                           MojoReadDataFlags flags) {
    878   RequestContext request_context;
    879   scoped_refptr<Dispatcher> dispatcher(
    880       GetDispatcher(data_pipe_consumer_handle));
    881   if (!dispatcher)
    882     return MOJO_RESULT_INVALID_ARGUMENT;
    883 
    884   return dispatcher->ReadData(elements, num_bytes, flags);
    885 }
    886 
    887 MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle,
    888                                const void** buffer,
    889                                uint32_t* buffer_num_bytes,
    890                                MojoReadDataFlags flags) {
    891   RequestContext request_context;
    892   scoped_refptr<Dispatcher> dispatcher(
    893       GetDispatcher(data_pipe_consumer_handle));
    894   if (!dispatcher)
    895     return MOJO_RESULT_INVALID_ARGUMENT;
    896 
    897   return dispatcher->BeginReadData(buffer, buffer_num_bytes, flags);
    898 }
    899 
    900 MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle,
    901                              uint32_t num_bytes_read) {
    902   RequestContext request_context;
    903   scoped_refptr<Dispatcher> dispatcher(
    904       GetDispatcher(data_pipe_consumer_handle));
    905   if (!dispatcher)
    906     return MOJO_RESULT_INVALID_ARGUMENT;
    907 
    908   return dispatcher->EndReadData(num_bytes_read);
    909 }
    910 
    911 MojoResult Core::CreateSharedBuffer(
    912     const MojoCreateSharedBufferOptions* options,
    913     uint64_t num_bytes,
    914     MojoHandle* shared_buffer_handle) {
    915   RequestContext request_context;
    916   MojoCreateSharedBufferOptions validated_options = {};
    917   MojoResult result = SharedBufferDispatcher::ValidateCreateOptions(
    918       options, &validated_options);
    919   if (result != MOJO_RESULT_OK)
    920     return result;
    921 
    922   scoped_refptr<SharedBufferDispatcher> dispatcher;
    923   result = SharedBufferDispatcher::Create(
    924       validated_options, GetNodeController(), num_bytes, &dispatcher);
    925   if (result != MOJO_RESULT_OK) {
    926     DCHECK(!dispatcher);
    927     return result;
    928   }
    929 
    930   *shared_buffer_handle = AddDispatcher(dispatcher);
    931   if (*shared_buffer_handle == MOJO_HANDLE_INVALID) {
    932     LOG(ERROR) << "Handle table full";
    933     dispatcher->Close();
    934     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    935   }
    936 
    937   return MOJO_RESULT_OK;
    938 }
    939 
    940 MojoResult Core::DuplicateBufferHandle(
    941     MojoHandle buffer_handle,
    942     const MojoDuplicateBufferHandleOptions* options,
    943     MojoHandle* new_buffer_handle) {
    944   RequestContext request_context;
    945   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
    946   if (!dispatcher)
    947     return MOJO_RESULT_INVALID_ARGUMENT;
    948 
    949   // Don't verify |options| here; that's the dispatcher's job.
    950   scoped_refptr<Dispatcher> new_dispatcher;
    951   MojoResult result =
    952       dispatcher->DuplicateBufferHandle(options, &new_dispatcher);
    953   if (result != MOJO_RESULT_OK)
    954     return result;
    955 
    956   *new_buffer_handle = AddDispatcher(new_dispatcher);
    957   if (*new_buffer_handle == MOJO_HANDLE_INVALID) {
    958     LOG(ERROR) << "Handle table full";
    959     dispatcher->Close();
    960     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    961   }
    962 
    963   return MOJO_RESULT_OK;
    964 }
    965 
    966 MojoResult Core::MapBuffer(MojoHandle buffer_handle,
    967                            uint64_t offset,
    968                            uint64_t num_bytes,
    969                            void** buffer,
    970                            MojoMapBufferFlags flags) {
    971   RequestContext request_context;
    972   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
    973   if (!dispatcher)
    974     return MOJO_RESULT_INVALID_ARGUMENT;
    975 
    976   std::unique_ptr<PlatformSharedBufferMapping> mapping;
    977   MojoResult result = dispatcher->MapBuffer(offset, num_bytes, flags, &mapping);
    978   if (result != MOJO_RESULT_OK)
    979     return result;
    980 
    981   DCHECK(mapping);
    982   void* address = mapping->GetBase();
    983   {
    984     base::AutoLock locker(mapping_table_lock_);
    985     result = mapping_table_.AddMapping(std::move(mapping));
    986   }
    987   if (result != MOJO_RESULT_OK)
    988     return result;
    989 
    990   *buffer = address;
    991   return MOJO_RESULT_OK;
    992 }
    993 
    994 MojoResult Core::UnmapBuffer(void* buffer) {
    995   RequestContext request_context;
    996   base::AutoLock lock(mapping_table_lock_);
    997   return mapping_table_.RemoveMapping(buffer);
    998 }
    999 
   1000 MojoResult Core::WrapPlatformHandle(const MojoPlatformHandle* platform_handle,
   1001                                     MojoHandle* mojo_handle) {
   1002   ScopedPlatformHandle handle;
   1003   MojoResult result = MojoPlatformHandleToScopedPlatformHandle(platform_handle,
   1004                                                                &handle);
   1005   if (result != MOJO_RESULT_OK)
   1006     return result;
   1007 
   1008   return CreatePlatformHandleWrapper(std::move(handle), mojo_handle);
   1009 }
   1010 
   1011 MojoResult Core::UnwrapPlatformHandle(MojoHandle mojo_handle,
   1012                                       MojoPlatformHandle* platform_handle) {
   1013   ScopedPlatformHandle handle;
   1014   MojoResult result = PassWrappedPlatformHandle(mojo_handle, &handle);
   1015   if (result != MOJO_RESULT_OK)
   1016     return result;
   1017 
   1018   return ScopedPlatformHandleToMojoPlatformHandle(std::move(handle),
   1019                                                   platform_handle);
   1020 }
   1021 
   1022 MojoResult Core::WrapPlatformSharedBufferHandle(
   1023     const MojoPlatformHandle* platform_handle,
   1024     size_t size,
   1025     MojoPlatformSharedBufferHandleFlags flags,
   1026     MojoHandle* mojo_handle) {
   1027   DCHECK(size);
   1028   ScopedPlatformHandle handle;
   1029   MojoResult result = MojoPlatformHandleToScopedPlatformHandle(platform_handle,
   1030                                                                &handle);
   1031   if (result != MOJO_RESULT_OK)
   1032     return result;
   1033 
   1034   bool read_only = flags & MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_READ_ONLY;
   1035   scoped_refptr<PlatformSharedBuffer> platform_buffer =
   1036       PlatformSharedBuffer::CreateFromPlatformHandle(size, read_only,
   1037                                                      std::move(handle));
   1038   if (!platform_buffer)
   1039     return MOJO_RESULT_UNKNOWN;
   1040 
   1041   scoped_refptr<SharedBufferDispatcher> dispatcher;
   1042   result = SharedBufferDispatcher::CreateFromPlatformSharedBuffer(
   1043       platform_buffer, &dispatcher);
   1044   if (result != MOJO_RESULT_OK)
   1045     return result;
   1046 
   1047   MojoHandle h = AddDispatcher(dispatcher);
   1048   if (h == MOJO_HANDLE_INVALID) {
   1049     dispatcher->Close();
   1050     return MOJO_RESULT_RESOURCE_EXHAUSTED;
   1051   }
   1052 
   1053   *mojo_handle = h;
   1054   return MOJO_RESULT_OK;
   1055 }
   1056 
   1057 MojoResult Core::UnwrapPlatformSharedBufferHandle(
   1058     MojoHandle mojo_handle,
   1059     MojoPlatformHandle* platform_handle,
   1060     size_t* size,
   1061     MojoPlatformSharedBufferHandleFlags* flags) {
   1062   scoped_refptr<Dispatcher> dispatcher;
   1063   MojoResult result = MOJO_RESULT_OK;
   1064   {
   1065     base::AutoLock lock(handles_lock_);
   1066     result = handles_.GetAndRemoveDispatcher(mojo_handle, &dispatcher);
   1067     if (result != MOJO_RESULT_OK)
   1068       return result;
   1069   }
   1070 
   1071   if (dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER) {
   1072     dispatcher->Close();
   1073     return MOJO_RESULT_INVALID_ARGUMENT;
   1074   }
   1075 
   1076   SharedBufferDispatcher* shm_dispatcher =
   1077       static_cast<SharedBufferDispatcher*>(dispatcher.get());
   1078   scoped_refptr<PlatformSharedBuffer> platform_shared_buffer =
   1079       shm_dispatcher->PassPlatformSharedBuffer();
   1080   CHECK(platform_shared_buffer);
   1081 
   1082   CHECK(size);
   1083   *size = platform_shared_buffer->GetNumBytes();
   1084 
   1085   CHECK(flags);
   1086   *flags = MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE;
   1087   if (platform_shared_buffer->IsReadOnly())
   1088     *flags |= MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_READ_ONLY;
   1089 
   1090   ScopedPlatformHandle handle = platform_shared_buffer->PassPlatformHandle();
   1091   return ScopedPlatformHandleToMojoPlatformHandle(std::move(handle),
   1092                                                   platform_handle);
   1093 }
   1094 
   1095 void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
   1096   base::AutoLock lock(handles_lock_);
   1097   handles_.GetActiveHandlesForTest(handles);
   1098 }
   1099 
   1100 MojoResult Core::WaitManyInternal(const MojoHandle* handles,
   1101                                   const MojoHandleSignals* signals,
   1102                                   uint32_t num_handles,
   1103                                   MojoDeadline deadline,
   1104                                   uint32_t* result_index,
   1105                                   HandleSignalsState* signals_states) {
   1106   CHECK(handles);
   1107   CHECK(signals);
   1108   DCHECK_GT(num_handles, 0u);
   1109   if (result_index) {
   1110     DCHECK_EQ(*result_index, static_cast<uint32_t>(-1));
   1111   }
   1112 
   1113   // The primary caller of |WaitManyInternal()| is |Wait()|, which only waits on
   1114   // a single handle. In the common case of a single handle, this avoid a heap
   1115   // allocation.
   1116   base::StackVector<scoped_refptr<Dispatcher>, 1> dispatchers;
   1117   dispatchers->reserve(num_handles);
   1118   for (uint32_t i = 0; i < num_handles; i++) {
   1119     scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handles[i]);
   1120     if (!dispatcher) {
   1121       if (result_index)
   1122         *result_index = i;
   1123       return MOJO_RESULT_INVALID_ARGUMENT;
   1124     }
   1125     dispatchers->push_back(dispatcher);
   1126   }
   1127 
   1128   // TODO(vtl): Should make the waiter live (permanently) in TLS.
   1129   Waiter waiter;
   1130   waiter.Init();
   1131 
   1132   uint32_t i;
   1133   MojoResult rv = MOJO_RESULT_OK;
   1134   for (i = 0; i < num_handles; i++) {
   1135     rv = dispatchers[i]->AddAwakable(
   1136         &waiter, signals[i], i, signals_states ? &signals_states[i] : nullptr);
   1137     if (rv != MOJO_RESULT_OK) {
   1138       if (result_index)
   1139         *result_index = i;
   1140       break;
   1141     }
   1142   }
   1143   uint32_t num_added = i;
   1144 
   1145   if (rv == MOJO_RESULT_ALREADY_EXISTS) {
   1146     rv = MOJO_RESULT_OK;  // The i-th one is already "triggered".
   1147   } else if (rv == MOJO_RESULT_OK) {
   1148     uintptr_t uintptr_result = *result_index;
   1149     rv = waiter.Wait(deadline, &uintptr_result);
   1150     *result_index = static_cast<uint32_t>(uintptr_result);
   1151   }
   1152 
   1153   // Make sure no other dispatchers try to wake |waiter| for the current
   1154   // |Wait()|/|WaitMany()| call. (Only after doing this can |waiter| be
   1155   // destroyed, but this would still be required if the waiter were in TLS.)
   1156   for (i = 0; i < num_added; i++) {
   1157     dispatchers[i]->RemoveAwakable(
   1158         &waiter, signals_states ? &signals_states[i] : nullptr);
   1159   }
   1160   if (signals_states) {
   1161     for (; i < num_handles; i++)
   1162       signals_states[i] = dispatchers[i]->GetHandleSignalsState();
   1163   }
   1164 
   1165   return rv;
   1166 }
   1167 
   1168 // static
   1169 void Core::PassNodeControllerToIOThread(
   1170     std::unique_ptr<NodeController> node_controller) {
   1171   // It's OK to leak this reference. At this point we know the IO loop is still
   1172   // running, and we know the NodeController will observe its eventual
   1173   // destruction. This tells the NodeController to delete itself when that
   1174   // happens.
   1175   node_controller.release()->DestroyOnIOThreadShutdown();
   1176 }
   1177 
   1178 }  // namespace edk
   1179 }  // namespace mojo
   1180