• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 "base/synchronization/waitable_event_watcher.h"
6 
7 #include "base/functional/bind.h"
8 #include "base/functional/callback.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/memory/raw_ptr.h"
11 #include "base/run_loop.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/task/sequenced_task_runner.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "base/test/bind.h"
16 #include "base/test/task_environment.h"
17 #include "base/threading/platform_thread.h"
18 #include "build/build_config.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 namespace base {
22 
23 namespace {
24 
25 // The main thread types on which each waitable event should be tested.
26 const test::TaskEnvironment::MainThreadType testing_main_threads[] = {
27     test::TaskEnvironment::MainThreadType::DEFAULT,
28     test::TaskEnvironment::MainThreadType::IO,
29 #if !BUILDFLAG(IS_IOS)  // iOS does not allow direct running of the UI loop.
30     test::TaskEnvironment::MainThreadType::UI,
31 #endif
32 };
33 
QuitWhenSignaled(WaitableEvent * event)34 void QuitWhenSignaled(WaitableEvent* event) {
35   RunLoop::QuitCurrentWhenIdleDeprecated();
36 }
37 
38 class DecrementCountContainer {
39  public:
DecrementCountContainer(int * counter)40   explicit DecrementCountContainer(int* counter) : counter_(counter) {}
OnWaitableEventSignaled(WaitableEvent * object)41   void OnWaitableEventSignaled(WaitableEvent* object) {
42     // NOTE: |object| may be already deleted.
43     --(*counter_);
44   }
45 
46  private:
47   raw_ptr<int> counter_;
48 };
49 
50 }  // namespace
51 
52 class WaitableEventWatcherTest
53     : public testing::TestWithParam<test::TaskEnvironment::MainThreadType> {};
54 
TEST_P(WaitableEventWatcherTest,BasicSignalManual)55 TEST_P(WaitableEventWatcherTest, BasicSignalManual) {
56   test::TaskEnvironment task_environment(GetParam());
57 
58   // A manual-reset event that is not yet signaled.
59   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
60                       WaitableEvent::InitialState::NOT_SIGNALED);
61 
62   WaitableEventWatcher watcher;
63   watcher.StartWatching(&event, BindOnce(&QuitWhenSignaled),
64                         SequencedTaskRunner::GetCurrentDefault());
65 
66   event.Signal();
67 
68   RunLoop().Run();
69 
70   EXPECT_TRUE(event.IsSignaled());
71 }
72 
TEST_P(WaitableEventWatcherTest,BasicSignalAutomatic)73 TEST_P(WaitableEventWatcherTest, BasicSignalAutomatic) {
74   test::TaskEnvironment task_environment(GetParam());
75 
76   WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC,
77                       WaitableEvent::InitialState::NOT_SIGNALED);
78 
79   WaitableEventWatcher watcher;
80   watcher.StartWatching(&event, BindOnce(&QuitWhenSignaled),
81                         SequencedTaskRunner::GetCurrentDefault());
82 
83   event.Signal();
84 
85   RunLoop().Run();
86 
87   // The WaitableEventWatcher consumes the event signal.
88   EXPECT_FALSE(event.IsSignaled());
89 }
90 
TEST_P(WaitableEventWatcherTest,BasicCancel)91 TEST_P(WaitableEventWatcherTest, BasicCancel) {
92   test::TaskEnvironment task_environment(GetParam());
93 
94   // A manual-reset event that is not yet signaled.
95   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
96                       WaitableEvent::InitialState::NOT_SIGNALED);
97 
98   WaitableEventWatcher watcher;
99 
100   watcher.StartWatching(&event, BindOnce(&QuitWhenSignaled),
101                         SequencedTaskRunner::GetCurrentDefault());
102 
103   watcher.StopWatching();
104 }
105 
TEST_P(WaitableEventWatcherTest,CancelAfterSet)106 TEST_P(WaitableEventWatcherTest, CancelAfterSet) {
107   test::TaskEnvironment task_environment(GetParam());
108 
109   // A manual-reset event that is not yet signaled.
110   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
111                       WaitableEvent::InitialState::NOT_SIGNALED);
112 
113   WaitableEventWatcher watcher;
114 
115   int counter = 1;
116   DecrementCountContainer delegate(&counter);
117   WaitableEventWatcher::EventCallback callback = BindOnce(
118       &DecrementCountContainer::OnWaitableEventSignaled, Unretained(&delegate));
119   watcher.StartWatching(&event, std::move(callback),
120                         SequencedTaskRunner::GetCurrentDefault());
121 
122   event.Signal();
123 
124   // Let the background thread do its business
125   PlatformThread::Sleep(Milliseconds(30));
126 
127   watcher.StopWatching();
128 
129   RunLoop().RunUntilIdle();
130 
131   // Our delegate should not have fired.
132   EXPECT_EQ(1, counter);
133 }
134 
TEST_P(WaitableEventWatcherTest,OutlivesTaskEnvironment)135 TEST_P(WaitableEventWatcherTest, OutlivesTaskEnvironment) {
136   // Simulate a task environment that dies before an WaitableEventWatcher.  This
137   // ordinarily doesn't happen when people use the Thread class, but it can
138   // happen when people use the Singleton pattern or atexit.
139   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
140                       WaitableEvent::InitialState::NOT_SIGNALED);
141   {
142     std::unique_ptr<WaitableEventWatcher> watcher;
143     {
144       test::TaskEnvironment task_environment(GetParam());
145       watcher = std::make_unique<WaitableEventWatcher>();
146 
147       watcher->StartWatching(&event, BindOnce(&QuitWhenSignaled),
148                              SequencedTaskRunner::GetCurrentDefault());
149     }
150   }
151 }
152 
TEST_P(WaitableEventWatcherTest,SignaledAtStartManual)153 TEST_P(WaitableEventWatcherTest, SignaledAtStartManual) {
154   test::TaskEnvironment task_environment(GetParam());
155 
156   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
157                       WaitableEvent::InitialState::SIGNALED);
158 
159   WaitableEventWatcher watcher;
160   watcher.StartWatching(&event, BindOnce(&QuitWhenSignaled),
161                         SequencedTaskRunner::GetCurrentDefault());
162 
163   RunLoop().Run();
164 
165   EXPECT_TRUE(event.IsSignaled());
166 }
167 
TEST_P(WaitableEventWatcherTest,SignaledAtStartAutomatic)168 TEST_P(WaitableEventWatcherTest, SignaledAtStartAutomatic) {
169   test::TaskEnvironment task_environment(GetParam());
170 
171   WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC,
172                       WaitableEvent::InitialState::SIGNALED);
173 
174   WaitableEventWatcher watcher;
175   watcher.StartWatching(&event, BindOnce(&QuitWhenSignaled),
176                         SequencedTaskRunner::GetCurrentDefault());
177 
178   RunLoop().Run();
179 
180   // The watcher consumes the event signal.
181   EXPECT_FALSE(event.IsSignaled());
182 }
183 
TEST_P(WaitableEventWatcherTest,StartWatchingInCallback)184 TEST_P(WaitableEventWatcherTest, StartWatchingInCallback) {
185   test::TaskEnvironment task_environment(GetParam());
186 
187   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
188                       WaitableEvent::InitialState::NOT_SIGNALED);
189 
190   WaitableEventWatcher watcher;
191   watcher.StartWatching(
192       &event,
193       BindOnce(
194           [](WaitableEventWatcher* watcher, WaitableEvent* event) {
195             // |event| is manual, so the second watcher will run
196             // immediately.
197             watcher->StartWatching(event, BindOnce(&QuitWhenSignaled),
198                                    SequencedTaskRunner::GetCurrentDefault());
199           },
200           &watcher),
201       SequencedTaskRunner::GetCurrentDefault());
202 
203   event.Signal();
204 
205   RunLoop().Run();
206 }
207 
TEST_P(WaitableEventWatcherTest,MultipleWatchersManual)208 TEST_P(WaitableEventWatcherTest, MultipleWatchersManual) {
209   test::TaskEnvironment task_environment(GetParam());
210 
211   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
212                       WaitableEvent::InitialState::NOT_SIGNALED);
213 
214   int watcher1_counter = 0;
215   int watcher2_counter = 0;
216 
217   int total_counter = 0;
218 
219   RunLoop run_loop;
220 
221   auto callback = [&run_loop, &total_counter](int* watcher_counter,
222                                               WaitableEvent*) {
223     ++(*watcher_counter);
224     if (++total_counter == 2) {
225       run_loop.Quit();
226     }
227   };
228 
229   WaitableEventWatcher watcher1;
230   watcher1.StartWatching(
231       &event,
232       BindOnce(BindLambdaForTesting(callback), Unretained(&watcher1_counter)),
233       SequencedTaskRunner::GetCurrentDefault());
234 
235   WaitableEventWatcher watcher2;
236   watcher2.StartWatching(
237       &event,
238       BindOnce(BindLambdaForTesting(callback), Unretained(&watcher2_counter)),
239       SequencedTaskRunner::GetCurrentDefault());
240 
241   event.Signal();
242   run_loop.Run();
243 
244   EXPECT_EQ(1, watcher1_counter);
245   EXPECT_EQ(1, watcher2_counter);
246   EXPECT_EQ(2, total_counter);
247   EXPECT_TRUE(event.IsSignaled());
248 }
249 
250 // Tests that only one async waiter gets called back for an auto-reset event.
TEST_P(WaitableEventWatcherTest,MultipleWatchersAutomatic)251 TEST_P(WaitableEventWatcherTest, MultipleWatchersAutomatic) {
252   test::TaskEnvironment task_environment(GetParam());
253 
254   WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC,
255                       WaitableEvent::InitialState::NOT_SIGNALED);
256 
257   int counter1 = 0;
258   int counter2 = 0;
259 
260   auto callback = [](RunLoop** run_loop, int* counter, WaitableEvent* event) {
261     ++(*counter);
262     (*run_loop)->QuitWhenIdle();
263   };
264 
265   // The same RunLoop instance cannot be Run more than once, and it is
266   // undefined which watcher will get called back first. Have the callback
267   // dereference this pointer to quit the loop, which will be updated on each
268   // Run.
269   RunLoop* current_run_loop;
270 
271   WaitableEventWatcher watcher1;
272   watcher1.StartWatching(
273       &event,
274       BindOnce(callback, Unretained(&current_run_loop), Unretained(&counter1)),
275       SequencedTaskRunner::GetCurrentDefault());
276 
277   WaitableEventWatcher watcher2;
278   watcher2.StartWatching(
279       &event,
280       BindOnce(callback, Unretained(&current_run_loop), Unretained(&counter2)),
281       SequencedTaskRunner::GetCurrentDefault());
282 
283   event.Signal();
284   {
285     RunLoop run_loop;
286     current_run_loop = &run_loop;
287     run_loop.Run();
288   }
289 
290   // Only one of the waiters should have been signaled.
291   EXPECT_TRUE((counter1 == 1) ^ (counter2 == 1));
292 
293   EXPECT_FALSE(event.IsSignaled());
294 
295   event.Signal();
296   {
297     RunLoop run_loop;
298     current_run_loop = &run_loop;
299     run_loop.Run();
300   }
301 
302   EXPECT_FALSE(event.IsSignaled());
303 
304   // The other watcher should have been signaled.
305   EXPECT_EQ(1, counter1);
306   EXPECT_EQ(1, counter2);
307 }
308 
309 // To help detect errors around deleting WaitableEventWatcher, an additional
310 // bool parameter is used to test sleeping between watching and deletion.
311 class WaitableEventWatcherDeletionTest
312     : public testing::TestWithParam<
313           std::tuple<test::TaskEnvironment::MainThreadType, bool>> {};
314 
TEST_P(WaitableEventWatcherDeletionTest,DeleteUnder)315 TEST_P(WaitableEventWatcherDeletionTest, DeleteUnder) {
316   auto [main_thread_type, delay_after_delete] = GetParam();
317 
318   // Delete the WaitableEvent out from under the Watcher. This is explictly
319   // allowed by the interface.
320 
321   test::TaskEnvironment task_environment(main_thread_type);
322 
323   {
324     WaitableEventWatcher watcher;
325 
326     auto* event = new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC,
327                                     WaitableEvent::InitialState::NOT_SIGNALED);
328 
329     watcher.StartWatching(event, BindOnce(&QuitWhenSignaled),
330                           SequencedTaskRunner::GetCurrentDefault());
331 
332     if (delay_after_delete) {
333       // On Windows that sleep() improves the chance to catch some problems.
334       // It postpones the dtor |watcher| (which immediately cancel the waiting)
335       // and gives some time to run to a created background thread.
336       // Unfortunately, that thread is under OS control and we can't
337       // manipulate it directly.
338       PlatformThread::Sleep(Milliseconds(30));
339     }
340 
341     delete event;
342   }
343 }
344 
TEST_P(WaitableEventWatcherDeletionTest,SignalAndDelete)345 TEST_P(WaitableEventWatcherDeletionTest, SignalAndDelete) {
346   auto [main_thread_type, delay_after_delete] = GetParam();
347 
348   // Signal and immediately delete the WaitableEvent out from under the Watcher.
349 
350   test::TaskEnvironment task_environment(main_thread_type);
351 
352   {
353     WaitableEventWatcher watcher;
354 
355     auto event = std::make_unique<WaitableEvent>(
356         WaitableEvent::ResetPolicy::AUTOMATIC,
357         WaitableEvent::InitialState::NOT_SIGNALED);
358 
359     watcher.StartWatching(event.get(), BindOnce(&QuitWhenSignaled),
360                           SequencedTaskRunner::GetCurrentDefault());
361     event->Signal();
362     event.reset();
363 
364     if (delay_after_delete) {
365       // On Windows that sleep() improves the chance to catch some problems.
366       // It postpones the dtor |watcher| (which immediately cancel the waiting)
367       // and gives some time to run to a created background thread.
368       // Unfortunately, that thread is under OS control and we can't
369       // manipulate it directly.
370       PlatformThread::Sleep(Milliseconds(30));
371     }
372 
373     // Wait for the watcher callback.
374     RunLoop().Run();
375   }
376 }
377 
378 // Tests deleting the WaitableEventWatcher between signaling the event and
379 // when the callback should be run.
TEST_P(WaitableEventWatcherDeletionTest,DeleteWatcherBeforeCallback)380 TEST_P(WaitableEventWatcherDeletionTest, DeleteWatcherBeforeCallback) {
381   auto [main_thread_type, delay_after_delete] = GetParam();
382 
383   test::TaskEnvironment task_environment(main_thread_type);
384   scoped_refptr<SingleThreadTaskRunner> task_runner =
385       SingleThreadTaskRunner::GetCurrentDefault();
386 
387   // Flag used to esnure that the |watcher_callback| never runs.
388   bool did_callback = false;
389 
390   WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC,
391                       WaitableEvent::InitialState::NOT_SIGNALED);
392   auto watcher = std::make_unique<WaitableEventWatcher>();
393 
394   // Queue up a series of tasks:
395   // 1. StartWatching the WaitableEvent
396   // 2. Signal the event (which will result in another task getting posted to
397   //    the |task_runner|)
398   // 3. Delete the WaitableEventWatcher
399   // 4. WaitableEventWatcher callback should run (from #2)
400 
401   WaitableEventWatcher::EventCallback watcher_callback = BindOnce(
402       [](bool* did_callback, WaitableEvent*) {
403         *did_callback = true;
404       },
405       Unretained(&did_callback));
406 
407   task_runner->PostTask(
408       FROM_HERE, BindOnce(IgnoreResult(&WaitableEventWatcher::StartWatching),
409                           Unretained(watcher.get()), Unretained(&event),
410                           std::move(watcher_callback), task_runner));
411   task_runner->PostTask(FROM_HERE,
412                         BindOnce(&WaitableEvent::Signal, Unretained(&event)));
413   task_runner->DeleteSoon(FROM_HERE, std::move(watcher));
414   if (delay_after_delete) {
415     task_runner->PostTask(FROM_HERE,
416                           BindOnce(&PlatformThread::Sleep, Milliseconds(30)));
417   }
418 
419   RunLoop().RunUntilIdle();
420 
421   EXPECT_FALSE(did_callback);
422 }
423 
424 INSTANTIATE_TEST_SUITE_P(All,
425                          WaitableEventWatcherTest,
426                          testing::ValuesIn(testing_main_threads));
427 
428 INSTANTIATE_TEST_SUITE_P(
429     All,
430     WaitableEventWatcherDeletionTest,
431     testing::Combine(testing::ValuesIn(testing_main_threads), testing::Bool()));
432 
433 }  // namespace base
434