atomic_timed_wait.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. // -*- C++ -*- header.
  2. // Copyright (C) 2020-2021 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. /** @file bits/atomic_timed_wait.h
  21. * This is an internal header file, included by other library headers.
  22. * Do not attempt to use it directly. @headername{atomic}
  23. */
  24. #ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
  25. #define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
  26. #pragma GCC system_header
  27. #include <bits/atomic_wait.h>
  28. #if __cpp_lib_atomic_wait
  29. #include <bits/functional_hash.h>
  30. #include <bits/this_thread_sleep.h>
  31. #include <chrono>
  32. #ifdef _GLIBCXX_HAVE_LINUX_FUTEX
  33. #include <exception> // std::terminate
  34. #include <sys/time.h>
  35. #endif
  36. namespace std _GLIBCXX_VISIBILITY(default)
  37. {
  38. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  39. namespace __detail
  40. {
  41. using __wait_clock_t = chrono::steady_clock;
  42. template<typename _Clock, typename _Dur>
  43. __wait_clock_t::time_point
  44. __to_wait_clock(const chrono::time_point<_Clock, _Dur>& __atime) noexcept
  45. {
  46. const typename _Clock::time_point __c_entry = _Clock::now();
  47. const __wait_clock_t::time_point __w_entry = __wait_clock_t::now();
  48. const auto __delta = __atime - __c_entry;
  49. using __w_dur = typename __wait_clock_t::duration;
  50. return __w_entry + chrono::ceil<__w_dur>(__delta);
  51. }
  52. template<typename _Dur>
  53. __wait_clock_t::time_point
  54. __to_wait_clock(const chrono::time_point<__wait_clock_t,
  55. _Dur>& __atime) noexcept
  56. {
  57. using __w_dur = typename __wait_clock_t::duration;
  58. return chrono::ceil<__w_dur>(__atime);
  59. }
  60. #ifdef _GLIBCXX_HAVE_LINUX_FUTEX
  61. #define _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT
  62. // returns true if wait ended before timeout
  63. template<typename _Dur>
  64. bool
  65. __platform_wait_until_impl(const __platform_wait_t* __addr,
  66. __platform_wait_t __old,
  67. const chrono::time_point<__wait_clock_t, _Dur>&
  68. __atime) noexcept
  69. {
  70. auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
  71. auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
  72. struct timespec __rt =
  73. {
  74. static_cast<std::time_t>(__s.time_since_epoch().count()),
  75. static_cast<long>(__ns.count())
  76. };
  77. auto __e = syscall (SYS_futex, __addr,
  78. static_cast<int>(__futex_wait_flags::
  79. __wait_bitset_private),
  80. __old, &__rt, nullptr,
  81. static_cast<int>(__futex_wait_flags::
  82. __bitset_match_any));
  83. if (__e)
  84. {
  85. if ((errno != ETIMEDOUT) && (errno != EINTR)
  86. && (errno != EAGAIN))
  87. __throw_system_error(errno);
  88. return true;
  89. }
  90. return false;
  91. }
  92. // returns true if wait ended before timeout
  93. template<typename _Clock, typename _Dur>
  94. bool
  95. __platform_wait_until(const __platform_wait_t* __addr, __platform_wait_t __old,
  96. const chrono::time_point<_Clock, _Dur>& __atime)
  97. {
  98. if constexpr (is_same_v<__wait_clock_t, _Clock>)
  99. {
  100. return __platform_wait_until_impl(__addr, __old, __atime);
  101. }
  102. else
  103. {
  104. if (!__platform_wait_until_impl(__addr, __old,
  105. __to_wait_clock(__atime)))
  106. {
  107. // We got a timeout when measured against __clock_t but
  108. // we need to check against the caller-supplied clock
  109. // to tell whether we should return a timeout.
  110. if (_Clock::now() < __atime)
  111. return true;
  112. }
  113. return false;
  114. }
  115. }
  116. #else
  117. // define _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT and implement __platform_wait_until()
  118. // if there is a more efficient primitive supported by the platform
  119. // (e.g. __ulock_wait())which is better than pthread_cond_clockwait
  120. #endif // ! PLATFORM_TIMED_WAIT
  121. // Returns true if wait ended before timeout.
  122. // _Clock must be either steady_clock or system_clock.
  123. template<typename _Clock, typename _Dur>
  124. bool
  125. __cond_wait_until_impl(__condvar& __cv, mutex& __mx,
  126. const chrono::time_point<_Clock, _Dur>& __atime)
  127. {
  128. static_assert(std::__is_one_of<_Clock, chrono::steady_clock,
  129. chrono::system_clock>::value);
  130. auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
  131. auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
  132. __gthread_time_t __ts =
  133. {
  134. static_cast<std::time_t>(__s.time_since_epoch().count()),
  135. static_cast<long>(__ns.count())
  136. };
  137. #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
  138. if constexpr (is_same_v<chrono::steady_clock, _Clock>)
  139. __cv.wait_until(__mx, CLOCK_MONOTONIC, __ts);
  140. else
  141. #endif
  142. __cv.wait_until(__mx, __ts);
  143. return _Clock::now() < __atime;
  144. }
  145. // returns true if wait ended before timeout
  146. template<typename _Clock, typename _Dur>
  147. bool
  148. __cond_wait_until(__condvar& __cv, mutex& __mx,
  149. const chrono::time_point<_Clock, _Dur>& __atime)
  150. {
  151. #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
  152. if constexpr (is_same_v<_Clock, chrono::steady_clock>)
  153. return __detail::__cond_wait_until_impl(__cv, __mx, __atime);
  154. else
  155. #endif
  156. if constexpr (is_same_v<_Clock, chrono::system_clock>)
  157. return __detail::__cond_wait_until_impl(__cv, __mx, __atime);
  158. else
  159. {
  160. if (__cond_wait_until_impl(__cv, __mx,
  161. __to_wait_clock(__atime)))
  162. {
  163. // We got a timeout when measured against __clock_t but
  164. // we need to check against the caller-supplied clock
  165. // to tell whether we should return a timeout.
  166. if (_Clock::now() < __atime)
  167. return true;
  168. }
  169. return false;
  170. }
  171. }
  172. struct __timed_waiter_pool : __waiter_pool_base
  173. {
  174. // returns true if wait ended before timeout
  175. template<typename _Clock, typename _Dur>
  176. bool
  177. _M_do_wait_until(__platform_wait_t* __addr, __platform_wait_t __old,
  178. const chrono::time_point<_Clock, _Dur>& __atime)
  179. {
  180. #ifdef _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT
  181. return __platform_wait_until(__addr, __old, __atime);
  182. #else
  183. __platform_wait_t __val;
  184. __atomic_load(__addr, &__val, __ATOMIC_RELAXED);
  185. if (__val == __old)
  186. {
  187. lock_guard<mutex> __l(_M_mtx);
  188. return __cond_wait_until(_M_cv, _M_mtx, __atime);
  189. }
  190. #endif // _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT
  191. }
  192. };
  193. struct __timed_backoff_spin_policy
  194. {
  195. __wait_clock_t::time_point _M_deadline;
  196. __wait_clock_t::time_point _M_t0;
  197. template<typename _Clock, typename _Dur>
  198. __timed_backoff_spin_policy(chrono::time_point<_Clock, _Dur>
  199. __deadline = _Clock::time_point::max(),
  200. chrono::time_point<_Clock, _Dur>
  201. __t0 = _Clock::now()) noexcept
  202. : _M_deadline(__to_wait_clock(__deadline))
  203. , _M_t0(__to_wait_clock(__t0))
  204. { }
  205. bool
  206. operator()() const noexcept
  207. {
  208. using namespace literals::chrono_literals;
  209. auto __now = __wait_clock_t::now();
  210. if (_M_deadline <= __now)
  211. return false;
  212. auto __elapsed = __now - _M_t0;
  213. if (__elapsed > 128ms)
  214. {
  215. this_thread::sleep_for(64ms);
  216. }
  217. else if (__elapsed > 64us)
  218. {
  219. this_thread::sleep_for(__elapsed / 2);
  220. }
  221. else if (__elapsed > 4us)
  222. {
  223. __thread_yield();
  224. }
  225. else
  226. return false;
  227. return true;
  228. }
  229. };
  230. template<typename _EntersWait>
  231. struct __timed_waiter : __waiter_base<__timed_waiter_pool>
  232. {
  233. using __base_type = __waiter_base<__timed_waiter_pool>;
  234. template<typename _Tp>
  235. __timed_waiter(const _Tp* __addr) noexcept
  236. : __base_type(__addr)
  237. {
  238. if constexpr (_EntersWait::value)
  239. _M_w._M_enter_wait();
  240. }
  241. ~__timed_waiter()
  242. {
  243. if constexpr (_EntersWait::value)
  244. _M_w._M_leave_wait();
  245. }
  246. // returns true if wait ended before timeout
  247. template<typename _Tp, typename _ValFn,
  248. typename _Clock, typename _Dur>
  249. bool
  250. _M_do_wait_until_v(_Tp __old, _ValFn __vfn,
  251. const chrono::time_point<_Clock, _Dur>&
  252. __atime) noexcept
  253. {
  254. __platform_wait_t __val;
  255. if (_M_do_spin(__old, std::move(__vfn), __val,
  256. __timed_backoff_spin_policy(__atime)))
  257. return true;
  258. return __base_type::_M_w._M_do_wait_until(__base_type::_M_addr, __val, __atime);
  259. }
  260. // returns true if wait ended before timeout
  261. template<typename _Pred,
  262. typename _Clock, typename _Dur>
  263. bool
  264. _M_do_wait_until(_Pred __pred, __platform_wait_t __val,
  265. const chrono::time_point<_Clock, _Dur>&
  266. __atime) noexcept
  267. {
  268. for (auto __now = _Clock::now(); __now < __atime;
  269. __now = _Clock::now())
  270. {
  271. if (__base_type::_M_w._M_do_wait_until(
  272. __base_type::_M_addr, __val, __atime)
  273. && __pred())
  274. return true;
  275. if (__base_type::_M_do_spin(__pred, __val,
  276. __timed_backoff_spin_policy(__atime, __now)))
  277. return true;
  278. }
  279. return false;
  280. }
  281. // returns true if wait ended before timeout
  282. template<typename _Pred,
  283. typename _Clock, typename _Dur>
  284. bool
  285. _M_do_wait_until(_Pred __pred,
  286. const chrono::time_point<_Clock, _Dur>&
  287. __atime) noexcept
  288. {
  289. __platform_wait_t __val;
  290. if (__base_type::_M_do_spin(__pred, __val,
  291. __timed_backoff_spin_policy(__atime)))
  292. return true;
  293. return _M_do_wait_until(__pred, __val, __atime);
  294. }
  295. template<typename _Tp, typename _ValFn,
  296. typename _Rep, typename _Period>
  297. bool
  298. _M_do_wait_for_v(_Tp __old, _ValFn __vfn,
  299. const chrono::duration<_Rep, _Period>&
  300. __rtime) noexcept
  301. {
  302. __platform_wait_t __val;
  303. if (_M_do_spin_v(__old, std::move(__vfn), __val))
  304. return true;
  305. if (!__rtime.count())
  306. return false; // no rtime supplied, and spin did not acquire
  307. auto __reltime = chrono::ceil<__wait_clock_t::duration>(__rtime);
  308. return __base_type::_M_w._M_do_wait_until(
  309. __base_type::_M_addr,
  310. __val,
  311. chrono::steady_clock::now() + __reltime);
  312. }
  313. template<typename _Pred,
  314. typename _Rep, typename _Period>
  315. bool
  316. _M_do_wait_for(_Pred __pred,
  317. const chrono::duration<_Rep, _Period>& __rtime) noexcept
  318. {
  319. __platform_wait_t __val;
  320. if (__base_type::_M_do_spin(__pred, __val))
  321. return true;
  322. if (!__rtime.count())
  323. return false; // no rtime supplied, and spin did not acquire
  324. auto __reltime = chrono::ceil<__wait_clock_t::duration>(__rtime);
  325. return _M_do_wait_until(__pred, __val,
  326. chrono::steady_clock::now() + __reltime);
  327. }
  328. };
  329. using __enters_timed_wait = __timed_waiter<std::true_type>;
  330. using __bare_timed_wait = __timed_waiter<std::false_type>;
  331. } // namespace __detail
  332. // returns true if wait ended before timeout
  333. template<typename _Tp, typename _ValFn,
  334. typename _Clock, typename _Dur>
  335. bool
  336. __atomic_wait_address_until_v(const _Tp* __addr, _Tp&& __old, _ValFn&& __vfn,
  337. const chrono::time_point<_Clock, _Dur>&
  338. __atime) noexcept
  339. {
  340. __detail::__enters_timed_wait __w{__addr};
  341. return __w._M_do_wait_until_v(__old, __vfn, __atime);
  342. }
  343. template<typename _Tp, typename _Pred,
  344. typename _Clock, typename _Dur>
  345. bool
  346. __atomic_wait_address_until(const _Tp* __addr, _Pred __pred,
  347. const chrono::time_point<_Clock, _Dur>&
  348. __atime) noexcept
  349. {
  350. __detail::__enters_timed_wait __w{__addr};
  351. return __w._M_do_wait_until(__pred, __atime);
  352. }
  353. template<typename _Pred,
  354. typename _Clock, typename _Dur>
  355. bool
  356. __atomic_wait_address_until_bare(const __detail::__platform_wait_t* __addr,
  357. _Pred __pred,
  358. const chrono::time_point<_Clock, _Dur>&
  359. __atime) noexcept
  360. {
  361. __detail::__bare_timed_wait __w{__addr};
  362. return __w._M_do_wait_until(__pred, __atime);
  363. }
  364. template<typename _Tp, typename _ValFn,
  365. typename _Rep, typename _Period>
  366. bool
  367. __atomic_wait_address_for_v(const _Tp* __addr, _Tp&& __old, _ValFn&& __vfn,
  368. const chrono::duration<_Rep, _Period>& __rtime) noexcept
  369. {
  370. __detail::__enters_timed_wait __w{__addr};
  371. return __w._M_do_wait_for_v(__old, __vfn, __rtime);
  372. }
  373. template<typename _Tp, typename _Pred,
  374. typename _Rep, typename _Period>
  375. bool
  376. __atomic_wait_address_for(const _Tp* __addr, _Pred __pred,
  377. const chrono::duration<_Rep, _Period>& __rtime) noexcept
  378. {
  379. __detail::__enters_timed_wait __w{__addr};
  380. return __w._M_do_wait_for(__pred, __rtime);
  381. }
  382. template<typename _Pred,
  383. typename _Rep, typename _Period>
  384. bool
  385. __atomic_wait_address_for_bare(const __detail::__platform_wait_t* __addr,
  386. _Pred __pred,
  387. const chrono::duration<_Rep, _Period>& __rtime) noexcept
  388. {
  389. __detail::__bare_timed_wait __w{__addr};
  390. return __w._M_do_wait_for(__pred, __rtime);
  391. }
  392. _GLIBCXX_END_NAMESPACE_VERSION
  393. } // namespace std
  394. #endif // __cpp_lib_atomic_wait
  395. #endif // _GLIBCXX_ATOMIC_TIMED_WAIT_H