Futex-inl.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * Copyright 2013-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <folly/detail/Futex.h>
  18. #include <folly/synchronization/ParkingLot.h>
  19. namespace folly {
  20. namespace detail {
  21. /** Optimal when TargetClock is the same type as Clock.
  22. *
  23. * Otherwise, both Clock::now() and TargetClock::now() must be invoked. */
  24. template <typename TargetClock, typename Clock, typename Duration>
  25. typename TargetClock::time_point time_point_conv(
  26. std::chrono::time_point<Clock, Duration> const& time) {
  27. using std::chrono::duration_cast;
  28. using TimePoint = std::chrono::time_point<Clock, Duration>;
  29. using TargetDuration = typename TargetClock::duration;
  30. using TargetTimePoint = typename TargetClock::time_point;
  31. if (time == TimePoint::max()) {
  32. return TargetTimePoint::max();
  33. } else if (std::is_same<Clock, TargetClock>::value) {
  34. // in place of time_point_cast, which cannot compile without if-constexpr
  35. auto const delta = time.time_since_epoch();
  36. return TargetTimePoint(duration_cast<TargetDuration>(delta));
  37. } else {
  38. // different clocks with different epochs, so non-optimal case
  39. auto const delta = time - Clock::now();
  40. return TargetClock::now() + duration_cast<TargetDuration>(delta);
  41. }
  42. }
  43. /**
  44. * Available overloads, with definitions elsewhere
  45. *
  46. * These functions are treated as ADL-extension points, the templates above
  47. * call these functions without them having being pre-declared. This works
  48. * because ADL lookup finds the definitions of these functions when you pass
  49. * the relevant arguments
  50. */
  51. int futexWakeImpl(
  52. const Futex<std::atomic>* futex,
  53. int count,
  54. uint32_t wakeMask);
  55. FutexResult futexWaitImpl(
  56. const Futex<std::atomic>* futex,
  57. uint32_t expected,
  58. std::chrono::system_clock::time_point const* absSystemTime,
  59. std::chrono::steady_clock::time_point const* absSteadyTime,
  60. uint32_t waitMask);
  61. int futexWakeImpl(
  62. const Futex<EmulatedFutexAtomic>* futex,
  63. int count,
  64. uint32_t wakeMask);
  65. FutexResult futexWaitImpl(
  66. const Futex<EmulatedFutexAtomic>* futex,
  67. uint32_t expected,
  68. std::chrono::system_clock::time_point const* absSystemTime,
  69. std::chrono::steady_clock::time_point const* absSteadyTime,
  70. uint32_t waitMask);
  71. template <typename Futex, typename Deadline>
  72. typename std::enable_if<Deadline::clock::is_steady, FutexResult>::type
  73. futexWaitImpl(
  74. Futex* futex,
  75. uint32_t expected,
  76. Deadline const& deadline,
  77. uint32_t waitMask) {
  78. return futexWaitImpl(futex, expected, nullptr, &deadline, waitMask);
  79. }
  80. template <typename Futex, typename Deadline>
  81. typename std::enable_if<!Deadline::clock::is_steady, FutexResult>::type
  82. futexWaitImpl(
  83. Futex* futex,
  84. uint32_t expected,
  85. Deadline const& deadline,
  86. uint32_t waitMask) {
  87. return futexWaitImpl(futex, expected, &deadline, nullptr, waitMask);
  88. }
  89. template <typename Futex>
  90. FutexResult
  91. futexWait(const Futex* futex, uint32_t expected, uint32_t waitMask) {
  92. auto rv = futexWaitImpl(futex, expected, nullptr, nullptr, waitMask);
  93. assert(rv != FutexResult::TIMEDOUT);
  94. return rv;
  95. }
  96. template <typename Futex>
  97. int futexWake(const Futex* futex, int count, uint32_t wakeMask) {
  98. return futexWakeImpl(futex, count, wakeMask);
  99. }
  100. template <typename Futex, class Clock, class Duration>
  101. FutexResult futexWaitUntil(
  102. const Futex* futex,
  103. uint32_t expected,
  104. std::chrono::time_point<Clock, Duration> const& deadline,
  105. uint32_t waitMask) {
  106. using Target = typename std::conditional<
  107. Clock::is_steady,
  108. std::chrono::steady_clock,
  109. std::chrono::system_clock>::type;
  110. auto const converted = time_point_conv<Target>(deadline);
  111. return converted == Target::time_point::max()
  112. ? futexWaitImpl(futex, expected, nullptr, nullptr, waitMask)
  113. : futexWaitImpl(futex, expected, converted, waitMask);
  114. }
  115. } // namespace detail
  116. } // namespace folly