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(¤t_run_loop), Unretained(&counter1)),
275 SequencedTaskRunner::GetCurrentDefault());
276
277 WaitableEventWatcher watcher2;
278 watcher2.StartWatching(
279 &event,
280 BindOnce(callback, Unretained(¤t_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