• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&current_run_loop), Unretained(&counter1)),
265       SequencedTaskRunnerHandle::Get());
266 
267   WaitableEventWatcher watcher2;
268   watcher2.StartWatching(
269       &event,
270       BindOnce(callback, Unretained(&current_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