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.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10
11 #include "base/compiler_specific.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/time/time.h"
15 #include "build/build_config.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace base {
19
TEST(WaitableEventTest,ManualBasics)20 TEST(WaitableEventTest, ManualBasics) {
21 WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
22 WaitableEvent::InitialState::NOT_SIGNALED);
23
24 EXPECT_FALSE(event.IsSignaled());
25
26 event.Signal();
27 EXPECT_TRUE(event.IsSignaled());
28 EXPECT_TRUE(event.IsSignaled());
29
30 event.Reset();
31 EXPECT_FALSE(event.IsSignaled());
32 EXPECT_FALSE(event.TimedWait(Milliseconds(10)));
33
34 event.Signal();
35 event.Wait();
36 EXPECT_TRUE(event.TimedWait(Milliseconds(10)));
37 }
38
TEST(WaitableEventTest,ManualInitiallySignaled)39 TEST(WaitableEventTest, ManualInitiallySignaled) {
40 WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
41 WaitableEvent::InitialState::SIGNALED);
42
43 EXPECT_TRUE(event.IsSignaled());
44 EXPECT_TRUE(event.IsSignaled());
45
46 event.Reset();
47
48 EXPECT_FALSE(event.IsSignaled());
49 EXPECT_FALSE(event.IsSignaled());
50
51 event.Signal();
52
53 event.Wait();
54 EXPECT_TRUE(event.IsSignaled());
55 EXPECT_TRUE(event.IsSignaled());
56 }
57
TEST(WaitableEventTest,AutoBasics)58 TEST(WaitableEventTest, AutoBasics) {
59 WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC,
60 WaitableEvent::InitialState::NOT_SIGNALED);
61
62 EXPECT_FALSE(event.IsSignaled());
63
64 event.Signal();
65 EXPECT_TRUE(event.IsSignaled());
66 EXPECT_FALSE(event.IsSignaled());
67
68 event.Reset();
69 EXPECT_FALSE(event.IsSignaled());
70 EXPECT_FALSE(event.TimedWait(Milliseconds(10)));
71
72 event.Signal();
73 event.Wait();
74 EXPECT_FALSE(event.TimedWait(Milliseconds(10)));
75
76 event.Signal();
77 EXPECT_TRUE(event.TimedWait(Milliseconds(10)));
78 }
79
TEST(WaitableEventTest,AutoInitiallySignaled)80 TEST(WaitableEventTest, AutoInitiallySignaled) {
81 WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC,
82 WaitableEvent::InitialState::SIGNALED);
83
84 EXPECT_TRUE(event.IsSignaled());
85 EXPECT_FALSE(event.IsSignaled());
86
87 event.Signal();
88
89 EXPECT_TRUE(event.IsSignaled());
90 EXPECT_FALSE(event.IsSignaled());
91 }
92
TEST(WaitableEventTest,WaitManyShortcut)93 TEST(WaitableEventTest, WaitManyShortcut) {
94 WaitableEvent* ev[5];
95 for (auto*& i : ev) {
96 i = new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC,
97 WaitableEvent::InitialState::NOT_SIGNALED);
98 }
99
100 ev[3]->Signal();
101 EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u);
102
103 ev[3]->Signal();
104 EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u);
105
106 ev[4]->Signal();
107 EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 4u);
108
109 ev[0]->Signal();
110 EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 0u);
111
112 for (auto* i : ev)
113 delete i;
114 }
115
TEST(WaitableEventTest,WaitManyLeftToRight)116 TEST(WaitableEventTest, WaitManyLeftToRight) {
117 WaitableEvent* ev[5];
118 for (auto*& i : ev) {
119 i = new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC,
120 WaitableEvent::InitialState::NOT_SIGNALED);
121 }
122
123 // Test for consistent left-to-right return behavior across all permutations
124 // of the input array. This is to verify that only the indices -- and not
125 // the WaitableEvents' addresses -- are relevant in determining who wins when
126 // multiple events are signaled.
127
128 std::sort(ev, ev + 5);
129 do {
130 ev[0]->Signal();
131 ev[1]->Signal();
132 EXPECT_EQ(0u, WaitableEvent::WaitMany(ev, 5));
133
134 ev[2]->Signal();
135 EXPECT_EQ(1u, WaitableEvent::WaitMany(ev, 5));
136 EXPECT_EQ(2u, WaitableEvent::WaitMany(ev, 5));
137
138 ev[3]->Signal();
139 ev[4]->Signal();
140 ev[0]->Signal();
141 EXPECT_EQ(0u, WaitableEvent::WaitMany(ev, 5));
142 EXPECT_EQ(3u, WaitableEvent::WaitMany(ev, 5));
143 ev[2]->Signal();
144 EXPECT_EQ(2u, WaitableEvent::WaitMany(ev, 5));
145 EXPECT_EQ(4u, WaitableEvent::WaitMany(ev, 5));
146 } while (std::next_permutation(ev, ev + 5));
147
148 for (auto* i : ev)
149 delete i;
150 }
151
152 class WaitableEventSignaler : public PlatformThread::Delegate {
153 public:
WaitableEventSignaler(TimeDelta delay,WaitableEvent * event)154 WaitableEventSignaler(TimeDelta delay, WaitableEvent* event)
155 : delay_(delay),
156 event_(event) {
157 }
158
ThreadMain()159 void ThreadMain() override {
160 PlatformThread::Sleep(delay_);
161 event_->Signal();
162 }
163
164 private:
165 const TimeDelta delay_;
166 raw_ptr<WaitableEvent> event_;
167 };
168
169 // Tests that a WaitableEvent can be safely deleted when |Wait| is done without
170 // additional synchronization.
TEST(WaitableEventTest,WaitAndDelete)171 TEST(WaitableEventTest, WaitAndDelete) {
172 WaitableEvent* ev =
173 new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC,
174 WaitableEvent::InitialState::NOT_SIGNALED);
175
176 PlatformThreadHandle thread;
177 {
178 // Signaler can't outlive event.
179 WaitableEventSignaler signaler(Milliseconds(10), ev);
180 PlatformThread::Create(0, &signaler, &thread);
181 ev->Wait();
182 }
183 delete ev;
184
185 PlatformThread::Join(thread);
186 }
187
188 // Tests that a WaitableEvent can be safely deleted when |WaitMany| is done
189 // without additional synchronization.
TEST(WaitableEventTest,WaitMany)190 TEST(WaitableEventTest, WaitMany) {
191 WaitableEvent* ev[5];
192 for (auto*& i : ev) {
193 i = new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC,
194 WaitableEvent::InitialState::NOT_SIGNALED);
195 }
196
197 PlatformThreadHandle thread;
198 {
199 // Signaler can't outlive event.
200 WaitableEventSignaler signaler(Milliseconds(10), ev[2]);
201 PlatformThread::Create(0, &signaler, &thread);
202 size_t index = WaitableEvent::WaitMany(ev, 5);
203 EXPECT_EQ(2u, index);
204 }
205
206 for (auto* i : ev)
207 delete i;
208
209 PlatformThread::Join(thread);
210 }
211
212 // Tests that using TimeDelta::Max() on TimedWait() is not the same as passing
213 // a timeout of 0. (crbug.com/465948)
TEST(WaitableEventTest,TimedWait)214 TEST(WaitableEventTest, TimedWait) {
215 WaitableEvent* ev =
216 new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC,
217 WaitableEvent::InitialState::NOT_SIGNALED);
218
219 PlatformThreadHandle thread;
220 TimeDelta thread_delay = Milliseconds(10);
221 {
222 // Signaler can't outlive event.
223 WaitableEventSignaler signaler(thread_delay, ev);
224 TimeTicks start = TimeTicks::Now();
225 PlatformThread::Create(0, &signaler, &thread);
226 EXPECT_TRUE(ev->TimedWait(TimeDelta::Max()));
227 EXPECT_GE(TimeTicks::Now() - start, thread_delay);
228 }
229 delete ev;
230
231 PlatformThread::Join(thread);
232 }
233
234 // Tests that a sub-ms TimedWait doesn't time out promptly.
TEST(WaitableEventTest,SubMsTimedWait)235 TEST(WaitableEventTest, SubMsTimedWait) {
236 WaitableEvent ev(WaitableEvent::ResetPolicy::AUTOMATIC,
237 WaitableEvent::InitialState::NOT_SIGNALED);
238
239 TimeDelta delay = Microseconds(900);
240 TimeTicks start_time = TimeTicks::Now();
241 ev.TimedWait(delay);
242 EXPECT_GE(TimeTicks::Now() - start_time, delay);
243 }
244
245 // Tests that timeouts of zero return immediately (true if already signaled,
246 // false otherwise).
TEST(WaitableEventTest,ZeroTimeout)247 TEST(WaitableEventTest, ZeroTimeout) {
248 WaitableEvent ev;
249 TimeTicks start_time = TimeTicks::Now();
250 EXPECT_FALSE(ev.TimedWait(TimeDelta()));
251 EXPECT_LT(TimeTicks::Now() - start_time, Milliseconds(1));
252
253 ev.Signal();
254 start_time = TimeTicks::Now();
255 EXPECT_TRUE(ev.TimedWait(TimeDelta()));
256 EXPECT_LT(TimeTicks::Now() - start_time, Milliseconds(1));
257 }
258
259 // Same as ZeroTimeout for negative timeouts.
TEST(WaitableEventTest,NegativeTimeout)260 TEST(WaitableEventTest, NegativeTimeout) {
261 WaitableEvent ev;
262 TimeTicks start_time = TimeTicks::Now();
263 EXPECT_FALSE(ev.TimedWait(Milliseconds(-10)));
264 EXPECT_LT(TimeTicks::Now() - start_time, Milliseconds(1));
265
266 ev.Signal();
267 start_time = TimeTicks::Now();
268 EXPECT_TRUE(ev.TimedWait(Milliseconds(-10)));
269 EXPECT_LT(TimeTicks::Now() - start_time, Milliseconds(1));
270 }
271
272 } // namespace base
273