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