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

Futex::futexWait returns FutexResult

Summary: [Folly] `Futex::futexWait` returns `FutexResult`.

Reviewed By: nbronson

Differential Revision: D6673871

fbshipit-source-id: 378c69d8362970e985da31e31d8e9b0179d2917f
parent 8bfee85e
...@@ -52,10 +52,10 @@ struct Futex : Atom<uint32_t>, boost::noncopyable { ...@@ -52,10 +52,10 @@ struct Futex : Atom<uint32_t>, boost::noncopyable {
/** Puts the thread to sleep if this->load() == expected. Returns true when /** Puts the thread to sleep if this->load() == expected. Returns true when
* it is returning because it has consumed a wake() event, false for any * it is returning because it has consumed a wake() event, false for any
* other return (signal, this->load() != expected, or spurious wakeup). */ * other return (signal, this->load() != expected, or spurious wakeup). */
bool futexWait(uint32_t expected, uint32_t waitMask = -1) { FutexResult futexWait(uint32_t expected, uint32_t waitMask = -1) {
auto rv = futexWaitImpl(expected, nullptr, nullptr, waitMask); auto rv = futexWaitImpl(expected, nullptr, nullptr, waitMask);
assert(rv != FutexResult::TIMEDOUT); assert(rv != FutexResult::TIMEDOUT);
return rv == FutexResult::AWOKEN; return rv;
} }
/** Similar to futexWait but also accepts a deadline until when the wait call /** Similar to futexWait but also accepts a deadline until when the wait call
......
...@@ -102,7 +102,7 @@ struct MemoryIdler { ...@@ -102,7 +102,7 @@ struct MemoryIdler {
template < template <
template <typename> class Atom, template <typename> class Atom,
typename Clock = std::chrono::steady_clock> typename Clock = std::chrono::steady_clock>
static bool futexWait( static FutexResult futexWait(
Futex<Atom>& fut, Futex<Atom>& fut,
uint32_t expected, uint32_t expected,
uint32_t waitMask = -1, uint32_t waitMask = -1,
...@@ -110,7 +110,6 @@ struct MemoryIdler { ...@@ -110,7 +110,6 @@ struct MemoryIdler {
defaultIdleTimeout.load(std::memory_order_acquire), defaultIdleTimeout.load(std::memory_order_acquire),
size_t stackToRetain = kDefaultStackToRetain, size_t stackToRetain = kDefaultStackToRetain,
float timeoutVariationFrac = 0.5) { float timeoutVariationFrac = 0.5) {
if (idleTimeout == Clock::duration::max()) { if (idleTimeout == Clock::duration::max()) {
// no need to use futexWaitUntil if no timeout is possible // no need to use futexWaitUntil if no timeout is possible
return fut.futexWait(expected, waitMask); return fut.futexWait(expected, waitMask);
...@@ -128,7 +127,7 @@ struct MemoryIdler { ...@@ -128,7 +127,7 @@ struct MemoryIdler {
// finished before timeout hit, no flush // finished before timeout hit, no flush
assert(rv == FutexResult::VALUE_CHANGED || rv == FutexResult::AWOKEN || assert(rv == FutexResult::VALUE_CHANGED || rv == FutexResult::AWOKEN ||
rv == FutexResult::INTERRUPTED); rv == FutexResult::INTERRUPTED);
return rv == FutexResult::AWOKEN; return rv;
} }
} }
......
...@@ -39,14 +39,14 @@ typedef DeterministicSchedule DSched; ...@@ -39,14 +39,14 @@ typedef DeterministicSchedule DSched;
template <template <typename> class Atom> template <template <typename> class Atom>
void run_basic_thread( void run_basic_thread(
Futex<Atom>& f) { Futex<Atom>& f) {
EXPECT_TRUE(f.futexWait(0)); EXPECT_EQ(FutexResult::AWOKEN, f.futexWait(0));
} }
template <template <typename> class Atom> template <template <typename> class Atom>
void run_basic_tests() { void run_basic_tests() {
Futex<Atom> f(0); Futex<Atom> f(0);
EXPECT_FALSE(f.futexWait(1)); EXPECT_EQ(FutexResult::VALUE_CHANGED, f.futexWait(1));
EXPECT_EQ(f.futexWake(), 0); EXPECT_EQ(f.futexWake(), 0);
auto thr = DSched::thread(std::bind(run_basic_thread<Atom>, std::ref(f))); auto thr = DSched::thread(std::bind(run_basic_thread<Atom>, std::ref(f)));
...@@ -191,7 +191,8 @@ void run_wake_blocked_test() { ...@@ -191,7 +191,8 @@ void run_wake_blocked_test() {
for (auto delay = std::chrono::milliseconds(1);; delay *= 2) { for (auto delay = std::chrono::milliseconds(1);; delay *= 2) {
bool success = false; bool success = false;
Futex<Atom> f(0); Futex<Atom> f(0);
auto thr = DSched::thread([&] { success = f.futexWait(0); }); auto thr = DSched::thread(
[&] { success = FutexResult::AWOKEN == f.futexWait(0); });
/* sleep override */ std::this_thread::sleep_for(delay); /* sleep override */ std::this_thread::sleep_for(delay);
f.store(1); f.store(1);
f.futexWake(1); f.futexWake(1);
......
...@@ -95,7 +95,7 @@ namespace folly { namespace detail { ...@@ -95,7 +95,7 @@ namespace folly { namespace detail {
/// used type /// used type
template <> template <>
struct Futex<MockAtom> { struct Futex<MockAtom> {
MOCK_METHOD2(futexWait, bool(uint32_t, uint32_t)); MOCK_METHOD2(futexWait, FutexResult(uint32_t, uint32_t));
MOCK_METHOD3(futexWaitUntil, MOCK_METHOD3(futexWaitUntil,
FutexResult(uint32_t, const MockClock::time_point&, uint32_t)); FutexResult(uint32_t, const MockClock::time_point&, uint32_t));
}; };
...@@ -114,7 +114,9 @@ TEST(MemoryIdler, futexWaitValueChangedEarly) { ...@@ -114,7 +114,9 @@ TEST(MemoryIdler, futexWaitValueChangedEarly) {
EXPECT_CALL(fut, futexWaitUntil(1, AllOf(Ge(begin + idleTimeout), EXPECT_CALL(fut, futexWaitUntil(1, AllOf(Ge(begin + idleTimeout),
Lt(begin + 2 * idleTimeout)), -1)) Lt(begin + 2 * idleTimeout)), -1))
.WillOnce(Return(FutexResult::VALUE_CHANGED)); .WillOnce(Return(FutexResult::VALUE_CHANGED));
EXPECT_FALSE((MemoryIdler::futexWait<MockAtom, MockClock>(fut, 1))); EXPECT_EQ(
FutexResult::VALUE_CHANGED,
(MemoryIdler::futexWait<MockAtom, MockClock>(fut, 1)));
} }
TEST(MemoryIdler, futexWaitValueChangedLate) { TEST(MemoryIdler, futexWaitValueChangedLate) {
...@@ -129,8 +131,10 @@ TEST(MemoryIdler, futexWaitValueChangedLate) { ...@@ -129,8 +131,10 @@ TEST(MemoryIdler, futexWaitValueChangedLate) {
Lt(begin + 2 * idleTimeout)), -1)) Lt(begin + 2 * idleTimeout)), -1))
.WillOnce(Return(FutexResult::TIMEDOUT)); .WillOnce(Return(FutexResult::TIMEDOUT));
EXPECT_CALL(fut, futexWait(1, -1)) EXPECT_CALL(fut, futexWait(1, -1))
.WillOnce(Return(false)); .WillOnce(Return(FutexResult::VALUE_CHANGED));
EXPECT_FALSE((MemoryIdler::futexWait<MockAtom, MockClock>(fut, 1))); EXPECT_EQ(
FutexResult::VALUE_CHANGED,
(MemoryIdler::futexWait<MockAtom, MockClock>(fut, 1)));
} }
TEST(MemoryIdler, futexWaitAwokenEarly) { TEST(MemoryIdler, futexWaitAwokenEarly) {
...@@ -143,7 +147,9 @@ TEST(MemoryIdler, futexWaitAwokenEarly) { ...@@ -143,7 +147,9 @@ TEST(MemoryIdler, futexWaitAwokenEarly) {
.WillOnce(Return(begin)); .WillOnce(Return(begin));
EXPECT_CALL(fut, futexWaitUntil(1, Ge(begin + idleTimeout), -1)) EXPECT_CALL(fut, futexWaitUntil(1, Ge(begin + idleTimeout), -1))
.WillOnce(Return(FutexResult::AWOKEN)); .WillOnce(Return(FutexResult::AWOKEN));
EXPECT_TRUE((MemoryIdler::futexWait<MockAtom, MockClock>(fut, 1))); EXPECT_EQ(
FutexResult::AWOKEN,
(MemoryIdler::futexWait<MockAtom, MockClock>(fut, 1)));
} }
TEST(MemoryIdler, futexWaitAwokenLate) { TEST(MemoryIdler, futexWaitAwokenLate) {
...@@ -156,28 +162,31 @@ TEST(MemoryIdler, futexWaitAwokenLate) { ...@@ -156,28 +162,31 @@ TEST(MemoryIdler, futexWaitAwokenLate) {
.WillOnce(Return(begin)); .WillOnce(Return(begin));
EXPECT_CALL(fut, futexWaitUntil(1, begin + idleTimeout, -1)) EXPECT_CALL(fut, futexWaitUntil(1, begin + idleTimeout, -1))
.WillOnce(Return(FutexResult::TIMEDOUT)); .WillOnce(Return(FutexResult::TIMEDOUT));
EXPECT_CALL(fut, futexWait(1, -1)) EXPECT_CALL(fut, futexWait(1, -1)).WillOnce(Return(FutexResult::AWOKEN));
.WillOnce(Return(true)); EXPECT_EQ(
EXPECT_TRUE((MemoryIdler::futexWait<MockAtom, MockClock>( FutexResult::AWOKEN,
fut, 1, -1, idleTimeout, 100, 0.0f))); (MemoryIdler::futexWait<MockAtom, MockClock>(
fut, 1, -1, idleTimeout, 100, 0.0f)));
} }
TEST(MemoryIdler, futexWaitImmediateFlush) { TEST(MemoryIdler, futexWaitImmediateFlush) {
StrictMock<Futex<MockAtom>> fut; StrictMock<Futex<MockAtom>> fut;
auto clock = MockClock::setup(); auto clock = MockClock::setup();
EXPECT_CALL(fut, futexWait(2, 0xff)) EXPECT_CALL(fut, futexWait(2, 0xff)).WillOnce(Return(FutexResult::AWOKEN));
.WillOnce(Return(true)); EXPECT_EQ(
EXPECT_TRUE((MemoryIdler::futexWait<MockAtom, MockClock>( FutexResult::AWOKEN,
fut, 2, 0xff, std::chrono::seconds(0)))); (MemoryIdler::futexWait<MockAtom, MockClock>(
fut, 2, 0xff, std::chrono::seconds(0))));
} }
TEST(MemoryIdler, futexWaitNeverFlush) { TEST(MemoryIdler, futexWaitNeverFlush) {
StrictMock<Futex<MockAtom>> fut; StrictMock<Futex<MockAtom>> fut;
auto clock = MockClock::setup(); auto clock = MockClock::setup();
EXPECT_CALL(fut, futexWait(1, -1)) EXPECT_CALL(fut, futexWait(1, -1)).WillOnce(Return(FutexResult::AWOKEN));
.WillOnce(Return(true)); EXPECT_EQ(
EXPECT_TRUE((MemoryIdler::futexWait<MockAtom, MockClock>( FutexResult::AWOKEN,
fut, 1, -1, MockClock::duration::max()))); (MemoryIdler::futexWait<MockAtom, MockClock>(
fut, 1, -1, MockClock::duration::max())));
} }
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