blob: 85791eab891eeefb38c55bdc4baa1fdbc4c832c6 [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{
James Feist3909dc82020-04-03 10:58:55 -070013
14constexpr const size_t timerQueueTimeoutSeconds = 5;
Ed Tanous1abe55e2018-09-05 08:30:59 -070015namespace detail
16{
James Feistf0af8592020-03-27 16:28:59 -070017
James Feistcb6cb492020-04-03 13:36:17 -070018constexpr const size_t maxSize = 100;
Ed Tanouse0d918b2018-03-27 17:41:04 -070019// fast timer queue for fixed tick value.
Ed Tanous1abe55e2018-09-05 08:30:59 -070020class TimerQueue
21{
22 public:
23 TimerQueue()
24 {
James Feistcb6cb492020-04-03 13:36:17 -070025 dq.set_capacity(maxSize);
Ed Tanouse0d918b2018-03-27 17:41:04 -070026 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070027
Ed Tanous271584a2019-07-09 16:24:22 -070028 void cancel(size_t k)
Ed Tanous1abe55e2018-09-05 08:30:59 -070029 {
Ed Tanous271584a2019-07-09 16:24:22 -070030 size_t index = k - step;
Ed Tanousb01bf292019-03-25 19:25:26 +000031 if (index < dq.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -070032 {
Ed Tanousb01bf292019-03-25 19:25:26 +000033 dq[index].second = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070034 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070035 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070036
James Feistcb6cb492020-04-03 13:36:17 -070037 std::optional<size_t> add(std::function<void()> f)
Ed Tanous1abe55e2018-09-05 08:30:59 -070038 {
James Feistcb6cb492020-04-03 13:36:17 -070039 if (dq.size() == maxSize)
40 {
41 return std::nullopt;
42 }
43
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 dq.push_back(
45 std::make_pair(std::chrono::steady_clock::now(), std::move(f)));
Ed Tanous271584a2019-07-09 16:24:22 -070046 size_t ret = step + dq.size() - 1;
Ed Tanouse0d918b2018-03-27 17:41:04 -070047
Ed Tanous1abe55e2018-09-05 08:30:59 -070048 BMCWEB_LOG_DEBUG << "timer add inside: " << this << ' ' << ret;
49 return ret;
50 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070051
Ed Tanous1abe55e2018-09-05 08:30:59 -070052 void process()
53 {
54 auto now = std::chrono::steady_clock::now();
55 while (!dq.empty())
56 {
57 auto& x = dq.front();
Jan Sowinski2b5e08e2020-01-09 17:16:02 +010058 // Check expiration time only for active handlers,
59 // remove canceled ones immediately
Ed Tanous1abe55e2018-09-05 08:30:59 -070060 if (x.second)
61 {
James Feistf0af8592020-03-27 16:28:59 -070062 if (now - x.first <
63 std::chrono::seconds(timerQueueTimeoutSeconds))
Jan Sowinski2b5e08e2020-01-09 17:16:02 +010064 {
65 break;
66 }
67
Ed Tanous1abe55e2018-09-05 08:30:59 -070068 BMCWEB_LOG_DEBUG << "timer call: " << this << ' ' << step;
Gunnar Millscaa3ce32020-07-08 14:46:53 -050069 // we know that timer handlers are very simple currently; call
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 // here
71 x.second();
72 }
73 dq.pop_front();
74 step++;
75 }
76 }
77
78 private:
79 using storage_type =
80 std::pair<std::chrono::time_point<std::chrono::steady_clock>,
81 std::function<void()>>;
82
83 boost::circular_buffer_space_optimized<storage_type,
84 std::allocator<storage_type>>
85 dq{};
86
87 // boost::circular_buffer<storage_type> dq{20};
88 // std::deque<storage_type> dq{};
Ed Tanous271584a2019-07-09 16:24:22 -070089 size_t step{};
Ed Tanouse0d918b2018-03-27 17:41:04 -070090};
Ed Tanous1abe55e2018-09-05 08:30:59 -070091} // namespace detail
92} // namespace crow