rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
scheduler.h
Go to the documentation of this file.
1/**
2 * @file scheduler.h
3 *
4 * @date May 18, 2014
5 * @author Andrey Belomutskiy, (c) 2012-2020
6 */
7#pragma once
8
9#include <cstdint>
10
11#ifndef EFI_UNIT_TEST_VERBOSE_ACTION
12#define EFI_UNIT_TEST_VERBOSE_ACTION 0
13#endif
14
15#if EFI_UNIT_TEST
16#include <cassert>
17#include <iostream>
18#endif
19
20// For safely storing and manipulating addresses as integral values
21using scheduler_arg_t = uintptr_t;
22
23template<class To, class From>
24std::enable_if_t<
25 sizeof(To) == sizeof(From) &&
26 std::is_trivially_copyable_v<From> &&
27 std::is_trivially_copyable_v<To>,
28 To>
29// constexpr support needs compiler magic
30bit_cast(const From& src) noexcept
31{
32 static_assert(std::is_trivially_constructible_v<To>,
33 "This implementation additionally requires "
34 "destination type to be trivially constructible");
35
36 To dst;
37 std::memcpy(&dst, &src, sizeof(To));
38 return dst;
39}
40
41template<typename T>
43private:
44
46
47public:
48
49 static_assert(alignof(T) >= 2, "Type must be at least 2-aligned");
50 static_assert(sizeof(scheduler_arg_t) == sizeof(void*), "Unexpected scheduler_arg_t (i.e. m_raw) size, won't hold pointer");
51
52 static constexpr TaggedPointer fromRaw(scheduler_arg_t raw) {
53 return TaggedPointer{raw};
54 }
55
56 template<typename U = T>
57 static constexpr TaggedPointer make(U ptr, const bool flag) requires std::is_pointer_v<U> {
58 #if EFI_UNIT_TEST
59 assert((reinterpret_cast<scheduler_arg_t>(ptr) & scheduler_arg_t{1}) == 0);
60 #endif
61 return TaggedPointer{reinterpret_cast<scheduler_arg_t>(ptr) | (flag ? 1 : 0)};
62 }
63
64 [[nodiscard]] constexpr T* getOriginalPointer() const {
65 return reinterpret_cast<T*>(m_raw & ~scheduler_arg_t{1});
66 }
67
68 [[nodiscard]] constexpr bool getFlag() const {
69 return m_raw & scheduler_arg_t{1};
70 }
71
72 [[nodiscard]] constexpr scheduler_arg_t getRaw() const {
73 return m_raw;
74 }
75
76 explicit constexpr operator bool() const { return m_raw != 0; }
77
78 explicit TaggedPointer(scheduler_arg_t const raw) noexcept : m_raw{raw} { }
79
80 TaggedPointer() noexcept = default;
81
82 TaggedPointer(TaggedPointer const&) noexcept = default;
83 TaggedPointer(TaggedPointer&& other) noexcept : m_raw{other.m_raw} {
84 other.m_raw = 0;
85 }
86
87 TaggedPointer& operator=(TaggedPointer const&) noexcept = default;
89 m_raw = other.m_raw;
90 other.m_raw = 0;
91 return *this;
92 }
93};
94
95// Regarding overhead, starting from GCC 10.1 through gcc 15 and clang 15-20 you have everything on -O0
96// but at -O1 there are not even constructors in ASM...
97// Few more ASM instructions on minGw but due to CRT in WIN requiring some stack alignment by Windows OS
98class action_s {
99private:
100 using schfunc_t = void (*)(scheduler_arg_t);
101
104
105 // We want to have callback name in tests for easy debug
106#if EFI_UNIT_TEST
107 char const* fn_name{};
108 constexpr action_s(const schfunc_t callback, char const* const fn_name_) noexcept : m_callback(callback), fn_name{fn_name_} {}
109 constexpr action_s(const schfunc_t callback, const scheduler_arg_t param, char const* const fn_name_) noexcept : m_callback(callback), m_param(param), fn_name{fn_name_} {}
110#else
111 constexpr action_s(const schfunc_t callback) noexcept : m_callback(callback) {}
112 constexpr action_s(const schfunc_t callback, const scheduler_arg_t param) noexcept : m_callback(callback), m_param(param) {}
113#endif
114
115 // We can pass either pointer or integral this enforces the rule at compile time
116 // Applies correct cast to argument
117 template<typename T>
118 static constexpr T from_scheduler_arg_t(scheduler_arg_t raw) noexcept {
119 static_assert(std::is_pointer_v<T> || std::is_integral_v<T>, "Unsupported type");
120 if constexpr (std::is_pointer_v<T>) {
121 return reinterpret_cast<T>(raw);
122 } else {
123 return static_cast<T>(raw);
124 }
125 }
126
127 // We can pass either pointer or integral this enforces the rule at compile time
128 // Applies correct cast to argument
129 template<typename T>
130 static constexpr scheduler_arg_t to_scheduler_arg_t(T val) noexcept {
131 static_assert(std::is_pointer_v<T> || std::is_integral_v<T>, "Unsupported type");
132 if constexpr (std::is_pointer_v<T>) {
133 return reinterpret_cast<scheduler_arg_t>(val);
134 } else {
135 return static_cast<scheduler_arg_t>(val);
136 }
137 }
138
139 // Wraps the original function for unified signature
140 // Applies correct cast to argument before dispatching to Func
141 template<auto Func, typename Arg>
142 static constexpr void trampoline(scheduler_arg_t raw) noexcept {
143 static_assert(std::is_pointer_v<Arg> || std::is_integral_v<Arg>, "Unsupported type");
144 #if EFI_UNIT_TEST_VERBOSE_ACTION
145 std::cout << "action_s::trampoline: " << __PRETTY_FUNCTION__ << "(" << reinterpret_cast<scheduler_arg_t>(Func) << ") "
146 "with raw arg = " << raw << "; is_ptr = " << std::is_pointer_v<Arg> << std::endl;
147 #endif
148 if constexpr (std::is_pointer_v<Arg>) {
149 Func(reinterpret_cast<Arg>(raw));
150 } else {
151 Func(static_cast<Arg>(raw));
152 }
153 }
154
155 // Wrapper for zero arg callbacks
156 template<auto Func>
157 static constexpr void trampoline_no_arg(scheduler_arg_t) noexcept {
158 #if EFI_UNIT_TEST_VERBOSE_ACTION
159 std::cout << "action_s::trampoline_no_arg: " << __PRETTY_FUNCTION__ << "(" << reinterpret_cast<scheduler_arg_t>(Func) << ") with no arg" << std::endl;
160 #endif
161 Func(); // stored argument is ignored
162 }
163
164public:
165
166 action_s() noexcept = default;
167
168 action_s(action_s const&) noexcept = default;
169 action_s(action_s&& other) noexcept : m_callback{other.m_callback}, m_param{other.m_param}
170 #if EFI_UNIT_TEST
171 , fn_name {other.fn_name}
172 #endif
173 {
174 other.m_callback = nullptr;
175 other.m_param = 0;
176 #if EFI_UNIT_TEST
177 other.fn_name = "Moved";
178 #endif
179 }
180
181 action_s& operator=(action_s const&) noexcept = default;
182 action_s& operator=(action_s&& other) noexcept {
183 m_callback = other.m_callback;
184 m_param = other.m_param;
185 other.m_callback = nullptr;
186 other.m_param = 0;
187 #if EFI_UNIT_TEST
188 fn_name = other.fn_name;
189 other.fn_name = "Moved";
190 #endif
191 return *this;
192 }
193
194 // Factory: wraps a typed function (integral or pointer) with the unified signature
195 template<auto Func, typename Arg>
196 static constexpr action_s make(Arg arg) noexcept(std::is_nothrow_constructible_v<action_s, schfunc_t, scheduler_arg_t>) {
197 static_assert(std::is_invocable_r_v<void, decltype(Func), Arg>, "Function signature mismatch");
198 #if EFI_UNIT_TEST_VERBOSE_ACTION
199 std::cout << "action_s::make: " << __PRETTY_FUNCTION__ << "(" << reinterpret_cast<scheduler_arg_t>(Func) << ") "
200 "with raw arg = " << arg << "; is_ptr = " << std::is_pointer_v<Arg> << std::endl;
201 #endif
202 if constexpr (std::is_pointer_v<Arg>) {
203 // alignment is a must because pointers have to be dividable by 2 with no loss (i.e., no loss on bit shifts)
204 // if it is 1-aligned, there will be address data in the last bit, so it cannot be used for any flags
205 // There could be theoretic architectures where it is the case though I don't know what to do then,
206 // Maybe introduce some other member for flag here?
207 // Anyway, we have so much code relying on specific architecture, and we are not testing on some fancy
208 // PowerPC/mainframe/... machines so should always be true, but just in case...
209 static_assert(alignof(std::remove_pointer_t<Arg>) >= 2, "Pointer must be at least 2-aligned");
210 static_assert(sizeof(scheduler_arg_t) == sizeof(void*), "Unexpected scheduler_arg_t size");
211 }
212 #if EFI_UNIT_TEST
213 return action_s(&trampoline<Func, Arg>, to_scheduler_arg_t(arg), __PRETTY_FUNCTION__);
214 #else
215 return action_s(&trampoline<Func, Arg>, to_scheduler_arg_t(arg));
216 #endif
217 }
218
219 // For functions with no arguments
220 template<auto Func>
221 static constexpr action_s make() noexcept(std::is_nothrow_constructible_v<action_s, schfunc_t>) {
222 static_assert(std::is_invocable_r_v<void, decltype(Func)>, "Function signature mismatch");
223 #if EFI_UNIT_TEST
224 return action_s(&trampoline_no_arg<Func>, __PRETTY_FUNCTION__);
225 #else
226 return action_s(&trampoline_no_arg<Func>);
227 #endif
228 }
229
230 void execute() const {
231 if (m_callback) {
232 #if EFI_UNIT_TEST_VERBOSE_ACTION
233 std::cout << "action_s::execute: " << fn_name << "(" << reinterpret_cast<scheduler_arg_t>(m_callback) << ") "
234 "with raw arg = " << m_param << std::endl;
235 #endif
237 } else {
238 #ifdef WE_HAVE_CRITICAL_ERROR_METHOD
239 efiCriticalError("clear nullptr");
240 #endif
241
242 #if EFI_UNIT_TEST
243 assert(false);
244 #endif
245 }
246 }
247
248 [[nodiscard]] constexpr schfunc_t getCallback() const { return m_callback; }
249 [[nodiscard]] constexpr scheduler_arg_t const& getArgumentRaw() const { return m_param; }
250
251 template<typename T>
252 [[nodiscard]] constexpr T getArgument() const { return from_scheduler_arg_t<T>(m_param); }
253
254 explicit constexpr operator bool() const { return m_callback != nullptr; }
255
256 bool constexpr operator==(const action_s& other) const {
257 return m_callback == other.m_callback && m_param == other.m_param;
258 }
259
260#if EFI_UNIT_TEST
261 [[nodiscard]] constexpr char const* getCallbackName() const { return fn_name ? fn_name : "nullptr"; }
262#endif
263};
264
265/**
266 * This structure holds information about an event scheduled in the future: when to execute what callback with what parameters
267 */
268#pragma pack(push, 4)
270 [[nodiscard]] efitick_t getMomentNt() const {
271 return momentNt;
272 }
273
274#if EFI_UNIT_TEST
275 #ifndef NT2US
276 #define NT2US(x) ((x) / US_TO_NT_MULTIPLIER)
277 #endif
278
279 [[nodiscard]] efitick_t getMomentUs() const {
280 return NT2US(momentNt);
281 }
282#endif
283
284 void setMomentNt(efitick_t p_moment) {
285 momentNt = p_moment;
286 }
287
288#if EFI_SIMULATOR
289 // used by signal_executor_sleep executor implementation
290 virtual_timer_t timer;
291#endif /* EFI_SIMULATOR */
292
293 // Scheduler implementation uses a sorted linked list of these scheduling records.
295
297 /**
298 * timestamp represented as 64-bit value of ticks since MCU start
299 */
300private:
301 volatile efitick_t momentNt = 0;
302};
303#pragma pack(pop)
304
305struct Scheduler {
306 /**
307 * @brief Schedule an action to be executed in the future.
308 *
309 * scheduleByAngle is useful if you want to schedule something in terms of crank angle instead of time.
310 *
311 * @param msg Name of this event to use for logging in case of an error.
312 * @param scheduling Storage to use for the scheduled event. If null, one will be used from the pool.
313 * @param targetTime When to execute the specified action. If this time is in the past or
314 * very near future, it may execute immediately.
315 * @param action An action to execute at the specified time.
316 */
317 virtual void schedule(const char *msg, scheduling_s *scheduling, efitick_t targetTime, action_s const& action) = 0;
318
319 /**
320 * @brief Cancel the specified scheduling_s so that, if currently scheduled, it does not execute.
321 *
322 * @param scheduling The scheduling_s to cancel.
323 */
324 virtual void cancel(scheduling_s* scheduling) = 0;
325};
326
static constexpr action_s make(Arg arg) noexcept(std::is_nothrow_constructible_v< action_s, schfunc_t, scheduler_arg_t >)
Definition scheduler.h:196
constexpr action_s(const schfunc_t callback, char const *const fn_name_) noexcept
Definition scheduler.h:108
static constexpr scheduler_arg_t to_scheduler_arg_t(T val) noexcept
Definition scheduler.h:130
action_s & operator=(action_s const &) noexcept=default
constexpr action_s(const schfunc_t callback) noexcept
Definition scheduler.h:111
constexpr T getArgument() const
Definition scheduler.h:252
static constexpr T from_scheduler_arg_t(scheduler_arg_t raw) noexcept
Definition scheduler.h:118
action_s() noexcept=default
constexpr char const * getCallbackName() const
Definition scheduler.h:261
constexpr action_s(const schfunc_t callback, const scheduler_arg_t param, char const *const fn_name_) noexcept
Definition scheduler.h:109
void execute() const
Definition scheduler.h:230
constexpr action_s(const schfunc_t callback, const scheduler_arg_t param) noexcept
Definition scheduler.h:112
schfunc_t m_callback
Definition scheduler.h:102
char const * fn_name
Definition scheduler.h:107
scheduler_arg_t m_param
Definition scheduler.h:103
static constexpr void trampoline(scheduler_arg_t raw) noexcept
Definition scheduler.h:142
static constexpr void trampoline_no_arg(scheduler_arg_t) noexcept
Definition scheduler.h:157
constexpr schfunc_t getCallback() const
Definition scheduler.h:248
static constexpr action_s make() noexcept(std::is_nothrow_constructible_v< action_s, schfunc_t >)
Definition scheduler.h:221
constexpr scheduler_arg_t const & getArgumentRaw() const
Definition scheduler.h:249
void(*)(scheduler_arg_t) schfunc_t
Definition scheduler.h:100
action_s & operator=(action_s &&other) noexcept
Definition scheduler.h:182
bool constexpr operator==(const action_s &other) const
Definition scheduler.h:256
void efiCriticalError(const char *message)
Scheduler * getScheduler()
Definition engine.cpp:585
uintptr_t scheduler_arg_t
Definition scheduler.h:21
std::enable_if_t< sizeof(To)==sizeof(From) &&std::is_trivially_copyable_v< From > &&std::is_trivially_copyable_v< To >, To > bit_cast(const From &src) noexcept
Definition scheduler.h:30
virtual void cancel(scheduling_s *scheduling)=0
Cancel the specified scheduling_s so that, if currently scheduled, it does not execute.
virtual void schedule(const char *msg, scheduling_s *scheduling, efitick_t targetTime, action_s const &action)=0
Schedule an action to be executed in the future.
constexpr T * getOriginalPointer() const
Definition scheduler.h:64
TaggedPointer(scheduler_arg_t const raw) noexcept
Definition scheduler.h:78
TaggedPointer & operator=(TaggedPointer const &) noexcept=default
static constexpr TaggedPointer fromRaw(scheduler_arg_t raw)
Definition scheduler.h:52
constexpr scheduler_arg_t getRaw() const
Definition scheduler.h:72
TaggedPointer & operator=(TaggedPointer &&other) noexcept
Definition scheduler.h:88
constexpr bool getFlag() const
Definition scheduler.h:68
TaggedPointer() noexcept=default
scheduler_arg_t m_raw
Definition scheduler.h:45
static constexpr TaggedPointer make(U ptr, const bool flag)
Definition scheduler.h:57
virtual_timer_t timer
Definition scheduler.h:290
efitick_t getMomentUs() const
Definition scheduler.h:279
scheduling_s * nextScheduling_s
Definition scheduler.h:294
efitick_t getMomentNt() const
Definition scheduler.h:270
action_s action
Definition scheduler.h:296
volatile efitick_t momentNt
Definition scheduler.h:301
void setMomentNt(efitick_t p_moment)
Definition scheduler.h:284
static tstrWifiInitParam param