• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter 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 "flutter/fml/synchronization/waitable_event.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 
11 #include <atomic>
12 #include <thread>
13 #include <type_traits>
14 #include <vector>
15 
16 #include "flutter/fml/macros.h"
17 #include "gtest/gtest.h"
18 
19 namespace fml {
20 namespace {
21 
22 constexpr TimeDelta kEpsilonTimeout = TimeDelta::FromMilliseconds(20);
23 constexpr TimeDelta kTinyTimeout = TimeDelta::FromMilliseconds(100);
24 constexpr TimeDelta kActionTimeout = TimeDelta::FromMilliseconds(10000);
25 
26 // Sleeps for a "very small" amount of time.
27 
SleepFor(TimeDelta duration)28 void SleepFor(TimeDelta duration) {
29   std::this_thread::sleep_for(
30       std::chrono::nanoseconds(duration.ToNanoseconds()));
31 }
32 
EpsilonRandomSleep()33 void EpsilonRandomSleep() {
34   TimeDelta duration =
35       TimeDelta::FromMilliseconds(static_cast<unsigned>(rand()) % 20u);
36   SleepFor(duration);
37 }
38 
39 // AutoResetWaitableEvent ------------------------------------------------------
40 
TEST(AutoResetWaitableEventTest,Basic)41 TEST(AutoResetWaitableEventTest, Basic) {
42   AutoResetWaitableEvent ev;
43   EXPECT_FALSE(ev.IsSignaledForTest());
44   ev.Signal();
45   EXPECT_TRUE(ev.IsSignaledForTest());
46   ev.Wait();
47   EXPECT_FALSE(ev.IsSignaledForTest());
48   ev.Reset();
49   EXPECT_FALSE(ev.IsSignaledForTest());
50   ev.Signal();
51   EXPECT_TRUE(ev.IsSignaledForTest());
52   ev.Reset();
53   EXPECT_FALSE(ev.IsSignaledForTest());
54   EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::Zero()));
55   EXPECT_FALSE(ev.IsSignaledForTest());
56   EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
57   EXPECT_FALSE(ev.IsSignaledForTest());
58   ev.Signal();
59   EXPECT_TRUE(ev.IsSignaledForTest());
60   EXPECT_FALSE(ev.WaitWithTimeout(TimeDelta::Zero()));
61   EXPECT_FALSE(ev.IsSignaledForTest());
62   EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
63   EXPECT_FALSE(ev.IsSignaledForTest());
64   ev.Signal();
65   EXPECT_FALSE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
66   EXPECT_FALSE(ev.IsSignaledForTest());
67 }
68 
TEST(AutoResetWaitableEventTest,MultipleWaiters)69 TEST(AutoResetWaitableEventTest, MultipleWaiters) {
70   AutoResetWaitableEvent ev;
71 
72   for (size_t i = 0u; i < 5u; i++) {
73     std::atomic_uint wake_count(0u);
74     std::vector<std::thread> threads;
75     for (size_t j = 0u; j < 4u; j++) {
76       threads.push_back(std::thread([&ev, &wake_count]() {
77         if (rand() % 2 == 0)
78           ev.Wait();
79         else
80           EXPECT_FALSE(ev.WaitWithTimeout(kActionTimeout));
81         wake_count.fetch_add(1u);
82         // Note: We can't say anything about the signaled state of |ev| here,
83         // since the main thread may have already signaled it again.
84       }));
85     }
86 
87     // Unfortunately, we can't really wait for the threads to be waiting, so we
88     // just sleep for a bit, and count on them having started and advanced to
89     // waiting.
90     SleepFor(kTinyTimeout + kTinyTimeout);
91 
92     for (size_t j = 0u; j < threads.size(); j++) {
93       unsigned old_wake_count = wake_count.load();
94       EXPECT_EQ(j, old_wake_count);
95 
96       // Each |Signal()| should wake exactly one thread.
97       ev.Signal();
98 
99       // Poll for |wake_count| to change.
100       while (wake_count.load() == old_wake_count)
101         SleepFor(kEpsilonTimeout);
102 
103       EXPECT_FALSE(ev.IsSignaledForTest());
104 
105       // And once it's changed, wait a little longer, to see if any other
106       // threads are awoken (they shouldn't be).
107       SleepFor(kEpsilonTimeout);
108 
109       EXPECT_EQ(old_wake_count + 1u, wake_count.load());
110 
111       EXPECT_FALSE(ev.IsSignaledForTest());
112     }
113 
114     // Having done that, if we signal |ev| now, it should stay signaled.
115     ev.Signal();
116     SleepFor(kEpsilonTimeout);
117     EXPECT_TRUE(ev.IsSignaledForTest());
118 
119     for (auto& thread : threads)
120       thread.join();
121 
122     ev.Reset();
123   }
124 }
125 
126 // ManualResetWaitableEvent ----------------------------------------------------
127 
TEST(ManualResetWaitableEventTest,Basic)128 TEST(ManualResetWaitableEventTest, Basic) {
129   ManualResetWaitableEvent ev;
130   EXPECT_FALSE(ev.IsSignaledForTest());
131   ev.Signal();
132   EXPECT_TRUE(ev.IsSignaledForTest());
133   ev.Wait();
134   EXPECT_TRUE(ev.IsSignaledForTest());
135   ev.Reset();
136   EXPECT_FALSE(ev.IsSignaledForTest());
137   EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::Zero()));
138   EXPECT_FALSE(ev.IsSignaledForTest());
139   EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
140   EXPECT_FALSE(ev.IsSignaledForTest());
141   ev.Signal();
142   EXPECT_TRUE(ev.IsSignaledForTest());
143   EXPECT_FALSE(ev.WaitWithTimeout(TimeDelta::Zero()));
144   EXPECT_TRUE(ev.IsSignaledForTest());
145   EXPECT_FALSE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
146   EXPECT_TRUE(ev.IsSignaledForTest());
147 }
148 
TEST(ManualResetWaitableEventTest,SignalMultiple)149 TEST(ManualResetWaitableEventTest, SignalMultiple) {
150   ManualResetWaitableEvent ev;
151 
152   for (size_t i = 0u; i < 10u; i++) {
153     for (size_t num_waiters = 1u; num_waiters < 5u; num_waiters++) {
154       std::vector<std::thread> threads;
155       for (size_t j = 0u; j < num_waiters; j++) {
156         threads.push_back(std::thread([&ev]() {
157           EpsilonRandomSleep();
158 
159           if (rand() % 2 == 0)
160             ev.Wait();
161           else
162             EXPECT_FALSE(ev.WaitWithTimeout(kActionTimeout));
163         }));
164       }
165 
166       EpsilonRandomSleep();
167 
168       ev.Signal();
169 
170       // The threads will only terminate once they've successfully waited (or
171       // timed out).
172       for (auto& thread : threads)
173         thread.join();
174 
175       ev.Reset();
176     }
177   }
178 }
179 
180 }  // namespace
181 }  // namespace fml
182