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