forked from brainboxdotcc/DPP
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtimer.cpp
More file actions
137 lines (120 loc) · 3.68 KB
/
Copy pathtimer.cpp
File metadata and controls
137 lines (120 loc) · 3.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/************************************************************************************
*
* D++, A Lightweight C++ library for Discord
*
* Copyright 2021 Craig Edwards and D++ contributors
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
************************************************************************************/
#include <dpp/timer.h>
#include <dpp/cluster.h>
#include <dpp/json.h>
#include <atomic>
namespace dpp {
std::atomic<timer> next_handle = 1;
timer cluster::start_timer(timer_callback_t on_tick, uint64_t frequency, timer_callback_t on_stop) {
timer_t new_timer;
new_timer.handle = next_handle++;
new_timer.next_tick = time(nullptr) + frequency;
new_timer.on_tick = std::move(on_tick);
new_timer.on_stop = std::move(on_stop);
new_timer.frequency = frequency;
std::lock_guard<std::mutex> l(timer_guard);
next_timer.emplace(new_timer);
return new_timer.handle;
}
bool cluster::stop_timer(timer t) {
/*
* Because iterating a priority queue is at best O(log n) we don't actually walk the queue
* looking for the timer to remove. Instead, we just insert the timer handle into a std::set
* to inform the tick_timers() function later if it sees a handle in this set, it is to
* have its on_stop() called and it is not to be rescheduled.
*/
std::lock_guard<std::mutex> l(timer_guard);
deleted_timers.emplace(t);
return true;
}
void cluster::tick_timers() {
time_t now = time(nullptr);
{
std::lock_guard<std::mutex> l(timer_guard);
if (next_timer.empty()) {
return;
}
}
do {
timer_t cur_timer;
{
std::lock_guard<std::mutex> l(timer_guard);
if (next_timer.top().next_tick > now) {
/* Nothing to do */
break;
}
cur_timer = std::move(next_timer.top());
next_timer.pop();
}
timers_deleted_t::iterator deleted_iter{};
bool deleted{};
{
std::lock_guard<std::mutex> l(timer_guard);
deleted_iter = deleted_timers.find(cur_timer.handle);
deleted = deleted_iter != deleted_timers.end();
}
if (!deleted) {
cur_timer.on_tick(cur_timer.handle);
cur_timer.next_tick += cur_timer.frequency;
{
std::lock_guard<std::mutex> l(timer_guard);
next_timer.emplace(std::move(cur_timer));
}
} else {
/* Deleted timers are not reinserted into the priority queue and their on_stop is called */
if (cur_timer.on_stop) {
cur_timer.on_stop(cur_timer.handle);
}
{
std::lock_guard<std::mutex> l(timer_guard);
deleted_timers.erase(deleted_iter);
}
}
} while (true);
}
#ifndef DPP_NO_CORO
async<timer> cluster::co_sleep(uint64_t seconds) {
return async<timer>{[this, seconds] (auto &&cb) mutable {
start_timer([this, cb] (dpp::timer handle) {
cb(handle);
stop_timer(handle);
}, seconds);
}};
}
#endif
oneshot_timer::oneshot_timer(class cluster* cl, uint64_t duration, timer_callback_t callback) : owner(cl) {
/* Create timer */
th = cl->start_timer([callback, this](dpp::timer timer_handle) {
callback(this->get_handle());
this->owner->stop_timer(this->th);
}, duration);
}
timer oneshot_timer::get_handle() {
return this->th;
}
void oneshot_timer::cancel() {
owner->stop_timer(this->th);
}
oneshot_timer::~oneshot_timer() {
cancel();
}
}