1 // Copyright 2017 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 <memory>
6
7 #include "mojo/public/cpp/bindings/sync_handle_registry.h"
8 #include "base/bind.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12
13 namespace mojo {
14
15 class SyncHandleRegistryTest : public testing::Test {
16 public:
SyncHandleRegistryTest()17 SyncHandleRegistryTest() : registry_(SyncHandleRegistry::current()) {}
18
registry()19 const scoped_refptr<SyncHandleRegistry>& registry() { return registry_; }
20
21 private:
22 scoped_refptr<SyncHandleRegistry> registry_;
23
24 DISALLOW_COPY_AND_ASSIGN(SyncHandleRegistryTest);
25 };
26
TEST_F(SyncHandleRegistryTest,DuplicateEventRegistration)27 TEST_F(SyncHandleRegistryTest, DuplicateEventRegistration) {
28 bool called1 = false;
29 bool called2 = false;
30 auto callback = [](bool* called) { *called = true; };
31 auto callback1 = base::Bind(callback, &called1);
32 auto callback2 = base::Bind(callback, &called2);
33
34 base::WaitableEvent e(base::WaitableEvent::ResetPolicy::MANUAL,
35 base::WaitableEvent::InitialState::SIGNALED);
36 registry()->RegisterEvent(&e, callback1);
37 registry()->RegisterEvent(&e, callback2);
38
39 const bool* stop_flags[] = {&called1, &called2};
40 registry()->Wait(stop_flags, 2);
41
42 EXPECT_TRUE(called1);
43 EXPECT_TRUE(called2);
44 registry()->UnregisterEvent(&e, callback1);
45
46 called1 = false;
47 called2 = false;
48
49 registry()->Wait(stop_flags, 2);
50
51 EXPECT_FALSE(called1);
52 EXPECT_TRUE(called2);
53
54 registry()->UnregisterEvent(&e, callback2);
55 }
56
TEST_F(SyncHandleRegistryTest,UnregisterDuplicateEventInNestedWait)57 TEST_F(SyncHandleRegistryTest, UnregisterDuplicateEventInNestedWait) {
58 base::WaitableEvent e(base::WaitableEvent::ResetPolicy::MANUAL,
59 base::WaitableEvent::InitialState::SIGNALED);
60 bool called1 = false;
61 bool called2 = false;
62 bool called3 = false;
63 auto callback1 = base::Bind([](bool* called) { *called = true; }, &called1);
64 auto callback2 = base::Bind(
65 [](base::WaitableEvent* e, const base::Closure& other_callback,
66 scoped_refptr<SyncHandleRegistry> registry, bool* called) {
67 registry->UnregisterEvent(e, other_callback);
68 *called = true;
69 },
70 &e, callback1, registry(), &called2);
71 auto callback3 = base::Bind([](bool* called) { *called = true; }, &called3);
72
73 registry()->RegisterEvent(&e, callback1);
74 registry()->RegisterEvent(&e, callback2);
75 registry()->RegisterEvent(&e, callback3);
76
77 const bool* stop_flags[] = {&called1, &called2, &called3};
78 registry()->Wait(stop_flags, 3);
79
80 // We don't make any assumptions about the order in which callbacks run, so
81 // we can't check |called1| - it may or may not get set depending on internal
82 // details. All we know is |called2| should be set, and a subsequent wait
83 // should definitely NOT set |called1|.
84 EXPECT_TRUE(called2);
85 EXPECT_TRUE(called3);
86
87 called1 = false;
88 called2 = false;
89 called3 = false;
90
91 registry()->UnregisterEvent(&e, callback2);
92 registry()->Wait(stop_flags, 3);
93
94 EXPECT_FALSE(called1);
95 EXPECT_FALSE(called2);
96 EXPECT_TRUE(called3);
97 }
98
TEST_F(SyncHandleRegistryTest,UnregisterAndRegisterForNewEventInCallback)99 TEST_F(SyncHandleRegistryTest, UnregisterAndRegisterForNewEventInCallback) {
100 auto e = std::make_unique<base::WaitableEvent>(
101 base::WaitableEvent::ResetPolicy::MANUAL,
102 base::WaitableEvent::InitialState::SIGNALED);
103 bool called = false;
104 base::Closure callback_holder;
105 auto callback = base::Bind(
106 [](std::unique_ptr<base::WaitableEvent>* e,
107 base::Closure* callback_holder,
108 scoped_refptr<SyncHandleRegistry> registry, bool* called) {
109 EXPECT_FALSE(*called);
110
111 registry->UnregisterEvent(e->get(), *callback_holder);
112 e->reset();
113 *called = true;
114
115 base::WaitableEvent nested_event(
116 base::WaitableEvent::ResetPolicy::MANUAL,
117 base::WaitableEvent::InitialState::SIGNALED);
118 bool nested_called = false;
119 auto nested_callback =
120 base::Bind([](bool* called) { *called = true; }, &nested_called);
121 registry->RegisterEvent(&nested_event, nested_callback);
122 const bool* stop_flag = &nested_called;
123 registry->Wait(&stop_flag, 1);
124 registry->UnregisterEvent(&nested_event, nested_callback);
125 },
126 &e, &callback_holder, registry(), &called);
127 callback_holder = callback;
128
129 registry()->RegisterEvent(e.get(), callback);
130
131 const bool* stop_flag = &called;
132 registry()->Wait(&stop_flag, 1);
133 EXPECT_TRUE(called);
134 }
135
TEST_F(SyncHandleRegistryTest,UnregisterAndRegisterForSameEventInCallback)136 TEST_F(SyncHandleRegistryTest, UnregisterAndRegisterForSameEventInCallback) {
137 base::WaitableEvent e(base::WaitableEvent::ResetPolicy::MANUAL,
138 base::WaitableEvent::InitialState::SIGNALED);
139 bool called = false;
140 base::Closure callback_holder;
141 auto callback = base::Bind(
142 [](base::WaitableEvent* e, base::Closure* callback_holder,
143 scoped_refptr<SyncHandleRegistry> registry, bool* called) {
144 EXPECT_FALSE(*called);
145
146 registry->UnregisterEvent(e, *callback_holder);
147 *called = true;
148
149 bool nested_called = false;
150 auto nested_callback =
151 base::Bind([](bool* called) { *called = true; }, &nested_called);
152 registry->RegisterEvent(e, nested_callback);
153 const bool* stop_flag = &nested_called;
154 registry->Wait(&stop_flag, 1);
155 registry->UnregisterEvent(e, nested_callback);
156
157 EXPECT_TRUE(nested_called);
158 },
159 &e, &callback_holder, registry(), &called);
160 callback_holder = callback;
161
162 registry()->RegisterEvent(&e, callback);
163
164 const bool* stop_flag = &called;
165 registry()->Wait(&stop_flag, 1);
166 EXPECT_TRUE(called);
167 }
168
TEST_F(SyncHandleRegistryTest,RegisterDuplicateEventFromWithinCallback)169 TEST_F(SyncHandleRegistryTest, RegisterDuplicateEventFromWithinCallback) {
170 base::WaitableEvent e(base::WaitableEvent::ResetPolicy::MANUAL,
171 base::WaitableEvent::InitialState::SIGNALED);
172 bool called = false;
173 int call_count = 0;
174 auto callback = base::Bind(
175 [](base::WaitableEvent* e, scoped_refptr<SyncHandleRegistry> registry,
176 bool* called, int* call_count) {
177 // Don't re-enter.
178 ++(*call_count);
179 if (*called)
180 return;
181
182 *called = true;
183
184 bool called2 = false;
185 auto callback2 =
186 base::Bind([](bool* called) { *called = true; }, &called2);
187 registry->RegisterEvent(e, callback2);
188
189 const bool* stop_flag = &called2;
190 registry->Wait(&stop_flag, 1);
191
192 registry->UnregisterEvent(e, callback2);
193 },
194 &e, registry(), &called, &call_count);
195
196 registry()->RegisterEvent(&e, callback);
197
198 const bool* stop_flag = &called;
199 registry()->Wait(&stop_flag, 1);
200
201 EXPECT_TRUE(called);
202 EXPECT_EQ(2, call_count);
203
204 registry()->UnregisterEvent(&e, callback);
205 }
206
TEST_F(SyncHandleRegistryTest,UnregisterUniqueEventInNestedWait)207 TEST_F(SyncHandleRegistryTest, UnregisterUniqueEventInNestedWait) {
208 auto e1 = std::make_unique<base::WaitableEvent>(
209 base::WaitableEvent::ResetPolicy::MANUAL,
210 base::WaitableEvent::InitialState::NOT_SIGNALED);
211 base::WaitableEvent e2(base::WaitableEvent::ResetPolicy::MANUAL,
212 base::WaitableEvent::InitialState::SIGNALED);
213 bool called1 = false;
214 bool called2 = false;
215 auto callback1 = base::Bind([](bool* called) { *called = true; }, &called1);
216 auto callback2 = base::Bind(
217 [](std::unique_ptr<base::WaitableEvent>* e1,
218 const base::Closure& other_callback,
219 scoped_refptr<SyncHandleRegistry> registry, bool* called) {
220 // Prevent re-entrancy.
221 if (*called)
222 return;
223
224 registry->UnregisterEvent(e1->get(), other_callback);
225 *called = true;
226 e1->reset();
227
228 // Nest another wait.
229 bool called3 = false;
230 auto callback3 =
231 base::Bind([](bool* called) { *called = true; }, &called3);
232 base::WaitableEvent e3(base::WaitableEvent::ResetPolicy::MANUAL,
233 base::WaitableEvent::InitialState::SIGNALED);
234 registry->RegisterEvent(&e3, callback3);
235
236 // This nested Wait() must not attempt to wait on |e1| since it has
237 // been unregistered. This would crash otherwise, since |e1| has been
238 // deleted. See http://crbug.com/761097.
239 const bool* stop_flags[] = {&called3};
240 registry->Wait(stop_flags, 1);
241
242 EXPECT_TRUE(called3);
243 registry->UnregisterEvent(&e3, callback3);
244 },
245 &e1, callback1, registry(), &called2);
246
247 registry()->RegisterEvent(e1.get(), callback1);
248 registry()->RegisterEvent(&e2, callback2);
249
250 const bool* stop_flags[] = {&called1, &called2};
251 registry()->Wait(stop_flags, 2);
252
253 EXPECT_TRUE(called2);
254
255 registry()->UnregisterEvent(&e2, callback2);
256 }
257
258 } // namespace mojo
259