Home | History | Annotate | Download | only in lib
      1 // Copyright 2016 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/public/cpp/bindings/sync_handle_registry.h"
      6 
      7 #include "base/lazy_instance.h"
      8 #include "base/logging.h"
      9 #include "base/stl_util.h"
     10 #include "base/threading/thread_local.h"
     11 #include "mojo/public/c/system/core.h"
     12 
     13 namespace mojo {
     14 namespace {
     15 
     16 base::LazyInstance<base::ThreadLocalPointer<SyncHandleRegistry>>::Leaky
     17     g_current_sync_handle_watcher = LAZY_INSTANCE_INITIALIZER;
     18 
     19 }  // namespace
     20 
     21 // static
     22 scoped_refptr<SyncHandleRegistry> SyncHandleRegistry::current() {
     23   scoped_refptr<SyncHandleRegistry> result(
     24       g_current_sync_handle_watcher.Pointer()->Get());
     25   if (!result) {
     26     result = new SyncHandleRegistry();
     27     DCHECK_EQ(result.get(), g_current_sync_handle_watcher.Pointer()->Get());
     28   }
     29   return result;
     30 }
     31 
     32 bool SyncHandleRegistry::RegisterHandle(const Handle& handle,
     33                                         MojoHandleSignals handle_signals,
     34                                         const HandleCallback& callback) {
     35   DCHECK(thread_checker_.CalledOnValidThread());
     36 
     37   if (base::ContainsKey(handles_, handle))
     38     return false;
     39 
     40   MojoResult result = MojoAddHandle(wait_set_handle_.get().value(),
     41                                     handle.value(), handle_signals);
     42   if (result != MOJO_RESULT_OK)
     43     return false;
     44 
     45   handles_[handle] = callback;
     46   return true;
     47 }
     48 
     49 void SyncHandleRegistry::UnregisterHandle(const Handle& handle) {
     50   DCHECK(thread_checker_.CalledOnValidThread());
     51   if (!base::ContainsKey(handles_, handle))
     52     return;
     53 
     54   MojoResult result =
     55       MojoRemoveHandle(wait_set_handle_.get().value(), handle.value());
     56   DCHECK_EQ(MOJO_RESULT_OK, result);
     57   handles_.erase(handle);
     58 }
     59 
     60 bool SyncHandleRegistry::WatchAllHandles(const bool* should_stop[],
     61                                          size_t count) {
     62   DCHECK(thread_checker_.CalledOnValidThread());
     63 
     64   MojoResult result;
     65   uint32_t num_ready_handles;
     66   MojoHandle ready_handle;
     67   MojoResult ready_handle_result;
     68 
     69   scoped_refptr<SyncHandleRegistry> preserver(this);
     70   while (true) {
     71     for (size_t i = 0; i < count; ++i)
     72       if (*should_stop[i])
     73         return true;
     74     do {
     75       result = Wait(wait_set_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE,
     76                     MOJO_DEADLINE_INDEFINITE, nullptr);
     77       if (result != MOJO_RESULT_OK)
     78         return false;
     79 
     80       // TODO(yzshen): Theoretically it can reduce sync call re-entrancy if we
     81       // give priority to the handle that is waiting for sync response.
     82       num_ready_handles = 1;
     83       result = MojoGetReadyHandles(wait_set_handle_.get().value(),
     84                                    &num_ready_handles, &ready_handle,
     85                                    &ready_handle_result, nullptr);
     86       if (result != MOJO_RESULT_OK && result != MOJO_RESULT_SHOULD_WAIT)
     87         return false;
     88     } while (result == MOJO_RESULT_SHOULD_WAIT);
     89 
     90     const auto iter = handles_.find(Handle(ready_handle));
     91     iter->second.Run(ready_handle_result);
     92   };
     93 
     94   return false;
     95 }
     96 
     97 SyncHandleRegistry::SyncHandleRegistry() {
     98   MojoHandle handle;
     99   MojoResult result = MojoCreateWaitSet(&handle);
    100   CHECK_EQ(MOJO_RESULT_OK, result);
    101   wait_set_handle_.reset(Handle(handle));
    102   CHECK(wait_set_handle_.is_valid());
    103 
    104   DCHECK(!g_current_sync_handle_watcher.Pointer()->Get());
    105   g_current_sync_handle_watcher.Pointer()->Set(this);
    106 }
    107 
    108 SyncHandleRegistry::~SyncHandleRegistry() {
    109   DCHECK(thread_checker_.CalledOnValidThread());
    110 
    111   // This object may be destructed after the thread local storage slot used by
    112   // |g_current_sync_handle_watcher| is reset during thread shutdown.
    113   // For example, another slot in the thread local storage holds a referrence to
    114   // this object, and that slot is cleaned up after
    115   // |g_current_sync_handle_watcher|.
    116   if (!g_current_sync_handle_watcher.Pointer()->Get())
    117     return;
    118 
    119   // If this breaks, it is likely that the global variable is bulit into and
    120   // accessed from multiple modules.
    121   DCHECK_EQ(this, g_current_sync_handle_watcher.Pointer()->Get());
    122 
    123   g_current_sync_handle_watcher.Pointer()->Set(nullptr);
    124 }
    125 
    126 }  // namespace mojo
    127