1// <experimental/timer> -*- C++ -*- 2 3// Copyright (C) 2015-2021 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 <chrono> 38#include <system_error> 39#include <thread> 40#include <experimental/netfwd> 41#include <experimental/io_context> 42#include <experimental/bits/net.h> 43 44namespace std _GLIBCXX_VISIBILITY(default) 45{ 46_GLIBCXX_BEGIN_NAMESPACE_VERSION 47namespace experimental 48{ 49namespace net 50{ 51inline 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