FastLED 3.10.6
Loading...
Searching...
No Matches
executor.h
Go to the documentation of this file.
1#pragma once
2
42
43#include "fl/task/promise.h"
45#include "fl/task/scheduler.h"
46#include "fl/stl/singleton.h"
47#include "fl/task/task.h"
48#include "platforms/await.h"
49#include "fl/stl/cstddef.h" // for size_t
50#include "fl/stl/stdint.h" // for u8
51#include "fl/stl/vector.h"
52#include "fl/stl/noexcept.h"
53
54namespace fl {
55namespace task {
56
64enum class ExecFlags : u8 {
65 TASKS = 1 << 0,
66 COROUTINES = 1 << 1,
67 SYSTEM = 1 << 2,
68 ALL = (1 << 0) | (1 << 1) | (1 << 2)
69};
70
72 return static_cast<ExecFlags>(static_cast<u8>(a) | static_cast<u8>(b));
73}
74
75inline bool operator&(ExecFlags a, ExecFlags b) {
76 return (static_cast<u8>(a) & static_cast<u8>(b)) != 0;
77}
78
79namespace detail {
82int& await_depth_tls();
83} // namespace detail
84
86class Runner {
87public:
88 virtual ~Runner() FL_NO_EXCEPT = default;
89
91 virtual void update() = 0;
92
94 virtual bool has_active_tasks() const = 0;
95
97 virtual size_t active_task_count() const = 0;
98};
99
101class Executor {
102public:
103 static Executor& instance();
104
106 void register_runner(Runner* r);
107
109 void unregister_runner(Runner* r);
110
112 void update_all();
113
115 bool has_active_tasks() const;
116
118 size_t total_active_tasks() const;
119
120private:
122};
123
136void run(fl::u32 microseconds = 1000, ExecFlags flags = ExecFlags::ALL);
137
138
139
142size_t active_tasks();
143
146bool has_tasks();
147
183template<typename T>
185 // Handle invalid promises
186 if (!p.valid()) {
187 return PromiseResult<T>(Error("Invalid promise"));
188 }
189
190 // If already completed, return immediately
191 if (p.is_completed()) {
192 if (p.is_resolved()) {
193 return PromiseResult<T>(p.value());
194 } else {
195 return PromiseResult<T>(p.error());
196 }
197 }
198
199 // Track recursion depth to prevent infinite loops
200 int& await_depth = detail::await_depth_tls();
201 if (await_depth > 10) {
202 return PromiseResult<T>(Error("await_top_level recursion limit exceeded - possible infinite loop"));
203 }
204
205 ++await_depth;
206
207 // Wait for promise to complete while pumping async tasks
208 int pump_count = 0;
209 const int max_pump_iterations = 10000; // Safety limit
210
211 while (!p.is_completed() && pump_count < max_pump_iterations) {
212 // Update the promise first (in case it's not managed by async system)
213 p.update();
214
215 // Check if completed after update
216 if (p.is_completed()) {
217 break;
218 }
219
220 // Platform-agnostic async pump and yield
221 run(1000);
222
223 ++pump_count;
224 }
225
226 --await_depth;
227
228 // Check for timeout
229 if (pump_count >= max_pump_iterations) {
230 return PromiseResult<T>(Error("await_top_level timeout - promise did not complete"));
231 }
232
233 // Return the result
234 if (p.is_resolved()) {
235 return PromiseResult<T>(p.value());
236 } else {
237 return PromiseResult<T>(p.error());
238 }
239}
240
241} // namespace task
242} // namespace fl
243
244// ============================================================================
245// Await API Comparison: await() vs await_top_level()
246// ============================================================================
247//
248// FastLED provides two await functions for different contexts:
249//
250// 1. fl::task::await() - For coroutines (ESP32/Host only)
251// - Zero CPU overhead (true OS-level blocking)
252// - Must be called from fl::task::coroutine() context
253// - Suspends coroutine thread until promise completes
254// - Platform support: ESP32 (FreeRTOS), Host/Stub (std::thread)
255//
256// 2. fl::task::await_top_level() - For main loop/top-level code (All platforms)
257// - High CPU usage (busy-wait with run(1000))
258// - Safe to call from Arduino loop() or main()
259// - NOT safe in promise callbacks or nested async operations
260// - Platform support: All platforms
261//
262// **When to use which?**
263// - In fl::task::coroutine(): Use fl::task::await() for zero CPU waste
264// - In Arduino loop() or main(): Use fl::task::await_top_level()
265// - Other platforms without coroutine support: Use fl::task::await_top_level()
266//
267// ============================================================================
268
269
270
271namespace fl {
272namespace task {
273
306template<typename T>
308 Promise<T> p,
309 fl::u32 timeout_ms = fl::platforms::kAwaitDefaultTimeoutMs) FL_NO_EXCEPT {
310 return fl::platforms::await(p, timeout_ms);
311}
312
313} // namespace task
314} // namespace fl
fl::vector< Runner * > mRunners
Definition executor.h:121
void update_all()
Update all registered runners.
void register_runner(Runner *r)
Register a runner.
size_t total_active_tasks() const
Get total number of active tasks across all runners.
static Executor & instance()
void unregister_runner(Runner *r)
Unregister a runner.
Task executor (singleton) — manages registered runners.
Definition executor.h:101
const Error & error() const FL_NO_EXCEPT
Get the error (only valid if is_rejected() returns true)
Definition promise.h:167
bool valid() const FL_NO_EXCEPT
Check if Promise is valid.
Definition promise.h:108
void update() FL_NO_EXCEPT
Update Promise state in main loop - should be called periodically This processes pending callbacks wh...
Definition promise.h:134
const T & value() const FL_NO_EXCEPT
Get the result value (only valid if is_resolved() returns true)
Definition promise.h:158
bool is_completed() const FL_NO_EXCEPT
Check if Promise is completed (resolved or rejected)
Definition promise.h:140
bool is_resolved() const FL_NO_EXCEPT
Check if Promise is resolved (completed successfully)
Definition promise.h:146
Promise class that provides fluent .then() and .catch_() semantics This is a lightweight wrapper arou...
Definition promise.h:58
Result type for promise operations.
virtual void update()=0
Update this runner (called during task pumping)
virtual ~Runner() FL_NO_EXCEPT=default
virtual size_t active_task_count() const =0
Get number of active tasks (for debugging/monitoring)
virtual bool has_active_tasks() const =0
Check if this runner has active tasks.
Generic task runner interface.
Definition executor.h:86
Compile-time linker keep-alive hook for a single fl::Bus.
Definition bus_info.h:57
int & await_depth_tls()
Get reference to thread-local await recursion depth.
bool has_tasks()
Check if any systems have active tasks.
ExecFlags operator|(ExecFlags a, ExecFlags b)
Definition executor.h:71
void run(fl::u32 microseconds, ExecFlags flags)
Run selected task subsystems.
size_t active_tasks()
Get the number of active tasks across all systems.
PromiseResult< T > await(Promise< T > p, fl::u32 timeout_ms=fl::platforms::kAwaitDefaultTimeoutMs) FL_NO_EXCEPT
Await promise completion in a coroutine (Trampoline to platform implementation)
Definition executor.h:307
PromiseResult< T > await_top_level(Promise< T > p)
Synchronously wait for a promise to complete (ONLY safe in top-level contexts)
Definition executor.h:184
ExecFlags
Flags controlling which subsystems run() pumps.
Definition executor.h:64
bool operator&(ExecFlags a, ExecFlags b)
Definition executor.h:75
unsigned char u8
Definition stdint.h:131
InputGamut g FL_NO_EXCEPT
Definition rgbw.h:121
Base definition for an LED controller.
Definition crgb.hpp:179
Promise-based fluent API for FastLED - standalone async primitives.
Task scheduler — manages timer and frame-based tasks.