100.00% Lines (62/62) 100.00% Functions (8/8)
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   #include <boost/capy/ex/detail/timer_service.hpp> 10   #include <boost/capy/ex/detail/timer_service.hpp>
11   11  
12   namespace boost { 12   namespace boost {
13   namespace capy { 13   namespace capy {
14   namespace detail { 14   namespace detail {
15   15  
HITCBC 16   20 timer_service:: 16   20 timer_service::
HITCBC 17   20 timer_service(execution_context& ctx) 17   20 timer_service(execution_context& ctx)
HITCBC 18   40 : thread_([this] { run(); }) 18   40 : thread_([this] { run(); })
19   { 19   {
20   (void)ctx; 20   (void)ctx;
HITCBC 21   20 } 21   20 }
22   22  
HITCBC 23   40 timer_service:: 23   40 timer_service::
HITCBC 24   20 ~timer_service() 24   20 ~timer_service()
25   { 25   {
HITCBC 26   20 stop_and_join(); 26   20 stop_and_join();
HITCBC 27   40 } 27   40 }
28   28  
29   timer_service::timer_id 29   timer_service::timer_id
HITCBC 30   135 timer_service:: 30   135 timer_service::
31   schedule_at( 31   schedule_at(
32   std::chrono::steady_clock::time_point deadline, 32   std::chrono::steady_clock::time_point deadline,
33   std::function<void()> cb) 33   std::function<void()> cb)
34   { 34   {
HITCBC 35   135 std::lock_guard lock(mutex_); 35   135 std::lock_guard lock(mutex_);
HITCBC 36   135 auto id = ++next_id_; 36   135 auto id = ++next_id_;
HITCBC 37   135 active_ids_.insert(id); 37   135 active_ids_.insert(id);
HITCBC 38   135 queue_.push(entry{deadline, id, std::move(cb)}); 38   135 queue_.push(entry{deadline, id, std::move(cb)});
HITCBC 39   135 cv_.notify_one(); 39   135 cv_.notify_one();
HITCBC 40   135 return id; 40   135 return id;
HITCBC 41   135 } 41   135 }
42   42  
43   void 43   void
HITCBC 44   43 timer_service:: 44   43 timer_service::
45   cancel(timer_id id) 45   cancel(timer_id id)
46   { 46   {
HITCBC 47   43 std::unique_lock lock(mutex_); 47   43 std::unique_lock lock(mutex_);
HITCBC 48   43 if(!active_ids_.contains(id)) 48   43 if(!active_ids_.contains(id))
HITCBC 49   34 return; 49   36 return;
HITCBC 50   9 if(executing_id_ == id) 50   7 if(executing_id_ == id)
51   { 51   {
52   // Callback is running — wait for it to finish. 52   // Callback is running — wait for it to finish.
53   // run() erases from active_ids_ after execution. 53   // run() erases from active_ids_ after execution.
HITCBC 54   6 while(executing_id_ == id) 54   2 while(executing_id_ == id)
HITCBC 55   3 cancel_cv_.wait(lock); 55   1 cancel_cv_.wait(lock);
HITCBC 56   3 return; 56   1 return;
57   } 57   }
HITCBC 58   6 active_ids_.erase(id); 58   6 active_ids_.erase(id);
HITCBC 59   43 } 59   43 }
60   60  
61   void 61   void
HITCBC 62   40 timer_service:: 62   40 timer_service::
63   stop_and_join() 63   stop_and_join()
64   { 64   {
65   { 65   {
HITCBC 66   40 std::lock_guard lock(mutex_); 66   40 std::lock_guard lock(mutex_);
HITCBC 67   40 stopped_ = true; 67   40 stopped_ = true;
HITCBC 68   40 } 68   40 }
HITCBC 69   40 cv_.notify_one(); 69   40 cv_.notify_one();
HITCBC 70   40 if(thread_.joinable()) 70   40 if(thread_.joinable())
HITCBC 71   20 thread_.join(); 71   20 thread_.join();
HITCBC 72   40 } 72   40 }
73   73  
74   void 74   void
HITCBC 75   20 timer_service:: 75   20 timer_service::
76   shutdown() 76   shutdown()
77   { 77   {
HITCBC 78   20 stop_and_join(); 78   20 stop_and_join();
HITCBC 79   20 } 79   20 }
80   80  
81   void 81   void
HITCBC 82   20 timer_service:: 82   20 timer_service::
83   run() 83   run()
84   { 84   {
HITCBC 85   20 std::unique_lock lock(mutex_); 85   20 std::unique_lock lock(mutex_);
86   for(;;) 86   for(;;)
87   { 87   {
HITCBC 88   199 if(stopped_) 88   202 if(stopped_)
HITCBC 89   20 return; 89   20 return;
90   90  
HITCBC 91   179 if(queue_.empty()) 91   182 if(queue_.empty())
92   { 92   {
HITCBC 93   19 cv_.wait(lock); 93   18 cv_.wait(lock);
HITCBC 94   53 continue; 94   56 continue;
95   } 95   }
96   96  
HITCBC 97   160 auto deadline = queue_.top().deadline; 97   164 auto deadline = queue_.top().deadline;
HITCBC 98   160 auto now = std::chrono::steady_clock::now(); 98   164 auto now = std::chrono::steady_clock::now();
HITCBC 99   160 if(deadline > now) 99   164 if(deadline > now)
100   { 100   {
HITCBC 101   32 cv_.wait_until(lock, deadline); 101   36 cv_.wait_until(lock, deadline);
HITCBC 102   32 continue; 102   36 continue;
103   } 103   }
104   104  
105   // Pop the entry (const_cast needed because priority_queue::top is const) 105   // Pop the entry (const_cast needed because priority_queue::top is const)
HITCBC 106   128 auto e = std::move(const_cast<entry&>(queue_.top())); 106   128 auto e = std::move(const_cast<entry&>(queue_.top()));
HITCBC 107   128 queue_.pop(); 107   128 queue_.pop();
108   108  
109   // Skip if cancelled (no longer in active set) 109   // Skip if cancelled (no longer in active set)
HITCBC 110   128 if(!active_ids_.contains(e.id)) 110   128 if(!active_ids_.contains(e.id))
HITCBC 111   2 continue; 111   2 continue;
112   112  
HITCBC 113   126 executing_id_ = e.id; 113   126 executing_id_ = e.id;
HITCBC 114   126 lock.unlock(); 114   126 lock.unlock();
HITCBC 115   126 e.callback(); 115   126 e.callback();
HITCBC 116   126 lock.lock(); 116   126 lock.lock();
HITCBC 117   126 active_ids_.erase(e.id); 117   126 active_ids_.erase(e.id);
HITCBC 118   126 executing_id_ = 0; 118   126 executing_id_ = 0;
HITCBC 119   126 cancel_cv_.notify_all(); 119   126 cancel_cv_.notify_all();
HITCBC 120   307 } 120   310 }
HITCBC 121   20 } 121   20 }
122   122  
123   } // detail 123   } // detail
124   } // capy 124   } // capy
125   } // boost 125   } // boost