#include "base/include/fml/synchronization/waitable_event.h"
#include <cerrno>
#include <ctime>
#include "base/include/fml/time/time_delta.h"
#include "base/include/fml/time/time_point.h"
namespace lynx {
namespace fml {
template <typename ConditionFn>
bool WaitWithTimeoutImpl(std::unique_lock<std::mutex>* locker,
std::condition_variable* cv, ConditionFn condition,
TimeDelta timeout) {
if (condition()) {
return false;
}
TimeDelta wait_remaining = timeout;
TimePoint start = TimePoint::Now();
while (true) {
if (std::cv_status::timeout ==
cv->wait_for(*locker, std::chrono::nanoseconds(
wait_remaining.ToNanoseconds()))) {
return true;
}
if (condition()) {
return false;
}
TimePoint now = TimePoint::Now();
TimeDelta elapsed = now - start;
if (elapsed >= timeout) {
return true;
}
wait_remaining = timeout - elapsed;
}
}
void AutoResetWaitableEvent::Signal() {
std::scoped_lock locker(mutex_);
signaled_ = true;
cv_.notify_one();
}
void AutoResetWaitableEvent::Reset() {
std::scoped_lock locker(mutex_);
signaled_ = false;
}
void AutoResetWaitableEvent::Wait() {
std::unique_lock<std::mutex> locker(mutex_);
while (!signaled_) {
cv_.wait(locker);
}
signaled_ = false;
}
bool AutoResetWaitableEvent::WaitWithTimeout(TimeDelta timeout) {
std::unique_lock<std::mutex> locker(mutex_);
if (signaled_) {
signaled_ = false;
return false;
}
TimeDelta wait_remaining = timeout;
TimePoint start = TimePoint::Now();
while (true) {
if (std::cv_status::timeout ==
cv_.wait_for(
locker, std::chrono::nanoseconds(wait_remaining.ToNanoseconds()))) {
return true;
}
if (signaled_) {
break;
}
TimePoint now = TimePoint::Now();
TimeDelta elapsed = now - start;
if (elapsed >= timeout) {
return true;
}
wait_remaining = timeout - elapsed;
}
signaled_ = false;
return false;
}
bool AutoResetWaitableEvent::IsSignaledForTest() {
std::scoped_lock locker(mutex_);
return signaled_;
}
void ManualResetWaitableEvent::Signal() {
std::scoped_lock locker(mutex_);
signaled_ = true;
signal_id_++;
cv_.notify_all();
}
void ManualResetWaitableEvent::Reset() {
std::scoped_lock locker(mutex_);
signaled_ = false;
}
void ManualResetWaitableEvent::Wait() {
std::unique_lock<std::mutex> locker(mutex_);
if (signaled_) {
return;
}
auto last_signal_id = signal_id_;
do {
cv_.wait(locker);
} while (signal_id_ == last_signal_id);
}
bool ManualResetWaitableEvent::WaitWithTimeout(TimeDelta timeout) {
std::unique_lock<std::mutex> locker(mutex_);
auto last_signal_id = signal_id_;
bool rv = WaitWithTimeoutImpl(
&locker, &cv_,
[this, last_signal_id]() {
return signaled_ || signal_id_ != last_signal_id;
},
timeout);
return rv;
}
bool ManualResetWaitableEvent::IsSignaledForTest() {
std::scoped_lock locker(mutex_);
return signaled_;
}
}
}