FastLED 3.9.15
Loading...
Searching...
No Matches
task.cpp.hpp
Go to the documentation of this file.
1#include "fl/task/task.h"
2#include "fl/stl/limits.h"
3#include "fl/task/scheduler.h"
4#include "fl/stl/sstream.h"
5#include "fl/stl/unique_ptr.h"
6#include "fl/stl/atomic.h"
7#include "platforms/coroutine.h"
8#include "fl/stl/noexcept.h"
9
10namespace fl {
11namespace task {
12
13namespace {
14// Generate trace label from TracePoint
15string make_trace_label(const TracePoint& trace) {
16 sstream ss;
17 ss << fl::get<0>(trace) << ":" << fl::get<1>(trace);
18 return ss.str();
19}
20
21// Task ID generator (atomic for thread safety)
23 static fl::atomic<int> id(0); // okay static in header
24 return id.fetch_add(1) + 1;
25}
26} // namespace
27
28} // namespace task
29} // namespace fl
30
31namespace fl {
32namespace task {
33
34//=============================================================================
35// Coroutine - RAII wrapper around platform-specific implementation
36//=============================================================================
37
38class Coroutine {
39public:
40 using TaskFunction = fl::function<void()>;
41
42 Coroutine(fl::string name, TaskFunction function, size_t stack_size = 4096, u8 priority = 5, int core_id = -1)
43 : mImpl(platforms::createTaskCoroutine(fl::move(name), fl::move(function), stack_size, priority, core_id)) {
44 }
45
47
49 Coroutine& operator=(const Coroutine&) FL_NOEXCEPT = delete;
51 Coroutine& operator=(Coroutine&&) FL_NOEXCEPT = delete;
52
53 void stop() {
54 if (mImpl) {
55 mImpl->stop();
56 }
57 }
58
59 bool isRunning() const {
60 return mImpl ? mImpl->isRunning() : false;
61 }
62
63 static void exitCurrent() {
64 platforms::ICoroutineTask::exitCurrent();
65 }
66
67private:
68 platforms::TaskCoroutinePtr mImpl;
69};
70
71} // namespace task
72} // namespace fl
73
74namespace fl {
75namespace task {
76
77//=============================================================================
78// ITaskImpl - Virtual Interface
79//=============================================================================
80
81class ITaskImpl {
82public:
83 virtual ~ITaskImpl() FL_NOEXCEPT = default;
84 virtual void set_then(function<void()> on_then) = 0;
85 virtual void set_catch(function<void(const Error&)> on_catch) = 0;
86 virtual void set_canceled() = 0;
87 virtual int id() const = 0;
88 virtual void set_id(int id) = 0;
89 virtual bool has_then() const = 0;
90 virtual bool has_catch() const = 0;
91 virtual string trace_label() const = 0;
92 virtual TaskType type() const = 0;
93 virtual int interval_ms() const = 0;
94 virtual void set_interval_ms(int interval_ms) = 0;
95 virtual u32 last_run_time() const = 0;
96 virtual void set_last_run_time(u32 time) = 0;
97 virtual bool ready_to_run(u32 current_time) const = 0;
98 virtual bool ready_to_run_frame_task(u32 current_time) const = 0;
99 virtual bool is_canceled() const = 0;
100 virtual bool is_auto_registered() const = 0;
101 virtual void execute_then() = 0;
102 virtual void execute_catch(const Error& error) = 0;
104
105 // Coroutine methods (no-op for non-coroutine tasks)
106 virtual void stop() = 0;
107 virtual bool isRunning() const = 0;
108};
109
110//=============================================================================
111// TimeTask - Time-based task implementation
112//=============================================================================
113
114class TimeTask : public ITaskImpl {
115public:
117 : mTaskId(next_task_id())
118 , mType(type)
120 , mTraceLabel(trace ? make_unique<string>(make_trace_label(*trace)) : nullptr)
121 // Use (max)() to prevent macro expansion by Arduino.h's max macro
122 , mLastRunTime((numeric_limits<u32>::max)()) {}
123
124 void set_then(function<void()> on_then) override {
125 mThenCallback = fl::move(on_then);
126 mHasThen = true;
127 }
128
129 void set_catch(function<void(const Error&)> on_catch) override {
130 mCatchCallback = fl::move(on_catch);
131 mHasCatch = true;
132 }
133
134 void set_canceled() override {
135 mCanceled = true;
136 // Release callbacks immediately to free captured variables (e.g. promises
137 // holding response objects). Without this, captures survive until the
138 // scheduler erases the task on its next update pass.
139 mThenCallback = {};
140 mCatchCallback = {};
141 mHasThen = false;
142 mHasCatch = false;
143 }
144
145 int id() const override { return mTaskId; }
146 void set_id(int id) override { mTaskId = id; }
147 bool has_then() const override { return mHasThen; }
148 bool has_catch() const override { return mHasCatch; }
149 string trace_label() const override { return mTraceLabel ? *mTraceLabel : ""; }
150 TaskType type() const override { return mType; }
151 int interval_ms() const override { return mIntervalMs; }
153 u32 last_run_time() const override { return mLastRunTime; }
154 void set_last_run_time(u32 time) override { mLastRunTime = time; }
155 bool is_canceled() const override { return mCanceled; }
156 bool is_auto_registered() const override { return mAutoRegistered; }
157
158 bool ready_to_run(u32 current_time) const override {
160 return false; // Frame tasks not ready during regular updates
161 }
162 if (mIntervalMs <= 0) return true;
163 // Use (max)() to prevent macro expansion by Arduino.h's max macro
164 if (mLastRunTime == (fl::numeric_limits<u32>::max)()) return true;
165 return (current_time - mLastRunTime) >= static_cast<u32>(mIntervalMs);
166 }
167
168 bool ready_to_run_frame_task(u32 /*current_time*/) const override {
170 }
171
172 void execute_then() override {
173 if (mHasThen && mThenCallback) {
175 }
176 }
177
178 void execute_catch(const Error& error) override {
179 if (mHasCatch && mCatchCallback) {
180 mCatchCallback(error);
181 }
182 }
183
185 mAutoRegistered = true;
186 }
187
188 void stop() override {
189 mRunning = false;
190 mCanceled = true; // Mark as canceled so scheduler removes it
191 }
192
193 bool isRunning() const override {
194 return mRunning && !mCanceled;
195 }
196
197private:
201 bool mCanceled = false;
202 bool mAutoRegistered = false;
203 bool mRunning = true; // Time tasks start running immediately
205 bool mHasThen = false;
206 bool mHasCatch = false;
210};
211
212//=============================================================================
213// CoroutineTask - OS-level coroutine task
214//=============================================================================
215
216class CoroutineTask : public ITaskImpl {
217public:
219 : mTaskId(next_task_id())
220 , mTraceLabel(config.trace ? make_unique<string>(make_trace_label(*config.trace)) : nullptr)
221 , mCoroutine(make_unique<Coroutine>(config.name, config.func, config.stack_size, config.priority,
222 config.core_id.has_value() ? config.core_id.value() : -1)) {}
223
224 void set_then(function<void()>) override { /* Coroutine tasks don't use then */ }
225 void set_catch(function<void(const Error&)>) override { /* Coroutine tasks don't use catch */ }
226 void set_canceled() override { mCanceled = true; }
227
228 int id() const override { return mTaskId; }
229 void set_id(int id) override { mTaskId = id; }
230 bool has_then() const override { return false; }
231 bool has_catch() const override { return false; }
232 string trace_label() const override { return mTraceLabel ? *mTraceLabel : ""; }
233 TaskType type() const override { return TaskType::kCoroutine; }
234 int interval_ms() const override { return 0; }
235 void set_interval_ms(int) override { /* Coroutine tasks don't use intervals */ }
236 fl::u32 last_run_time() const override { return 0; }
237 void set_last_run_time(fl::u32) override {}
238 bool is_canceled() const override { return mCanceled; }
239 bool is_auto_registered() const override { return mAutoRegistered; }
240
241 bool ready_to_run(fl::u32) const override { return false; }
242 bool ready_to_run_frame_task(fl::u32) const override { return false; }
243
244 void execute_then() override {}
245 void execute_catch(const Error&) override {}
246
248 mAutoRegistered = true;
249 }
250
251 void stop() override {
252 if (mCoroutine) {
253 mCoroutine->stop();
254 }
255 }
256
257 bool isRunning() const override {
258 return mCoroutine ? mCoroutine->isRunning() : false;
259 }
260
261private:
263 bool mCanceled = false;
264 bool mAutoRegistered = false;
267};
268
269//=============================================================================
270// Handle - Public API Implementation
271//=============================================================================
272
274
275// Fluent API
276Handle& Handle::then(function<void()> on_then) {
277 if (mImpl) {
278 mImpl->set_then(fl::move(on_then));
279 if (!mImpl->is_auto_registered()) {
280 mImpl->auto_register_with_scheduler();
282 }
283 }
284 return *this;
285}
286
287Handle& Handle::catch_(function<void(const Error&)> on_catch) {
288 if (mImpl) {
289 mImpl->set_catch(fl::move(on_catch));
290 }
291 return *this;
292}
293
295 if (mImpl) {
296 mImpl->set_canceled();
297 }
298 return *this;
299}
300
301// Getters
302int Handle::id() const { return mImpl ? mImpl->id() : 0; }
303bool Handle::has_then() const { return mImpl ? mImpl->has_then() : false; }
304bool Handle::has_catch() const { return mImpl ? mImpl->has_catch() : false; }
305string Handle::trace_label() const { return mImpl ? mImpl->trace_label() : ""; }
306TaskType Handle::type() const { return mImpl ? mImpl->type() : TaskType::kEveryMs; }
307int Handle::interval_ms() const { return mImpl ? mImpl->interval_ms() : 0; }
308void Handle::set_interval_ms(int interval_ms) { if (mImpl) mImpl->set_interval_ms(interval_ms); }
309fl::u32 Handle::last_run_time() const { return mImpl ? mImpl->last_run_time() : 0; }
310void Handle::set_last_run_time(fl::u32 time) { if (mImpl) mImpl->set_last_run_time(time); }
311bool Handle::ready_to_run(fl::u32 current_time) const { return mImpl ? mImpl->ready_to_run(current_time) : false; }
312bool Handle::is_valid() const { return mImpl != nullptr; }
313bool Handle::isCoroutine() const { return mImpl && mImpl->type() == TaskType::kCoroutine; }
314
315// Coroutine control
316void Handle::stop() { if (mImpl) mImpl->stop(); }
317bool Handle::isRunning() const { return mImpl ? mImpl->isRunning() : false; }
318
319// Free function builders (were static methods on class fl::task)
320Handle every_ms(int interval_ms) {
322}
323
324Handle every_ms(int interval_ms, const TracePoint& trace) {
325 return Handle(fl::make_shared<TimeTask>(TaskType::kEveryMs, interval_ms, trace));
326}
327
331
332Handle at_framerate(int fps, const TracePoint& trace) {
333 return Handle(fl::make_shared<TimeTask>(TaskType::kAtFramerate, 1000 / fps, trace));
334}
335
339
343
347
351
352Handle after_frame(function<void()> on_then) {
353 Handle t = after_frame();
354 t.then(fl::move(on_then));
355 return t;
356}
357
358Handle after_frame(function<void()> on_then, const TracePoint& trace) {
359 Handle t = after_frame(trace);
360 t.then(fl::move(on_then));
361 return t;
362}
363
366}
367
368// Static coroutine control
370
371// Internal methods for Scheduler (friend access only)
372void Handle::_set_id(int id) { if (mImpl) mImpl->set_id(id); }
373int Handle::_id() const { return mImpl ? mImpl->id() : 0; }
374bool Handle::_is_canceled() const { return mImpl ? mImpl->is_canceled() : true; }
375bool Handle::_ready_to_run(fl::u32 current_time) const { return mImpl ? mImpl->ready_to_run(current_time) : false; }
376bool Handle::_ready_to_run_frame_task(fl::u32 current_time) const { return mImpl ? mImpl->ready_to_run_frame_task(current_time) : false; }
377void Handle::_set_last_run_time(fl::u32 time) { if (mImpl) mImpl->set_last_run_time(time); }
378bool Handle::_has_then() const { return mImpl ? mImpl->has_then() : false; }
379void Handle::_execute_then() { if (mImpl) mImpl->execute_then(); }
380void Handle::_execute_catch(const Error& error) { if (mImpl) mImpl->execute_catch(error); }
381TaskType Handle::_type() const { return mImpl ? mImpl->type() : TaskType::kEveryMs; }
382string Handle::_trace_label() const { return mImpl ? mImpl->trace_label() : ""; }
383
384} // namespace task
385} // namespace fl
string str() const FL_NOEXCEPT
Definition strstream.h:43
platforms::TaskCoroutinePtr mImpl
Definition task.cpp.hpp:68
Coroutine(fl::string name, TaskFunction function, size_t stack_size=4096, u8 priority=5, int core_id=-1)
Definition task.cpp.hpp:42
bool isRunning() const
Definition task.cpp.hpp:59
fl::function< void()> TaskFunction
Definition task.cpp.hpp:40
~Coroutine() FL_NOEXCEPT=default
static void exitCurrent()
Definition task.cpp.hpp:63
unique_ptr< string > mTraceLabel
Definition task.cpp.hpp:265
void execute_catch(const Error &) override
Definition task.cpp.hpp:245
bool ready_to_run_frame_task(fl::u32) const override
Definition task.cpp.hpp:242
void auto_register_with_scheduler() override
Definition task.cpp.hpp:247
bool ready_to_run(fl::u32) const override
Definition task.cpp.hpp:241
CoroutineTask(const CoroutineConfig &config)
Definition task.cpp.hpp:218
int id() const override
Definition task.cpp.hpp:228
void set_id(int id) override
Definition task.cpp.hpp:229
void execute_then() override
Definition task.cpp.hpp:244
TaskType type() const override
Definition task.cpp.hpp:233
string trace_label() const override
Definition task.cpp.hpp:232
void stop() override
Definition task.cpp.hpp:251
void set_last_run_time(fl::u32) override
Definition task.cpp.hpp:237
bool is_canceled() const override
Definition task.cpp.hpp:238
void set_then(function< void()>) override
Definition task.cpp.hpp:224
bool is_auto_registered() const override
Definition task.cpp.hpp:239
int interval_ms() const override
Definition task.cpp.hpp:234
bool has_then() const override
Definition task.cpp.hpp:230
bool isRunning() const override
Definition task.cpp.hpp:257
bool has_catch() const override
Definition task.cpp.hpp:231
unique_ptr< Coroutine > mCoroutine
Definition task.cpp.hpp:266
void set_catch(function< void(const Error &)>) override
Definition task.cpp.hpp:225
void set_interval_ms(int) override
Definition task.cpp.hpp:235
void set_canceled() override
Definition task.cpp.hpp:226
fl::u32 last_run_time() const override
Definition task.cpp.hpp:236
Handle & then(function< void()> on_then) FL_NOEXCEPT
Definition task.cpp.hpp:276
Handle() FL_NOEXCEPT=default
string trace_label() const FL_NOEXCEPT
Definition task.cpp.hpp:305
bool _is_canceled() const FL_NOEXCEPT
Definition task.cpp.hpp:374
int id() const FL_NOEXCEPT
Definition task.cpp.hpp:302
bool isRunning() const FL_NOEXCEPT
Definition task.cpp.hpp:317
bool _ready_to_run(u32 current_time) const FL_NOEXCEPT
bool ready_to_run(u32 current_time) const FL_NOEXCEPT
Handle & catch_(function< void(const Error &)> on_catch) FL_NOEXCEPT
Definition task.cpp.hpp:287
void _set_last_run_time(u32 time) FL_NOEXCEPT
void _execute_then() FL_NOEXCEPT
Definition task.cpp.hpp:379
bool is_valid() const FL_NOEXCEPT
Definition task.cpp.hpp:312
u32 last_run_time() const FL_NOEXCEPT
Definition task.cpp.hpp:309
bool _ready_to_run_frame_task(u32 current_time) const FL_NOEXCEPT
void stop() FL_NOEXCEPT
Definition task.cpp.hpp:316
int _id() const FL_NOEXCEPT
Definition task.cpp.hpp:373
TaskType type() const FL_NOEXCEPT
Definition task.cpp.hpp:306
bool has_then() const FL_NOEXCEPT
Definition task.cpp.hpp:303
bool has_catch() const FL_NOEXCEPT
Definition task.cpp.hpp:304
bool isCoroutine() const FL_NOEXCEPT
Definition task.cpp.hpp:313
void _execute_catch(const Error &error) FL_NOEXCEPT
Definition task.cpp.hpp:380
bool _has_then() const FL_NOEXCEPT
Definition task.cpp.hpp:378
int interval_ms() const FL_NOEXCEPT
Definition task.cpp.hpp:307
string _trace_label() const FL_NOEXCEPT
Definition task.cpp.hpp:382
Handle & cancel() FL_NOEXCEPT
Definition task.cpp.hpp:294
void _set_id(int id) FL_NOEXCEPT
Definition task.cpp.hpp:372
void set_interval_ms(int interval_ms) FL_NOEXCEPT
Definition task.cpp.hpp:308
void set_last_run_time(u32 time) FL_NOEXCEPT
shared_ptr< ITaskImpl > mImpl
Definition task.h:194
TaskType _type() const FL_NOEXCEPT
Definition task.cpp.hpp:381
Task Handle with fluent API (was class fl::task, renamed to avoid namespace collision)
Definition task.h:139
virtual bool is_auto_registered() const =0
virtual TaskType type() const =0
virtual void set_id(int id)=0
virtual bool has_catch() const =0
virtual void execute_then()=0
virtual void set_canceled()=0
virtual bool isRunning() const =0
virtual void set_interval_ms(int interval_ms)=0
virtual bool ready_to_run(u32 current_time) const =0
virtual string trace_label() const =0
virtual int interval_ms() const =0
virtual void set_last_run_time(u32 time)=0
virtual void set_catch(function< void(const Error &)> on_catch)=0
virtual bool ready_to_run_frame_task(u32 current_time) const =0
virtual void auto_register_with_scheduler()=0
virtual ~ITaskImpl() FL_NOEXCEPT=default
virtual bool is_canceled() const =0
virtual bool has_then() const =0
virtual void set_then(function< void()> on_then)=0
virtual void execute_catch(const Error &error)=0
virtual u32 last_run_time() const =0
virtual void stop()=0
static Scheduler & instance()
int add_task(Handle t)
void execute_catch(const Error &error) override
Definition task.cpp.hpp:178
void set_interval_ms(int interval_ms) override
Definition task.cpp.hpp:152
string trace_label() const override
Definition task.cpp.hpp:149
void execute_then() override
Definition task.cpp.hpp:172
TimeTask(TaskType type, int interval_ms, optional< TracePoint > trace=nullopt)
Definition task.cpp.hpp:116
bool is_canceled() const override
Definition task.cpp.hpp:155
bool isRunning() const override
Definition task.cpp.hpp:193
u32 last_run_time() const override
Definition task.cpp.hpp:153
void set_id(int id) override
Definition task.cpp.hpp:146
void set_canceled() override
Definition task.cpp.hpp:134
bool is_auto_registered() const override
Definition task.cpp.hpp:156
TaskType type() const override
Definition task.cpp.hpp:150
bool ready_to_run(u32 current_time) const override
Definition task.cpp.hpp:158
void set_catch(function< void(const Error &)> on_catch) override
Definition task.cpp.hpp:129
int id() const override
Definition task.cpp.hpp:145
void auto_register_with_scheduler() override
Definition task.cpp.hpp:184
int interval_ms() const override
Definition task.cpp.hpp:151
unique_ptr< string > mTraceLabel
Definition task.cpp.hpp:204
void set_then(function< void()> on_then) override
Definition task.cpp.hpp:124
bool has_then() const override
Definition task.cpp.hpp:147
bool has_catch() const override
Definition task.cpp.hpp:148
function< void()> mThenCallback
Definition task.cpp.hpp:208
void set_last_run_time(u32 time) override
Definition task.cpp.hpp:154
void stop() override
Definition task.cpp.hpp:188
function< void(const Error &)> mCatchCallback
Definition task.cpp.hpp:209
bool ready_to_run_frame_task(u32) const override
Definition task.cpp.hpp:168
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
string make_trace_label(const TracePoint &trace)
Definition task.cpp.hpp:15
Handle every_ms(int interval_ms)
Definition task.cpp.hpp:320
Handle at_framerate(int fps)
Definition task.cpp.hpp:328
Handle before_frame()
Definition task.cpp.hpp:336
Handle coroutine(const CoroutineConfig &config)
Definition task.cpp.hpp:364
Handle after_frame()
Definition task.cpp.hpp:344
void exit_current()
Definition task.cpp.hpp:369
TaskType
Definition task.h:116
Configuration for OS-level coroutine tasks.
Definition task.h:129
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition move.h:28
unsigned char u8
Definition stdint.h:131
constexpr int type_rank< T >::value
constexpr common_type_t< T, U > max(T a, U b) FL_NOEXCEPT
Definition math.h:75
AtomicFake< T > atomic
Definition atomic.h:26
fl::u64 time() FL_NOEXCEPT
Alias for millis64() - returns 64-bit millisecond time.
Definition chrono.h:346
fl::enable_if<!fl::is_array< T >::value, unique_ptr< T > >::type make_unique(Args &&... args) FL_NOEXCEPT
Definition unique_ptr.h:261
Optional< T > optional
Definition optional.h:16
shared_ptr< T > make_shared(Args &&... args) FL_NOEXCEPT
Definition shared_ptr.h:414
constexpr nullopt_t nullopt
Definition optional.h:13
pair_element< I, T1, T2 >::type & get(pair< T1, T2 > &p) FL_NOEXCEPT
Definition pair.h:115
fl::tuple< const char *, int, fl::u32 > TracePoint
A structure to hold source trace information.
Definition trace.h:51
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NOEXCEPT
Task scheduler — manages timer and frame-based tasks.
static constexpr T max() FL_NOEXCEPT
Definition limits.h:108
Error type for promises.
Definition promise.h:39