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
|
|
@ -136,7 +136,15 @@ graph TB
|
|||
- `src/scheduler/meson.build` — add `sched_election.c` to the normal build's `scheduler_srcs` (both drivers link it, since it lives in the single `xce_scheduler` binary alongside `scheduler.c`/`sim_loop.c`); confirm whether it also needs adding to `sched_sim_isolation_lib`'s source set (Req 5 AC 17 coverage), mirroring how `sim_limit.c` was added there for the analogous reason during `scheduler-sim-diagnostics` task 6.
|
||||
- White-box test files (`test_sim_*.c`, `test_repl_*.c`, `test_scheduler_*.c`, per this codebase's established "duplicate, don't share" stub convention) — any file that `#include`s `plugin.c`/`resource.c`/`scheduler.c` without linking its full dependency set will need its link-satisfying stubs updated for the new `xce_sched_core_t*` signatures, following the exact ripple-fix pattern already used for `limit_get_configured_limits()`/`limit_get_usage_instances()` (scheduler-sim-diagnostics task 2.1's Implementation Note) and `limit_seed_config()` (bug-1825's own remediation). Extracting `sched_job_picker()`/`sched_allocator()` into `sched_election.c` specifically limits this ripple for `sim_loop.c`'s own white-box tests: they now only need to link the small new file to exercise real election/allocation, not the whole of `scheduler.c`.
|
||||
|
||||
> Exactly one new file (`sched_election.c`) is introduced, extracting two existing functions rather than adding new behavior — justified by the isolation-boundary and file-size reasons given above, not by any new component or abstraction layer. Every other change is a signature/call-site migration of an existing function, or a small addition inside an existing file.
|
||||
- `src/scheduler/src/sim_alloc.c` (**new file**, added during task 4.1's implementation) — `sim_bootstrap_seqjob_allocator()`/`sim_bootstrap_parjob_allocator()`, bootstrapping `core->seqjob_allocator`/`core->parjob_allocator` for simulation mode, mirroring the established `sim_picker.c`/`sim_limit.c` bootstrap precedent exactly. Fixes bug-1829: these two fields (read directly by `sched_make_seqjob_allocation()`/`sched_make_parjob_allocation()`, not looked up via `core->plugins`) were never populated for the simulation driver at all, which was undiscovered until task 4.1 made `sched_allocator()` genuinely reach `sched_make_allocation()` in sim mode for the first time — before that, this code path was structurally unreachable in simulation mode, so the gap had zero prior symptoms. Without this fix, task 4.1's own acceptance criteria (a live dispatch decision, not an unconditional pend) could not be met at all. See "Known Seam Gap: Host-Scoped Limit Fan-Out During Live Seqjob/Parjob Dispatch" below for a limitation this fix's own mechanism introduces.
|
||||
|
||||
> Two new files are introduced: `sched_election.c` (task 3.1) and `sim_alloc.c` (task 4.1, fixing bug-1829). Both extract or bootstrap existing behavior rather than adding new behavior — justified by the isolation-boundary/file-size reasons above (`sched_election.c`) and by a genuinely blocking pre-existing gap discovered only once live sim-mode allocation became reachable (`sim_alloc.c`), not by any new component or abstraction layer. Every other change is a signature/call-site migration of an existing function, or a small addition inside an existing file.
|
||||
|
||||
### Known Seam Gap: Host-Scoped Limit Fan-Out During Live Seqjob/Parjob Dispatch
|
||||
|
||||
**Confirmed during task 4.1's review, mechanism-traced end to end — not resolved by this task, explicitly owned by tasks 4.2/5.2.** `register_seqjob_allocator()`/`register_parjob_allocator()`'s own `init_fn` (a pre-existing, real, out-of-boundary dependency this feature's tasks 1.2/2.3 never touched, since those covered `job_election_hook`/`prepare_allocation_hook`/`commit_hook`, not `init_fn`) still requires a real `xce_scheduler_t*`, which simulation mode does not have. `sim_bootstrap_seqjob_allocator()`/`sim_bootstrap_parjob_allocator()` satisfy this with a throwaway `xce_scheduler_t` wrapper, calling `plugin_register()` (not `plugin_register_core()`) against it — which means the seqjob/parjob plugin instances' own `xce_sched_plugin_t.core` field (task 1.2) ends up honestly pointing at the **wrapper's** core, not `sim->core`. `seqjob_allocator.c`/`parjob_allocator.c`'s `my_alloc()` then derives its own `sched`/`core` reference from `plugin->sched`/`plugin->core` (its OWN plugin instance, not the `core` parameter threaded down from `sched_make_allocation()`), so `sched_try_alloc_on_host_()` → `plugin_prepare_allocation()`'s fan-out during a REAL sim-mode seqjob/parjob dispatch attempt iterates the **wrapper's** plugin registry, not `sim->core.plugins` — meaning any plugin registered only against `sim->core` directly (the limit plugin, via `sim_bootstrap_limit_plugin()`) is never reached for host-scoped matching during a live sim-mode dispatch.
|
||||
|
||||
This is a genuine functional gap (not a harmless unused-registry artifact — the wrapper's registry is on the real, executed code path), confined specifically to host-scoped limit matching during a live seqjob/parjob allocation attempt in simulation mode. It does not affect: global-limit matching (reached via `plugin_job_election()`, called directly against `sim->core` before allocation, per the "Plugin Hook Dispatchers"/"Limit Plugin Core-Safe Matching" components above); normal mode (unaffected, its own `xce_scheduler_t` is the real one throughout); or the jbuf rendezvous, decision-commit, or accounting-state correctness of the dispatch itself (the allocation DECISION and its resource charge are correct; only a specific plugin hook's visibility during that decision's host search is narrowed). Tasks 4.2 and 5.2 own closing or re-scoping this gap as part of their own host-scoped-limit-under-live-dispatch work.
|
||||
|
||||
## System Flows
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
- _Boundary: Unified Picker/Allocator Threads_
|
||||
|
||||
- [ ] 4. Integration: wire simulation mode onto the shared implementation
|
||||
- [ ] 4.1 Replace simulation mode's placeholder picker with the shared picker/allocator pair
|
||||
- [x] 4.1 Replace simulation mode's placeholder picker with the shared picker/allocator pair
|
||||
- Replace simulation mode's own always-pend placeholder thread with the shared job-picking and allocation thread pair from 3.1, spawned against simulation mode's own core state
|
||||
- Confirm the existing one-job-at-a-time hand-off guarantee between picking and allocating still holds now that simulation mode genuinely uses it for the first time
|
||||
- TDD: write a new fixture using a non-stack-local (static or heap-allocated) simulation driver instance — a prior, still-recurring bug class in this exact area came from a stack-local instance outliving a never-joined thread, and this change doubles the number of such threads, so this must be positively confirmed, not assumed safe by analogy
|
||||
|
|
@ -85,6 +85,15 @@
|
|||
- _Requirements: 3.4, 3.5_
|
||||
- _Boundary: Sim-Mode Reconciliation Narrowing_
|
||||
|
||||
- [ ] 4.3 Close the host-scoped limit fan-out seam gap for live simulation-mode dispatch
|
||||
- Found during task 4.1's review, mechanism-traced and documented in design.md's "Known Seam Gap: Host-Scoped Limit Fan-Out During Live Seqjob/Parjob Dispatch": `sim_bootstrap_seqjob_allocator()`/`sim_bootstrap_parjob_allocator()`'s throwaway-wrapper registration means the seqjob/parjob allocator plugins' prepare-allocation-hook fan-out iterates the wrapper's own separate plugin registry, never reaching any plugin (the limit plugin included) registered only against simulation mode's real core — so a host-scoped limit's usage instance can never be created via a live seqjob/parjob dispatch attempt today
|
||||
- Fix this with an honest, narrow seam (mirroring the `unsatisfiable_cache` callback pattern from 1.1, or an equally narrow alternative) satisfying seqjob/parjob's own pre-existing `init_fn` requirement for a real `xce_scheduler_t*` without substituting a separate plugin registry for the fan-out itself — do not repeat the throwaway-wrapper-with-a-separate-registry shape that created this gap
|
||||
- TDD: a test proving a host-scoped limit registered directly against simulation mode's real core is matched and its usage instance created during a genuine seqjob or parjob dispatch attempt, independent of recorded-decision reconciliation and independent of global-limit matching
|
||||
- Observable: a host-scoped limit's usage instance is created and visible via the existing configured-limits/usage-instances accessors after a live simulation-mode dispatch that never touched reconciliation
|
||||
- _Depends: 4.1_
|
||||
- _Requirements: 2.2_
|
||||
- _Boundary: Unified Picker/Allocator Threads, Limit Plugin Core-Safe Matching_
|
||||
|
||||
- [ ] 5. Validation: prove equivalence and the concrete acceptance test
|
||||
- [ ] 5.1 Prove identical decisions and accounting state under resource contention across both drivers
|
||||
- Build a resource-contention fixture (multiple jobs, capacity insufficient for all of them, including capacity constrained by a matching limit) and drive it through both drivers
|
||||
|
|
@ -95,7 +104,7 @@
|
|||
- [ ] 5.2 Prove the concrete acceptance test: real global and host-scoped limit usage visible against a real replay
|
||||
- Drive a real simulation session through a replay whose original live session had both a global and a host-scoped limit actively enforced
|
||||
- Observable: the existing limit-inspection command displays real, non-zero usage for both limits against this replay, where today it reports no active usage instance for either
|
||||
- _Depends: 4.1, 4.2_
|
||||
- _Depends: 4.1, 4.2, 4.3_
|
||||
- _Requirements: 2.1, 2.2, 2.3, 2.4_
|
||||
|
||||
- [ ] 5.3 Re-run existing simulation-mode equivalence suites and reconcile any behavior change
|
||||
|
|
@ -115,6 +124,7 @@
|
|||
## Implementation Notes
|
||||
|
||||
- **Task 1.1**: initial submission implemented before tests were written (TDD-mandate violation, caught in review round 1) — the real RED phase must be captured by reverting production files to HEAD via a saved patch + `git checkout --`, rebuilding to see the genuine failure, then reapplying. Retroactively-written tests plus a passing GREEN build alone do not satisfy this project's TDD discipline; the reviewer independently re-derives RED by reverting your changes, so skipping this is always caught.
|
||||
- **Task 4.1**: making a driver-safe function GENUINELY reachable for the first time (sim mode's allocator finally calling `sched_make_allocation()` for real) can expose a pre-existing gap that had zero prior symptoms simply because the code path was previously unreachable (bug-1829: `core->seqjob_allocator`/`parjob_allocator` were never bootstrapped for sim mode at all). Fixing such a blocking bug inside the task that exposes it is acceptable (same precedent as bug-1828, task 2.3) — but a fix that works around a plugin's own out-of-boundary dependency (here, `seqjob_allocator_init()`/`parjob_allocator_init()` needing a real `xce_scheduler_t*`) via a throwaway wrapper with its OWN separate plugin registry can silently reintroduce exactly the two-realities-diverge risk this whole feature exists to eliminate — it did here (task 4.3 exists specifically to close it). When a workaround must stand in for a real fix, prefer an honest narrow seam (mirroring 1.1's callback pattern) over substituting an entire parallel registry/struct, and document the exact substitution's blast radius in design.md immediately, not after review catches the gap.
|
||||
- **Task 3.1**: two pre-existing, out-of-boundary gaps blocked a real end-to-end fixture and were correctly routed around rather than fixed: (a) `seqjob_allocator_init()`/`parjob_allocator_init()` still read `plugin->sched` (not `plugin->core`) — a throwaway `xce_scheduler_t wrapper` local satisfies that registration precondition in tests, but `&(wrapper.core)`, never `&wrapper`, must be what's actually passed to the core-safe functions under test; (b) `make_sched_job()`'s parse path doesn't thread `submit.maxtasks/mintasks` into the parsed primary resreq, so a test needing a specific seqjob-vs-parjob routing must set `job->schedobj->u.primary->resreq->maxTasks/minTasks` directly after construction. Whoever eventually fixes either of these two gaps should grep for this pattern across the test suite.
|
||||
- **Task 2.3**: while migrating a plugin's matching functions, writing the mandated TDD test for a code path that had genuinely never been exercised before (zero prior test call sites for `match_job_host_limit_()`/`limit_prepare_allocation()`) surfaced a real pre-existing bug (bug-1828) blocking that path entirely — the same defect class as bug-1786, fixed the same way, never applied to this sibling function. Fixing a blocking, in-boundary, minimally-scoped pre-existing bug discovered this way is acceptable within a task rather than escalating, but its buglog entry must state the REAL impact (here: host-scoped limits were never enforced in any mode, not merely a display gap) rather than the narrower symptom that surfaced it — the first-written impact description undersold this until review caught it.
|
||||
- **Task 1.3**: grep for ALL call sites of a function before migrating it, not just the ones named in the task brief — `host_iter.c`'s `sched_host_iter_next()` and `parjob_allocator.c`/`seqjob_allocator.c`'s `my_alloc()` all call the capacity-check functions directly, not only via `sched_try_alloc_on_host_()`. A private `static` helper with no other callers besides the functions being migrated should be migrated alongside them (leaving it stale forces an ugly cast, which this codebase's own design explicitly forbids in shared code).
|
||||
|
|
|
|||
|
|
@ -22509,6 +22509,40 @@
|
|||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-09-18T15:14:00Z"
|
||||
},
|
||||
{
|
||||
"id": "bug-1829",
|
||||
"timestamp": "2026-09-19T04:00:00Z",
|
||||
"error_message": "AddressSanitizer: SEGV (NULL pointer read) in sched_make_seqjob_allocation (src/scheduler/src/scheduler.c:59, `plugin->job_alloc_fn` where `plugin = core->seqjob_allocator` is NULL), called from sched_make_primary_alloc_ -> sched_make_primary_allocation -> sched_make_allocation -> sched_allocator (sched_election.c) -> the real pthread spawned by sched_sim_driver_run() (sim_loop.c). Discovered while writing the mandated TDD test for scheduler-sim-live-allocation task 4.1 (its own Observable: 'a simulation-mode session ... produces a genuine dispatch or pend decision for a job based on its actual resource availability, instead of unconditionally pending it') -- the crash is 100% reproducible for ANY job reaching primary resource allocation in simulation mode, regardless of resreq shape or dispatch/pend outcome (sched_make_parjob_allocation has the identical NULL-core->parjob_allocator crash for maxTasks>1 jobs).",
|
||||
"root_cause": "core->seqjob_allocator/core->parjob_allocator (xce_sched_core_t fields, core.h) are never populated for the simulation driver, anywhere. Normal mode populates them via sched_init()'s sched_register_plugins() -> register_seqjob_allocator()/register_parjob_allocator() (plugins/seqjob_allocator.c, plugins/parjob_allocator.c), whose init_fn does `((xce_scheduler_t*)plugin->sched)->core.seqjob_allocator = plugin` -- REQUIRING a genuine, live xce_scheduler_t*. sched_sim_driver_start() (sim.c) registers no plugin at all (sim.h's own documented 'Known scope boundary'), and xce_sched_sim_driver_t deliberately has no xce_scheduler_t*/xce_scheduler_t field of its own (Req 5 AC 17, simulation isolation). This is NOT limited to the init_fn: every one of these two plugins' RUNTIME hooks (seqjob_prepare_allocation()/my_alloc(), parjob_prepare_allocation()/my_alloc(), and several internal static helpers taking xce_scheduler_t* sched as a parameter) ALSO read `plugin->sched->core.*` (resmgr for the 'slots'/rusage lookups, workers for host_iter, and sched_make_allocs()/sched_try_alloc_on_host_() in scheduler.c/resource.c which ALSO take xce_scheduler_t*/need `sched->core.resmgr`) on every single allocation attempt, not just at registration. This gap was already discovered and explicitly deferred by scheduler-sim-live-allocation task 3.1 (see test_sched_election_sim_fixture.c's own header comment: 'a pre-existing, tracked, OUT-OF-SCOPE gap ... NOT one of task 3.1's five permitted changes -- fixing it would be scope creep into a different, not-yet-assigned task') -- task 3.1's own fixture never reached this crash only because IT registers seqjob_allocator directly against a real, throwaway xce_scheduler_t wrapper whose OWN .core IS the core under test (single-core fixture), a shape simulation mode itself can never have (its core lives inside xce_sched_sim_driver_t, never xce_scheduler_t). Task 4.1 is the first task whose OWN production change (spawning the real sched_job_picker()/sched_allocator() thread pair against simulation mode's own core, replacing the old always-PEND sim_picker_thread_fn() placeholder that never called sched_make_allocation() at all) makes this code path reachable in simulation mode for the first time ever.",
|
||||
"fix": "PARTIALLY FIXED (2026-09-19, scheduler-sim-live-allocation task 4.1, within that task's own file boundary -- a full fix is tracked as NOT YET DONE, see below). New file src/scheduler/src/sim_alloc.c (added to scheduler_srcs and sched_sim_isolation_lib, meson.build) provides sim_bootstrap_seqjob_allocator()/sim_bootstrap_parjob_allocator(), called from sched_sim_driver_run() (sim_loop.c) right after the existing sim_bootstrap_picker()/sim_bootstrap_limit_plugin() calls (same ordering constraint, same 'extern declared where consumed' idiom). Each builds a long-lived (heap-allocated, never freed -- same accepted-leak convention this file family already uses for its own never-joined threads), throwaway xce_scheduler_t wrapper, points its .core.resmgr/.core.workers fields (both `var`, core.h -- plain assignable rtti handles, not embedded values) at simulation mode's OWN resmgr/workers objects BEFORE calling the real, unmodified register_seqjob_allocator()/register_parjob_allocator() against it, then copies the resulting plugin pointer onto sim->core.seqjob_allocator/parjob_allocator. Because resmgr/workers are shared BY REFERENCE, any resource/worker registered later against the real sim->core (via the genuine event-ingest path) is immediately visible through the wrapper's aliased fields too, so seqjob_prepare_allocation()/my_alloc() see simulation mode's REAL, live resource/worker state -- not an empty, disconnected copy. Verified live: test_sim_live_allocation.c (new dedicated fixture, real scheduler_srcs link, real WORKERS_PUSH/RESOURCES_PUSH/JOBS_PUSH replay events, real sched_sim_driver_run() call, static-storage xce_sched_sim_driver_t) drives a job with a satisfiable resource want through the full real chain and observes a genuine `[sim] DISPATCH jobid=...` -- previously impossible (would have crashed) before this fix, PEND-only after reverting to sim_picker_thread_fn() at HEAD (confirmed RED). Full scheduler suite: 81/81, zero regressions (25 pre-existing white-box sim tests that #include sim_loop.c directly needed matching link-satisfying no-op/PEND-only stubs for the two new bootstrap functions and for the sched_job_picker()/sched_allocator() symbols sim_loop.c now calls directly instead of its own removed sim_picker_thread_fn() -- none of those 25 files test genuine resource-based allocation, so behavior-preserving stubs keep their existing assertions valid unchanged). NOT YET FIXED (tracked follow-up, explicitly out of task 4.1's file boundary): each wrapper's own core.plugins registry is separate from sim->core.plugins, so a plugin registered only against sim->core (e.g. the limit plugin via sim_bootstrap_limit_plugin()) is never reached by plugin_prepare_allocation()'s fan-out when it runs inside seqjob/parjob's own call chain rooted at the wrapper's core -- limit-plugin host-scoped matching under a REAL simulation-mode dispatch is not yet wired end-to-end (task 4.2/5.2's own territory, which specifically covers limit-usage parity under live sim-mode dispatch -- re-verify this exact scenario when implementing those). The FULL, root-cause fix -- retyping seqjob_allocator.c's/parjob_allocator.c's runtime hooks and internal helpers from `plugin->sched`/`xce_scheduler_t* sched` parameters to the already-available `plugin->core`/`xce_sched_core_t*` (task 1.2's own established pattern, mirroring task 2.3's limit.c migration) -- was NOT attempted: those hooks also call sched_make_allocs() (scheduler.c) and sched_try_alloc_on_host_() (resource.c) with the same xce_scheduler_t*, and scheduler.c/resource.c were explicitly out of task 4.1's file boundary (already migrated/committed by earlier tasks in this spec). A future task should do this properly rather than layering more wrapper-aliasing tricks.",
|
||||
"files": [
|
||||
"src/scheduler/src/sim_alloc.c (new file)",
|
||||
"src/scheduler/src/sim_loop.c (sched_sim_driver_run() call sites)",
|
||||
"src/scheduler/meson.build (scheduler_srcs, sched_sim_isolation_lib)",
|
||||
"src/scheduler/testsuite/test_sim_live_allocation.c (new file, RED/GREEN proof)",
|
||||
"src/scheduler/src/plugins/seqjob_allocator.c (root cause, not modified)",
|
||||
"src/scheduler/src/plugins/parjob_allocator.c (root cause, not modified)"
|
||||
],
|
||||
"tags": [
|
||||
"scheduler",
|
||||
"sim-mode",
|
||||
"asan",
|
||||
"segv",
|
||||
"null-deref",
|
||||
"seqjob_allocator",
|
||||
"parjob_allocator",
|
||||
"plugin-sched-vs-plugin-core",
|
||||
"scheduler-sim-live-allocation",
|
||||
"task-4.1",
|
||||
"partially-fixed",
|
||||
"follow-up-tracked"
|
||||
],
|
||||
"related_bugs": [
|
||||
"bug-1828"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-09-19T04:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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