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