Home | History | Annotate | Line # | Download | only in experimental
      1 // <experimental/timer> -*- C++ -*-
      2 
      3 // Copyright (C) 2015-2024 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 #include <bits/requires_hosted.h> // experimental is currently omitted
     36 
     37 #if __cplusplus >= 201402L
     38 
     39 #include <bits/chrono.h>
     40 #include <system_error>
     41 #include <thread>
     42 #include <experimental/netfwd>
     43 #include <experimental/io_context>
     44 #include <experimental/bits/net.h>
     45 
     46 namespace std _GLIBCXX_VISIBILITY(default)
     47 {
     48 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     49 namespace experimental
     50 {
     51 namespace net
     52 {
     53 inline namespace v1
     54 {
     55 
     56   /** @addtogroup networking-ts
     57    *  @{
     58    */
     59 
     60   template<typename _Clock>
     61     struct wait_traits
     62     {
     63       static typename _Clock::duration
     64       to_wait_duration(const typename _Clock::duration& __d)
     65       { return __d; }
     66 
     67       static typename _Clock::duration
     68       to_wait_duration(const typename _Clock::time_point& __t)
     69       {
     70 	auto __now = _Clock::now();
     71 	auto __diff = __t - __now;
     72 	if (__diff > _Clock::duration::max())
     73 	  return _Clock::duration::max();
     74 	if (__diff < _Clock::duration::min())
     75 	  return _Clock::duration::min();
     76 	return __diff;
     77       }
     78     };
     79 
     80   template<typename _Clock, typename _WaitTraits>
     81     class basic_waitable_timer
     82     {
     83     public:
     84       // types:
     85 
     86       using executor_type = io_context::executor_type;
     87       using clock_type = _Clock;
     88       using duration = typename clock_type::duration;
     89       using time_point = typename clock_type::time_point;
     90       using traits_type = _WaitTraits;
     91 
     92       // construct / copy / destroy:
     93 
     94       explicit
     95       basic_waitable_timer(io_context& __ctx)
     96       : _M_ex(__ctx.get_executor()), _M_expiry()
     97       { }
     98 
     99       basic_waitable_timer(io_context& __ctx, const time_point& __t)
    100       : _M_ex(__ctx.get_executor()), _M_expiry(__t)
    101       { }
    102 
    103       basic_waitable_timer(io_context& __ctx, const duration& __d)
    104       : _M_ex(__ctx.get_executor()), _M_expiry(_Clock::now() + __d)
    105       { }
    106 
    107       basic_waitable_timer(const basic_waitable_timer&) = delete;
    108 
    109       basic_waitable_timer(basic_waitable_timer&& __rhs)
    110       : _M_ex(std::move(__rhs._M_ex)), _M_expiry(__rhs._M_expiry)
    111       {
    112 	_M_key.swap(__rhs._M_key);
    113 	__rhs._M_expiry = time_point{};
    114       }
    115 
    116       ~basic_waitable_timer() { cancel(); }
    117 
    118       basic_waitable_timer& operator=(const basic_waitable_timer&) = delete;
    119 
    120       basic_waitable_timer&
    121       operator=(basic_waitable_timer&& __rhs)
    122       {
    123 	if (this == std::addressof(__rhs))
    124 	  return *this;
    125 	cancel();
    126 	_M_ex = std::move(__rhs._M_ex);
    127 	_M_expiry = __rhs._M_expiry;
    128 	__rhs._M_expiry = time_point{};
    129 	_M_key.swap(__rhs._M_key);
    130 	return *this;
    131       }
    132 
    133       // basic_waitable_timer operations:
    134 
    135       executor_type get_executor() noexcept { return _M_ex; }
    136 
    137       size_t cancel() { return _M_ex.context().cancel(*this); }
    138       size_t cancel_one() { return _M_ex.context().cancel_one(*this); }
    139 
    140       time_point expiry() const { return _M_expiry; }
    141 
    142       size_t expires_at(const time_point& __t)
    143       {
    144 	size_t __cancelled = cancel();
    145 	_M_expiry = __t;
    146 	return __cancelled;
    147       }
    148 
    149       size_t expires_after(const duration& __d)
    150       { return expires_at(_Clock::now() + __d); }
    151 
    152       void wait();
    153       void wait(error_code& __ec);
    154 
    155       template<typename _CompletionToken>
    156 	__deduced_t<_CompletionToken, void(error_code)>
    157 	async_wait(_CompletionToken&& __token)
    158 	{
    159 	  async_completion<_CompletionToken, void(error_code)> __init(__token);
    160 	  _M_ex.context().async_wait(*this,
    161 				     std::move(__init.completion_handler));
    162 	  return __init.result.get();
    163 	}
    164 
    165     private:
    166       executor_type _M_ex;
    167       time_point _M_expiry;
    168 
    169       struct _Key { };  // TODO move _M_expiry into here?
    170       unique_ptr<_Key> _M_key{new _Key};
    171 
    172       friend class io_context;
    173     };
    174 
    175   using system_timer = basic_waitable_timer<chrono::system_clock>;
    176   using steady_timer = basic_waitable_timer<chrono::steady_clock>;
    177   using high_resolution_timer
    178     = basic_waitable_timer<chrono::high_resolution_clock>;
    179 
    180   template<typename _Clock, typename _WaitTraits>
    181     void
    182     basic_waitable_timer<_Clock, _WaitTraits>::wait()
    183     {
    184       _M_ex.dispatch([this] {
    185 	  while (clock_type::now() < _M_expiry)
    186 	    this_thread::sleep_for(traits_type::to_wait_duration(_M_expiry));
    187       }, allocator<void>{});
    188     }
    189 
    190   template<typename _Clock, typename _WaitTraits>
    191     void
    192     basic_waitable_timer<_Clock, _WaitTraits>::wait(error_code&)
    193     {
    194       _M_ex.dispatch([this] {
    195 	  while (clock_type::now() < _M_expiry)
    196 	    this_thread::sleep_for(traits_type::to_wait_duration(_M_expiry));
    197       }, allocator<void>{});
    198     }
    199 
    200   /// @}
    201 
    202 } // namespace v1
    203 } // namespace net
    204 } // namespace experimental
    205 _GLIBCXX_END_NAMESPACE_VERSION
    206 } // namespace std
    207 
    208 #endif // C++14
    209 
    210 #endif // _GLIBCXX_EXPERIMENTAL_TIMER
    211