feat(scheduler-sim-live-allocation): wire simulation mode onto shared picker/allocator (task 4.1)
Replaces sim_picker_thread_fn() (the always-PEND placeholder) with the real sched_job_picker()/sched_allocator() threads (task 3.1), spawned against &(sim->core) in sched_sim_driver_run(). Simulation mode now genuinely uses the jbuf capacity-1 rendezvous for the first time (confirmed still exactly one producer/one consumer). Adds sched_election.c to sched_sim_isolation_lib. Fixes bug-1829 (blocking, only reachable once sim_allocator() actually called sched_make_allocation() for the first time): core->seqjob_ allocator/parjob_allocator were never bootstrapped for simulation mode at all. Fixed via new sim_alloc.c (sim_bootstrap_seqjob_allocator()/ sim_bootstrap_parjob_allocator()), mirroring the sim_picker.c/ sim_limit.c precedent. That fix's own workaround -- a throwaway xce_scheduler_t wrapper satisfying seqjob/parjob's init_fn -- has a documented, narrow side effect: prepare_allocation_hook fan-out during a live seqjob/parjob dispatch attempt reaches the wrapper's own separate plugin registry, not sim->core.plugins, so a plugin registered only against the real sim core (the limit plugin) isn't reached for host-scoped matching during a live dispatch yet. Documented in design.md's new "Known Seam Gap" section; task 4.3 added to tasks.md to close it before task 5.2's acceptance test can pass for the host-scoped case. TDD: new end-to-end test drives a real .replay with an empty decisions array (ruling out reconciliation) through the real thread pair, proving a genuine DISPATCH from live resource availability. 25 pre-existing white-box sim/repl test files given link-satisfying stubs reproducing the OLD always-PEND contract unchanged -- their own assertions are untouched (task 5.3's job to reconcile deeper). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLSNJhNoULvVcUhXEFafQC
This commit is contained in:
parent
4195331b47
commit
08df64930b
33 changed files with 3809 additions and 92 deletions
|
|
@ -19,6 +19,7 @@ scheduler_srcs = [
|
|||
'src/sim_loop.c',
|
||||
'src/sim_picker.c',
|
||||
'src/sim_limit.c',
|
||||
'src/sim_alloc.c',
|
||||
'src/sim_verify.c',
|
||||
'src/sim_record.c',
|
||||
'src/repl.c',
|
||||
|
|
@ -102,8 +103,8 @@ sched_core_isolation_lib = static_library(
|
|||
# the simulation driver's own files, consumed by
|
||||
# testsuite/test_sim_isolation.c to prove at build time that
|
||||
# sim.c/sim_loop.c/sim_record.c/repl.c/repl_fmt.c/repl_break.c/repl_info.c/
|
||||
# repl_params.c/sim_picker.c/sim_limit.c reference zero controller-facing
|
||||
# symbols (client/netio/xceapi/delay/idgen). All files are compiled
|
||||
# repl_params.c/sim_picker.c/sim_limit.c/sched_election.c reference zero
|
||||
# controller-facing symbols (client/netio/xceapi/delay/idgen). All files are compiled
|
||||
# together into ONE archive -- task 11.2 added sim_loop.c as a sibling
|
||||
# file to task 11.1's sim.c, task 11.5 added sim_record.c as a third, task
|
||||
# 12.1 added repl.c as a fourth, task 12.2 added repl_break.c/repl_info.c
|
||||
|
|
@ -126,13 +127,43 @@ sched_core_isolation_lib = static_library(
|
|||
# core_clock.c) never-mechanically-covered gap for the sim driver, which is
|
||||
# exactly the omission a prior round of this same task left in place by
|
||||
# adding sim_limit.c to scheduler_srcs above without also adding it here.
|
||||
# scheduler-sim-live-allocation spec's task 4.1 adds sched_election.c as an
|
||||
# eleventh: sim_loop.c's sched_sim_driver_run() now calls sched_job_picker()/
|
||||
# sched_allocator() (sched_election.c) directly, no longer the file's own,
|
||||
# now-removed sim_picker_thread_fn() -- the same "cover every file the
|
||||
# driver's own compiled object actually calls" rationale sim_picker.c/
|
||||
# sim_limit.c's own additions above already establish. Task 3.1 (which
|
||||
# relocated sched_job_picker()/sched_allocator() out of scheduler.c into
|
||||
# this new file) deliberately deferred this addition to task 4.1, since
|
||||
# sim_loop.c did not yet call either function until this task wired the
|
||||
# real spawn in.
|
||||
# Same "compiling to an object is enough, no real linking needed" rationale
|
||||
# as sched_core_isolation_lib above.
|
||||
# as sched_core_isolation_lib above -- sched_election.c's own undefined
|
||||
# references (sched_make_allocation()/sched_commit_decision(), scheduler.c)
|
||||
# are themselves already core-safe (verified by task 3.1's own fixture) and
|
||||
# remain undefined in this archive exactly like every other cross-file call
|
||||
# already does; nm(1)'s FORBIDDEN_SYMBOLS check (test_sim_isolation.c) only
|
||||
# flags controller-facing names, none of which sched_election.c references.
|
||||
# Task 4.1 also adds sim_alloc.c as a twelfth (bug-1829 fix): sim_loop.c now
|
||||
# also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
# allocator() (sim_alloc.c), the same "cover every file the driver's own
|
||||
# compiled object actually calls" rationale as sched_election.c immediately
|
||||
# above. sim_alloc.c #includes scheduler.h (for the throwaway xce_scheduler_t
|
||||
# wrapper its own file header comment explains) -- safe here for the exact
|
||||
# same reason sched_election.c's own scheduler.h include is safe: this file
|
||||
# is not part of test_sim_isolation.c's own enumerated text-scan list (that
|
||||
# list only ever covered sim.h/sim.c/sim_loop.c/sim_picker.c/sim_record.c/
|
||||
# repl.c/repl.h/repl_break.c/repl_info.c/repl_internal.h/repl_params.c, never
|
||||
# extended to sim_limit.c or sched_election.c either), and its own compiled
|
||||
# object references zero controller-facing symbols (register_seqjob_
|
||||
# allocator()/register_parjob_allocator(), plugins/seqjob_allocator.c and
|
||||
# plugins/parjob_allocator.c, touch only core-scoped resource/worker state).
|
||||
sched_sim_isolation_lib = static_library(
|
||||
'sched_sim_isolation',
|
||||
['src/sim.c', 'src/sim_loop.c', 'src/sim_picker.c', 'src/sim_limit.c',
|
||||
'src/sim_record.c', 'src/repl.c', 'src/repl_fmt.c', 'src/repl_break.c',
|
||||
'src/repl_info.c', 'src/repl_params.c', 'src/repl_rollup.c'],
|
||||
'src/sim_alloc.c', 'src/sim_record.c', 'src/repl.c', 'src/repl_fmt.c',
|
||||
'src/repl_break.c', 'src/repl_info.c', 'src/repl_params.c',
|
||||
'src/repl_rollup.c', 'src/sched_election.c'],
|
||||
include_directories: incdir,
|
||||
dependencies: scheduler_deps,
|
||||
install: false)
|
||||
|
|
|
|||
194
src/scheduler/src/sim_alloc.c
Normal file
194
src/scheduler/src/sim_alloc.c
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "plugin.h"
|
||||
#include "scheduler.h"
|
||||
#include "sim.h"
|
||||
#include "utils.h"
|
||||
|
||||
/*
|
||||
* sim_alloc.c - scheduler-sim-live-allocation spec, task 4.1 (Req 1.1, 1.2,
|
||||
* boundary: Unified Picker/Allocator Threads). Split out of sim_loop.c (this
|
||||
* project's 800-line-per-file convention -- see sim_loop.c's own file header
|
||||
* comment) rather than folded into it, the same "new sibling file when the
|
||||
* owning file has zero line-budget headroom" precedent sim_picker.c/
|
||||
* sim_limit.c already establish.
|
||||
*
|
||||
* ── The gap this closes ──────────────────────────────────────────────────
|
||||
* Task 4.1 wires sched_sim_driver_run() to spawn the REAL sched_job_picker()/
|
||||
* sched_allocator() thread pair (sched_election.c) against simulation
|
||||
* mode's own core state -- for the first time ever, a simulation-mode
|
||||
* session can reach sched_allocator()'s real sched_make_allocation() call,
|
||||
* which dispatches to sched_make_seqjob_allocation()/sched_make_parjob_
|
||||
* allocation() (scheduler.c) based on the job's maxTasks. Both of THOSE
|
||||
* unconditionally dereference `core->seqjob_allocator`/`core->parjob_
|
||||
* allocator` -- fields that, for simulation mode, were NEVER populated
|
||||
* anywhere: sched_sim_driver_start() (sim.c) registers no plugin at all
|
||||
* (sim.h's own documented "Known scope boundary"), and normal mode's own
|
||||
* registration path, register_seqjob_allocator()/register_parjob_
|
||||
* allocator() (plugins/seqjob_allocator.c, plugins/parjob_allocator.c),
|
||||
* requires a genuine `xce_scheduler_t*` -- their own init_fn writes
|
||||
* `((xce_scheduler_t*)plugin->sched)->core.seqjob_allocator = plugin`, and
|
||||
* every one of their runtime hooks (seqjob_prepare_allocation()/my_alloc(),
|
||||
* parjob_prepare_allocation()/my_alloc()) ALSO reads `plugin->sched`
|
||||
* throughout, not merely at registration time -- an `xce_sched_sim_driver_t`
|
||||
* deliberately has no such field (Req 5 AC 17). This is a real, tracked,
|
||||
* pre-existing gap: test_sched_election_sim_fixture.c's own header comment
|
||||
* (task 3.1) already flagged it ("a pre-existing, tracked, OUT-OF-SCOPE
|
||||
* gap... NOT one of task 3.1's five permitted changes"), routing around it
|
||||
* in that test with a throwaway xce_scheduler_t wrapper because that test
|
||||
* never needed the wrapper and the core-under-test to be the SAME core.
|
||||
* Task 4.1 is the first task that actually reaches this code path in
|
||||
* PRODUCTION (the old, now-removed sim_picker_thread_fn() never called
|
||||
* sched_make_allocation() at all) -- without this fix, ANY job reaching
|
||||
* real allocation in simulation mode crashes (NULL deref on
|
||||
* `core->seqjob_allocator`/`parjob_allocator`), for every resreq shape,
|
||||
* regardless of dispatch/pend outcome. Closing it is a direct
|
||||
* precondition for this task's own Observable ("produces a genuine
|
||||
* dispatch or pend decision... based on actual resource availability"),
|
||||
* exactly the "blocking, in-boundary, minimally-scoped pre-existing bug
|
||||
* discovered via TDD" this codebase's own precedent (bug-1828, task 2.3)
|
||||
* treats as acceptable to fix within the task that discovers it -- logged
|
||||
* as bug-1829 (.wolf/buglog.json) with the real impact stated in full.
|
||||
*
|
||||
* A FULL fix -- retyping seqjob_allocator.c's/parjob_allocator.c's runtime
|
||||
* hooks from `plugin->sched` to the already-available `plugin->core` field
|
||||
* (task 1.2), mirroring task 2.3's limit.c migration -- is NOT attempted
|
||||
* here: those hooks also call sched_make_allocs()/sched_try_alloc_on_
|
||||
* host_() (scheduler.c/resource.c) with the SAME xce_scheduler_t*, and
|
||||
* scheduler.c is explicitly out of this task's file boundary (already
|
||||
* migrated/committed). That full migration is real, tracked follow-up work
|
||||
* (logged in the same buglog entry), not this task's job.
|
||||
*
|
||||
* ── The fix ─────────────────────────────────────────────────────────────
|
||||
* A long-lived (heap-allocated, never freed -- same "accepted leak, no
|
||||
* sim-driver teardown exists" convention this file family already
|
||||
* establishes for the picker/allocator threads themselves), throwaway
|
||||
* `xce_scheduler_t` wrapper per allocator plugin, whose `.core.resmgr`/
|
||||
* `.core.workers` fields are pointed at simulation mode's OWN resmgr/
|
||||
* workers `var` handles (core.h) -- not copied data, the SAME underlying
|
||||
* rtti-managed container objects -- before the real, unmodified
|
||||
* register_seqjob_allocator()/register_parjob_allocator() runs against the
|
||||
* wrapper. `var` (core.h) is a plain assignable reference, not an embedded
|
||||
* value, so any resource/worker registered later against sim->core (via
|
||||
* the real event-ingest path, after this bootstrap runs) is immediately
|
||||
* visible through the wrapper's aliased fields too -- the two plugins'
|
||||
* runtime hooks (which read resmgr/workers off `plugin->sched->core`)
|
||||
* therefore see simulation mode's REAL, live resource/worker state, not an
|
||||
* empty, disconnected copy. Every other call these plugins make
|
||||
* (sched_check_shared_satisfy()/sched_try_alloc_on_host_(), both core-safe
|
||||
* since tasks 1.3/2.1) is invoked with `&(wrapper->core)` throughout their
|
||||
* own internal call chain (never mixed with `sim->core` directly), so the
|
||||
* plugin's own internal plugin-hook fan-out (plugin_prepare_allocation(),
|
||||
* task 1.2) stays self-consistent against the wrapper's own plugin
|
||||
* registry -- which holds exactly the one allocator plugin this bootstrap
|
||||
* registered onto it, nothing else.
|
||||
*
|
||||
* Known limitation (out of this task's Observable, tracked in the same
|
||||
* buglog entry): because each wrapper's OWN `core.plugins` registry is
|
||||
* separate from `sim->core.plugins`, a plugin registered only against
|
||||
* `sim->core` (e.g. sim_bootstrap_limit_plugin()'s limit plugin) is NOT
|
||||
* reached by plugin_prepare_allocation()'s fan-out when it runs inside
|
||||
* these allocators' own call chain -- limit-plugin host-scoped matching
|
||||
* under a REAL simulation-mode dispatch is therefore not yet wired
|
||||
* end-to-end. That is squarely task 4.2/5.2's own territory (limit-usage
|
||||
* parity under live sim-mode dispatch), not task 4.1's (which only needs a
|
||||
* genuine dispatch/pend decision to exist at all).
|
||||
*/
|
||||
|
||||
/*
|
||||
* sim_bootstrap_seqjob_allocator/sim_bootstrap_parjob_allocator - consumed
|
||||
* by sim_loop.c via a plain `extern` declared there, same "extern declared
|
||||
* where consumed" idiom this file family already uses throughout
|
||||
* (sim_bootstrap_picker()/sim_bootstrap_limit_plugin(), sim_picker.c/
|
||||
* sim_limit.c). Must run after sched_sim_driver_start() (whose
|
||||
* xce_sched_core_init() call would otherwise wipe sim->core.seqjob_
|
||||
* allocator/parjob_allocator, matching bug-1598's own documented reset
|
||||
* semantics) and before either sched_job_picker()/sched_allocator() thread
|
||||
* is spawned -- the same ordering constraint sim_bootstrap_picker()/
|
||||
* sim_bootstrap_limit_plugin() already have, and the same call site in
|
||||
* sched_sim_driver_run().
|
||||
*/
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
xce_scheduler_t* wrapper;
|
||||
int rc;
|
||||
|
||||
if (sim == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
wrapper = (xce_scheduler_t*)calloc(1, sizeof(*wrapper));
|
||||
if (wrapper == NULL) {
|
||||
ERROR("%s out of memory bootstrapping the sim-mode seqjob "
|
||||
"allocator plugin",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = xce_sched_core_init(&(wrapper->core));
|
||||
if (rc < 0) {
|
||||
ERROR("%s failed to init the seqjob allocator bootstrap wrapper "
|
||||
"core (rc=%d)",
|
||||
__func__, rc);
|
||||
free(wrapper);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Share sim's own resource/worker registries -- see this file's own
|
||||
* header comment for the full rationale. `sim->core.resmgr`/`workers`
|
||||
* are `var` handles (core.h), plain assignable references, not
|
||||
* embedded values -- this aliases the SAME underlying rtti-managed
|
||||
* container objects, not a disconnected copy. */
|
||||
wrapper->core.resmgr = sim->core.resmgr;
|
||||
wrapper->core.workers = sim->core.workers;
|
||||
|
||||
rc = register_seqjob_allocator(wrapper);
|
||||
if (rc < 0) {
|
||||
ERROR("%s failed to register the sim-mode seqjob allocator plugin "
|
||||
"(rc=%d)",
|
||||
__func__, rc);
|
||||
return; /* wrapper leaked -- accepted, see header comment */
|
||||
}
|
||||
|
||||
sim->core.seqjob_allocator = wrapper->core.seqjob_allocator;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
xce_scheduler_t* wrapper;
|
||||
int rc;
|
||||
|
||||
if (sim == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
wrapper = (xce_scheduler_t*)calloc(1, sizeof(*wrapper));
|
||||
if (wrapper == NULL) {
|
||||
ERROR("%s out of memory bootstrapping the sim-mode parjob "
|
||||
"allocator plugin",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = xce_sched_core_init(&(wrapper->core));
|
||||
if (rc < 0) {
|
||||
ERROR("%s failed to init the parjob allocator bootstrap wrapper "
|
||||
"core (rc=%d)",
|
||||
__func__, rc);
|
||||
free(wrapper);
|
||||
return;
|
||||
}
|
||||
|
||||
wrapper->core.resmgr = sim->core.resmgr;
|
||||
wrapper->core.workers = sim->core.workers;
|
||||
|
||||
rc = register_parjob_allocator(wrapper);
|
||||
if (rc < 0) {
|
||||
ERROR("%s failed to register the sim-mode parjob allocator plugin "
|
||||
"(rc=%d)",
|
||||
__func__, rc);
|
||||
return; /* wrapper leaked -- accepted, see header comment */
|
||||
}
|
||||
|
||||
sim->core.parjob_allocator = wrapper->core.parjob_allocator;
|
||||
}
|
||||
|
|
@ -85,16 +85,37 @@
|
|||
* repl.h, itself already on this file's include list -- no new controller-
|
||||
* facing symbol enters this file's reachable set.
|
||||
*
|
||||
* Picker-driving thread (sim_picker_thread_fn, below): stands in for BOTH
|
||||
* the normal-mode picker AND allocator threads (scheduler.c), which the
|
||||
* simulation driver cannot use directly (no xce_scheduler_t*, Req 5 AC 17)
|
||||
* -- without it, the first ReplaySession would block forever on
|
||||
* cbuf_get(&core->decisions) with nothing to ever produce the closing NULL
|
||||
* marker. Conservatively PENDs every candidate job (real resource-matching
|
||||
* allocation belongs to the not-yet-designed scheduler-allocation spec) via
|
||||
* the real on_pend()/make_pend_decision()/make_pendreason() production
|
||||
* calls -- see that function's own doc comment for the full reasoning.
|
||||
* Picker/allocator threads (scheduler-sim-live-allocation spec, task 4.1,
|
||||
* Req 1.1/1.2/3.3/4.2/4.3/5.1, design.md's "Unified Picker/Allocator
|
||||
* Threads"): sched_sim_driver_run() (below) spawns the SAME
|
||||
* sched_job_picker()/sched_allocator() thread pair (sched_election.c) that
|
||||
* sched_init() (scheduler.c) spawns for normal mode -- not a mode-specific
|
||||
* stand-in. This replaces this file's own former sim_picker_thread_fn(),
|
||||
* which stood in for BOTH threads at once (no xce_scheduler_t*, Req 5 AC
|
||||
* 17) and, by its own documented "known scope boundary", conservatively
|
||||
* PENDed every candidate job regardless of actual resource availability --
|
||||
* real resource-matching allocation belonged to the not-yet-designed
|
||||
* scheduler-allocation spec at the time it was written. That spec (and the
|
||||
* migration tasks 1.1-3.1 that followed it) made sched_job_picker()/
|
||||
* sched_allocator() themselves driver-agnostic (xce_sched_core_t*-typed,
|
||||
* touching nothing outside core->*), so simulation mode can now spawn the
|
||||
* real, unmodified pair directly against &(sim->core) instead of a
|
||||
* placeholder -- without either thread, the first ReplaySession would still
|
||||
* block forever on cbuf_get(&core->decisions) with nothing to ever produce
|
||||
* the closing NULL marker, exactly as sim_picker_thread_fn()'s own removed
|
||||
* comment noted, but now for the genuine two-thread jbuf-rendezvous
|
||||
* pipeline instead of a single fused thread.
|
||||
*
|
||||
* sched_job_picker()/sched_allocator() are declared in scheduler.h, not
|
||||
* included here (Req 5 AC 17 forbids this file from including
|
||||
* scheduler.h -- it #includes client.h, a forbidden header per this file's
|
||||
* own isolation boundary, test_sim_isolation.c). Declared locally instead,
|
||||
* same "extern declared where consumed" idiom this file already uses for
|
||||
* sim_bootstrap_picker()/sim_bootstrap_limit_plugin() below -- see those
|
||||
* declarations' own comments for the precedent.
|
||||
*/
|
||||
extern void* sched_job_picker(void* arg);
|
||||
extern void* sched_allocator(void* arg);
|
||||
|
||||
/* Shared with sim.c (task 11.1) -- see that file's own file header comment
|
||||
* for the full message-shape discrimination technique. Declared locally
|
||||
|
|
@ -417,6 +438,20 @@ extern void sim_bootstrap_picker(xce_sched_sim_driver_t* sim);
|
|||
* file header comment for the full mechanism/bug trace. */
|
||||
extern void sim_bootstrap_limit_plugin(xce_sched_sim_driver_t* sim);
|
||||
|
||||
/* sim_bootstrap_seqjob_allocator/sim_bootstrap_parjob_allocator -
|
||||
* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): populate
|
||||
* sim->core.seqjob_allocator/parjob_allocator so sched_allocator()'s real
|
||||
* sched_make_allocation() call (now genuinely reachable in simulation mode,
|
||||
* this task's own change) does not crash on a NULL plugin pointer the
|
||||
* moment any job reaches primary resource allocation. Moved to sim_alloc.c
|
||||
* (this file's own "zero line-budget headroom", see this file's header
|
||||
* comment) -- extern'd here per this file family's established "declared
|
||||
* where consumed" idiom, same as sim_bootstrap_picker()/sim_bootstrap_
|
||||
* limit_plugin() immediately above. See sim_alloc.c's own file header
|
||||
* comment for the full mechanism/bug trace. */
|
||||
extern void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim);
|
||||
extern void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim);
|
||||
|
||||
/*
|
||||
* sim_print_decision - Req 5 AC 19's default: "If --sim-output is not
|
||||
* specified, decisions are printed to stdout only." This task (11.2) owns
|
||||
|
|
@ -507,80 +542,6 @@ static inline void sim_print_decision_gate(const xce_sched_sim_driver_t* sim,
|
|||
sim_print_decision(d);
|
||||
}
|
||||
|
||||
/*
|
||||
* sim_picker_thread_fn - the simulation driver's picker-driving thread
|
||||
* (Req 5 AC 18's pseudocode: `core_go()` signals it, the driver's own
|
||||
* decision-drain loop blocks on `cbuf_get(&core->decisions)` until it
|
||||
* produces the end-of-session NULL marker). Mirrors scheduler.c's
|
||||
* sched_job_picker() outer wbuf-wait/begin_session/next_job/end_session
|
||||
* loop, parameterized on xce_sched_core_t* directly instead of
|
||||
* xce_scheduler_t* -- same core-scoped-thread precedent
|
||||
* test_core_full_cycle.c's test_picker_thread_fn() already establishes for
|
||||
* testing, now load-bearing PRODUCTION code (see this file's own header
|
||||
* comment for why one is unavoidable here).
|
||||
*
|
||||
* Known scope boundary (task 11.2): real resource-matching allocation
|
||||
* (sched_make_allocation(), scheduler.c) requires a live xce_scheduler_t*
|
||||
* this driver deliberately does not have (Req 5 AC 17) and has no
|
||||
* pure-core equivalent yet -- that extraction belongs to the separate,
|
||||
* not-yet-designed scheduler-allocation spec (.kiro/specs/scheduler-
|
||||
* allocation), not this task. Until it exists, this thread -- acting as
|
||||
* BOTH picker and allocator in one thread (no separate jbuf hand-off is
|
||||
* needed: nothing else ever drains jbuf here) -- conservatively PENDs every
|
||||
* candidate next_job() returns, via the real on_pend()/make_pend_decision()/
|
||||
* make_pendreason() production calls, rather than fabricate a DISPATCH
|
||||
* decision with no real worker/resource assignment behind it.
|
||||
*
|
||||
* Runs for the simulation driver's entire lifetime (one wbuf-wait/session
|
||||
* cycle per xce_core_signal_go() call, forever) -- never joined or
|
||||
* cancelled: no sim-driver teardown/fini function exists yet (task 11.1
|
||||
* did not build one either), the same gap sched_job_picker()/
|
||||
* sched_allocator() do not have in normal mode only because sched_fini()
|
||||
* already exists there.
|
||||
*/
|
||||
static void* sim_picker_thread_fn(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
xce_decision_t* decision = NULL;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
/* No resolvable picker (sim_register_default_picker()'s own
|
||||
* doc comment) -- close the session immediately with zero
|
||||
* decisions rather than leave the driver's drain loop blocked
|
||||
* forever. */
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* sim_reconcile_unaccounted_jobs - Recorded-Decision Reconciliation
|
||||
* (scheduler-sim-decision-parity spec, design.md's "Recorded-Decision
|
||||
|
|
@ -937,6 +898,7 @@ int sched_sim_driver_run(xce_sched_sim_driver_t* sim,
|
|||
const sched_sim_args_t* args)
|
||||
{
|
||||
pthread_t picker_tid;
|
||||
pthread_t allocator_tid;
|
||||
xce_core_event_t* buf_events = NULL;
|
||||
int buf_cap = 0;
|
||||
int buf_n = 0;
|
||||
|
|
@ -951,6 +913,8 @@ int sched_sim_driver_run(xce_sched_sim_driver_t* sim,
|
|||
xce_repl_pre_replay_pause(sim);
|
||||
sim_bootstrap_picker(sim);
|
||||
sim_bootstrap_limit_plugin(sim);
|
||||
sim_bootstrap_seqjob_allocator(sim);
|
||||
sim_bootstrap_parjob_allocator(sim);
|
||||
|
||||
/* Req 5 AC 19 (task 11.5): the first two --sim-output messages, written
|
||||
* exactly once, before the event loop below runs -- see sim_record.c's
|
||||
|
|
@ -971,7 +935,21 @@ int sched_sim_driver_run(xce_sched_sim_driver_t* sim,
|
|||
}
|
||||
}
|
||||
|
||||
rc = pthread_create(&picker_tid, NULL, sim_picker_thread_fn, &(sim->core));
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (design.md's "Unified
|
||||
* Picker/Allocator Threads", Req 1.1/1.2/4.2/4.3/5.1): the single real
|
||||
* pthread_create(sim_picker_thread_fn) spawn this call site used to make
|
||||
* becomes these two -- sched_job_picker()/sched_allocator()
|
||||
* (sched_election.c), the identical, unmodified thread pair sched_init()
|
||||
* (scheduler.c, normal mode) spawns, both handed &(sim->core) directly.
|
||||
* Precondition (design.md's Service Interface): sched_resolve_job_picker()
|
||||
* must succeed once either thread's own loop needs it -- satisfied here
|
||||
* because sim_bootstrap_picker() (above) already ran before this point,
|
||||
* unchanged ordering from the pre-4.1 sequence. Like the picker thread
|
||||
* these replace, neither is ever joined or cancelled -- no sim-driver
|
||||
* teardown/fini function exists (this file's own header comment), the
|
||||
* same pre-existing gap normal mode does not have only because
|
||||
* sched_fini() exists there. */
|
||||
rc = pthread_create(&picker_tid, NULL, sched_job_picker, &(sim->core));
|
||||
if (rc != 0) {
|
||||
ERROR("%s failed to start the simulation picker thread: %s", __func__,
|
||||
strerror(rc));
|
||||
|
|
@ -979,6 +957,14 @@ int sched_sim_driver_run(xce_sched_sim_driver_t* sim,
|
|||
return -rc;
|
||||
}
|
||||
|
||||
rc = pthread_create(&allocator_tid, NULL, sched_allocator, &(sim->core));
|
||||
if (rc != 0) {
|
||||
ERROR("%s failed to start the simulation allocator thread: %s",
|
||||
__func__, strerror(rc));
|
||||
xce_core_set_active_for_logging(NULL);
|
||||
return -rc;
|
||||
}
|
||||
|
||||
/* Req 5 AC 16 (task 11.5, "What-if branching"): once --sim-alt-events
|
||||
* is set, the ONGOING event/session stream comes from
|
||||
* sim->alt_events_file instead of sim->replay_file -- the initial
|
||||
|
|
|
|||
|
|
@ -2077,3 +2077,33 @@ sched_election_sim_fixture_test = executable(
|
|||
test('scheduler election sim fixture test',
|
||||
sched_election_sim_fixture_test, suite: 'scheduler',
|
||||
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||
|
||||
# scheduler-sim-live-allocation spec, task 4.1 (Req 1.1, 1.2, 3.3, 4.2, 4.3,
|
||||
# 5.1, boundary: Unified Picker/Allocator Threads, Sim Driver): proves
|
||||
# sched_sim_driver_run() (sim_loop.c) itself -- not just the relocated
|
||||
# thread pair in isolation (task 3.1's own sched_election_sim_fixture_test
|
||||
# above) -- genuinely dispatches a job against simulation mode's own core
|
||||
# state when driven from a real `.replay` stream, closing the always-PEND
|
||||
# gap sim_picker_thread_fn() (now removed) documented as its own "known
|
||||
# scope boundary". Same real-scheduler_srcs link technique as
|
||||
# sched_election_sim_fixture_test immediately above: sched_allocator()
|
||||
# (sched_election.c) reaches the real sched_make_allocation()/
|
||||
# seqjob_allocator.c chain, none of which is reachable via a white-box
|
||||
# #include of sim_loop.c alone.
|
||||
sched_sim_live_allocation_test_srcs = ['test_sim_live_allocation.c']
|
||||
foreach f : scheduler_srcs
|
||||
if f != 'src/main.c'
|
||||
sched_sim_live_allocation_test_srcs += ['../' + f]
|
||||
endif
|
||||
endforeach
|
||||
|
||||
sched_sim_live_allocation_test = executable(
|
||||
'sched_sim_live_allocation_test',
|
||||
sched_sim_live_allocation_test_srcs,
|
||||
include_directories:[incdir],
|
||||
dependencies: [scheduler_test_deps],
|
||||
install: false)
|
||||
|
||||
test('scheduler sim live allocation test',
|
||||
sched_sim_live_allocation_test, suite: 'scheduler',
|
||||
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||
|
|
|
|||
|
|
@ -274,6 +274,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -242,6 +242,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -292,6 +292,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -262,6 +262,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -258,6 +258,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -257,6 +257,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -206,6 +206,122 @@ int put_resvals(zarray_t* array, int nres, int* idxs, float* vals)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -245,6 +245,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -222,6 +222,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -221,6 +221,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -233,6 +233,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -276,6 +276,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -252,6 +252,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -423,6 +423,122 @@ int sched_account_jobs(xce_sched_core_t* core)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -404,6 +404,122 @@ int sched_account_jobs(xce_sched_core_t* core)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -362,6 +362,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -273,6 +273,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
524
src/scheduler/testsuite/test_sim_live_allocation.c
Normal file
524
src/scheduler/testsuite/test_sim_live_allocation.c
Normal file
|
|
@ -0,0 +1,524 @@
|
|||
/*
|
||||
* test_sim_live_allocation.c - scheduler-sim-live-allocation spec, task 4.1
|
||||
* (Req 1.1, 1.2, 3.3, 4.2, 4.3, 5.1, boundary: Unified Picker/Allocator
|
||||
* Threads, Sim Driver).
|
||||
*
|
||||
* Task 4.1 replaces simulation mode's own always-PEND placeholder thread
|
||||
* (sim_picker_thread_fn(), now removed from sim_loop.c) with the SAME
|
||||
* sched_job_picker()/sched_allocator() thread pair (sched_election.c, task
|
||||
* 3.1) normal mode's own sched_init() spawns -- sched_sim_driver_run()
|
||||
* (sim_loop.c) now makes two pthread_create() calls against &(sim->core)
|
||||
* instead of one. This file is the Observable this task's own text
|
||||
* requires: "a simulation-mode session, driven from a real replay with no
|
||||
* changes to the replay format, produces a genuine dispatch or pend
|
||||
* decision for a job based on its actual resource availability, instead of
|
||||
* unconditionally pending it."
|
||||
*
|
||||
* ── Link style: real scheduler_srcs, not a white-box #include ────────────
|
||||
* Unlike most sim-family tests in this directory (which #include individual
|
||||
* .c files directly to reach `static` functions or to avoid pulling in
|
||||
* normal-mode-only machinery), this file links the REAL, unmodified
|
||||
* `scheduler_srcs` object list (minus src/main.c) -- the exact technique
|
||||
* test_sched_election_sim_fixture.c's own meson.build entry already
|
||||
* establishes (see testsuite/meson.build, "same real-scheduler_srcs link
|
||||
* technique"). This is deliberate: sched_allocator() (sched_election.c)
|
||||
* calls the REAL sched_make_allocation()/sched_commit_decision()
|
||||
* (scheduler.c), which in turn reach the REAL seqjob_allocator.c plugin --
|
||||
* none of that is `static` or reachable via a small, hand-picked white-box
|
||||
* #include set the way sim_loop.c's own internals are. Linking the real
|
||||
* scheduler_srcs gets the entire real allocation chain "for free", with no
|
||||
* stubs standing in for genuine resource-matching logic -- the one thing
|
||||
* this test exists to prove is genuinely exercised.
|
||||
*
|
||||
* ── Why the fixture cannot simply replay a normal-mode recording ─────────
|
||||
* sim_reconcile_unaccounted_jobs() (sim_loop.c) triggers, unconditionally,
|
||||
* on ANY job in core->jobs with `accounts == NULL` every round -- including
|
||||
* a job freshly pushed via a JOBS_PUSH event earlier in the SAME round's
|
||||
* file position, not merely one "already resolved before this replay run
|
||||
* started tracking it live" (see test_sim_contention_parity.c's own header
|
||||
* comment for the identical concern in a sibling test). If the round's own
|
||||
* ReplaySession carried a matching recorded DISPATCH decision for this
|
||||
* job, reconciliation -- which runs strictly BEFORE xce_core_signal_go()
|
||||
* unblocks the live picker each round -- would claim the job first, and
|
||||
* this test would silently end up proving Recorded-Decision Reconciliation
|
||||
* instead of the NEW live picker/allocator path. This fixture therefore
|
||||
* hand-builds a `.replay` stream whose lone ReplaySession carries an EMPTY
|
||||
* decisions list (append_replay_session() below, same "leave decisions at
|
||||
* new_ReplaySession()'s zero-value default" technique test_sim_event_loop.c
|
||||
* already establishes) -- guaranteeing reconciliation finds nothing to
|
||||
* reconstruct and the job reaches the live sched_job_picker()/
|
||||
* sched_allocator() pair genuinely.
|
||||
*
|
||||
* ── Fixture shape ──────────────────────────────────────────────────────
|
||||
* A minimal header+snapshot (via a real, throwaway xce_scheduler_t +
|
||||
* sched_record_start(), same technique test_sim_event_loop.c's/
|
||||
* test_sim_resource_contention.c's own write_header_and_snapshot()/
|
||||
* fixture_init() establish, discarded immediately after producing the
|
||||
* bytes -- never confused with the actual xce_sched_sim_driver_t under
|
||||
* test below) records job_pick_plugin="builtin_fcfs" (threaded onto
|
||||
* ReplayHeader.schedPolicy, then back onto sim->core.job_pick_plugin by
|
||||
* sched_sim_driver_start(), sim.h's own doc comment) with an otherwise
|
||||
* empty core (no queues/workers/jobs/resources baked into the snapshot
|
||||
* itself -- avoids any snapshot-save/restore field-completeness risk for
|
||||
* data this test does not need captured that way). Everything the job
|
||||
* needs is instead pushed as real, wire-encoded ReplayEvent messages
|
||||
* immediately after the snapshot -- resourcesPush ("slots"), workersPush
|
||||
* (one worker with real spare "slots" capacity, register_slots_resource()/
|
||||
* make_wire_worker()'s own proven shape from test_parjob_e2e_multislot.c),
|
||||
* queueUpdate, then jobsPush (one job, mintasks=maxtasks=1, resreq
|
||||
* "select[type==any] rusage[mem=1]" -- test_sched_election_sim_fixture.c's
|
||||
* own proven-to-parse-as-bare-PRIMARY resreq text) -- exercising the real,
|
||||
* already-proven-correct JOBS_PUSH ingest path
|
||||
* (xce_core_push_events()->core_build_job(), which resreq-maxtasks-wiring
|
||||
* already confirmed correctly threads submit.mintasks/maxtasks into
|
||||
* primary->resreq->minTasks/maxTasks for this exact event type -- no
|
||||
* mintasks/maxtasks workaround needed here, unlike a job built directly via
|
||||
* make_sched_job(), task 3.1's own documented gap).
|
||||
*
|
||||
* ── bug-1598/1632/1763 fixture-safety requirement (task 4.1's own text) ──
|
||||
* sched_sim_driver_run() spawns TWO real, never-joined pthreads (the
|
||||
* picker, now genuinely sched_job_picker(), AND the allocator,
|
||||
* sched_allocator()) that read `&(sim->core)` for the rest of the process's
|
||||
* life -- doubling the surface area bug-1598's own recurring "stack-local
|
||||
* sim driver instance outlives a never-joined thread" bug class already
|
||||
* documented three times over (bug-1598, bug-1632, bug-1763, the last still
|
||||
* NOT FIXED and explicitly out of scope elsewhere). g_sim below is declared
|
||||
* `static` (file/process lifetime, zero-initialized by the C runtime before
|
||||
* main() even runs), NOT stack-local inside the test function -- so even
|
||||
* though this binary's single RUN_TEST() (matching test_sched_election_
|
||||
* sim_fixture.c's own "exactly one RUN_TEST(), process exits immediately
|
||||
* after" convention, belt-and-suspenders here) returns and the process
|
||||
* exits shortly after, the two spawned threads never dereference a stack
|
||||
* frame that could have already been reclaimed -- positively confirmed,
|
||||
* not assumed safe by analogy, per this task's own explicit TDD
|
||||
* requirement. sched_sim_driver_start() (sim.c) unconditionally
|
||||
* memset()s the whole struct as its own first action (same reasoning
|
||||
* bug-1598's own fix documents for why `static` is safe here: this test
|
||||
* binary calls sched_sim_driver_run() exactly once, so no second call's
|
||||
* memset can ever stomp a still-live zombie thread's state from a first
|
||||
* call), so this file does not separately memset g_sim itself.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <unity/unity.h>
|
||||
|
||||
#include "controller.capnp.h"
|
||||
#include "recording.h"
|
||||
#include "resobj.h"
|
||||
#include "scheduler.h"
|
||||
#include "sim.h"
|
||||
#include "xstring.h"
|
||||
|
||||
/* write_capnp_message (recording.c) has no public header declaration --
|
||||
* every existing white-box test reaches it via a direct #include of
|
||||
* recording.c into the same TU. This file instead LINKS the real
|
||||
* scheduler_srcs (see this file's own header comment), so it is declared
|
||||
* locally instead, matching this codebase's established "extern declared
|
||||
* where consumed" idiom (sim_loop.c's own local externs for msg_root_
|
||||
* has_shape()/sim_decision_eq()/sched_job_picker()/sched_allocator() follow
|
||||
* the identical pattern for the identical reason). */
|
||||
extern int write_capnp_message(FILE* f, struct capn* c);
|
||||
|
||||
#define WORKER_NAME "sim_live_alloc_worker"
|
||||
#define QUEUE_NAME "normal"
|
||||
#define TEST_RESREQ ((char*)"select[type==any] rusage[mem=1]")
|
||||
#define TEST_JOBID ((uint64_t)940101ULL)
|
||||
#define WORKER_SLOTS 4.0f
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Fixture helpers */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static void make_tmp_dir(char* out, size_t out_len, const char* suffix)
|
||||
{
|
||||
char tmpl[PATH_MAX];
|
||||
|
||||
snprintf(tmpl, sizeof(tmpl), "/tmp/sched_simlivealloc%s_XXXXXX", suffix);
|
||||
TEST_ASSERT_NOT_NULL(mkdtemp(tmpl));
|
||||
TEST_ASSERT_TRUE(strlen(tmpl) < out_len);
|
||||
strcpy(out, tmpl);
|
||||
}
|
||||
|
||||
/* make_wire_worker - identical proven shape to
|
||||
* test_parjob_e2e_multislot.c's own make_wire_worker(): a real xce_worker_t
|
||||
* wire payload carrying one "slots" resval, ready for a real
|
||||
* XCE_CORE_EVENT_WORKERS_PUSH ingest. */
|
||||
static xce_worker_t* make_wire_worker(const char* name, float slots)
|
||||
{
|
||||
xce_worker_t* w = (xce_worker_t*)calloc(1, sizeof(*w));
|
||||
xce_val_t* val = (xce_val_t*)calloc(1, sizeof(*val));
|
||||
xce_name_val_t* nv = (xce_name_val_t*)calloc(1, sizeof(*nv));
|
||||
xce_name_val_t** nv_ptrs = (xce_name_val_t**)calloc(1, sizeof(*nv_ptrs));
|
||||
|
||||
TEST_ASSERT_NOT_NULL(w);
|
||||
TEST_ASSERT_NOT_NULL(val);
|
||||
TEST_ASSERT_NOT_NULL(nv);
|
||||
TEST_ASSERT_NOT_NULL(nv_ptrs);
|
||||
|
||||
val->which = Value_u_fvalue;
|
||||
val->u.fvalue = slots;
|
||||
|
||||
nv->name = strdup("slots");
|
||||
nv->val = val;
|
||||
nv_ptrs[0] = nv;
|
||||
|
||||
w->name = strdup(name);
|
||||
w->status = 0;
|
||||
w->nresvals_to_sched = 1;
|
||||
w->resvals_to_sched = nv_ptrs;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static xce_queue_t* make_wire_queue(const char* name, int32_t priority)
|
||||
{
|
||||
xce_queue_t* q = (xce_queue_t*)calloc(1, sizeof(*q));
|
||||
|
||||
TEST_ASSERT_NOT_NULL(q);
|
||||
|
||||
q->queue = strdup(name);
|
||||
q->status = QUEUE_STAT_OPEN;
|
||||
q->priority = priority;
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
/* make_push_job - identical proven shape to test_parjob_e2e_multislot.c's/
|
||||
* test_maxtasks_wiring_sim_driver_parity.c's own make_push_job(): a real
|
||||
* xce_job_t/job_submit_data_t pair ready for a real
|
||||
* XCE_CORE_EVENT_JOBS_PUSH ingest (core_build_job()), which
|
||||
* resreq-maxtasks-wiring already proved correctly threads
|
||||
* submit.mintasks/maxtasks into the parsed primary resreq for this exact
|
||||
* event type. */
|
||||
static xce_job_t* make_push_job(uint64_t jobid, char* resreq_str, char* user,
|
||||
char* queue, char* project, uint32_t mintasks,
|
||||
uint32_t maxtasks)
|
||||
{
|
||||
xce_job_t* j = (xce_job_t*)calloc(1, sizeof(*j));
|
||||
|
||||
TEST_ASSERT_NOT_NULL(j);
|
||||
|
||||
j->jobid = jobid;
|
||||
j->state = JOB_STAT_PEND;
|
||||
j->sub_time = 1000;
|
||||
j->queue_time = 1000;
|
||||
|
||||
j->submit = (job_submit_data_t*)calloc(1, sizeof(*(j->submit)));
|
||||
TEST_ASSERT_NOT_NULL(j->submit);
|
||||
|
||||
j->submit->queue = queue;
|
||||
j->submit->user = user;
|
||||
j->submit->project_name = project;
|
||||
j->submit->resreq = resreq_str;
|
||||
j->submit->mintasks = mintasks;
|
||||
j->submit->maxtasks = maxtasks;
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
/* append_resourcespush_event/append_workerspush_event/
|
||||
* append_queueupdate_event/append_jobspush_event/append_replay_session/
|
||||
* append_end_of_stream_marker - same encode_<Type>_ptr()/
|
||||
* write_capnp_message() technique test_maxtasks_wiring_sim_driver_parity.c's
|
||||
* own append_jobspush_event()/test_sim_event_loop.c's own
|
||||
* append_jobstatechange_event()/append_replay_session()/
|
||||
* append_end_of_stream_marker() already prove works, extended here to the
|
||||
* two sibling push event types (resourcesPush/workersPush) this fixture
|
||||
* also needs. */
|
||||
static void append_resourcespush_event(FILE* f, uint64_t ts,
|
||||
xce_resource_t** resources, int n)
|
||||
{
|
||||
xce_resource_data_t wrap;
|
||||
replay_event_t src;
|
||||
struct capn c;
|
||||
struct capn_segment* cs;
|
||||
ReplayEvent_ptr p;
|
||||
|
||||
memset(&wrap, 0, sizeof(wrap));
|
||||
wrap.n_total = n;
|
||||
wrap.count = n;
|
||||
wrap.resources = resources;
|
||||
|
||||
memset(&src, 0, sizeof(src));
|
||||
src.ts = ts;
|
||||
src.body_which = ReplayEvent_body_resourcesPush;
|
||||
src.body.resources_push = &wrap;
|
||||
|
||||
capn_init_malloc(&c);
|
||||
cs = capn_root(&c).seg;
|
||||
encode_ReplayEvent_ptr(cs, &p, &src);
|
||||
capn_setp(capn_root(&c), 0, p.p);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, write_capnp_message(f, &c));
|
||||
capn_free(&c);
|
||||
}
|
||||
|
||||
static void append_workerspush_event(FILE* f, uint64_t ts,
|
||||
xce_worker_t** workers, int n)
|
||||
{
|
||||
xce_workers_data_t wrap;
|
||||
replay_event_t src;
|
||||
struct capn c;
|
||||
struct capn_segment* cs;
|
||||
ReplayEvent_ptr p;
|
||||
|
||||
memset(&wrap, 0, sizeof(wrap));
|
||||
wrap.n_total = n;
|
||||
wrap.count = n;
|
||||
wrap.workers = workers;
|
||||
|
||||
memset(&src, 0, sizeof(src));
|
||||
src.ts = ts;
|
||||
src.body_which = ReplayEvent_body_workersPush;
|
||||
src.body.workers_push = &wrap;
|
||||
|
||||
capn_init_malloc(&c);
|
||||
cs = capn_root(&c).seg;
|
||||
encode_ReplayEvent_ptr(cs, &p, &src);
|
||||
capn_setp(capn_root(&c), 0, p.p);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, write_capnp_message(f, &c));
|
||||
capn_free(&c);
|
||||
}
|
||||
|
||||
static void append_queueupdate_event(FILE* f, uint64_t ts, xce_queue_t* q)
|
||||
{
|
||||
replay_event_t src;
|
||||
struct capn c;
|
||||
struct capn_segment* cs;
|
||||
ReplayEvent_ptr p;
|
||||
|
||||
memset(&src, 0, sizeof(src));
|
||||
src.ts = ts;
|
||||
src.body_which = ReplayEvent_body_queueUpdate;
|
||||
src.body.queue_update = q;
|
||||
|
||||
capn_init_malloc(&c);
|
||||
cs = capn_root(&c).seg;
|
||||
encode_ReplayEvent_ptr(cs, &p, &src);
|
||||
capn_setp(capn_root(&c), 0, p.p);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, write_capnp_message(f, &c));
|
||||
capn_free(&c);
|
||||
}
|
||||
|
||||
static void append_jobspush_event(FILE* f, uint64_t ts, xce_job_t** jobs,
|
||||
int njobs)
|
||||
{
|
||||
xce_jobs_data_t wrap;
|
||||
replay_event_t src;
|
||||
struct capn c;
|
||||
struct capn_segment* cs;
|
||||
ReplayEvent_ptr p;
|
||||
|
||||
memset(&wrap, 0, sizeof(wrap));
|
||||
wrap.n_total = njobs;
|
||||
wrap.count = njobs;
|
||||
wrap.jobs = jobs;
|
||||
|
||||
memset(&src, 0, sizeof(src));
|
||||
src.ts = ts;
|
||||
src.body_which = ReplayEvent_body_jobsPush;
|
||||
src.body.jobs_push = &wrap;
|
||||
|
||||
capn_init_malloc(&c);
|
||||
cs = capn_root(&c).seg;
|
||||
encode_ReplayEvent_ptr(cs, &p, &src);
|
||||
capn_setp(capn_root(&c), 0, p.p);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, write_capnp_message(f, &c));
|
||||
capn_free(&c);
|
||||
}
|
||||
|
||||
/* append_replay_session - a minimal ReplaySession with only beginRound set
|
||||
* -- decisions/summary deliberately left at new_ReplaySession()'s
|
||||
* zero-value defaults (empty decisions list). See this file's own header
|
||||
* comment ("Why the fixture cannot simply replay a normal-mode recording")
|
||||
* for why an EMPTY decisions list is load-bearing here, not incidental. */
|
||||
static void append_replay_session(FILE* f, uint64_t begin_round)
|
||||
{
|
||||
struct capn c;
|
||||
struct capn_segment* cs;
|
||||
ReplaySession_ptr sp;
|
||||
|
||||
capn_init_malloc(&c);
|
||||
cs = capn_root(&c).seg;
|
||||
sp = new_ReplaySession(cs);
|
||||
ReplaySession_set_beginRound(sp, begin_round);
|
||||
capn_setp(capn_root(&c), 0, sp.p);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, write_capnp_message(f, &c));
|
||||
capn_free(&c);
|
||||
}
|
||||
|
||||
static void append_end_of_stream_marker(FILE* f)
|
||||
{
|
||||
replay_event_t src;
|
||||
struct capn c;
|
||||
struct capn_segment* cs;
|
||||
ReplayEvent_ptr p;
|
||||
|
||||
memset(&src, 0, sizeof(src));
|
||||
src.body_which = ReplayEvent_body_endSession;
|
||||
|
||||
capn_init_malloc(&c);
|
||||
cs = capn_root(&c).seg;
|
||||
encode_ReplayEvent_ptr(cs, &p, &src);
|
||||
capn_setp(capn_root(&c), 0, p.p);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, write_capnp_message(f, &c));
|
||||
capn_free(&c);
|
||||
}
|
||||
|
||||
/* write_header_and_snapshot - produces a valid ReplayHeader+SnapshotEntry
|
||||
* prefix at a fresh temp path via the real sched_record_start(), same
|
||||
* technique test_sim_event_loop.c's own write_header_and_snapshot()/
|
||||
* test_sim_resource_contention.c's own fixture_init()+sched_record_start()
|
||||
* pair establish -- but deliberately does NOT call sched_record_stop() (see
|
||||
* test_sim_event_loop.c's own identical rationale: that call would append
|
||||
* its own endSession marker immediately, before this fixture's own events
|
||||
* ever get appended). The throwaway xce_scheduler_t built here exists
|
||||
* SOLELY to produce these bytes -- it is discarded the moment this function
|
||||
* returns, never confused with g_sim (the actual xce_sched_sim_driver_t
|
||||
* under test) below. Registers the REAL builtin_fcfs plugin (not a stub)
|
||||
* so the recorded job_pick_plugin="builtin_fcfs" genuinely matches what
|
||||
* sim_bootstrap_picker() (bug-1567, sim_picker.c) looks for -- the same
|
||||
* "real builtin_fcfs, real worker, no stub" precedent test_sim_resource_
|
||||
* contention.c's own fixture_init() already establishes. */
|
||||
static FILE* write_header_and_snapshot(char* out_path, size_t out_path_len)
|
||||
{
|
||||
char record_dir[PATH_MAX];
|
||||
xce_scheduler_t sched;
|
||||
xce_sched_plugin_t* fcfs;
|
||||
int rc;
|
||||
|
||||
make_tmp_dir(record_dir, sizeof(record_dir), "_r");
|
||||
|
||||
memset(&sched, 0, sizeof(sched));
|
||||
mylock_init(&(sched.record_lock));
|
||||
|
||||
rc = xce_sched_core_init(&(sched.core));
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
|
||||
fcfs = builtin_fcfs_new_plugin();
|
||||
TEST_ASSERT_NOT_NULL(fcfs);
|
||||
rc = plugin_register_core(&(sched.core), fcfs);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
sched.core.job_pick_plugin = (char*)"builtin_fcfs";
|
||||
sched.record_dir = record_dir;
|
||||
|
||||
rc = sched_record_start(&sched, "live_alloc.replay");
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
TEST_ASSERT_TRUE(strlen(sched.record_file_path) < out_path_len);
|
||||
strcpy(out_path, sched.record_file_path);
|
||||
|
||||
return sched.record_file;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* The sim driver under test -- static storage, see this file's own header */
|
||||
/* comment ("bug-1598/1632/1763 fixture-safety requirement") for why. */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static xce_sched_sim_driver_t g_sim;
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* The test */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Observable (task 4.1's own text): "a simulation-mode session, driven from
|
||||
* a real replay with no changes to the replay format, produces a genuine
|
||||
* dispatch or pend decision for a job based on its actual resource
|
||||
* availability, instead of unconditionally pending it." This fixture gives
|
||||
* the job real, sufficient resource availability (a worker with 4.0 free
|
||||
* "slots" against a 1-task job's auto-injected 1-slot-per-task want, per
|
||||
* test_sched_election_sim_fixture.c's own documented convention) --
|
||||
* asserting the job reaches JOB_STAT_RUN with a real, non-NULL allocation
|
||||
* is the strongest possible proof this task's Observable calls for: the
|
||||
* removed sim_picker_thread_fn() placeholder could structurally NEVER
|
||||
* produce this outcome, only PEND, regardless of resource availability.
|
||||
*/
|
||||
static void
|
||||
test_sim_driver_run_dispatches_a_job_with_available_resources(void)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
FILE* f;
|
||||
xce_resource_t* slots_res;
|
||||
xce_resource_t* res_ptrs[1];
|
||||
xce_worker_t* worker_ptrs[1];
|
||||
xce_queue_t* queue;
|
||||
xce_job_t* job_ptrs[1];
|
||||
sched_sim_args_t args;
|
||||
xce_sched_job_t* sjob;
|
||||
int rc;
|
||||
|
||||
f = write_header_and_snapshot(path, sizeof(path));
|
||||
|
||||
slots_res = (xce_resource_t*)calloc(1, sizeof(*slots_res));
|
||||
TEST_ASSERT_NOT_NULL(slots_res);
|
||||
slots_res->name = strdup("slots");
|
||||
res_ptrs[0] = slots_res;
|
||||
append_resourcespush_event(f, 1001ULL, res_ptrs, 1);
|
||||
|
||||
worker_ptrs[0] = make_wire_worker(WORKER_NAME, WORKER_SLOTS);
|
||||
append_workerspush_event(f, 1002ULL, worker_ptrs, 1);
|
||||
|
||||
queue = make_wire_queue(QUEUE_NAME, 1);
|
||||
append_queueupdate_event(f, 1003ULL, queue);
|
||||
|
||||
job_ptrs[0] = make_push_job(TEST_JOBID, TEST_RESREQ, (char*)"alice",
|
||||
(char*)QUEUE_NAME, (char*)"proj1", 1, 1);
|
||||
append_jobspush_event(f, 1004ULL, job_ptrs, 1);
|
||||
|
||||
/* Empty decisions -- see this file's own header comment for why this
|
||||
* is load-bearing, not incidental. */
|
||||
append_replay_session(f, 2000ULL);
|
||||
append_end_of_stream_marker(f);
|
||||
fclose(f);
|
||||
|
||||
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(&g_sim, &args);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||
0, rc, "sched_sim_driver_run() must complete this fixture's single "
|
||||
"round and reach its own end-of-stream marker");
|
||||
|
||||
sjob = sched_get_job(&(g_sim.core), TEST_JOBID);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(
|
||||
sjob, "the job pushed via the real JOBS_PUSH ingest path must be "
|
||||
"present in the simulation driver's own core state");
|
||||
TEST_ASSERT_EQUAL_UINT_MESSAGE(
|
||||
JOB_STAT_RUN, sjob->state,
|
||||
"the shared sched_job_picker()/sched_allocator() pair (spawned "
|
||||
"directly against simulation mode's own core state by "
|
||||
"sched_sim_driver_run(), scheduler-sim-live-allocation task 4.1) "
|
||||
"must genuinely DISPATCH a job whose resource request is satisfied "
|
||||
"by a real, replayed worker -- not unconditionally PEND it the way "
|
||||
"the removed sim_picker_thread_fn() placeholder always did");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(
|
||||
sjob->allocs, "a genuine DISPATCH must leave a real, non-NULL "
|
||||
"allocation behind (sched_commit_decision()'s "
|
||||
"DISPATCH branch, scheduler.c) -- not merely a "
|
||||
"state flip with no resource assignment behind it");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_sim_driver_run_dispatches_a_job_with_available_resources);
|
||||
return UNITY_END();
|
||||
}
|
||||
|
|
@ -281,6 +281,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -323,6 +323,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -233,6 +233,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -319,6 +319,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -296,6 +296,122 @@ int sched_account_jobs(xce_sched_core_t* core)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -467,6 +467,122 @@ static void reset_plugin_session_spies(void)
|
|||
sizeof(g_end_session_spy_active_ok));
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -265,6 +265,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
|
|
@ -264,6 +264,122 @@ int sched_resolve_job_picker(xce_sched_core_t* core, xce_sched_plugin_t** out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1: sim_loop.c's real
|
||||
* sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* spawns sched_job_picker()/sched_allocator() (sched_election.c) directly
|
||||
* instead of its own, now-removed sim_picker_thread_fn() -- an undefined
|
||||
* reference at link time in this white-box TU otherwise, since
|
||||
* sched_election.c's own sched_allocator() calls the REAL
|
||||
* sched_make_allocation()/sched_commit_decision() (scheduler.c), neither
|
||||
* part of this file's own hand-picked white-box #include set (this file's
|
||||
* own header comment lists that set). This file's own test(s) do not
|
||||
* exercise genuine resource-matching allocation, so this link-satisfying
|
||||
* pair faithfully reproduces the exact PEND-only contract the REMOVED
|
||||
* sim_picker_thread_fn() itself used to provide -- split across the SAME
|
||||
* two-thread jbuf hand-off the real production pair now uses (one
|
||||
* producer, one consumer, matching the project's jbuf capacity-1
|
||||
* rendezvous invariant) instead of the old single fused thread -- so this
|
||||
* file's own existing assertions are unaffected by this task's production
|
||||
* change. Genuine resource-based dispatch through the real, unmodified
|
||||
* sched_job_picker()/sched_allocator() pair is proved separately by
|
||||
* test_sim_live_allocation.c (task 4.1's own dedicated fixture, which
|
||||
* links the real scheduler_srcs instead of white-boxing individual files,
|
||||
* precisely so it can reach the real allocation chain this stub
|
||||
* deliberately does not). */
|
||||
void* sched_job_picker(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
int go = 0;
|
||||
uint64_t jobid = 0;
|
||||
|
||||
cbuf_get(&(core->wbuf), &go);
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
continue;
|
||||
}
|
||||
|
||||
picker->picker_iface->begin_session(picker);
|
||||
|
||||
for (;;) {
|
||||
xce_sched_job_t* job = picker->picker_iface->next_job(picker);
|
||||
|
||||
if (job == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
jobid = job->jobid;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
}
|
||||
|
||||
jobid = 0;
|
||||
cbuf_put(&(core->jbuf), &jobid);
|
||||
|
||||
picker->picker_iface->end_session(picker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sched_allocator(void* arg)
|
||||
{
|
||||
xce_sched_core_t* core = (xce_sched_core_t*)arg;
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
|
||||
for (;;) {
|
||||
uint64_t jobid = 0;
|
||||
xce_decision_t* decision = NULL;
|
||||
xce_sched_job_t* job;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
continue;
|
||||
}
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
if (job == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)sched_resolve_job_picker(core, &picker);
|
||||
if (picker != NULL) {
|
||||
picker->picker_iface->on_pend(picker, job->jobid);
|
||||
}
|
||||
|
||||
decision = make_pend_decision(make_pendreason(job->jobid));
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 4.1 (bug-1829 fix): sim_loop.c's
|
||||
* real sched_sim_driver_run() (white-box #include'd into this TU above) now
|
||||
* also calls sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_
|
||||
* allocator() (sim_alloc.c) -- undefined references at link time in this
|
||||
* white-box TU otherwise, since neither symbol is part of this file's own
|
||||
* hand-picked white-box #include set. This file's own test(s) exercise the
|
||||
* link-satisfying sched_job_picker()/sched_allocator() stub pair above
|
||||
* (which never reaches real primary allocation), so a true no-op is the
|
||||
* correct, behavior-preserving stand-in here -- the real bootstrap logic is
|
||||
* exercised separately by test_sim_live_allocation.c (task 4.1's own
|
||||
* dedicated fixture, which links the real scheduler_srcs). */
|
||||
void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim)
|
||||
{
|
||||
(void)sim;
|
||||
}
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue