FastLED 3.9.15
Loading...
Searching...
No Matches
async.cpp
Go to the documentation of this file.
1#include "fl/async.h"
2#include "fl/functional.h"
3#include "fl/singleton.h"
4#include "fl/algorithm.h"
5#include "fl/task.h"
6#include "fl/time.h"
7#include "fl/warn.h"
8
9// Platform-specific includes
10#ifdef __EMSCRIPTEN__
11extern "C" void emscripten_sleep(unsigned int ms);
12#endif
13
14namespace fl {
15
19
21 if (runner && fl::find(mRunners.begin(), mRunners.end(), runner) == mRunners.end()) {
22 mRunners.push_back(runner);
23 }
24}
25
27 auto it = fl::find(mRunners.begin(), mRunners.end(), runner);
28 if (it != mRunners.end()) {
29 mRunners.erase(it);
30 }
31}
32
34 // Update all registered runners
35 for (auto* runner : mRunners) {
36 if (runner) {
37 runner->update();
38 }
39 }
40}
41
43 for (const auto* runner : mRunners) {
44 if (runner && runner->has_active_tasks()) {
45 return true;
46 }
47 }
48 return false;
49}
50
52 size_t total = 0;
53 for (const auto* runner : mRunners) {
54 if (runner) {
55 total += runner->active_task_count();
56 }
57 }
58 return total;
59}
60
61// Public API functions
62
67
69 // Always pump all async tasks first
70 async_run();
71
72 // Platform-specific yielding behavior
73#ifdef __EMSCRIPTEN__
74 // WASM: Use emscripten_sleep to yield control to browser event loop
75 emscripten_sleep(1); // Sleep for 1ms to yield to browser
76#endif
77 for (int i = 0; i < 5; ++i) {
78 async_run(); // Give other async tasks a chance
79 }
80}
81
85
89
90// Scheduler implementation
94
96 if (t.get_impl()) {
97 t.get_impl()->mTaskId = mNextTaskId++;
98 int task_id = t.get_impl()->mTaskId;
99 mTasks.push_back(fl::move(t));
100 return task_id;
101 }
102 return 0; // Invalid task
103}
104
106 uint32_t current_time = fl::time();
107
108 // Use index-based iteration to avoid iterator invalidation issues
109 for (fl::size i = 0; i < mTasks.size();) {
110 task& t = mTasks[i];
111 auto impl = t.get_impl();
112
113 if (!impl || impl->is_canceled()) {
114 // erase() returns bool in HeapVector, not iterator
115 mTasks.erase(mTasks.begin() + i);
116 // Don't increment i since we just removed an element
117 } else {
118 // Check if task is ready to run (frame tasks will return false here)
119 bool should_run = impl->ready_to_run(current_time);
120
121 if (should_run) {
122 // Update last run time for recurring tasks
123 impl->set_last_run_time(current_time);
124
125 // Execute the task
126 if (impl->has_then()) {
127 impl->execute_then();
128 } else {
129 warn_no_then(impl->id(), impl->trace_label());
130 }
131
132 // Remove one-shot tasks, keep recurring ones
133 bool is_recurring = (impl->type() == TaskType::kEveryMs || impl->type() == TaskType::kAtFramerate);
134 if (is_recurring) {
135 ++i; // Keep recurring tasks
136 } else {
137 // erase() returns bool in HeapVector, not iterator
138 mTasks.erase(mTasks.begin() + i);
139 // Don't increment i since we just removed an element
140 }
141 } else {
142 ++i;
143 }
144 }
145 }
146}
147
151
155
157 uint32_t current_time = fl::time();
158
159 // Use index-based iteration to avoid iterator invalidation issues
160 for (fl::size i = 0; i < mTasks.size();) {
161 task& t = mTasks[i];
162 auto impl = t.get_impl();
163
164 if (!impl || impl->is_canceled()) {
165 // erase() returns bool in HeapVector, not iterator
166 mTasks.erase(mTasks.begin() + i);
167 // Don't increment i since we just removed an element
168 } else if (impl->type() == task_type) {
169 // This is a frame task of the type we're looking for
170 bool should_run = impl->ready_to_run_frame_task(current_time);
171
172 if (should_run) {
173 // Update last run time for frame tasks (though they don't use it)
174 impl->set_last_run_time(current_time);
175
176 // Execute the task
177 if (impl->has_then()) {
178 impl->execute_then();
179 } else {
180 warn_no_then(impl->id(), impl->trace_label());
181 }
182
183 // Frame tasks are always one-shot, so remove them after execution
184 mTasks.erase(mTasks.begin() + i);
185 // Don't increment i since we just removed an element
186 } else {
187 ++i;
188 }
189 } else {
190 ++i; // Not the task type we're looking for
191 }
192 }
193}
194
195void Scheduler::warn_no_then(int task_id, const fl::string& trace_label) {
196 if (!trace_label.empty()) {
197 FL_WARN(fl::string("[fl::task] Warning: no then() callback set for Task#") << task_id << " launched at " << trace_label);
198 } else {
199 FL_WARN(fl::string("[fl::task] Warning: no then() callback set for Task#") << task_id);
200 }
201}
202
203void Scheduler::warn_no_catch(int task_id, const fl::string& trace_label, const Error& error) {
204 if (!trace_label.empty()) {
205 FL_WARN(fl::string("[fl::task] Warning: no catch_() callback set for Task#") << task_id << " launched at " << trace_label << ". Error: " << error.message);
206 } else {
207 FL_WARN(fl::string("[fl/task] Warning: no catch_() callback set for Task#") << task_id << ". Error: " << error.message);
208 }
209}
210
211} // namespace fl
size_t total_active_tasks() const
Get total number of active tasks across all runners.
Definition async.cpp:51
bool has_active_tasks() const
Check if there are any active async tasks.
Definition async.cpp:42
static AsyncManager & instance()
Definition async.cpp:16
void update_all()
Update all registered async runners.
Definition async.cpp:33
void register_runner(async_runner *runner)
Register an async runner.
Definition async.cpp:20
fl::vector< async_runner * > mRunners
Definition async.h:99
void unregister_runner(async_runner *runner)
Unregister an async runner.
Definition async.cpp:26
Async task manager (singleton)
Definition async.h:79
int mNextTaskId
Definition async.h:257
static Scheduler & instance()
Definition async.cpp:91
void update()
Definition async.cpp:105
int add_task(task t)
Definition async.cpp:95
void update_before_frame_tasks()
Definition async.cpp:148
void warn_no_catch(int task_id, const fl::string &trace_label, const Error &error)
Definition async.cpp:203
void update_after_frame_tasks()
Definition async.cpp:152
fl::vector< task > mTasks
Definition async.h:256
void warn_no_then(int task_id, const fl::string &trace_label)
Definition async.cpp:195
void update_tasks_of_type(TaskType task_type)
Definition async.cpp:156
static T & instance()
Definition singleton.h:11
bool empty() const
Definition str.h:350
Generic asynchronous task runner interface.
Definition async.h:64
static uint32_t t
Definition Luminova.h:54
Universal timing functions for FastLED.
constexpr remove_reference< T >::type && move(T &&t) noexcept
Definition move.h:27
Iterator find(Iterator first, Iterator last, const T &value)
Definition algorithm.h:172
void async_yield()
Platform-specific async yield function.
Definition async.cpp:68
size_t async_active_tasks()
Get the number of active async tasks across all systems.
Definition async.cpp:82
fl::u32 time()
Universal millisecond timer - returns milliseconds since system startup.
Definition time.cpp:136
TaskType
Definition task.h:43
@ kBeforeFrame
Definition task.h:46
@ kAfterFrame
Definition task.h:47
@ kAtFramerate
Definition task.h:45
@ kEveryMs
Definition task.h:44
void async_run()
Run all registered async tasks once.
Definition async.cpp:63
bool async_has_tasks()
Check if any async systems have active tasks.
Definition async.cpp:86
IMPORTANT!
Definition crgb.h:20
Generic asynchronous task management for FastLED.
fl::string message
Definition promise.h:54
Error type for promises.
Definition promise.h:53
#define FL_WARN
Definition warn.h:12