Commit 082df133 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

A test semaphore with no wake policy

Summary: [Folly] A test semaphore with no wake policy, and a rename of the existing test semaphore template for clarity that it has a wake policy.

Reviewed By: nbronson

Differential Revision: D15909983

fbshipit-source-id: 291566daab4838030e25fce862d42e15f2a4a8aa
parent 7851b439
......@@ -31,8 +31,6 @@
namespace folly {
namespace test {
enum class SemaphoreWakePolicy { Fifo, Lifo };
// Semaphore
//
// A basic portable semaphore, primarily intended for testing scenarios. Likely
......@@ -40,13 +38,84 @@ enum class SemaphoreWakePolicy { Fifo, Lifo };
//
// In the interest of portability, uses only synchronization mechanisms shipped
// with all implementations of C++: std::mutex and std::condition_variable.
template <SemaphoreWakePolicy WakePolicy>
class Semaphore {
public:
Semaphore() : value_(0) {}
Semaphore() {}
explicit Semaphore(std::size_t value) : value_(value) {}
bool try_wait() {
std::unique_lock<std::mutex> l{m_};
if (value_ > 0) {
--value_;
return true;
} else {
return false;
}
}
template <typename PreWait, typename PostWait>
void wait(PreWait pre_wait, PostWait post_wait) {
std::unique_lock<std::mutex> l{m_};
pre_wait();
if (value_ > 0) {
--value_;
post_wait();
} else {
++waiting_;
cv_.wait(l, [&] { return signaled_ > 0; });
--signaled_;
post_wait();
}
}
void wait() {
wait([] {}, [] {});
}
template <typename PrePost>
void post(PrePost pre_post) {
std::unique_lock<std::mutex> l{m_};
pre_post();
if (!waiting_) {
++value_;
} else {
--waiting_;
++signaled_;
cv_.notify_one();
}
}
void post() {
post([] {});
}
private:
std::size_t value_ = 0;
std::size_t waiting_ = 0;
std::size_t signaled_ = 0;
std::mutex m_;
std::condition_variable cv_;
};
enum class SemaphoreWakePolicy { Fifo, Lifo };
// PolicySemaphore
//
// A basic portable semaphore, primarily intended for testing scenarios. Likely
// to be much less performant than better-optimized semaphore implementations.
//
// Like Semaphore above, but with controlled wake order.
//
// In the interest of portability, uses only synchronization mechanisms shipped
// with all implementations of C++: std::mutex and std::condition_variable.
template <SemaphoreWakePolicy WakePolicy>
class PolicySemaphore {
public:
PolicySemaphore() {}
explicit PolicySemaphore(std::size_t value) : value_(value) {}
bool try_wait() {
std::unique_lock<std::mutex> lock{mutex_};
if (value_) {
......@@ -132,13 +201,13 @@ class Semaphore {
terminate_with<std::invalid_argument>("wake-policy");
}
std::size_t value_;
std::size_t value_ = 0;
std::mutex mutex_;
WaiterList waiters_;
};
using FifoSemaphore = Semaphore<SemaphoreWakePolicy::Fifo>;
using LifoSemaphore = Semaphore<SemaphoreWakePolicy::Lifo>;
using FifoSemaphore = PolicySemaphore<SemaphoreWakePolicy::Fifo>;
using LifoSemaphore = PolicySemaphore<SemaphoreWakePolicy::Lifo>;
} // namespace test
} // namespace folly
......@@ -50,7 +50,7 @@ class WaitForAll {
};
template <SemaphoreWakePolicy WakePolicy>
auto wake_policy(Semaphore<WakePolicy> const&) {
auto wake_policy(PolicySemaphore<WakePolicy> const&) {
return WakePolicy;
}
......@@ -177,6 +177,19 @@ void test_concurrent_split_waiters_posters() {
} // namespace
class SemaphoreTest : public testing::Test {};
TEST_F(SemaphoreTest, basic) {
test_basic<Semaphore>();
}
TEST_F(SemaphoreTest, multi_ping_pong) {
test_multi_ping_pong<Semaphore>();
}
TEST_F(SemaphoreTest, concurrent_split_waiters_posters) {
test_concurrent_split_waiters_posters<Semaphore>();
}
class FifoSemaphoreTest : public testing::Test {};
TEST_F(FifoSemaphoreTest, basic) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment