#include <folly/coro/Mutex.h>
#include <cassert>
#if FOLLY_HAS_COROUTINES
using namespace folly::coro;
Mutex::~Mutex() {
assert(
state_.load(std::memory_order_relaxed) == unlockedState() ||
state_.load(std::memory_order_relaxed) == nullptr);
assert(waiters_ == nullptr);
}
void Mutex::unlock() noexcept {
assert(state_.load(std::memory_order_relaxed) != unlockedState());
auto* waitersHead = waiters_;
if (waitersHead == nullptr) {
void* currentState = state_.load(std::memory_order_relaxed);
if (currentState == nullptr) {
const bool releasedLock = state_.compare_exchange_strong(
currentState,
unlockedState(),
std::memory_order_release,
std::memory_order_relaxed);
if (releasedLock) {
return;
}
}
currentState = state_.exchange(nullptr, std::memory_order_acquire);
assert(currentState != unlockedState());
assert(currentState != nullptr);
auto* waiter = static_cast<LockAwaiter*>(currentState);
do {
auto* temp = waiter->next_;
waiter->next_ = waitersHead;
waitersHead = waiter;
waiter = temp;
} while (waiter != nullptr);
}
assert(waitersHead != nullptr);
waiters_ = waitersHead->next_;
waitersHead->awaitingCoroutine_.resume();
}
bool Mutex::lockAsyncImpl(LockAwaiter* awaiter) {
void* oldValue = state_.load(std::memory_order_relaxed);
while (true) {
if (oldValue == unlockedState()) {
void* newValue = nullptr;
if (state_.compare_exchange_weak(
oldValue,
newValue,
std::memory_order_acquire,
std::memory_order_relaxed)) {
return false;
}
} else {
void* newValue = awaiter;
awaiter->next_ = static_cast<LockAwaiter*>(oldValue);
if (state_.compare_exchange_weak(
oldValue,
newValue,
std::memory_order_release,
std::memory_order_relaxed)) {
return true;
}
}
}
}
#endif