// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "mojo/public/cpp/bindings/sync_handle_registry.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/stl_util.h" #include "base/threading/thread_local.h" #include "mojo/public/c/system/core.h" namespace mojo { namespace { base::LazyInstance> g_current_sync_handle_watcher = LAZY_INSTANCE_INITIALIZER; } // namespace // static scoped_refptr SyncHandleRegistry::current() { scoped_refptr result( g_current_sync_handle_watcher.Pointer()->Get()); if (!result) { result = new SyncHandleRegistry(); DCHECK_EQ(result.get(), g_current_sync_handle_watcher.Pointer()->Get()); } return result; } bool SyncHandleRegistry::RegisterHandle(const Handle& handle, MojoHandleSignals handle_signals, const HandleCallback& callback) { DCHECK(thread_checker_.CalledOnValidThread()); if (ContainsKey(handles_, handle)) return false; MojoResult result = MojoAddHandle(wait_set_handle_.get().value(), handle.value(), handle_signals); if (result != MOJO_RESULT_OK) return false; handles_[handle] = callback; return true; } void SyncHandleRegistry::UnregisterHandle(const Handle& handle) { DCHECK(thread_checker_.CalledOnValidThread()); if (!ContainsKey(handles_, handle)) return; MojoResult result = MojoRemoveHandle(wait_set_handle_.get().value(), handle.value()); DCHECK_EQ(MOJO_RESULT_OK, result); handles_.erase(handle); } bool SyncHandleRegistry::WatchAllHandles(const bool* should_stop[], size_t count) { DCHECK(thread_checker_.CalledOnValidThread()); MojoResult result; uint32_t num_ready_handles; MojoHandle ready_handle; MojoResult ready_handle_result; scoped_refptr preserver(this); while (true) { for (size_t i = 0; i < count; ++i) if (*should_stop[i]) return true; do { result = Wait(wait_set_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE, nullptr); if (result != MOJO_RESULT_OK) return false; // TODO(yzshen): Theoretically it can reduce sync call re-entrancy if we // give priority to the handle that is waiting for sync response. num_ready_handles = 1; result = MojoGetReadyHandles(wait_set_handle_.get().value(), &num_ready_handles, &ready_handle, &ready_handle_result, nullptr); if (result != MOJO_RESULT_OK && result != MOJO_RESULT_SHOULD_WAIT) return false; } while (result == MOJO_RESULT_SHOULD_WAIT); const auto iter = handles_.find(Handle(ready_handle)); iter->second.Run(ready_handle_result); }; return false; } SyncHandleRegistry::SyncHandleRegistry() { MojoHandle handle; MojoResult result = MojoCreateWaitSet(&handle); CHECK_EQ(MOJO_RESULT_OK, result); wait_set_handle_.reset(Handle(handle)); CHECK(wait_set_handle_.is_valid()); DCHECK(!g_current_sync_handle_watcher.Pointer()->Get()); g_current_sync_handle_watcher.Pointer()->Set(this); } SyncHandleRegistry::~SyncHandleRegistry() { DCHECK(thread_checker_.CalledOnValidThread()); g_current_sync_handle_watcher.Pointer()->Set(nullptr); } } // namespace mojo