// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/fml/synchronization/waitable_event.h"

#include "flutter/fml/logging.h"
#include "flutter/fml/time/time_delta.h"
#include "flutter/fml/time/time_point.h"

#include <errno.h>
#include <time.h>

namespace fml {

// Waits with a timeout on |condition()|. Returns true on timeout, or false if
// |condition()| ever returns true. |condition()| should have no side effects
// (and will always be called with |*mutex| held).
template <typename ConditionFn>
bool WaitWithTimeoutImpl(std::unique_lock<std::mutex>* locker,
                         std::condition_variable* cv,
                         ConditionFn condition,
                         TimeDelta timeout) {
  FML_DCHECK(locker->owns_lock());

  if (condition()) {
    return false;
  }

  // We may get spurious wakeups.
  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;  // Definitely timed out.
    }

    // We may have been awoken.
    if (condition()) {
      return false;
    }

    // Or the wakeup may have been spurious.
    TimePoint now = TimePoint::Now();
    FML_DCHECK(now >= start);
    TimeDelta elapsed = now - start;
    // It's possible that we may have timed out anyway.
    if (elapsed >= timeout) {
      return true;
    }

    // Otherwise, recalculate the amount that we have left to wait.
    wait_remaining = timeout - elapsed;
  }
}

// AutoResetWaitableEvent ------------------------------------------------------

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;
  }

  // We may get spurious wakeups.
  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;  // Definitely timed out.
    }

    // We may have been awoken.
    if (signaled_) {
      break;
    }

    // Or the wakeup may have been spurious.
    TimePoint now = TimePoint::Now();
    FML_DCHECK(now >= start);
    TimeDelta elapsed = now - start;
    // It's possible that we may have timed out anyway.
    if (elapsed >= timeout) {
      return true;
    }

    // Otherwise, recalculate the amount that we have left to wait.
    wait_remaining = timeout - elapsed;
  }

  signaled_ = false;
  return false;
}

bool AutoResetWaitableEvent::IsSignaledForTest() {
  std::scoped_lock locker(mutex_);
  return signaled_;
}

// ManualResetWaitableEvent ----------------------------------------------------

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_;
  // Disable thread-safety analysis for the lambda: We could annotate it with
  // |FML_EXCLUSIVE_LOCKS_REQUIRED(mutex_)|, but then the analyzer currently
  // isn't able to figure out that |WaitWithTimeoutImpl()| calls it while
  // holding |mutex_|.
  bool rv = WaitWithTimeoutImpl(
      &locker, &cv_,
      [this, last_signal_id]() {
        // Also check |signaled_| in case we're already signaled.
        return signaled_ || signal_id_ != last_signal_id;
      },
      timeout);
  FML_DCHECK(rv || signaled_ || signal_id_ != last_signal_id);
  return rv;
}

bool ManualResetWaitableEvent::IsSignaledForTest() {
  std::scoped_lock locker(mutex_);
  return signaled_;
}

}  // namespace fml
