Home | History | Annotate | Line # | Download | only in experimental
      1 // <experimental/timer> -*- C++ -*-
      2 
      3 // Copyright (C) 2015-2022 Free Software Foundation, Inc.
      4 //
      5 // This file is part of the GNU ISO C++ Library.  This library is free
      6 // software; you can redistribute it and/or modify it under the
      7 // terms of the GNU General Public License as published by the
      8 // Free Software Foundation; either version 3, or (at your option)
      9 // any later version.
     10 
     11 // This library is distributed in the hope that it will be useful,
     12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 // GNU General Public License for more details.
     15 
     16 // Under Section 7 of GPL version 3, you are granted additional
     17 // permissions described in the GCC Runtime Library Exception, version
     18 // 3.1, as published by the Free Software Foundation.
     19 
     20 // You should have received a copy of the GNU General Public License and
     21 // a copy of the GCC Runtime Library Exception along with this program;
     22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 // <http://www.gnu.org/licenses/>.
     24 
     25 /** @file experimental/timer
     26  *  This is a TS C++ Library header.
     27  *  @ingroup networking-ts
     28  */
     29 
     30 #ifndef _GLIBCXX_EXPERIMENTAL_TIMER
     31 #define _GLIBCXX_EXPERIMENTAL_TIMER 1
     32 
     33 #pragma GCC system_header
     34 
     35 #if __cplusplus >= 201402L
     36 
     37 #include <bits/chrono.h>
     38 #include <system_error>
     39 #include <thread>
     40 #include <experimental/netfwd>
     41 #include <experimental/io_context>
     42 #include <experimental/bits/net.h>
     43 
     44 namespace std _GLIBCXX_VISIBILITY(default)
     45 {
     46 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     47 namespace experimental
     48 {
     49 namespace net
     50 {
     51 inline namespace v1
     52 {
     53 
     54   /** @addtogroup networking-ts
     55    *  @{
     56    */
     57 
     58   template<typename _Clock>
     59     struct wait_traits
     60     {
     61       static typename _Clock::duration
     62       to_wait_duration(const typename _Clock::duration& __d)
     63       { return __d; }
     64 
     65       static typename _Clock::duration
     66       to_wait_duration(const typename _Clock::time_point& __t)
     67       {
     68 	auto __now = _Clock::now();
     69 	auto __diff = __t - __now;
     70 	if (__diff > _Clock::duration::max())
     71 	  return _Clock::duration::max();
     72 	if (__diff < _Clock::duration::min())
     73 	  return _Clock::duration::min();
     74 	return __diff;
     75       }
     76     };
     77 
     78   template<typename _Clock, typename _WaitTraits>
     79     class basic_waitable_timer
     80     {
     81     public:
     82       // types:
     83 
     84       using executor_type = io_context::executor_type;
     85       using clock_type = _Clock;
     86       using duration = typename clock_type::duration;
     87       using time_point = typename clock_type::time_point;
     88       using traits_type = _WaitTraits;
     89 
     90       // construct / copy / destroy:
     91 
     92       explicit
     93       basic_waitable_timer(io_context& __ctx)
     94       : _M_ex(__ctx.get_executor()), _M_expiry()
     95       { }
     96 
     97       basic_waitable_timer(io_context& __ctx, const time_point& __t)
     98       : _M_ex(__ctx.get_executor()), _M_expiry(__t)
     99       { }
    100 
    101       basic_waitable_timer(io_context& __ctx, const duration& __d)
    102       : _M_ex(__ctx.get_executor()), _M_expiry(_Clock::now() + __d)
    103       { }
    104 
    105       basic_waitable_timer(const basic_waitable_timer&) = delete;
    106 
    107       basic_waitable_timer(basic_waitable_timer&& __rhs)
    108       : _M_ex(std::move(__rhs._M_ex)), _M_expiry(__rhs._M_expiry)
    109       {
    110 	_M_key.swap(__rhs._M_key);
    111 	__rhs._M_expiry = time_point{};
    112       }
    113 
    114       ~basic_waitable_timer() { cancel(); }
    115 
    116       basic_waitable_timer& operator=(const basic_waitable_timer&) = delete;
    117 
    118       basic_waitable_timer&
    119       operator=(basic_waitable_timer&& __rhs)
    120       {
    121 	if (this == std::addressof(__rhs))
    122 	  return *this;
    123 	cancel();
    124 	_M_ex = std::move(__rhs._M_ex);
    125 	_M_expiry = __rhs._M_expiry;
    126 	__rhs._M_expiry = time_point{};
    127 	_M_key.swap(__rhs._M_key);
    128 	return *this;
    129       }
    130 
    131       // basic_waitable_timer operations:
    132 
    133       executor_type get_executor() noexcept { return _M_ex; }
    134 
    135       size_t cancel() { return _M_ex.context().cancel(*this); }
    136       size_t cancel_one() { return _M_ex.context().cancel_one(*this); }
    137 
    138       time_point expiry() const { return _M_expiry; }
    139 
    140       size_t expires_at(const time_point& __t)
    141       {
    142 	size_t __cancelled = cancel();
    143 	_M_expiry = __t;
    144 	return __cancelled;
    145       }
    146 
    147       size_t expires_after(const duration& __d)
    148       { return expires_at(_Clock::now() + __d); }
    149 
    150       void wait();
    151       void wait(error_code& __ec);
    152 
    153       template<typename _CompletionToken>
    154 	__deduced_t<_CompletionToken, void(error_code)>
    155 	async_wait(_CompletionToken&& __token)
    156 	{
    157 	  async_completion<_CompletionToken, void(error_code)> __init(__token);
    158 	  _M_ex.context().async_wait(*this,
    159 				     std::move(__init.completion_handler));
    160 	  return __init.result.get();
    161 	}
    162 
    163     private:
    164       executor_type _M_ex;
    165       time_point _M_expiry;
    166 
    167       struct _Key { };  // TODO move _M_expiry into here?
    168       unique_ptr<_Key> _M_key{new _Key};
    169 
    170       friend class io_context;
    171     };
    172 
    173   using system_timer = basic_waitable_timer<chrono::system_clock>;
    174   using steady_timer = basic_waitable_timer<chrono::steady_clock>;
    175   using high_resolution_timer
    176     = basic_waitable_timer<chrono::high_resolution_clock>;
    177 
    178   template<typename _Clock, typename _WaitTraits>
    179     void
    180     basic_waitable_timer<_Clock, _WaitTraits>::wait()
    181     {
    182       _M_ex.dispatch([this] {
    183 	  while (clock_type::now() < _M_expiry)
    184 	    this_thread::sleep_for(traits_type::to_wait_duration(_M_expiry));
    185       }, allocator<void>{});
    186     }
    187 
    188   template<typename _Clock, typename _WaitTraits>
    189     void
    190     basic_waitable_timer<_Clock, _WaitTraits>::wait(error_code&)
    191     {
    192       _M_ex.dispatch([this] {
    193 	  while (clock_type::now() < _M_expiry)
    194 	    this_thread::sleep_for(traits_type::to_wait_duration(_M_expiry));
    195       }, allocator<void>{});
    196     }
    197 
    198   /// @}
    199 
    200 } // namespace v1
    201 } // namespace net
    202 } // namespace experimental
    203 _GLIBCXX_END_NAMESPACE_VERSION
    204 } // namespace std
    205 
    206 #endif // C++14
    207 
    208 #endif // _GLIBCXX_EXPERIMENTAL_TIMER
    209