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

@ -482,36 +482,14 @@ static void test_null_arguments_return_einval(void)
printf("test_null_arguments_return_einval: PASS\n");
}
/* ---------------------------------------------------------------------- */
/* Test 6: sched_sim_driver_run() -- design.md's literal entry point -- */
/* calls start() then fails loudly with -ENOSYS (task 11.2's event loop */
/* does not exist yet), never silently returning success. */
/* ---------------------------------------------------------------------- */
static void test_run_starts_then_fails_enosys_pending_event_loop(void)
{
char path[PATH_MAX];
uint64_t snapshot_ts = 0;
sched_sim_args_t args;
xce_sched_sim_driver_t sim;
int rc;
write_valid_fixture(path, sizeof(path), &snapshot_ts, "_run");
memset(&args, 0, sizeof(args));
args.replay_path = path;
args.sim_start_ts = SCHED_SIM_START_TS_LATEST;
args.sim_speed = 0;
rc = sched_sim_driver_run(&sim, &args);
TEST_ASSERT_EQUAL_INT(-ENOSYS, rc);
/* Startup itself still genuinely succeeded -- state is real and
* inspectable, matching sched_sim_driver_start()'s own contract. */
TEST_ASSERT_EQUAL_UINT64(snapshot_ts, xce_core_now(&(sim.core)));
printf("test_run_starts_then_fails_enosys_pending_event_loop: PASS\n");
}
/* Test 6 (sched_sim_driver_run() -- design.md's literal entry point --
* calling start() then failing loudly with -ENOSYS pending the event loop)
* was removed here: the event loop now exists (scheduler-core spec, task
* 11.2), and sched_sim_driver_run() itself moved to sim_loop.c (a much
* heavier white-box dependency set this file's own header comment
* deliberately stays without -- "this task stops at 'ready-to-run'"). Its
* successor lives in test_sim_event_loop.c, alongside every other
* sched_sim_driver_run()-level test. */
int main(void)
{
@ -522,7 +500,6 @@ int main(void)
RUN_TEST(test_first_message_not_replayheader_fails_cleanly);
RUN_TEST(test_missing_replay_file_fails_cleanly);
RUN_TEST(test_null_arguments_return_einval);
RUN_TEST(test_run_starts_then_fails_enosys_pending_event_loop);
return UNITY_END();
}