#include <folly/coro/Baton.h>
#include <folly/experimental/coro/Coroutine.h>
#include <folly/synchronization/AtomicUtil.h>
#include <cassert>
#include <utility>
#if FOLLY_HAS_COROUTINES
using namespace folly::coro;
Baton::~Baton() {
assert(
state_.load(std::memory_order_relaxed) == static_cast<void*>(this) ||
state_.load(std::memory_order_relaxed) == nullptr);
}
void Baton::post() noexcept {
void* const signalledState = static_cast<void*>(this);
void* oldValue = state_.exchange(signalledState, std::memory_order_acq_rel);
if (oldValue != signalledState) {
WaitOperation* awaiter = static_cast<WaitOperation*>(oldValue);
while (awaiter != nullptr) {
std::exchange(awaiter, awaiter->next_)->awaitingCoroutine_.resume();
}
}
}
bool Baton::waitImpl(WaitOperation* awaiter) const noexcept {
const auto signalledState = static_cast<const void*>(this);
void* oldValue = state_.load(std::memory_order_acquire);
do {
if (oldValue == signalledState) {
return false;
}
awaiter->next_ = static_cast<WaitOperation*>(oldValue);
} while (!folly::atomic_compare_exchange_weak_explicit(
&state_,
&oldValue,
awaiter,
std::memory_order_release,
std::memory_order_acquire));
return true;
}
#endif