#include "flutter/fml/synchronization/waitable_event.h"
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <atomic>
#include <thread>
#include <type_traits>
#include <vector>
#include "flutter/fml/macros.h"
#include "gtest/gtest.h"
namespace fml {
namespace {
constexpr TimeDelta kEpsilonTimeout = TimeDelta::FromMilliseconds(20);
constexpr TimeDelta kTinyTimeout = TimeDelta::FromMilliseconds(100);
constexpr TimeDelta kActionTimeout = TimeDelta::FromMilliseconds(10000);
void SleepFor(TimeDelta duration) {
std::this_thread::sleep_for(
std::chrono::nanoseconds(duration.ToNanoseconds()));
}
void EpsilonRandomSleep() {
TimeDelta duration =
TimeDelta::FromMilliseconds(static_cast<unsigned>(rand()) % 20u);
SleepFor(duration);
}
TEST(AutoResetWaitableEventTest, Basic) {
AutoResetWaitableEvent ev;
EXPECT_FALSE(ev.IsSignaledForTest());
ev.Signal();
EXPECT_TRUE(ev.IsSignaledForTest());
ev.Wait();
EXPECT_FALSE(ev.IsSignaledForTest());
ev.Reset();
EXPECT_FALSE(ev.IsSignaledForTest());
ev.Signal();
EXPECT_TRUE(ev.IsSignaledForTest());
ev.Reset();
EXPECT_FALSE(ev.IsSignaledForTest());
EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::Zero()));
EXPECT_FALSE(ev.IsSignaledForTest());
EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
EXPECT_FALSE(ev.IsSignaledForTest());
ev.Signal();
EXPECT_TRUE(ev.IsSignaledForTest());
EXPECT_FALSE(ev.WaitWithTimeout(TimeDelta::Zero()));
EXPECT_FALSE(ev.IsSignaledForTest());
EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
EXPECT_FALSE(ev.IsSignaledForTest());
ev.Signal();
EXPECT_FALSE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
EXPECT_FALSE(ev.IsSignaledForTest());
}
TEST(AutoResetWaitableEventTest, MultipleWaiters) {
AutoResetWaitableEvent ev;
for (size_t i = 0u; i < 5u; i++) {
std::atomic_uint wake_count(0u);
std::vector<std::thread> threads;
for (size_t j = 0u; j < 4u; j++) {
threads.push_back(std::thread([&ev, &wake_count]() {
if (rand() % 2 == 0)
ev.Wait();
else
EXPECT_FALSE(ev.WaitWithTimeout(kActionTimeout));
wake_count.fetch_add(1u);
}));
}
SleepFor(kTinyTimeout + kTinyTimeout);
for (size_t j = 0u; j < threads.size(); j++) {
unsigned old_wake_count = wake_count.load();
EXPECT_EQ(j, old_wake_count);
ev.Signal();
while (wake_count.load() == old_wake_count)
SleepFor(kEpsilonTimeout);
EXPECT_FALSE(ev.IsSignaledForTest());
SleepFor(kEpsilonTimeout);
EXPECT_EQ(old_wake_count + 1u, wake_count.load());
EXPECT_FALSE(ev.IsSignaledForTest());
}
ev.Signal();
SleepFor(kEpsilonTimeout);
EXPECT_TRUE(ev.IsSignaledForTest());
for (auto& thread : threads)
thread.join();
ev.Reset();
}
}
TEST(ManualResetWaitableEventTest, Basic) {
ManualResetWaitableEvent ev;
EXPECT_FALSE(ev.IsSignaledForTest());
ev.Signal();
EXPECT_TRUE(ev.IsSignaledForTest());
ev.Wait();
EXPECT_TRUE(ev.IsSignaledForTest());
ev.Reset();
EXPECT_FALSE(ev.IsSignaledForTest());
EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::Zero()));
EXPECT_FALSE(ev.IsSignaledForTest());
EXPECT_TRUE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
EXPECT_FALSE(ev.IsSignaledForTest());
ev.Signal();
EXPECT_TRUE(ev.IsSignaledForTest());
EXPECT_FALSE(ev.WaitWithTimeout(TimeDelta::Zero()));
EXPECT_TRUE(ev.IsSignaledForTest());
EXPECT_FALSE(ev.WaitWithTimeout(TimeDelta::FromMilliseconds(1)));
EXPECT_TRUE(ev.IsSignaledForTest());
}
TEST(ManualResetWaitableEventTest, SignalMultiple) {
ManualResetWaitableEvent ev;
for (size_t i = 0u; i < 10u; i++) {
for (size_t num_waiters = 1u; num_waiters < 5u; num_waiters++) {
std::vector<std::thread> threads;
for (size_t j = 0u; j < num_waiters; j++) {
threads.push_back(std::thread([&ev]() {
EpsilonRandomSleep();
if (rand() % 2 == 0)
ev.Wait();
else
EXPECT_FALSE(ev.WaitWithTimeout(kActionTimeout));
}));
}
EpsilonRandomSleep();
ev.Signal();
for (auto& thread : threads)
thread.join();
ev.Reset();
}
}
}
}
}