Line data Source code
1 : /*
2 : * Copyright (C) 2004-2025 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 : #pragma once
18 :
19 : #include <thread>
20 : #include <functional>
21 : #include <map>
22 : #include <vector>
23 : #include <chrono>
24 : #include <memory>
25 : #include <atomic>
26 : #include <mutex>
27 : #include <condition_variable>
28 : #include <ciso646>
29 : #include <string>
30 :
31 : #include "noncopyable.h"
32 :
33 : #include "tracepoint.h"
34 : #include "trace-tools.h"
35 :
36 : namespace jami {
37 :
38 : extern std::atomic<uint64_t> task_cookie;
39 :
40 : /**
41 : * A runnable function
42 : */
43 : struct Job
44 : {
45 17636 : Job(std::function<void()>&& f, const char* file, uint32_t l)
46 17636 : : fn(std::move(f))
47 17636 : , filename(file)
48 17636 : , linum(l)
49 17636 : {}
50 :
51 : std::function<void()> fn;
52 : const char* filename;
53 : uint32_t linum;
54 :
55 : inline operator bool() const { return static_cast<bool>(fn); }
56 :
57 0 : void reset() { fn = {}; }
58 : };
59 :
60 : struct RepeatedJob
61 : {
62 0 : RepeatedJob(std::function<bool()>&& f, const char* file, uint32_t l)
63 0 : : fn(std::move(f))
64 0 : , filename(file)
65 0 : , linum(l)
66 0 : {}
67 :
68 : std::function<bool()> fn;
69 : const char* filename;
70 : uint32_t linum;
71 :
72 0 : inline operator bool() { return static_cast<bool>(fn); }
73 :
74 0 : void reset() { fn = {}; }
75 : };
76 :
77 : /**
78 : * A Job that can be disposed
79 : */
80 : class Task
81 : {
82 : public:
83 2152 : Task(std::function<void()>&& fn, const char* filename, uint32_t linum)
84 2152 : : job_(std::move(fn), filename, linum)
85 2152 : , cookie_(task_cookie++)
86 2152 : {}
87 :
88 : #pragma GCC diagnostic push
89 : #pragma GCC diagnostic ignored "-Wunused-parameter"
90 1111 : void run(const char* executor_name)
91 : {
92 1111 : if (job_.fn) {
93 : jami_tracepoint(scheduled_executor_task_begin, executor_name, job_.filename, job_.linum, cookie_);
94 1111 : job_.fn();
95 : jami_tracepoint(scheduled_executor_task_end, cookie_);
96 : }
97 1111 : }
98 : #pragma GCC pop
99 :
100 0 : void cancel() { job_.reset(); }
101 : bool isCancelled() const { return !job_; }
102 :
103 4304 : Job& job() { return job_; }
104 :
105 : private:
106 : Job job_;
107 : uint64_t cookie_;
108 : };
109 :
110 : /**
111 : * A RepeatedJob that can be disposed
112 : */
113 : class RepeatedTask
114 : {
115 : public:
116 0 : RepeatedTask(std::function<bool()>&& fn, const char* filename, uint32_t linum)
117 0 : : job_(std::move(fn), filename, linum)
118 0 : , cookie_(task_cookie++)
119 0 : {}
120 :
121 : #pragma GCC diagnostic push
122 : #pragma GCC diagnostic ignored "-Wunused-parameter"
123 0 : bool run(const char* executor_name)
124 : {
125 : bool cont;
126 0 : std::lock_guard l(lock_);
127 :
128 0 : if (not cancel_.load() and job_.fn) {
129 : jami_tracepoint(scheduled_executor_task_begin, executor_name, job_.filename, job_.linum, cookie_);
130 0 : cont = job_.fn();
131 : jami_tracepoint(scheduled_executor_task_end, cookie_);
132 :
133 : } else {
134 0 : cont = false;
135 : }
136 :
137 0 : if (not cont) {
138 0 : cancel_.store(true);
139 0 : job_.reset();
140 : }
141 :
142 0 : return static_cast<bool>(job_);
143 0 : }
144 : #pragma GCC pop
145 :
146 : void cancel() { cancel_.store(true); }
147 :
148 : void destroy()
149 : {
150 : cancel();
151 : std::lock_guard l(lock_);
152 : job_.reset();
153 : }
154 :
155 : bool isCancelled() const { return cancel_.load(); }
156 :
157 0 : RepeatedJob& job() { return job_; }
158 :
159 : private:
160 : NON_COPYABLE(RepeatedTask);
161 : RepeatedJob job_;
162 : mutable std::mutex lock_;
163 : std::atomic_bool cancel_ {false};
164 : uint64_t cookie_;
165 : };
166 :
167 : class ScheduledExecutor
168 : {
169 : public:
170 : using clock = std::chrono::steady_clock;
171 : using time_point = clock::time_point;
172 : using duration = clock::duration;
173 :
174 : ScheduledExecutor(const std::string& name_);
175 : ~ScheduledExecutor();
176 :
177 : /**
178 : * Schedule job to be run ASAP
179 : */
180 : void run(std::function<void()>&& job, const char* filename = CURRENT_FILENAME(), uint32_t linum = CURRENT_LINE());
181 :
182 : /**
183 : * Schedule job to be run at time t
184 : */
185 : std::shared_ptr<Task> schedule(std::function<void()>&& job,
186 : time_point t,
187 : const char* filename = CURRENT_FILENAME(),
188 : uint32_t linum = CURRENT_LINE());
189 :
190 : /**
191 : * Schedule job to be run after delay dt
192 : */
193 : std::shared_ptr<Task> scheduleIn(std::function<void()>&& job,
194 : duration dt,
195 : const char* filename = CURRENT_FILENAME(),
196 : uint32_t linum = CURRENT_LINE());
197 :
198 : /**
199 : * Schedule job to be run every dt, starting now.
200 : */
201 : std::shared_ptr<RepeatedTask> scheduleAtFixedRate(std::function<bool()>&& job,
202 : duration dt,
203 : const char* filename = CURRENT_FILENAME(),
204 : uint32_t linum = CURRENT_LINE());
205 :
206 : /**
207 : * Stop the scheduler, it is unable to be reversed
208 : */
209 : void stop();
210 :
211 : private:
212 : NON_COPYABLE(ScheduledExecutor);
213 :
214 : void loop();
215 : void schedule(std::shared_ptr<Task>, time_point t);
216 : void reschedule(std::shared_ptr<RepeatedTask>, time_point t, duration dt);
217 :
218 : std::string name_;
219 : std::shared_ptr<std::atomic<bool>> running_;
220 : std::map<time_point, std::vector<Job>> jobs_ {};
221 : std::mutex jobLock_ {};
222 : std::condition_variable cv_ {};
223 : std::thread thread_;
224 : };
225 :
226 : } // namespace jami
|