#include <folly/detail/Futex.h>
#include <array>
#include <cerrno>
#include <cstdint>
#include <cstring>
#include <folly/ScopeGuard.h>
#include <folly/hash/Hash.h>
#include <folly/portability/SysSyscall.h>
#include <folly/synchronization/ParkingLot.h>
#ifdef __linux__
#include <linux/futex.h>
#endif
usingnamespacestd::chrono;
namespace folly {
namespace detail {
namespace {
#ifdef __linux__
#ifndef FUTEX_WAIT_BITSET
#define FUTEX_WAIT_BITSET …
#endif
#ifndef FUTEX_WAKE_BITSET
#define FUTEX_WAKE_BITSET …
#endif
#ifndef FUTEX_PRIVATE_FLAG
#define FUTEX_PRIVATE_FLAG …
#endif
#ifndef FUTEX_CLOCK_REALTIME
#define FUTEX_CLOCK_REALTIME …
#endif
int nativeFutexWake(const void* addr, int count, uint32_t wakeMask) {
int rv = syscall(
__NR_futex,
addr,
FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG,
count,
nullptr,
nullptr,
wakeMask);
if (rv < 0) {
return 0;
}
return rv;
}
template <class Clock>
struct timespec timeSpecFromTimePoint(time_point<Clock> absTime) {
auto epoch = absTime.time_since_epoch();
if (epoch.count() < 0) {
epoch = Clock::duration::zero();
}
using time_t_seconds = duration<std::time_t, seconds::period>;
using long_nanos = duration<long int, nanoseconds::period>;
auto secs = duration_cast<time_t_seconds>(epoch);
auto nanos = duration_cast<long_nanos>(epoch - secs);
struct timespec result = {secs.count(), nanos.count()};
return result;
}
FutexResult nativeFutexWaitImpl(
const void* addr,
uint32_t expected,
system_clock::time_point const* absSystemTime,
steady_clock::time_point const* absSteadyTime,
uint32_t waitMask) {
assert(absSystemTime == nullptr || absSteadyTime == nullptr);
int op = FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG;
struct timespec ts;
struct timespec* timeout = nullptr;
if (absSystemTime != nullptr) {
op |= FUTEX_CLOCK_REALTIME;
ts = timeSpecFromTimePoint(*absSystemTime);
timeout = &ts;
} else if (absSteadyTime != nullptr) {
ts = timeSpecFromTimePoint(*absSteadyTime);
timeout = &ts;
}
int rv = syscall(
__NR_futex,
addr,
op,
expected,
timeout,
nullptr,
waitMask);
if (rv == 0) {
return FutexResult::AWOKEN;
} else {
switch (errno) {
case ETIMEDOUT:
assert(timeout != nullptr);
return FutexResult::TIMEDOUT;
case EINTR:
return FutexResult::INTERRUPTED;
case EWOULDBLOCK:
return FutexResult::VALUE_CHANGED;
default:
assert(false);
return FutexResult::VALUE_CHANGED;
}
}
}
#endif
Lot;
Lot parkingLot;
int emulatedFutexWake(const void* addr, int count, uint32_t waitMask) { … }
template <typename F>
FutexResult emulatedFutexWaitImpl(
F* futex,
uint32_t expected,
system_clock::time_point const* absSystemTime,
steady_clock::time_point const* absSteadyTime,
uint32_t waitMask) { … }
}
int futexWakeImpl(
const Futex<std::atomic>* futex, int count, uint32_t wakeMask) { … }
int futexWakeImpl(
const Futex<EmulatedFutexAtomic>* futex, int count, uint32_t wakeMask) { … }
FutexResult futexWaitImpl(
const Futex<std::atomic>* futex,
uint32_t expected,
system_clock::time_point const* absSystemTime,
steady_clock::time_point const* absSteadyTime,
uint32_t waitMask) { … }
FutexResult futexWaitImpl(
const Futex<EmulatedFutexAtomic>* futex,
uint32_t expected,
system_clock::time_point const* absSystemTime,
steady_clock::time_point const* absSteadyTime,
uint32_t waitMask) { … }
}
}