Commit 8477e256 authored by Aaryaman Sagar's avatar Aaryaman Sagar Committed by Facebook GitHub Bot

Explicitly qualify atomic_wait and atomic_notify function calls

Summary:
`std::atomic_wait()` and `std::atomic_notify_one()` are marked as unavailable.
Not really sure what that means, but it seems to be breaking some open source
builds https://github.com/facebook/folly/issues/1527.  Explicitly qualify the
calls into those functions to try and fix the build break.

Since we cannot conditionally import either of the above (because they are
marked as unavailable), we can't rely on the standard implementations.  To
prevent ADL from kicking in when the standard-library defines these, we fully
qualify these and use `tag_invoke` for the customization points used in tests.

Reviewed By: davidtgoldblatt

Differential Revision: D26742072

fbshipit-source-id: 9f44bbfd37530f5ecffa3e03d673cfb1df953299
parent 89a3d4a7
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
namespace folly { namespace folly {
// Using 'auto' for non-type template parameters is only possible from C++17 // Using 'auto' for non-type template parameters is only possible from C++17
#if __cplusplus >= 201703L #if FOLLY_CPLUSPLUS >= 201703L
// cpo_t<CPO> // cpo_t<CPO>
// //
...@@ -71,6 +71,6 @@ namespace folly { ...@@ -71,6 +71,6 @@ namespace folly {
template <const auto& Tag> template <const auto& Tag>
using cpo_t = std::decay_t<decltype(Tag)>; using cpo_t = std::decay_t<decltype(Tag)>;
#endif // __cplusplus >= 201703L #endif // FOLLY_CPLUSPLUS >= 201703L
} // namespace folly } // namespace folly
...@@ -16,9 +16,6 @@ ...@@ -16,9 +16,6 @@
#pragma once #pragma once
#include <condition_variable>
#include <cstdint>
#include <folly/detail/Futex.h> #include <folly/detail/Futex.h>
#include <folly/synchronization/ParkingLot.h> #include <folly/synchronization/ParkingLot.h>
...@@ -120,31 +117,31 @@ void atomic_notify_all_impl(const Atom<Integer, Args...>* atomic) { ...@@ -120,31 +117,31 @@ void atomic_notify_all_impl(const Atom<Integer, Args...>* atomic) {
return UnparkControl::RemoveContinue; return UnparkControl::RemoveContinue;
}); });
} }
} // namespace atomic_notification
} // namespace detail
template <typename Integer> template <typename Integer>
void atomic_wait(const std::atomic<Integer>* atomic, Integer expected) { void tag_invoke(
detail::atomic_notification::atomic_wait_impl(atomic, expected); atomic_wait_fn, const std::atomic<Integer>* atomic, Integer expected) {
atomic_wait_impl(atomic, expected);
} }
template <typename Integer, typename Clock, typename Duration> template <typename Integer, typename Clock, typename Duration>
std::cv_status atomic_wait_until( std::cv_status tag_invoke(
atomic_wait_until_fn,
const std::atomic<Integer>* atomic, const std::atomic<Integer>* atomic,
Integer expected, Integer expected,
const std::chrono::time_point<Clock, Duration>& deadline) { const std::chrono::time_point<Clock, Duration>& deadline) {
return detail::atomic_notification::atomic_wait_until_impl( return atomic_wait_until_impl(atomic, expected, deadline);
atomic, expected, deadline);
} }
template <typename Integer> template <typename Integer>
void atomic_notify_one(const std::atomic<Integer>* atomic) { void tag_invoke(atomic_notify_one_fn, const std::atomic<Integer>* atomic) {
detail::atomic_notification::atomic_notify_one_impl(atomic); atomic_notify_one_impl(atomic);
} }
template <typename Integer> template <typename Integer>
void atomic_notify_all(const std::atomic<Integer>* atomic) { void tag_invoke(atomic_notify_all_fn, const std::atomic<Integer>* atomic) {
detail::atomic_notification::atomic_notify_all_impl(atomic); atomic_notify_all_impl(atomic);
} }
} // namespace atomic_notification
} // namespace detail
} // namespace folly } // namespace folly
...@@ -45,20 +45,67 @@ namespace folly { ...@@ -45,20 +45,67 @@ namespace folly {
* is identical to futexWaitUntil() and returns std::cv_status * is identical to futexWaitUntil() and returns std::cv_status
*/ */
// mimic: std::atomic_wait, p1135r0 // mimic: std::atomic_wait, p1135r0
template <typename Integer> namespace detail {
void atomic_wait(const std::atomic<Integer>* atomic, Integer old); namespace atomic_notification {
template <typename Integer, typename Clock, typename Duration> struct atomic_wait_fn {
std::cv_status atomic_wait_until( public:
const std::atomic<Integer>* atomic, template <typename Atomic, typename Integer>
Integer old, constexpr void operator()(const Atomic* atomic, Integer integer) const {
const std::chrono::time_point<Clock, Duration>& deadline); tag_invoke(*this, atomic, integer);
}
};
} // namespace atomic_notification
} // namespace detail
constexpr inline auto atomic_wait =
detail::atomic_notification::atomic_wait_fn{};
// mimic: std::atomic_wait_until, p1135r0
namespace detail {
namespace atomic_notification {
struct atomic_wait_until_fn {
public:
template <typename Atomic, typename Integer, typename Clock, typename Dur>
constexpr std::cv_status operator()(
const Atomic* atomic,
Integer old,
const std::chrono::time_point<Clock, Dur>& deadline) const {
return tag_invoke(*this, atomic, old, deadline);
}
};
} // namespace atomic_notification
} // namespace detail
constexpr inline auto atomic_wait_until =
detail::atomic_notification::atomic_wait_until_fn{};
// mimic: std::atomic_notify_one, p1135r0 // mimic: std::atomic_notify_one, p1135r0
template <typename Integer> namespace detail {
void atomic_notify_one(const std::atomic<Integer>* atomic); namespace atomic_notification {
struct atomic_notify_one_fn {
public:
template <typename Atomic>
constexpr void operator()(const Atomic* atomic) const {
tag_invoke(*this, atomic);
}
};
} // namespace atomic_notification
} // namespace detail
constexpr inline auto atomic_notify_one =
detail::atomic_notification::atomic_notify_one_fn{};
// mimic: std::atomic_notify_all, p1135r0 // mimic: std::atomic_notify_all, p1135r0
template <typename Integer> namespace detail {
void atomic_notify_all(const std::atomic<Integer>* atomic); namespace atomic_notification {
struct atomic_notify_all_fn {
public:
template <typename Atomic>
constexpr void operator()(Atomic* atomic) const {
tag_invoke(*this, atomic);
}
};
} // namespace atomic_notification
} // namespace detail
constexpr inline auto atomic_notify_all =
detail::atomic_notification::atomic_notify_all_fn{};
// mimic: std::atomic_uint_fast_wait_t, p1135r0 // mimic: std::atomic_uint_fast_wait_t, p1135r0
using atomic_uint_fast_wait_t = std::atomic<std::uint32_t>; using atomic_uint_fast_wait_t = std::atomic<std::uint32_t>;
......
...@@ -1040,7 +1040,7 @@ inline void recordTimedWaiterAndClearTimedBit( ...@@ -1040,7 +1040,7 @@ inline void recordTimedWaiterAndClearTimedBit(
template <typename Atomic> template <typename Atomic>
void wakeTimedWaiters(Atomic* state, bool timedWaiters) { void wakeTimedWaiters(Atomic* state, bool timedWaiters) {
if (UNLIKELY(timedWaiters)) { if (UNLIKELY(timedWaiters)) {
atomic_notify_one(state); folly::atomic_notify_one(state); // evade ADL
} }
} }
...@@ -1665,7 +1665,10 @@ auto timedLock(Atomic& state, Deadline deadline, MakeProxy proxy) { ...@@ -1665,7 +1665,10 @@ auto timedLock(Atomic& state, Deadline deadline, MakeProxy proxy) {
// wait on the futex until signalled, if we get a timeout, the try_lock // wait on the futex until signalled, if we get a timeout, the try_lock
// fails // fails
auto result = atomic_wait_until(&state, previous | data, deadline); auto result = folly::atomic_wait_until( // evade ADL
&state,
previous | data,
deadline);
if (result == std::cv_status::timeout) { if (result == std::cv_status::timeout) {
return proxy(nullptr, std::uintptr_t{0}, false); return proxy(nullptr, std::uintptr_t{0}, false);
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <folly/Synchronized.h> #include <folly/Synchronized.h>
#include <folly/container/Array.h> #include <folly/container/Array.h>
#include <folly/container/Foreach.h> #include <folly/container/Foreach.h>
#include <folly/lang/CustomizationPoint.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <folly/synchronization/Baton.h> #include <folly/synchronization/Baton.h>
#include <folly/test/DeterministicSchedule.h> #include <folly/test/DeterministicSchedule.h>
...@@ -174,7 +175,8 @@ folly::detail::FutexResult futexWaitImpl( ...@@ -174,7 +175,8 @@ folly::detail::FutexResult futexWaitImpl(
} }
template <typename Clock, typename Duration> template <typename Clock, typename Duration>
std::cv_status atomic_wait_until( std::cv_status tag_invoke(
cpo_t<atomic_wait_until>,
const ManualAtomic<std::uintptr_t>*, const ManualAtomic<std::uintptr_t>*,
std::uintptr_t, std::uintptr_t,
const std::chrono::time_point<Clock, Duration>&) { const std::chrono::time_point<Clock, Duration>&) {
...@@ -182,7 +184,7 @@ std::cv_status atomic_wait_until( ...@@ -182,7 +184,7 @@ std::cv_status atomic_wait_until(
return std::cv_status::no_timeout; return std::cv_status::no_timeout;
} }
void atomic_notify_one(const ManualAtomic<std::uintptr_t>*) { void tag_invoke(cpo_t<atomic_notify_one>, const ManualAtomic<std::uintptr_t>*) {
ManualSchedule::beforeSharedAccess(); ManualSchedule::beforeSharedAccess();
} }
} // namespace test } // namespace test
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <folly/ScopeGuard.h> #include <folly/ScopeGuard.h>
#include <folly/concurrency/CacheLocality.h> #include <folly/concurrency/CacheLocality.h>
#include <folly/detail/Futex.h> #include <folly/detail/Futex.h>
#include <folly/lang/CustomizationPoint.h>
#include <folly/synchronization/AtomicNotification.h>
#include <folly/synchronization/detail/AtomicUtils.h> #include <folly/synchronization/detail/AtomicUtils.h>
#include <folly/synchronization/test/Semaphore.h> #include <folly/synchronization/test/Semaphore.h>
...@@ -684,18 +686,22 @@ detail::FutexResult deterministicFutexWaitImpl( ...@@ -684,18 +686,22 @@ detail::FutexResult deterministicFutexWaitImpl(
* waits and wakes * waits and wakes
*/ */
template <typename Integer> template <typename Integer>
void atomic_wait(const DeterministicAtomic<Integer>*, Integer) {} void tag_invoke(
cpo_t<atomic_wait>, const DeterministicAtomic<Integer>*, Integer) {}
template <typename Integer, typename Clock, typename Duration> template <typename Integer, typename Clock, typename Duration>
std::cv_status atomic_wait_until( std::cv_status tag_invoke(
cpo_t<atomic_wait_until>,
const DeterministicAtomic<Integer>*, const DeterministicAtomic<Integer>*,
Integer, Integer,
const std::chrono::time_point<Clock, Duration>&) { const std::chrono::time_point<Clock, Duration>&) {
return std::cv_status::no_timeout; return std::cv_status::no_timeout;
} }
template <typename Integer> template <typename Integer>
void atomic_notify_one(const DeterministicAtomic<Integer>*) {} void tag_invoke(cpo_t<atomic_notify_one>, const DeterministicAtomic<Integer>*) {
}
template <typename Integer> template <typename Integer>
void atomic_notify_all(const DeterministicAtomic<Integer>*) {} void tag_invoke(cpo_t<atomic_notify_all>, const DeterministicAtomic<Integer>*) {
}
/** /**
* DeterministicMutex is a drop-in replacement of std::mutex that * DeterministicMutex is a drop-in replacement of std::mutex that
......
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