/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include namespace folly { namespace detail { /** Optimal when TargetClock is the same type as Clock. * * Otherwise, both Clock::now() and TargetClock::now() must be invoked. */ template typename TargetClock::time_point time_point_conv( std::chrono::time_point const& time) { using std::chrono::duration_cast; using TimePoint = std::chrono::time_point; using TargetDuration = typename TargetClock::duration; using TargetTimePoint = typename TargetClock::time_point; if (time == TimePoint::max()) { return TargetTimePoint::max(); } else if (std::is_same::value) { // in place of time_point_cast, which cannot compile without if-constexpr auto const delta = time.time_since_epoch(); return TargetTimePoint(duration_cast(delta)); } else { // different clocks with different epochs, so non-optimal case auto const delta = time - Clock::now(); return TargetClock::now() + duration_cast(delta); } } /** * Available overloads, with definitions elsewhere * * These functions are treated as ADL-extension points, the templates above * call these functions without them having being pre-declared. This works * because ADL lookup finds the definitions of these functions when you pass * the relevant arguments */ int futexWakeImpl( const Futex* futex, int count, uint32_t wakeMask); FutexResult futexWaitImpl( const Futex* futex, uint32_t expected, std::chrono::system_clock::time_point const* absSystemTime, std::chrono::steady_clock::time_point const* absSteadyTime, uint32_t waitMask); int futexWakeImpl( const Futex* futex, int count, uint32_t wakeMask); FutexResult futexWaitImpl( const Futex* futex, uint32_t expected, std::chrono::system_clock::time_point const* absSystemTime, std::chrono::steady_clock::time_point const* absSteadyTime, uint32_t waitMask); template typename std::enable_if::type futexWaitImpl( Futex* futex, uint32_t expected, Deadline const& deadline, uint32_t waitMask) { return futexWaitImpl(futex, expected, nullptr, &deadline, waitMask); } template typename std::enable_if::type futexWaitImpl( Futex* futex, uint32_t expected, Deadline const& deadline, uint32_t waitMask) { return futexWaitImpl(futex, expected, &deadline, nullptr, waitMask); } template FutexResult futexWait(const Futex* futex, uint32_t expected, uint32_t waitMask) { auto rv = futexWaitImpl(futex, expected, nullptr, nullptr, waitMask); assert(rv != FutexResult::TIMEDOUT); return rv; } template int futexWake(const Futex* futex, int count, uint32_t wakeMask) { return futexWakeImpl(futex, count, wakeMask); } template FutexResult futexWaitUntil( const Futex* futex, uint32_t expected, std::chrono::time_point const& deadline, uint32_t waitMask) { using Target = typename std::conditional< Clock::is_steady, std::chrono::steady_clock, std::chrono::system_clock>::type; auto const converted = time_point_conv(deadline); return converted == Target::time_point::max() ? futexWaitImpl(futex, expected, nullptr, nullptr, waitMask) : futexWaitImpl(futex, expected, converted, waitMask); } } // namespace detail } // namespace folly