/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
#pragma once
+#include <mutex>
+
namespace folly {
namespace fibers {
template <typename WaitFunc>
TimedMutex::LockResult TimedMutex::lockHelper(WaitFunc&& waitFunc) {
- std::unique_lock<folly::SpinLock> lock(lock_);
+ std::unique_lock<folly::SpinLock> ulock(lock_);
if (!locked_) {
locked_ = true;
return LockResult::SUCCESS;
threadWaiters_.push_back(waiter);
}
- lock.unlock();
+ ulock.unlock();
if (!waitFunc(waiter)) {
return LockResult::TIMEOUT;
std::lock_guard<folly::SpinLock> lg(lock_);
auto stolen = notifiedFiber_ != &waiter;
- notifiedFiber_ = nullptr;
+ if (!stolen) {
+ notifiedFiber_ = nullptr;
+ }
return stolen;
}();
bool TimedMutex::timed_lock(
const std::chrono::duration<Rep, Period>& duration) {
auto result = lockHelper([&](MutexWaiter& waiter) {
- if (!waiter.baton.timed_wait(duration)) {
+ if (!waiter.baton.try_wait_for(duration)) {
// We timed out. Two cases:
// 1. We're still in the waiter list and we truly timed out
// 2. We're not in the waiter list anymore. This could happen if the baton
template <typename BatonType>
void TimedRWMutex<BatonType>::read_lock() {
- pthread_spin_lock(&lock_);
+ std::unique_lock<folly::SpinLock> ulock{lock_};
if (state_ == State::WRITE_LOCKED) {
MutexWaiter waiter;
read_waiters_.push_back(waiter);
- pthread_spin_unlock(&lock_);
+ ulock.unlock();
waiter.baton.wait();
assert(state_ == State::READ_LOCKED);
return;
assert(read_waiters_.empty());
state_ = State::READ_LOCKED;
readers_ += 1;
- pthread_spin_unlock(&lock_);
}
template <typename BatonType>
template <typename Rep, typename Period>
bool TimedRWMutex<BatonType>::timed_read_lock(
const std::chrono::duration<Rep, Period>& duration) {
- pthread_spin_lock(&lock_);
+ std::unique_lock<folly::SpinLock> ulock{lock_};
if (state_ == State::WRITE_LOCKED) {
MutexWaiter waiter;
read_waiters_.push_back(waiter);
- pthread_spin_unlock(&lock_);
+ ulock.unlock();
- if (!waiter.baton.timed_wait(duration)) {
+ if (!waiter.baton.try_wait_for(duration)) {
// We timed out. Two cases:
// 1. We're still in the waiter list and we truly timed out
// 2. We're not in the waiter list anymore. This could happen if the baton
// times out but the mutex is unlocked before we reach this code. In
// this case we'll pretend we got the lock on time.
- pthread_spin_lock(&lock_);
+ std::lock_guard<SpinLock> guard{lock_};
if (waiter.hook.is_linked()) {
read_waiters_.erase(read_waiters_.iterator_to(waiter));
- pthread_spin_unlock(&lock_);
return false;
}
- pthread_spin_unlock(&lock_);
}
return true;
}
assert(read_waiters_.empty());
state_ = State::READ_LOCKED;
readers_ += 1;
- pthread_spin_unlock(&lock_);
return true;
}
template <typename BatonType>
bool TimedRWMutex<BatonType>::try_read_lock() {
- pthread_spin_lock(&lock_);
+ std::lock_guard<SpinLock> guard{lock_};
if (state_ != State::WRITE_LOCKED) {
assert(
(state_ == State::UNLOCKED && readers_ == 0) ||
assert(read_waiters_.empty());
state_ = State::READ_LOCKED;
readers_ += 1;
- pthread_spin_unlock(&lock_);
return true;
}
- pthread_spin_unlock(&lock_);
return false;
}
template <typename BatonType>
void TimedRWMutex<BatonType>::write_lock() {
- pthread_spin_lock(&lock_);
+ std::unique_lock<folly::SpinLock> ulock{lock_};
if (state_ == State::UNLOCKED) {
verify_unlocked_properties();
state_ = State::WRITE_LOCKED;
- pthread_spin_unlock(&lock_);
return;
}
MutexWaiter waiter;
write_waiters_.push_back(waiter);
- pthread_spin_unlock(&lock_);
+ ulock.unlock();
waiter.baton.wait();
}
template <typename Rep, typename Period>
bool TimedRWMutex<BatonType>::timed_write_lock(
const std::chrono::duration<Rep, Period>& duration) {
- pthread_spin_lock(&lock_);
+ std::unique_lock<folly::SpinLock> ulock{lock_};
if (state_ == State::UNLOCKED) {
verify_unlocked_properties();
state_ = State::WRITE_LOCKED;
- pthread_spin_unlock(&lock_);
return true;
}
MutexWaiter waiter;
write_waiters_.push_back(waiter);
- pthread_spin_unlock(&lock_);
+ ulock.unlock();
- if (!waiter.baton.timed_wait(duration)) {
+ if (!waiter.baton.try_wait_for(duration)) {
// We timed out. Two cases:
// 1. We're still in the waiter list and we truly timed out
// 2. We're not in the waiter list anymore. This could happen if the baton
// times out but the mutex is unlocked before we reach this code. In
// this case we'll pretend we got the lock on time.
- pthread_spin_lock(&lock_);
+ std::lock_guard<SpinLock> guard{lock_};
if (waiter.hook.is_linked()) {
write_waiters_.erase(write_waiters_.iterator_to(waiter));
- pthread_spin_unlock(&lock_);
return false;
}
- pthread_spin_unlock(&lock_);
}
assert(state_ == State::WRITE_LOCKED);
return true;
template <typename BatonType>
bool TimedRWMutex<BatonType>::try_write_lock() {
- pthread_spin_lock(&lock_);
+ std::lock_guard<SpinLock> guard{lock_};
if (state_ == State::UNLOCKED) {
verify_unlocked_properties();
state_ = State::WRITE_LOCKED;
- pthread_spin_unlock(&lock_);
return true;
}
- pthread_spin_unlock(&lock_);
return false;
}
template <typename BatonType>
void TimedRWMutex<BatonType>::unlock() {
- pthread_spin_lock(&lock_);
+ std::lock_guard<SpinLock> guard{lock_};
assert(state_ != State::UNLOCKED);
assert(
(state_ == State::READ_LOCKED && readers_ > 0) ||
} else {
assert(state_ == State::READ_LOCKED);
}
- pthread_spin_unlock(&lock_);
}
template <typename BatonType>
void TimedRWMutex<BatonType>::downgrade() {
- pthread_spin_lock(&lock_);
+ std::lock_guard<SpinLock> guard{lock_};
assert(state_ == State::WRITE_LOCKED && readers_ == 0);
state_ = State::READ_LOCKED;
readers_ += 1;
to_wake.baton.post();
}
}
- pthread_spin_unlock(&lock_);
-}
-}
}
+} // namespace fibers
+} // namespace folly