/** 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
* other return (signal, this->load() != expected, or spurious wakeup). */
/** 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
* 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);
assert(rv != FutexResult::TIMEDOUT);
auto rv = futexWaitImpl(expected, nullptr, nullptr, waitMask);
assert(rv != FutexResult::TIMEDOUT);
- return rv == FutexResult::AWOKEN;
}
/** 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
template <
template <typename> class Atom,
typename Clock = std::chrono::steady_clock>
template <
template <typename> class Atom,
typename Clock = std::chrono::steady_clock>
+ static FutexResult futexWait(
Futex<Atom>& fut,
uint32_t expected,
uint32_t waitMask = -1,
Futex<Atom>& fut,
uint32_t expected,
uint32_t waitMask = -1,
defaultIdleTimeout.load(std::memory_order_acquire),
size_t stackToRetain = kDefaultStackToRetain,
float timeoutVariationFrac = 0.5) {
defaultIdleTimeout.load(std::memory_order_acquire),
size_t stackToRetain = kDefaultStackToRetain,
float timeoutVariationFrac = 0.5) {
if (idleTimeout == Clock::duration::max()) {
// no need to use futexWaitUntil if no timeout is possible
return fut.futexWait(expected, waitMask);
if (idleTimeout == Clock::duration::max()) {
// no need to use futexWaitUntil if no timeout is possible
return fut.futexWait(expected, waitMask);
// finished before timeout hit, no flush
assert(rv == FutexResult::VALUE_CHANGED || rv == FutexResult::AWOKEN ||
rv == FutexResult::INTERRUPTED);
// finished before timeout hit, no flush
assert(rv == FutexResult::VALUE_CHANGED || rv == FutexResult::AWOKEN ||
rv == FutexResult::INTERRUPTED);
- return rv == FutexResult::AWOKEN;
template <template <typename> class Atom>
void run_basic_thread(
Futex<Atom>& f) {
template <template <typename> class Atom>
void run_basic_thread(
Futex<Atom>& f) {
- EXPECT_TRUE(f.futexWait(0));
+ EXPECT_EQ(FutexResult::AWOKEN, f.futexWait(0));
}
template <template <typename> class Atom>
void run_basic_tests() {
Futex<Atom> f(0);
}
template <template <typename> class Atom>
void run_basic_tests() {
Futex<Atom> f(0);
- EXPECT_FALSE(f.futexWait(1));
+ EXPECT_EQ(FutexResult::VALUE_CHANGED, f.futexWait(1));
EXPECT_EQ(f.futexWake(), 0);
auto thr = DSched::thread(std::bind(run_basic_thread<Atom>, std::ref(f)));
EXPECT_EQ(f.futexWake(), 0);
auto thr = DSched::thread(std::bind(run_basic_thread<Atom>, std::ref(f)));
for (auto delay = std::chrono::milliseconds(1);; delay *= 2) {
bool success = false;
Futex<Atom> f(0);
for (auto delay = std::chrono::milliseconds(1);; delay *= 2) {
bool success = false;
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);
f.store(1);
f.futexWake(1);
/* sleep override */ std::this_thread::sleep_for(delay);
f.store(1);
f.futexWake(1);
/// used type
template <>
struct Futex<MockAtom> {
/// used type
template <>
struct Futex<MockAtom> {
- MOCK_METHOD2(futexWait, bool(uint32_t, uint32_t));
+ MOCK_METHOD2(futexWait, FutexResult(uint32_t, uint32_t));
MOCK_METHOD3(futexWaitUntil,
FutexResult(uint32_t, const MockClock::time_point&, uint32_t));
};
MOCK_METHOD3(futexWaitUntil,
FutexResult(uint32_t, const MockClock::time_point&, uint32_t));
};
EXPECT_CALL(fut, futexWaitUntil(1, AllOf(Ge(begin + idleTimeout),
Lt(begin + 2 * idleTimeout)), -1))
.WillOnce(Return(FutexResult::VALUE_CHANGED));
EXPECT_CALL(fut, futexWaitUntil(1, AllOf(Ge(begin + idleTimeout),
Lt(begin + 2 * idleTimeout)), -1))
.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) {
Lt(begin + 2 * idleTimeout)), -1))
.WillOnce(Return(FutexResult::TIMEDOUT));
EXPECT_CALL(fut, futexWait(1, -1))
Lt(begin + 2 * idleTimeout)), -1))
.WillOnce(Return(FutexResult::TIMEDOUT));
EXPECT_CALL(fut, futexWait(1, -1))
- .WillOnce(Return(false));
- EXPECT_FALSE((MemoryIdler::futexWait<MockAtom, MockClock>(fut, 1)));
+ .WillOnce(Return(FutexResult::VALUE_CHANGED));
+ EXPECT_EQ(
+ FutexResult::VALUE_CHANGED,
+ (MemoryIdler::futexWait<MockAtom, MockClock>(fut, 1)));
}
TEST(MemoryIdler, futexWaitAwokenEarly) {
}
TEST(MemoryIdler, futexWaitAwokenEarly) {
.WillOnce(Return(begin));
EXPECT_CALL(fut, futexWaitUntil(1, Ge(begin + idleTimeout), -1))
.WillOnce(Return(FutexResult::AWOKEN));
.WillOnce(Return(begin));
EXPECT_CALL(fut, futexWaitUntil(1, Ge(begin + idleTimeout), -1))
.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) {
.WillOnce(Return(begin));
EXPECT_CALL(fut, futexWaitUntil(1, begin + idleTimeout, -1))
.WillOnce(Return(FutexResult::TIMEDOUT));
.WillOnce(Return(begin));
EXPECT_CALL(fut, futexWaitUntil(1, begin + idleTimeout, -1))
.WillOnce(Return(FutexResult::TIMEDOUT));
- EXPECT_CALL(fut, futexWait(1, -1))
- .WillOnce(Return(true));
- EXPECT_TRUE((MemoryIdler::futexWait<MockAtom, MockClock>(
- fut, 1, -1, idleTimeout, 100, 0.0f)));
+ EXPECT_CALL(fut, futexWait(1, -1)).WillOnce(Return(FutexResult::AWOKEN));
+ EXPECT_EQ(
+ FutexResult::AWOKEN,
+ (MemoryIdler::futexWait<MockAtom, MockClock>(
+ fut, 1, -1, idleTimeout, 100, 0.0f)));
}
TEST(MemoryIdler, futexWaitImmediateFlush) {
StrictMock<Futex<MockAtom>> fut;
auto clock = MockClock::setup();
}
TEST(MemoryIdler, futexWaitImmediateFlush) {
StrictMock<Futex<MockAtom>> fut;
auto clock = MockClock::setup();
- EXPECT_CALL(fut, futexWait(2, 0xff))
- .WillOnce(Return(true));
- EXPECT_TRUE((MemoryIdler::futexWait<MockAtom, MockClock>(
- fut, 2, 0xff, std::chrono::seconds(0))));
+ EXPECT_CALL(fut, futexWait(2, 0xff)).WillOnce(Return(FutexResult::AWOKEN));
+ EXPECT_EQ(
+ FutexResult::AWOKEN,
+ (MemoryIdler::futexWait<MockAtom, MockClock>(
+ fut, 2, 0xff, std::chrono::seconds(0))));
}
TEST(MemoryIdler, futexWaitNeverFlush) {
StrictMock<Futex<MockAtom>> fut;
auto clock = MockClock::setup();
}
TEST(MemoryIdler, futexWaitNeverFlush) {
StrictMock<Futex<MockAtom>> fut;
auto clock = MockClock::setup();
- EXPECT_CALL(fut, futexWait(1, -1))
- .WillOnce(Return(true));
- EXPECT_TRUE((MemoryIdler::futexWait<MockAtom, MockClock>(
- fut, 1, -1, MockClock::duration::max())));
+ EXPECT_CALL(fut, futexWait(1, -1)).WillOnce(Return(FutexResult::AWOKEN));
+ EXPECT_EQ(
+ FutexResult::AWOKEN,
+ (MemoryIdler::futexWait<MockAtom, MockClock>(
+ fut, 1, -1, MockClock::duration::max())));