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>> 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 (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 (!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 g_current_sync_handle_watcher.Pointer()->Set(nullptr); 111 } 112 113 } // namespace mojo 114