feat(scheduler-core): implement simulation event loop and virtual clock advancement (task 11.2)

Add sim_loop.c implementing sched_sim_driver_run(): decode .replay
messages in file order, jump the virtual clock to each ReplayEvent's
exact timestamp as it's queued, and run a real push-events/go/drain/
end-session cycle on each ReplaySession boundary (AC 14, AC 18).

Task 11.1 left no picker registered against the isolated core and no
thread backing its cbufs, which deadlocks the decision drain the moment
a real event loop exists. Add plugin_register_core() (registers a
picker against a bare xce_sched_core_t*, no xce_scheduler_t* required)
and extract builtin_fcfs_new_plugin() from register_builtin_fcfs() as a
behavior-preserving factory, plus a picker-driving thread for the sim
driver. Since real resource allocation is unreachable without a live
xce_scheduler_t* (scheduler-allocation spec's job), the sim picker
thread conservatively PENDs every candidate rather than dispatching.

28/28 scheduler suite, 32/32 whole-project tests green.
This commit is contained in:
Rongsong Shen 2026-08-06 10:27:40 +00:00
parent 5d587ecf32
commit 7e1e861e4f
Signed by: rshen
SSH key fingerprint: SHA256:8Vf2pZ3h6rJa7EhGK+WaAQ9Mta/apZvteW6g9U/WKKk
11 changed files with 1248 additions and 76 deletions

View file

@ -205,22 +205,19 @@ extern int sched_sim_driver_start(xce_sched_sim_driver_t* sim,
* void* args)`, adapted to take the concrete sched_sim_args_t* this header
* defines rather than an opaque void* -- see sched_sim_args_t's own doc
* comment for why). This is what main.c's mode-selection branch calls when
* `--sim` is present (design.md's own Integration note).
* `--sim` is present (design.md's own Integration note). Defined in
* sim_loop.c (scheduler-core spec, task 11.2), not sim.c: calls
* sched_sim_driver_start() above (task 11.1) then runs Req 5 AC 13 step
* 5's event loop (Req 5 AC 14/18) -- decode each `.replay` message in file
* order, jump the virtual clock to each ReplayEvent's own timestamp as it
* is queued (AC 14), and on each ReplaySession boundary run one complete
* push-events -> start-session -> drain-decisions -> end-session round.
*
* Calls sched_sim_driver_start() above (task 11.1's own work, this task's
* Observable) then -- since task 11.2's event loop (Req 5 AC 13 step 5 /
* AC 14/18) does not exist yet -- fails loudly with -ENOSYS rather than
* silently returning success having processed zero events. This is the
* same "honest, temporary placeholder" precedent main.c's own pre-task-11.1
* `--sim` stub already established (task 5.2): startup is now genuinely
* real, working behavior; only the event loop remains a documented gap for
* task 11.2 to fill in, without requiring another main.c edit when it does
* (task 11.2 only needs to extend THIS function's body, after the
* sched_sim_driver_start() call, with the real event loop).
*
* Returns 0 (once task 11.2 lands) or a negative errno: whatever
* sched_sim_driver_start() returned on a startup failure, or -ENOSYS if
* startup succeeded but the event loop is not yet implemented.
* Returns 0 once the replay stream is exhausted (its ReplayEvent{endSession}
* marker is reached, Req 5 AC 20), or a negative errno: whatever
* sched_sim_driver_start() returned on a startup failure, or a pthread
* error standing up the picker-driving thread the event loop needs (see
* sim_loop.c's own file header comment for why one exists).
*/
extern int sched_sim_driver_run(xce_sched_sim_driver_t* sim,
const sched_sim_args_t* args);