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
19namespace fml {
20namespace {
21
22constexpr TimeDelta kEpsilonTimeout = TimeDelta::FromMilliseconds(20);
23constexpr TimeDelta kTinyTimeout = TimeDelta::FromMilliseconds(100);
24constexpr TimeDelta kActionTimeout = TimeDelta::FromMilliseconds(10000);
25
26// Sleeps for a "very small" amount of time.
27
28void SleepFor(TimeDelta duration) {
29 std::this_thread::sleep_for(
30 std::chrono::nanoseconds(duration.ToNanoseconds()));
31}
32
33void EpsilonRandomSleep() {
34 TimeDelta duration =
35 TimeDelta::FromMilliseconds(static_cast<unsigned>(rand()) % 20u);
36 SleepFor(duration);
37}
38
39// AutoResetWaitableEvent ------------------------------------------------------
40
41TEST(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
69TEST(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 }
82 wake_count.fetch_add(1u);
83 // Note: We can't say anything about the signaled state of |ev| here,
84 // since the main thread may have already signaled it again.
85 }));
86 }
87
88 // Unfortunately, we can't really wait for the threads to be waiting, so we
89 // just sleep for a bit, and count on them having started and advanced to
90 // waiting.
91 SleepFor(kTinyTimeout + kTinyTimeout);
92
93 for (size_t j = 0u; j < threads.size(); j++) {
94 unsigned old_wake_count = wake_count.load();
95 EXPECT_EQ(j, old_wake_count);
96
97 // Each |Signal()| should wake exactly one thread.
98 ev.Signal();
99
100 // Poll for |wake_count| to change.
101 while (wake_count.load() == old_wake_count) {
102 SleepFor(kEpsilonTimeout);
103 }
104
105 EXPECT_FALSE(ev.IsSignaledForTest());
106
107 // And once it's changed, wait a little longer, to see if any other
108 // threads are awoken (they shouldn't be).
109 SleepFor(kEpsilonTimeout);
110
111 EXPECT_EQ(old_wake_count + 1u, wake_count.load());
112
113 EXPECT_FALSE(ev.IsSignaledForTest());
114 }
115
116 // Having done that, if we signal |ev| now, it should stay signaled.
117 ev.Signal();
118 SleepFor(kEpsilonTimeout);
119 EXPECT_TRUE(ev.IsSignaledForTest());
120
121 for (auto& thread : threads) {
122 thread.join();
123 }
124
125 ev.Reset();
126 }
127}
128
129// ManualResetWaitableEvent ----------------------------------------------------
130
131TEST(ManualResetWaitableEventTest, Basic) {
132 ManualResetWaitableEvent ev;
133 EXPECT_FALSE(ev.IsSignaledForTest());
134 ev.Signal();
135 EXPECT_TRUE(ev.IsSignaledForTest());
136 ev.Wait();
137 EXPECT_TRUE(ev.IsSignaledForTest());
138 ev.Reset();
139 EXPECT_FALSE(ev.IsSignaledForTest());
140 EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::Zero()));
141 EXPECT_FALSE(ev.IsSignaledForTest());
142 EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
143 EXPECT_FALSE(ev.IsSignaledForTest());
144 ev.Signal();
145 EXPECT_TRUE(ev.IsSignaledForTest());
146 EXPECT_FALSE(ev.WaitWithTimeout(TimeDelta::Zero()));
147 EXPECT_TRUE(ev.IsSignaledForTest());
148 EXPECT_FALSE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
149 EXPECT_TRUE(ev.IsSignaledForTest());
150}
151
152TEST(ManualResetWaitableEventTest, SignalMultiple) {
153 ManualResetWaitableEvent ev;
154
155 for (size_t i = 0u; i < 10u; i++) {
156 for (size_t num_waiters = 1u; num_waiters < 5u; num_waiters++) {
157 std::vector<std::thread> threads;
158 for (size_t j = 0u; j < num_waiters; j++) {
159 threads.push_back(std::thread([&ev]() {
160 EpsilonRandomSleep();
161
162 if (rand() % 2 == 0) {
163 ev.Wait();
164 } else {
165 EXPECT_FALSE(ev.WaitWithTimeout(kActionTimeout));
166 }
167 }));
168 }
169
170 EpsilonRandomSleep();
171
172 ev.Signal();
173
174 // The threads will only terminate once they've successfully waited (or
175 // timed out).
176 for (auto& thread : threads) {
177 thread.join();
178 }
179
180 ev.Reset();
181 }
182 }
183}
184
185} // namespace
186} // namespace fml
187