| 218 | } |
| 219 | |
| 220 | void CoroutineRunner::run(fl::u32 us) FL_NOEXCEPT { |
| 221 | if (mCount == 0) return; |
| 222 | |
| 223 | auto& platform = ICoroutinePlatform::instance(); |
| 224 | fl::u32 start = platform.micros(); |
| 225 | |
| 226 | // Run at least one coroutine, then keep going until time budget exhausted |
| 227 | bool first = true; |
| 228 | while (first || (platform.micros() - start) < us) { |
| 229 | first = false; |
| 230 | |
| 231 | if (mCount == 0) break; |
| 232 | |
| 233 | // Pick next coroutine (round-robin) |
| 234 | if (mNextIndex >= mCount) { |
| 235 | mNextIndex = 0; |
| 236 | } |
| 237 | |
| 238 | CoroutineContext* ctx = mQueue[mNextIndex]; |
| 239 | ++mNextIndex; |
| 240 | |
| 241 | if (!ctx) continue; |
| 242 | |
| 243 | // Remove completed or stopped coroutines |
| 244 | if (ctx->is_completed()) { |
| 245 | remove(ctx); |
| 246 | continue; |
| 247 | } |
| 248 | |
| 249 | if (ctx->should_stop()) { |
| 250 | ctx->stop_and_complete(); |
| 251 | remove(ctx); |
| 252 | continue; |
| 253 | } |
| 254 | |
| 255 | // Skip coroutines that aren't ready (e.g. awaiting a promise) |
| 256 | if (!ctx->is_ready()) { |
| 257 | continue; |
| 258 | } |
| 259 | |
| 260 | // Resume this coroutine — it will run until it suspends |
| 261 | ctx->resume(); |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | void CoroutineRunner::stop_all() FL_NOEXCEPT { |
| 266 | for (size_t i = 0; i < mCount; ++i) { |
no test coverage detected