100.00% Lines (5/5) 100.00% Functions (2/2)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Michael Vandeberg 2   // Copyright (c) 2026 Michael Vandeberg
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/capy 7   // Official repository: https://github.com/cppalliance/capy
8   // 8   //
9   9  
10   #ifndef BOOST_CAPY_EX_TIMER_SERVICE_HPP 10   #ifndef BOOST_CAPY_EX_TIMER_SERVICE_HPP
11   #define BOOST_CAPY_EX_TIMER_SERVICE_HPP 11   #define BOOST_CAPY_EX_TIMER_SERVICE_HPP
12   12  
13   #include <boost/capy/detail/config.hpp> 13   #include <boost/capy/detail/config.hpp>
14   #include <boost/capy/ex/execution_context.hpp> 14   #include <boost/capy/ex/execution_context.hpp>
15   15  
16   #include <chrono> 16   #include <chrono>
17   #include <cstdint> 17   #include <cstdint>
18   #include <functional> 18   #include <functional>
19   #include <mutex> 19   #include <mutex>
20   #include <condition_variable> 20   #include <condition_variable>
21   #include <queue> 21   #include <queue>
22   #include <thread> 22   #include <thread>
23   #include <unordered_set> 23   #include <unordered_set>
24   #include <vector> 24   #include <vector>
25   25  
26   namespace boost { 26   namespace boost {
27   namespace capy { 27   namespace capy {
28   namespace detail { 28   namespace detail {
29   29  
30   /* Shared timer thread for an execution_context. 30   /* Shared timer thread for an execution_context.
31   31  
32   One background std::thread per execution_context. All timeouts 32   One background std::thread per execution_context. All timeouts
33   scheduled through this context share the same thread, which sleeps 33   scheduled through this context share the same thread, which sleeps
34   on a condition variable until the next deadline. 34   on a condition variable until the next deadline.
35   35  
36   The timer thread never touches coroutine frames or executors 36   The timer thread never touches coroutine frames or executors
37   directly — callbacks are responsible for posting work through 37   directly — callbacks are responsible for posting work through
38   the appropriate executor. 38   the appropriate executor.
39   */ 39   */
40   40  
41   class BOOST_CAPY_DECL 41   class BOOST_CAPY_DECL
42   timer_service 42   timer_service
43   : public execution_context::service 43   : public execution_context::service
44   { 44   {
45   public: 45   public:
46   using timer_id = std::uint64_t; 46   using timer_id = std::uint64_t;
47   47  
48   explicit timer_service(execution_context& ctx); 48   explicit timer_service(execution_context& ctx);
49   49  
50   // Calls shutdown() to join the background thread. 50   // Calls shutdown() to join the background thread.
51   // Handles the discard path in use_service_impl where 51   // Handles the discard path in use_service_impl where
52   // a duplicate service is deleted without shutdown(). 52   // a duplicate service is deleted without shutdown().
53   ~timer_service(); 53   ~timer_service();
54   54  
55   /** Schedule a callback to fire after a duration. 55   /** Schedule a callback to fire after a duration.
56   56  
57   The callback is invoked on the timer service's background 57   The callback is invoked on the timer service's background
58   thread. It must not block for extended periods. 58   thread. It must not block for extended periods.
59   59  
60   @return An id that can be passed to cancel(). 60   @return An id that can be passed to cancel().
61   */ 61   */
62   template<typename Rep, typename Period> 62   template<typename Rep, typename Period>
HITCBC 63   135 timer_id schedule_after( 63   135 timer_id schedule_after(
64   std::chrono::duration<Rep, Period> dur, 64   std::chrono::duration<Rep, Period> dur,
65   std::function<void()> cb) 65   std::function<void()> cb)
66   { 66   {
HITCBC 67   135 auto deadline = std::chrono::steady_clock::now() + dur; 67   135 auto deadline = std::chrono::steady_clock::now() + dur;
HITCBC 68   135 return schedule_at(deadline, std::move(cb)); 68   135 return schedule_at(deadline, std::move(cb));
69   } 69   }
70   70  
71   /** Cancel a pending timer. 71   /** Cancel a pending timer.
72   72  
73   After this function returns, the callback is guaranteed 73   After this function returns, the callback is guaranteed
74   not to be running and will never be invoked. If the 74   not to be running and will never be invoked. If the
75   callback is currently executing on the timer thread, 75   callback is currently executing on the timer thread,
76   this call blocks until it completes. 76   this call blocks until it completes.
77   77  
78   Safe to call with any id, including ids that have 78   Safe to call with any id, including ids that have
79   already fired, been cancelled, or were never issued. 79   already fired, been cancelled, or were never issued.
80   */ 80   */
81   void cancel(timer_id id); 81   void cancel(timer_id id);
82   82  
83   protected: 83   protected:
84   void shutdown() override; 84   void shutdown() override;
85   85  
86   private: 86   private:
87   void stop_and_join(); 87   void stop_and_join();
88   struct entry 88   struct entry
89   { 89   {
90   std::chrono::steady_clock::time_point deadline; 90   std::chrono::steady_clock::time_point deadline;
91   timer_id id; 91   timer_id id;
92   std::function<void()> callback; 92   std::function<void()> callback;
93   93  
HITCBC 94   664 bool operator>(entry const& o) const noexcept 94   664 bool operator>(entry const& o) const noexcept
95   { 95   {
HITCBC 96   664 return deadline > o.deadline; 96   664 return deadline > o.deadline;
97   } 97   }
98   }; 98   };
99   99  
100   timer_id schedule_at( 100   timer_id schedule_at(
101   std::chrono::steady_clock::time_point deadline, 101   std::chrono::steady_clock::time_point deadline,
102   std::function<void()> cb); 102   std::function<void()> cb);
103   103  
104   void run(); 104   void run();
105   105  
106   // warning C4251: std types need to have dll-interface 106   // warning C4251: std types need to have dll-interface
107   BOOST_CAPY_MSVC_WARNING_PUSH 107   BOOST_CAPY_MSVC_WARNING_PUSH
108   BOOST_CAPY_MSVC_WARNING_DISABLE(4251) 108   BOOST_CAPY_MSVC_WARNING_DISABLE(4251)
109   std::mutex mutex_; 109   std::mutex mutex_;
110   std::condition_variable cv_; 110   std::condition_variable cv_;
111   std::condition_variable cancel_cv_; 111   std::condition_variable cancel_cv_;
112   std::priority_queue< 112   std::priority_queue<
113   entry, 113   entry,
114   std::vector<entry>, 114   std::vector<entry>,
115   std::greater<>> queue_; 115   std::greater<>> queue_;
116   std::unordered_set<timer_id> active_ids_; 116   std::unordered_set<timer_id> active_ids_;
117   timer_id next_id_ = 0; 117   timer_id next_id_ = 0;
118   timer_id executing_id_ = 0; 118   timer_id executing_id_ = 0;
119   bool stopped_ = false; 119   bool stopped_ = false;
120   std::thread thread_; 120   std::thread thread_;
121   BOOST_CAPY_MSVC_WARNING_POP 121   BOOST_CAPY_MSVC_WARNING_POP
122   }; 122   };
123   123  
124   } // detail 124   } // detail
125   } // capy 125   } // capy
126   } // boost 126   } // boost
127   127  
128   #endif 128   #endif