blob: d83cd0e22927091a551da53cec3167e414f92c89 [file] [log] [blame]
Ed Tanouse0d918b2018-03-27 17:41:04 -07001#pragma once
2
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003#include "logging.h"
4
Ed Tanouse0d918b2018-03-27 17:41:04 -07005#include <boost/circular_buffer.hpp>
6#include <boost/circular_buffer/space_optimized.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -05007
Ed Tanous1abe55e2018-09-05 08:30:59 -07008#include <chrono>
9#include <functional>
Ed Tanouse0d918b2018-03-27 17:41:04 -070010
Ed Tanous1abe55e2018-09-05 08:30:59 -070011namespace crow
12{
13namespace detail
14{
James Feistf0af8592020-03-27 16:28:59 -070015
16constexpr const size_t timerQueueTimeoutSeconds = 5;
James Feistcb6cb492020-04-03 13:36:17 -070017constexpr const size_t maxSize = 100;
Ed Tanouse0d918b2018-03-27 17:41:04 -070018// fast timer queue for fixed tick value.
Ed Tanous1abe55e2018-09-05 08:30:59 -070019class TimerQueue
20{
21 public:
22 TimerQueue()
23 {
James Feistcb6cb492020-04-03 13:36:17 -070024 dq.set_capacity(maxSize);
Ed Tanouse0d918b2018-03-27 17:41:04 -070025 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070026
Ed Tanous271584a2019-07-09 16:24:22 -070027 void cancel(size_t k)
Ed Tanous1abe55e2018-09-05 08:30:59 -070028 {
Ed Tanous271584a2019-07-09 16:24:22 -070029 size_t index = k - step;
Ed Tanousb01bf292019-03-25 19:25:26 +000030 if (index < dq.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -070031 {
Ed Tanousb01bf292019-03-25 19:25:26 +000032 dq[index].second = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070033 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070034 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070035
James Feistcb6cb492020-04-03 13:36:17 -070036 std::optional<size_t> add(std::function<void()> f)
Ed Tanous1abe55e2018-09-05 08:30:59 -070037 {
James Feistcb6cb492020-04-03 13:36:17 -070038 if (dq.size() == maxSize)
39 {
40 return std::nullopt;
41 }
42
Ed Tanous1abe55e2018-09-05 08:30:59 -070043 dq.push_back(
44 std::make_pair(std::chrono::steady_clock::now(), std::move(f)));
Ed Tanous271584a2019-07-09 16:24:22 -070045 size_t ret = step + dq.size() - 1;
Ed Tanouse0d918b2018-03-27 17:41:04 -070046
Ed Tanous1abe55e2018-09-05 08:30:59 -070047 BMCWEB_LOG_DEBUG << "timer add inside: " << this << ' ' << ret;
48 return ret;
49 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070050
Ed Tanous1abe55e2018-09-05 08:30:59 -070051 void process()
52 {
53 auto now = std::chrono::steady_clock::now();
54 while (!dq.empty())
55 {
56 auto& x = dq.front();
Jan Sowinski2b5e08e2020-01-09 17:16:02 +010057 // Check expiration time only for active handlers,
58 // remove canceled ones immediately
Ed Tanous1abe55e2018-09-05 08:30:59 -070059 if (x.second)
60 {
James Feistf0af8592020-03-27 16:28:59 -070061 if (now - x.first <
62 std::chrono::seconds(timerQueueTimeoutSeconds))
Jan Sowinski2b5e08e2020-01-09 17:16:02 +010063 {
64 break;
65 }
66
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 BMCWEB_LOG_DEBUG << "timer call: " << this << ' ' << step;
Gunnar Millscaa3ce32020-07-08 14:46:53 -050068 // we know that timer handlers are very simple currently; call
Ed Tanous1abe55e2018-09-05 08:30:59 -070069 // here
70 x.second();
71 }
72 dq.pop_front();
73 step++;
74 }
75 }
76
77 private:
78 using storage_type =
79 std::pair<std::chrono::time_point<std::chrono::steady_clock>,
80 std::function<void()>>;
81
82 boost::circular_buffer_space_optimized<storage_type,
83 std::allocator<storage_type>>
84 dq{};
85
86 // boost::circular_buffer<storage_type> dq{20};
87 // std::deque<storage_type> dq{};
Ed Tanous271584a2019-07-09 16:24:22 -070088 size_t step{};
Ed Tanouse0d918b2018-03-27 17:41:04 -070089};
Ed Tanous1abe55e2018-09-05 08:30:59 -070090} // namespace detail
91} // namespace crow