FastLED 3.10.8
Loading...
Searching...
No Matches

◆ run()

void fl::task::run ( fl::u32 microseconds = 1000,
ExecFlags flags = ExecFlags::ALL )

Run selected task subsystems.

Pumps the requested subsystems and yields for up to microseconds.

Usage:

  • run() — pump ALL + yield for 1ms (default)
  • run(0) — pump ALL, no yield
  • run(250, ExecFlags::SYSTEM) — OS yield only; prefer yield_system(250)
  • run(1000, ExecFlags::TASKS | ExecFlags::COROUTINES) — skip OS yield
Parameters
microsecondsBudget in microseconds (default 1000 = 1ms)
flagsWhich subsystems to pump (default ALL)

Definition at line 76 of file executor.cpp.hpp.

76 {
77 // Re-entrancy guard: detect if run is called from within run
79 if (running) {
80 FL_WARN_ONCE("task::run re-entrancy detected, skipping nested call");
81 return;
82 }
83 running = true;
84 auto guard = fl::make_scope_exit([&running]() { running = false; });
85
86 const bool do_tasks = flags & ExecFlags::TASKS;
87 const bool do_coroutines = flags & ExecFlags::COROUTINES;
88 const bool do_system = flags & ExecFlags::SYSTEM;
89
90 // Calculate start time with rollover protection
91 fl::u32 begin_time = fl::micros();
92
93 // Lambda to get elapsed time (rollover-safe)
94 auto elapsed = [begin_time]() {
95 return fl::micros() - begin_time;
96 };
97
98 // Lambda to get remaining time until deadline expires
99 auto remaining = [elapsed, microseconds]() -> fl::u32 {
100 fl::u32 e = elapsed();
101 if (e >= microseconds) {
102 return 0;
103 }
104 return microseconds - e;
105 };
106
107 // Lambda to check if deadline has expired
108 auto expired = [remaining]() {
109 return remaining() == 0;
110 };
111
112 do {
113 // TASKS: Scheduler (fl::task timers) + Executor (fetch, HTTP server, audio)
114 if (do_tasks) {
117 }
118
119 // SYSTEM: OS-level yield.
120 //
121 // When the caller provided a non-zero microseconds budget we treat
122 // this as an explicit spin-wait on hardware (typical DMA / driver
123 // wait loops). In that case we MUST use a deep yield (>= 1 FreeRTOS
124 // tick on ESP32) so that lower-priority network tasks — WiFi,
125 // Ethernet lwIP, etc. — actually get CPU time. Previously this
126 // path was gated on an active WiFi mode check, which missed
127 // Ethernet-only deployments and also the pre-connection window
128 // where `esp_wifi_get_mode` still returns WIFI_MODE_NULL. That
129 // regression manifested as the ESP32-S3 I2S-vs-websockets
130 // starvation reported in https://github.com/FastLED/FastLED/issues/2254
131 // (Issue 1).
132 //
133 // When microseconds == 0 the caller wants the cheapest possible
134 // yield (we are between other pumped subsystems and will loop
135 // again immediately), so we keep the lightweight fl::yield() path.
136 //
137 // The sleep is clamped to whatever is left of the caller's budget,
138 // mirroring the COROUTINES branch below. This used to be a hardcoded
139 // pumpCoroutines(1000) that ignored `microseconds` entirely, so a
140 // caller asking for run(250, SYSTEM) slept 1000 us and overshot its
141 // own deadline by 750 us on every platform where pumpCoroutines
142 // honors the requested duration (host/stub -- CoroutineRunner::run).
143 //
144 // ESP32 behavior is unchanged: pumpCoroutines() there converts us to
145 // FreeRTOS ticks and floors at one tick for ANY non-zero request
146 // (coroutine_esp32.impl.hpp, the `if (ticks == 0) ticks = 1` branch
147 // added for #2254), so 250 and 1000 both yield exactly one tick. The
148 // deep-yield guarantee #2254 depends on still holds.
149 if (do_system) {
150 if (microseconds > 0) {
151 const fl::u32 time_left = remaining();
152 if (time_left) {
153 fl::platforms::ICoroutineRuntime::instance().pumpCoroutines(
154 fl::min(1000u, time_left));
155 }
156 } else {
157 fl::yield();
158 }
159 }
160
161 // COROUTINES: Platform cooperative coroutines (pumpCoroutines)
162 if (do_coroutines) {
163 auto time_left = remaining();
164 if (time_left) {
165 fl::u32 sleep_us = fl::min(1000u, time_left);
166 fl::platforms::ICoroutineRuntime::instance().pumpCoroutines(sleep_us);
167 }
168 }
169 } while (!expired());
170}
static T & instance() FL_NO_EXCEPT
Definition singleton.h:133
static Executor & instance() FL_NO_EXCEPT
void update_all() FL_NO_EXCEPT
Update all registered runners.
static Scheduler & instance() FL_NO_EXCEPT
void update() FL_NO_EXCEPT
#define FL_WARN_ONCE(...)
Definition log.h:439
duration< fl::i64, fl::micro > microseconds
Microseconds - duration with period of 1/1,000,000 seconds.
Definition chrono.h:103
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NO_EXCEPT
Definition math.h:71
fl::u32 micros() FL_NO_EXCEPT
Universal microsecond timer - returns microseconds since system startup.
scope_exit< decay_t< EF > > make_scope_exit(EF &&f)
Factory for C++11/14 (no CTAD).
Definition scope_exit.h:48
void yield() FL_NO_EXCEPT
Yield to the platform scheduler.
Definition yield.cpp.hpp:32

References COROUTINES, fl::FL_NO_EXCEPT, FL_WARN_ONCE, fl::SingletonThreadLocal< T, N >::instance(), fl::task::Executor::instance(), fl::task::Scheduler::instance(), fl::make_scope_exit(), fl::micros(), fl::min(), SYSTEM, TASKS, fl::task::Scheduler::update(), fl::task::Executor::update_all(), and fl::yield().

Referenced by fl::detail::delay_impl(), fl::net::http::fetch_update(), loop(), and fl::net::http::FetchEngineListener::onEndFrame().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: