diff --git a/.kiro/specs/scheduler-allocator-runner/tasks.md b/.kiro/specs/scheduler-allocator-runner/tasks.md index 4624c4fa..bb700434 100644 --- a/.kiro/specs/scheduler-allocator-runner/tasks.md +++ b/.kiro/specs/scheduler-allocator-runner/tasks.md @@ -1,7 +1,7 @@ # Implementation Plan - [ ] 1. Foundation: plan-iterator contract and allocator contract -- [ ] 1.1 Retype the plan generator's initialisation to take the scheduling core +- [x] 1.1 Retype the plan generator's initialisation to take the scheduling core - Change the plan-iterator initialisation parameter from the scheduler object to the scheduling core in the shared contract, in both built-in plan generators, in both allocators' current calls that initialise their plan generator (they pass the scheduling core instead of the scheduler object), and in the stub generator used by the plan-iterator contract tests - Update the parjob combinatorial tests' direct initialisation calls; turn the poisoned-scheduler case into a poisoned-core case that shows the plan sequence is identical with no core and with a poisoned core - Done when the full scheduler suite builds and passes under ASAN with no plan generator taking a scheduler object, and the poisoned-core test shows identical plan sequences for parjob diff --git a/src/scheduler/include/sched/alloc_iter.h b/src/scheduler/include/sched/alloc_iter.h index 25d04ba0..1c75b560 100644 --- a/src/scheduler/include/sched/alloc_iter.h +++ b/src/scheduler/include/sched/alloc_iter.h @@ -86,15 +86,15 @@ typedef struct xce_alloc_plan_iter_s xce_alloc_plan_iter_t; * xce_alloc_plan_iter_t* iter = &iter_storage; * xce_alloc_plan_t* plan; * - * if (iter->init(iter, primary_resreq, sched) != 0) { ... } + * if (iter->init(iter, primary_resreq, core) != 0) { ... } * while ((plan = iter->next(iter)) != NULL) { ... } * iter->fini(iter); */ struct xce_alloc_plan_iter_s { - /* Initialize the iterator for a given primary resreq and scheduler - * state. Returns 0 on success, nonzero on error. */ + /* Initialize the iterator for a given primary resreq and scheduling + * core state. Returns 0 on success, nonzero on error. */ int (*init)(xce_alloc_plan_iter_t* iter, xce_primary_resreq_t* resreq, - xce_scheduler_t* sched); + xce_sched_core_t* core); /* Return the next candidate plan, or NULL when exhausted. Successive * calls return plans ordered most-preferred to least-preferred, per diff --git a/src/scheduler/src/plugins/parjob_allocator.c b/src/scheduler/src/plugins/parjob_allocator.c index e061e523..e8c5fd10 100644 --- a/src/scheduler/src/plugins/parjob_allocator.c +++ b/src/scheduler/src/plugins/parjob_allocator.c @@ -158,10 +158,10 @@ static int parjob_prepare_allocation(void* arg, xce_sched_ctx_t* ctx) * * Pure function of maxTasks alone (Req 4 AC 1's "1host x N, 2hosts x * ceil(N/2), ..., Nhosts x 1" sequence, generalized to real partitions - * per requirements.md's "Data Structure Changes Summary"): `sched` is + * per requirements.md's "Data Structure Changes Summary"): `core` is * accepted (fixed by the shared xce_alloc_plan_iter_t.init() signature) * but never dereferenced -- plan SHAPE and ORDER never inspect - * sched->core.workers or any other live worker/resource state. Only + * core->workers or any other live worker/resource state. Only * try_alloc_on_host()/host_iter.c (task 4.2's job) ever look at live * worker state, to decide whether a generated plan succeeds. * @@ -184,7 +184,7 @@ static int parjob_prepare_allocation(void* arg, xce_sched_ctx_t* ctx) * documented "valid until the next next()/fini() call" contract. * * plan.ctx is left NULL here, exactly like seqjob_plan_iter_init()'s own - * convention (seqjob_allocator.c): init()'s fixed (iter, resreq, sched) + * convention (seqjob_allocator.c): init()'s fixed (iter, resreq, core) * signature has no ctx parameter to thread it through. Setting * plan->ctx = ctx on every plan returned from next(), before * constructing a host_iter from it, is the CALLER's responsibility @@ -201,15 +201,15 @@ typedef struct { static int parjob_plan_iter_init(xce_alloc_plan_iter_t* iter, xce_primary_resreq_t* resreq, - xce_scheduler_t* sched) + xce_sched_core_t* core) { parjob_plan_iter_priv_t* priv; int max_tasks; - /* Req 4 AC 1 / "pure function of the task count alone": sched is part + /* Req 4 AC 1 / "pure function of the task count alone": core is part * of the shared init() signature but never inspected -- plan * generation must not touch live worker/resource state. */ - (void)sched; + (void)core; if ((iter == NULL) || (resreq == NULL)) { return -EINVAL; @@ -651,7 +651,7 @@ static int my_alloc(xce_sched_plugin_t* plugin, xce_sched_ctx_t* ctx) plan_iter->next = parjob_plan_iter_next; plan_iter->fini = parjob_plan_iter_fini; - if (plan_iter->init(plan_iter, primary, sched) != 0) { + if (plan_iter->init(plan_iter, primary, core) != 0) { /* infra error (e.g. OOM) -- treated the same as "no candidates," * not a resource-availability determination (alloc_iter.h). */ return 0; diff --git a/src/scheduler/src/plugins/seqjob_allocator.c b/src/scheduler/src/plugins/seqjob_allocator.c index ab1edd35..61d2f0cc 100644 --- a/src/scheduler/src/plugins/seqjob_allocator.c +++ b/src/scheduler/src/plugins/seqjob_allocator.c @@ -141,15 +141,15 @@ typedef struct { static int seqjob_plan_iter_init(xce_alloc_plan_iter_t* iter, xce_primary_resreq_t* resreq, - xce_scheduler_t* sched) + xce_sched_core_t* core) { seqjob_plan_iter_priv_t* priv; /* Trivial plan: fixed shape (1 host x 1 slot), independent of the - * resreq/scheduler state -- both parameters exist only to satisfy Req + * resreq/core state -- both parameters exist only to satisfy Req * 2's shared init() signature. */ (void)resreq; - (void)sched; + (void)core; if (iter == NULL) { return -EINVAL; @@ -293,7 +293,7 @@ static int my_alloc(xce_sched_plugin_t* plugin, xce_sched_ctx_t* ctx) plan_iter->next = seqjob_plan_iter_next; plan_iter->fini = seqjob_plan_iter_fini; - if (plan_iter->init(plan_iter, ctx->primary, sched) != 0) { + if (plan_iter->init(plan_iter, ctx->primary, core) != 0) { /* An infrastructure error (e.g. OOM) is not a resource- * availability determination -- treat it the same as "no * candidates", matching alloc_iter.h's own error-propagation diff --git a/src/scheduler/testsuite/test_alloc_plan_iter.c b/src/scheduler/testsuite/test_alloc_plan_iter.c index aceabf78..bb0b770f 100644 --- a/src/scheduler/testsuite/test_alloc_plan_iter.c +++ b/src/scheduler/testsuite/test_alloc_plan_iter.c @@ -21,7 +21,7 @@ * is usable, not just that a struct literal type-checks. * * Both stub implementations ignore the real xce_primary_resreq_t/ - * xce_scheduler_t/plan/workers arguments (ok, per the header's own + * xce_sched_core_t/plan/workers arguments (ok, per the header's own * "each concrete plan-iterator implementation carries whatever it needs" * note) and always yield exactly one candidate before signaling stable * exhaustion. @@ -45,15 +45,15 @@ typedef struct { static int stub_plan_iter_init(xce_alloc_plan_iter_t* iter, xce_primary_resreq_t* resreq, - xce_scheduler_t* sched) + xce_sched_core_t* core) { stub_plan_priv_t* priv; - /* Stub: ignores the real resreq/sched state -- a real implementation + /* Stub: ignores the real resreq/core state -- a real implementation * (parjob's combinatorial one, seqjob's trivial one) would derive its * plan space from resreq->maxTasks here. */ (void)resreq; - (void)sched; + (void)core; if (iter == NULL) { return -EINVAL; diff --git a/src/scheduler/testsuite/test_parjob_combinatorial.c b/src/scheduler/testsuite/test_parjob_combinatorial.c index e9ffb851..b2c5530a 100644 --- a/src/scheduler/testsuite/test_parjob_combinatorial.c +++ b/src/scheduler/testsuite/test_parjob_combinatorial.c @@ -41,7 +41,7 @@ * - purity: plan shape/order is a pure function of maxTasks alone, * never inspecting live worker/scheduler state (Req 4 AC 1's "never * inspects live worker state" clause) -- proved by passing a NULL - * xce_scheduler_t* to init() and confirming plans still generate + * xce_sched_core_t* to init() and confirming plans still generate * correctly * - fini() releases the iterator's private state (Req 2 AC 5) * - Req 2 AC 6: next() calls pthread_testcancel() (or an equivalent @@ -521,21 +521,21 @@ static void test_single_task_yields_single_plan(void) /* * Req 4 AC 1 ("never inspects live worker state" / "pure function of the * task count alone"): the SAME maxTasks value must yield IDENTICAL plan - * sequences regardless of what (if anything) `sched` points to -- - * including a NULL scheduler, and a garbage-but-non-NULL one whose - * fields are never touched. Since parjob_plan_iter_init()/_next() never - * dereference `sched` at all, a non-NULL "poisoned" scheduler pointer - * that would crash on any real field access is a stronger proof of - * purity than merely passing NULL. + * sequences regardless of what (if anything) `core` points to -- + * including a NULL core, and a garbage-but-non-NULL one whose fields are + * never touched. Since parjob_plan_iter_init()/_next() never dereference + * `core` at all, a non-NULL "poisoned" core pointer that would crash on + * any real field access is a stronger proof of purity than merely + * passing NULL. */ -static void test_plan_generation_ignores_scheduler_state(void) +static void test_plan_generation_ignores_core_state(void) { xce_primary_resreq_t resreq; xce_alloc_plan_iter_t iter_a_storage; xce_alloc_plan_iter_t* iter_a = &iter_a_storage; xce_alloc_plan_iter_t iter_b_storage; - xce_alloc_plan_iter_t* iter_b = &iter_b_storage; - xce_scheduler_t* poisoned_sched = (xce_scheduler_t*)0x1; + xce_alloc_plan_iter_t* iter_b = &iter_b_storage; + xce_sched_core_t* poisoned_core = (xce_sched_core_t*)0x1; int k; memset(&resreq, 0, sizeof(resreq)); @@ -549,7 +549,7 @@ static void test_plan_generation_ignores_scheduler_state(void) /* A deliberately invalid, non-dereferenceable pointer -- init()/ * next() must never read through it, or this test would crash * instead of merely failing an assertion. */ - TEST_ASSERT_EQUAL_INT(0, iter_b->init(iter_b, &resreq, poisoned_sched)); + TEST_ASSERT_EQUAL_INT(0, iter_b->init(iter_b, &resreq, poisoned_core)); for (k = 1; k <= 7; k++) { xce_alloc_plan_t* plan_a = iter_a->next(iter_a); @@ -1229,7 +1229,7 @@ int main(void) RUN_TEST(test_plans_ordered_ascending_host_count_with_balanced_partitions); RUN_TEST(test_plans_for_evenly_divisible_task_count); RUN_TEST(test_single_task_yields_single_plan); - RUN_TEST(test_plan_generation_ignores_scheduler_state); + RUN_TEST(test_plan_generation_ignores_core_state); RUN_TEST(test_init_rejects_invalid_input); RUN_TEST(test_next_has_a_real_cancellation_point); RUN_TEST(test_multi_bucket_plan_succeeds_through_real_my_alloc);