• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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