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