blob: b61c188ea6941d3cf33f54567dd182baac46941a [file] [log] [blame]
Ed Tanouse0d918b2018-03-27 17:41:04 -07001#pragma once
2
Ed Tanouse0d918b2018-03-27 17:41:04 -07003#include <boost/circular_buffer.hpp>
4#include <boost/circular_buffer/space_optimized.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07005#include <chrono>
6#include <functional>
Ed Tanouse0d918b2018-03-27 17:41:04 -07007
Ed Tanousc94ad492019-10-10 15:39:33 -07008#include "logging.h"
Ed Tanous1abe55e2018-09-05 08:30:59 -07009
10namespace crow
11{
12namespace detail
13{
James Feistf0af8592020-03-27 16:28:59 -070014
15constexpr const size_t timerQueueTimeoutSeconds = 5;
James Feistcb6cb492020-04-03 13:36:17 -070016constexpr const size_t maxSize = 100;
Ed Tanouse0d918b2018-03-27 17:41:04 -070017// fast timer queue for fixed tick value.
Ed Tanous1abe55e2018-09-05 08:30:59 -070018class TimerQueue
19{
20 public:
21 TimerQueue()
22 {
James Feistcb6cb492020-04-03 13:36:17 -070023 dq.set_capacity(maxSize);
Ed Tanouse0d918b2018-03-27 17:41:04 -070024 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070025
Ed Tanous271584a2019-07-09 16:24:22 -070026 void cancel(size_t k)
Ed Tanous1abe55e2018-09-05 08:30:59 -070027 {
Ed Tanous271584a2019-07-09 16:24:22 -070028 size_t index = k - step;
Ed Tanousb01bf292019-03-25 19:25:26 +000029 if (index < dq.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -070030 {
Ed Tanousb01bf292019-03-25 19:25:26 +000031 dq[index].second = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070032 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070033 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070034
James Feistcb6cb492020-04-03 13:36:17 -070035 std::optional<size_t> add(std::function<void()> f)
Ed Tanous1abe55e2018-09-05 08:30:59 -070036 {
James Feistcb6cb492020-04-03 13:36:17 -070037 if (dq.size() == maxSize)
38 {
39 return std::nullopt;
40 }
41
Ed Tanous1abe55e2018-09-05 08:30:59 -070042 dq.push_back(
43 std::make_pair(std::chrono::steady_clock::now(), std::move(f)));
Ed Tanous271584a2019-07-09 16:24:22 -070044 size_t ret = step + dq.size() - 1;
Ed Tanouse0d918b2018-03-27 17:41:04 -070045
Ed Tanous1abe55e2018-09-05 08:30:59 -070046 BMCWEB_LOG_DEBUG << "timer add inside: " << this << ' ' << ret;
47 return ret;
48 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070049
Ed Tanous1abe55e2018-09-05 08:30:59 -070050 void process()
51 {
52 auto now = std::chrono::steady_clock::now();
53 while (!dq.empty())
54 {
55 auto& x = dq.front();
Jan Sowinski2b5e08e2020-01-09 17:16:02 +010056 // Check expiration time only for active handlers,
57 // remove canceled ones immediately
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 if (x.second)
59 {
James Feistf0af8592020-03-27 16:28:59 -070060 if (now - x.first <
61 std::chrono::seconds(timerQueueTimeoutSeconds))
Jan Sowinski2b5e08e2020-01-09 17:16:02 +010062 {
63 break;
64 }
65
Ed Tanous1abe55e2018-09-05 08:30:59 -070066 BMCWEB_LOG_DEBUG << "timer call: " << this << ' ' << step;
67 // we know that timer handlers are very simple currenty; call
68 // here
69 x.second();
70 }
71 dq.pop_front();
72 step++;
73 }
74 }
75
76 private:
77 using storage_type =
78 std::pair<std::chrono::time_point<std::chrono::steady_clock>,
79 std::function<void()>>;
80
81 boost::circular_buffer_space_optimized<storage_type,
82 std::allocator<storage_type>>
83 dq{};
84
85 // boost::circular_buffer<storage_type> dq{20};
86 // std::deque<storage_type> dq{};
Ed Tanous271584a2019-07-09 16:24:22 -070087 size_t step{};
Ed Tanouse0d918b2018-03-27 17:41:04 -070088};
Ed Tanous1abe55e2018-09-05 08:30:59 -070089} // namespace detail
90} // namespace crow