• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
current()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 
RegisterHandle(const Handle & handle,MojoHandleSignals handle_signals,const HandleCallback & callback)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 
UnregisterHandle(const Handle & handle)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 
WatchAllHandles(const bool * should_stop[],size_t count)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 
SyncHandleRegistry()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 
~SyncHandleRegistry()108 SyncHandleRegistry::~SyncHandleRegistry() {
109   DCHECK(thread_checker_.CalledOnValidThread());
110   g_current_sync_handle_watcher.Pointer()->Set(nullptr);
111 }
112 
113 }  // namespace mojo
114