You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
5.7KB

  1. // <experimental/timer> -*- C++ -*-
  2. // Copyright (C) 2015-2020 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 experimental/timer
  21. * This is a TS C++ Library header.
  22. * @ingroup networking-ts
  23. */
  24. #ifndef _GLIBCXX_EXPERIMENTAL_TIMER
  25. #define _GLIBCXX_EXPERIMENTAL_TIMER 1
  26. #pragma GCC system_header
  27. #if __cplusplus >= 201402L
  28. #include <chrono>
  29. #include <system_error>
  30. #include <thread>
  31. #include <experimental/netfwd>
  32. #include <experimental/io_context>
  33. #include <experimental/bits/net.h>
  34. namespace std _GLIBCXX_VISIBILITY(default)
  35. {
  36. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  37. namespace experimental
  38. {
  39. namespace net
  40. {
  41. inline namespace v1
  42. {
  43. /** @addtogroup networking-ts
  44. * @{
  45. */
  46. template<typename _Clock>
  47. struct wait_traits
  48. {
  49. static typename _Clock::duration
  50. to_wait_duration(const typename _Clock::duration& __d)
  51. { return __d; }
  52. static typename _Clock::duration
  53. to_wait_duration(const typename _Clock::time_point& __t)
  54. {
  55. auto __now = _Clock::now();
  56. auto __diff = __t - __now;
  57. if (__diff > _Clock::duration::max())
  58. return _Clock::duration::max();
  59. if (__diff < _Clock::duration::min())
  60. return _Clock::duration::min();
  61. return __diff;
  62. }
  63. };
  64. template<typename _Clock, typename _WaitTraits>
  65. class basic_waitable_timer
  66. {
  67. public:
  68. // types:
  69. typedef io_context::executor_type executor_type;
  70. typedef _Clock clock_type;
  71. typedef typename clock_type::duration duration;
  72. typedef typename clock_type::time_point time_point;
  73. typedef _WaitTraits traits_type;
  74. // construct / copy / destroy:
  75. explicit
  76. basic_waitable_timer(io_context& __ctx)
  77. : _M_ex(__ctx.get_executor()), _M_expiry()
  78. { }
  79. basic_waitable_timer(io_context& __ctx, const time_point& __t)
  80. : _M_ex(__ctx.get_executor()), _M_expiry(__t)
  81. { }
  82. basic_waitable_timer(io_context& __ctx, const duration& __d)
  83. : _M_ex(__ctx.get_executor()), _M_expiry(_Clock::now() + __d)
  84. { }
  85. basic_waitable_timer(const basic_waitable_timer&) = delete;
  86. basic_waitable_timer(basic_waitable_timer&& __rhs)
  87. : _M_ex(std::move(__rhs._M_ex)), _M_expiry(__rhs._M_expiry)
  88. {
  89. _M_key.swap(__rhs._M_key);
  90. __rhs._M_expiry = time_point{};
  91. }
  92. ~basic_waitable_timer() { cancel(); }
  93. basic_waitable_timer& operator=(const basic_waitable_timer&) = delete;
  94. basic_waitable_timer&
  95. operator=(basic_waitable_timer&& __rhs)
  96. {
  97. if (this == std::addressof(__rhs))
  98. return *this;
  99. cancel();
  100. _M_ex = std::move(__rhs._M_ex);
  101. _M_expiry = __rhs._M_expiry;
  102. __rhs._M_expiry = time_point{};
  103. _M_key.swap(__rhs._M_key);
  104. return *this;
  105. }
  106. // basic_waitable_timer operations:
  107. executor_type get_executor() noexcept { return _M_ex; }
  108. size_t cancel() { return _M_ex.context().cancel(*this); }
  109. size_t cancel_one() { return _M_ex.context().cancel_one(*this); }
  110. time_point expiry() const { return _M_expiry; }
  111. size_t expires_at(const time_point& __t)
  112. {
  113. size_t __cancelled = cancel();
  114. _M_expiry = __t;
  115. return __cancelled;
  116. }
  117. size_t expires_after(const duration& __d)
  118. { return expires_at(_Clock::now() + __d); }
  119. void wait();
  120. void wait(error_code& __ec);
  121. template<typename _CompletionToken>
  122. __deduced_t<_CompletionToken, void(error_code)>
  123. async_wait(_CompletionToken&& __token)
  124. {
  125. async_completion<_CompletionToken, void(error_code)> __init(__token);
  126. _M_ex.context().async_wait(*this,
  127. std::move(__init.completion_handler));
  128. return __init.result.get();
  129. }
  130. private:
  131. executor_type _M_ex;
  132. time_point _M_expiry;
  133. struct _Key { }; // TODO move _M_expiry into here?
  134. unique_ptr<_Key> _M_key{new _Key};
  135. friend class io_context;
  136. };
  137. typedef basic_waitable_timer<chrono::system_clock> system_timer;
  138. typedef basic_waitable_timer<chrono::steady_clock> steady_timer;
  139. typedef basic_waitable_timer<chrono::high_resolution_clock>
  140. high_resolution_timer;
  141. template<typename _Clock, typename _WaitTraits>
  142. void
  143. basic_waitable_timer<_Clock, _WaitTraits>::wait()
  144. {
  145. _M_ex.dispatch([this] {
  146. while (clock_type::now() < _M_expiry)
  147. this_thread::sleep_for(traits_type::to_wait_duration(_M_expiry));
  148. }, allocator<void>{});
  149. }
  150. template<typename _Clock, typename _WaitTraits>
  151. void
  152. basic_waitable_timer<_Clock, _WaitTraits>::wait(error_code&)
  153. {
  154. _M_ex.dispatch([this] {
  155. while (clock_type::now() < _M_expiry)
  156. this_thread::sleep_for(traits_type::to_wait_duration(_M_expiry));
  157. }, allocator<void>{});
  158. }
  159. /// @}
  160. } // namespace v1
  161. } // namespace net
  162. } // namespace experimental
  163. _GLIBCXX_END_NAMESPACE_VERSION
  164. } // namespace std
  165. #endif // C++14
  166. #endif // _GLIBCXX_EXPERIMENTAL_TIMER