bug-1498 (re-dispatch): sched_job_is_ready() was a stub returning 1, so any job lingering in the fcfs pendJobs queue was always elected. A dispatched job was never marked non-PEND (the controller defers its schedStartJob notify to the not-yet-implemented apply pump, controller/job.c), so fcfs_update_job re-enqueued it on every job update and the election thread re-dispatched the running job — the worker got conflicting signals and the job was SIGTERM'd. - sched_job_is_ready: elect only PEND, non-suspended jobs - sched_commit_decision (dispatch): mark the job JOB_STAT_RUN on dispatch so it leaves the PEND set and is no longer re-electable - fcfs_update_job: dedup via ordq_peek before enqueue bug-1497 (double-free): sched_update's resval paths transferred ownership of rv->val to sharedInst/w->resvals but left the request pointer set, so sched_pend_update_killer double-freed it -> use-after-free in build_host_eval_ctx. Clear rv->val = NULL on transfer. Tests: new scheduler/testsuite/test_redispatch.c (8 cases): sched_job_is_ready PEND gating + dispatch-commit marks the job RUN. Full scheduler meson suite green. Live-verified: a `sleep 60` job is elected exactly once, runs the full duration and exits 0 (`completed successfully`); before the fix it was re-dispatched at ~11s and killed (SIGTERM 143). Co-Authored-By: Claude <noreply@anthropic.com>
82 lines
4.6 KiB
Meson
82 lines
4.6 KiB
Meson
scheduler_test_src = [
|
|
'test.c',
|
|
]
|
|
|
|
scheduler_test_deps = [libxce_deps, librtti_dep, unity_dep, libxce_dep]
|
|
|
|
incdir = include_directories('../include', '../../include', '.', '../src', '../../lib')
|
|
|
|
scheduler_test = executable('sched_test',
|
|
scheduler_test_src,
|
|
include_directories:[incdir],
|
|
dependencies: [scheduler_test_deps],
|
|
install: false)
|
|
|
|
# White-box test for the notify single-job in-place update path
|
|
# (sched_update_existing_job). It #includes ../src/schedobj.c directly, so it
|
|
# is a standalone TU with its own main() — built as a separate executable.
|
|
sched_job_update_test = executable('sched_job_update_test',
|
|
['test_job_update.c'],
|
|
include_directories:[incdir],
|
|
dependencies: [scheduler_test_deps],
|
|
install: false)
|
|
|
|
# White-box test for the notify/dataset enqueue handlers. It #includes
|
|
# ../src/handler.c directly (enq_pend_update + the static handlers), so it is a
|
|
# standalone TU with its own main() — built as a separate executable.
|
|
sched_handlers_test = executable('sched_handlers_test',
|
|
['test_handlers.c'],
|
|
include_directories:[incdir],
|
|
dependencies: [scheduler_test_deps],
|
|
install: false)
|
|
|
|
# White-box test for the compact job-array push receive/expand path
|
|
# (job-array-single-wal-record task 5.3). It also #includes ../src/handler.c
|
|
# directly, but additionally needs a REAL sched->jobs kvmgr (sched_get_job/
|
|
# sched_add_job) to exercise the per-element dedup check for real — kept as
|
|
# its own binary rather than folded into sched_handlers_test so that file's
|
|
# "self-contained, only sched_init_config stubbed" story stays accurate.
|
|
sched_job_array_test = executable('sched_job_array_test',
|
|
['test_job_array_expand.c'],
|
|
include_directories:[incdir],
|
|
dependencies: [scheduler_test_deps],
|
|
install: false)
|
|
|
|
# Cross-daemon integration test (job-array-single-wal-record task 5.5): the
|
|
# REAL xce_encode()/xce_decode()/extract_data() -> scheduler_req_handler()
|
|
# chain (the top-level function vtask_entry() registers as its handler),
|
|
# proving one-push/N-tasks/log-once and redelivery-safety under genuinely
|
|
# re-decoded wire bytes -- one layer more real than sched_job_array_test's
|
|
# own wire-dispatch case, which stops at sched_handle_dataset(). Kept as its
|
|
# own binary for the same reason sched_job_array_test is separate from
|
|
# sched_handlers_test: it needs a REAL sched->jobs kvmgr for the dedup check.
|
|
sched_job_array_wire_e2e_test = executable('sched_job_array_wire_e2e_test',
|
|
['test_job_array_wire_e2e.c'],
|
|
include_directories:[incdir],
|
|
dependencies: [scheduler_test_deps],
|
|
install: false)
|
|
|
|
# White-box regression test for bug-1498 (scheduler re-dispatches a job it
|
|
# already dispatched): sched_job_is_ready PEND-gating + dispatch-commit marks
|
|
# the job RUN. It #includes ../src/scheduler.c directly, so it is a standalone
|
|
# TU with its own main() — built as a separate executable.
|
|
sched_redispatch_test = executable('sched_redispatch_test',
|
|
['test_redispatch.c'],
|
|
include_directories:[incdir],
|
|
dependencies: [scheduler_test_deps],
|
|
install: false)
|
|
|
|
# Register as meson tests so `meson test --suite scheduler` runs them all.
|
|
# detect_leaks=0 matches the suite convention (fixtures are not torn down).
|
|
test('scheduler test', scheduler_test, suite: 'scheduler',
|
|
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
|
test('scheduler job-update test', sched_job_update_test, suite: 'scheduler',
|
|
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
|
test('scheduler redispatch test', sched_redispatch_test, suite: 'scheduler',
|
|
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
|
test('scheduler handlers test', sched_handlers_test, suite: 'scheduler',
|
|
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
|
test('scheduler job-array expand test', sched_job_array_test, suite: 'scheduler',
|
|
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
|
test('scheduler job-array wire e2e test', sched_job_array_wire_e2e_test, suite: 'scheduler',
|
|
env: ['ASAN_OPTIONS=detect_leaks=0'])
|