FastLED 3.10.8
Loading...
Searching...
No Matches
scheduler.cpp.hpp
Go to the documentation of this file.
1#include "fl/task/scheduler.h"
2#include "fl/stl/singleton.h"
3#include "fl/stl/chrono.h"
4#include "fl/log/log.h"
5#include "fl/stl/compiler_control.h" // IWYU pragma: keep - FL_UNUSED
6#include "fl/stl/noexcept.h"
7
8namespace fl {
9namespace task {
10
13
19
23
25
26// Scheduler implementation
30
32 if (t.is_valid()) {
33 for (const Handle& existing : mTasks) {
34 if (existing.mImpl == t.mImpl) {
35 return existing._id();
36 }
37 }
38 int task_id = mNextTaskId.fetch_add(1);
39 t._set_id(task_id);
40 const bool is_frame_task = t._type() == TaskType::kBeforeFrame ||
41 t._type() == TaskType::kAfterFrame;
42 mTasks.push_back(fl::move(t));
43 if (is_frame_task && !mFrameListenerRegistered) {
44 // The dedicated final listener works even where the general
45 // EngineEvents listener list is disabled for memory reasons.
48 }
49 return task_id;
50 }
51 return 0; // Invalid task
52}
53
63
65 u32 current_time = fl::millis();
66
67 // Use index-based iteration to avoid iterator invalidation issues
68 for (fl::size i = 0; i < mTasks.size();) {
69 Handle& t = mTasks[i];
70
71 if (!t.is_valid() || t._is_canceled()) {
72 // erase() returns bool in fl::vector, not iterator
73 mTasks.erase(mTasks.begin() + i);
74 // Don't increment i since we just removed an element
75 } else {
76 // Check if task is ready to run (frame tasks will return false here)
77 bool should_run = t._ready_to_run(current_time);
78
79 if (should_run) {
80 // Update last run time for recurring tasks
81 t._set_last_run_time(current_time);
82
83 // Execute the task
84 if (t._has_then()) {
85 t._execute_then();
86 } else {
87 warn_no_then(t._id(), t._trace_label());
88 }
89
90 // Remove one-shot tasks, keep recurring ones
91 bool is_recurring = (t._type() == TaskType::kEveryMs || t._type() == TaskType::kAtFramerate);
92 if (is_recurring) {
93 ++i; // Keep recurring tasks
94 } else {
95 // erase() returns bool in fl::vector, not iterator
96 mTasks.erase(mTasks.begin() + i);
97 // Don't increment i since we just removed an element
98 }
99 } else {
100 ++i;
101 }
102 }
103 }
105}
106
115
124
126 u32 current_time = fl::millis();
127
129
130 // Stable handles isolate dispatch from callbacks that mutate mTasks.
131 // Separate reusable buffers preserve before/after nesting without a heap
132 // allocation on every frame after each buffer reaches its high-water mark.
133 fl::vector<Handle>& snapshot = task_type == TaskType::kBeforeFrame
136 snapshot.clear();
137 for (const Handle& task : mTasks) {
138 if (task._type() == task_type &&
139 task._ready_to_run_frame_task(current_time)) {
140 snapshot.push_back(task);
141 }
142 }
143
144 const u32 clear_generation = mClearGeneration;
145 for (Handle& task : snapshot) {
146 if (mClearGeneration != clear_generation) {
147 break;
148 }
149 if (!task.is_valid() || task._is_canceled()) {
150 continue;
151 }
152
153 task._set_last_run_time(current_time);
154 if (task._has_then()) {
155 task._execute_then();
156 } else {
157 warn_no_then(task._id(), task._trace_label());
158 }
159 }
160 snapshot.clear();
163}
164
166 for (fl::size i = 0; i < mTasks.size();) {
167 if (!mTasks[i].is_valid() || mTasks[i]._is_canceled()) {
168 mTasks.erase(mTasks.begin() + i);
169 } else {
170 ++i;
171 }
172 }
173}
174
177 return;
178 }
179 for (const Handle& task : mTasks) {
180 const TaskType type = task._type();
181 const bool is_frame_task = type == TaskType::kBeforeFrame ||
183 if (task.is_valid() && !task._is_canceled() && is_frame_task) {
184 return;
185 }
186 }
189}
190
191void Scheduler::warn_no_then(int task_id, const fl::string& trace_label) FL_NO_EXCEPT {
192 FL_UNUSED(task_id); // only consumed by FL_WARN, a no-op on small platforms
193 if (!trace_label.empty()) {
194 FL_WARN("[fl::task] Warning: no then() callback set for Task#" << task_id << " launched at " << trace_label);
195 } else {
196 FL_WARN("[fl::task] Warning: no then() callback set for Task#" << task_id);
197 }
198}
199
200void Scheduler::warn_no_catch(int task_id, const fl::string& trace_label, const Error& error) FL_NO_EXCEPT {
201 FL_UNUSED(task_id); // only consumed by FL_WARN, a no-op on small platforms
202 FL_UNUSED(error);
203 if (!trace_label.empty()) {
204 FL_WARN("[fl::task] Warning: no catch_() callback set for Task#" << task_id << " launched at " << trace_label << ". Error: " << error.message);
205 } else {
206 FL_WARN("[fl/task] Warning: no catch_() callback set for Task#" << task_id << ". Error: " << error.message);
207 }
208}
209
210} // namespace task
211} // namespace fl
FastLED chrono implementation - duration types for time measurements.
static void setFrameTaskListener(Listener *listener) FL_NO_EXCEPT
static T & instance() FL_NO_EXCEPT
Definition singleton.h:41
Task Handle with fluent API (was class fl::task, renamed to avoid namespace collision)
Definition task.h:156
~Scheduler() FL_NO_EXCEPT override
void clear_all_tasks() FL_NO_EXCEPT
fl::vector< Handle > mTasks
Definition scheduler.h:46
fl::atomic< int > mNextTaskId
Definition scheduler.h:49
void warn_no_then(int task_id, const fl::string &trace_label) FL_NO_EXCEPT
bool mUpdatingAfterFrameTasks
Definition scheduler.h:52
bool mFrameListenerRegistered
Definition scheduler.h:53
static Scheduler & instance() FL_NO_EXCEPT
void warn_no_catch(int task_id, const fl::string &trace_label, const Error &error) FL_NO_EXCEPT
fl::vector< Handle > mAfterFrameSnapshot
Definition scheduler.h:48
bool mUpdatingBeforeFrameTasks
Definition scheduler.h:51
int add_task(Handle t) FL_NO_EXCEPT
void update_after_frame_tasks() FL_NO_EXCEPT
void onEndFrame() FL_NO_EXCEPT override
void remove_inactive_tasks() FL_NO_EXCEPT
void update_frame_listener_registration() FL_NO_EXCEPT
void update() FL_NO_EXCEPT
fl::vector< Handle > mBeforeFrameSnapshot
Definition scheduler.h:47
void update_before_frame_tasks() FL_NO_EXCEPT
Scheduler() FL_NO_EXCEPT
void onBeginFrame() FL_NO_EXCEPT override
void update_tasks_of_type(TaskType task_type) FL_NO_EXCEPT
void clear() FL_NO_EXCEPT
Definition vector.h:634
void push_back(const T &value) FL_NO_EXCEPT
Definition vector.h:624
#define FL_UNUSED(x)
#define FL_WARN(...)
Definition log.h:437
Centralized logging categories for FastLED hardware interfaces and subsystems.
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
Definition move.h:30
TaskType
Identifies how a scheduled task is triggered.
Definition task.h:117
@ kBeforeFrame
Runs immediately before each FastLED frame is rendered.
Definition task.h:120
@ kAfterFrame
Runs immediately after each FastLED frame is rendered.
Definition task.h:121
@ kAtFramerate
Runs at a fixed number of times per second.
Definition task.h:119
@ kEveryMs
Runs after a fixed time interval.
Definition task.h:118
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
fl::u32 millis() FL_NO_EXCEPT
Universal millisecond timer - returns milliseconds since system startup.
Base definition for an LED controller.
Definition crgb.hpp:179
Task scheduler — manages timer and frame-based tasks.
Error type for promises.
Definition promise.h:39