Single scheduler driver: picks a Ready coro and steps it; on no Ready, classifies the wait-state and yields to the host (PendingTimer / PendingFrame / PendingHostCall / PendingEvent) or returns Ok when nothing alive remains. */
(&mut self)
| 318 | |
| 319 | /* Single scheduler driver: picks a Ready coro and steps it; on no Ready, classifies the wait-state and yields to the host (PendingTimer / PendingFrame / PendingHostCall / PendingEvent) or returns Ok when nothing alive remains. */ |
| 320 | pub(crate) fn top_loop(&mut self) -> Result<(), VmErr> { |
| 321 | loop { |
| 322 | // Charge the full scheduler scan so accumulating coroutines stay bounded. |
| 323 | self.charge_steps(self.scheduler.len().max(1))?; |
| 324 | self.wake_waiting_outers(); |
| 325 | let mut next_ready: Option<usize> = None; |
| 326 | let mut min_wake: Option<u64> = None; |
| 327 | let mut any_frame = false; |
| 328 | let mut any_event = false; |
| 329 | let mut any_host_call = false; |
| 330 | let mut alive = false; |
| 331 | for (i, h) in self.scheduler.iter().enumerate() { |
| 332 | match &h.state { |
| 333 | CoroState::Ready | CoroState::CancelPending => { next_ready = Some(i); alive = true; break; } |
| 334 | CoroState::Sleeping(w) => { |
| 335 | alive = true; |
| 336 | if min_wake.is_none_or(|m| *w < m) { min_wake = Some(*w); } |
| 337 | } |
| 338 | CoroState::WaitingForChildren { kind: WaitKind::Timeout { deadline_ns, .. }, .. } => { |
| 339 | alive = true; |
| 340 | if min_wake.is_none_or(|m| *deadline_ns < m) { min_wake = Some(*deadline_ns); } |
| 341 | } |
| 342 | CoroState::WaitingFrame => { any_frame = true; alive = true; } |
| 343 | CoroState::WaitingEvent => { any_event = true; alive = true; } |
| 344 | CoroState::WaitingHostCall(_) => { any_host_call = true; alive = true; } |
| 345 | CoroState::WaitingForChildren { .. } => { alive = true; } |
| 346 | CoroState::Done(_) | CoroState::Errored(_) | CoroState::Cancelled => {} |
| 347 | } |
| 348 | } |
| 349 | if !alive { return Ok(()); } |
| 350 | if let Some(i) = next_ready { |
| 351 | self.scheduler_step(i)?; |
| 352 | continue; |
| 353 | } |
| 354 | // Yield priority: frame tick > sleep/timeout deadline > host call > event. |
| 355 | if any_frame { return Err(VmErr::HostYield(SchedulerStatus::PendingFrame)); } |
| 356 | match min_wake { |
| 357 | Some(w) => { |
| 358 | let now = self.now_ns(); |
| 359 | if w > now { |
| 360 | if self.time_hook.is_some() { |
| 361 | return Err(VmErr::HostYield(SchedulerStatus::PendingTimer(w))); |
| 362 | } |
| 363 | self.virtual_clock_ns = w; |
| 364 | } |
| 365 | let now = self.now_ns(); |
| 366 | for h in self.scheduler.iter_mut() { |
| 367 | if let CoroState::Sleeping(w) = h.state && w <= now { |
| 368 | h.state = CoroState::Ready; |
| 369 | } |
| 370 | } |
| 371 | } |
| 372 | None => { |
| 373 | if any_host_call { return Err(VmErr::HostYield(SchedulerStatus::PendingHostCall)); } |
| 374 | if any_event { return Err(VmErr::HostYield(SchedulerStatus::PendingEvent)); } |
| 375 | return Ok(()); |
| 376 | } |
| 377 | } |
no test coverage detected