fix: scope per-build module-state reset to the config being built (#16) #17
No reviewers
Labels
No labels
bug
claude:done
claude:failed
claude:in-progress
claude:ready
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Catcrafts/Crafter.Build!17
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "claude/issue-16"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes the deterministic
crafter-build -rhang where a multi-target build freezes mid-compile — idle driver, no compiler process, never reachesN/N(issue #16).Root cause
Build()resets eachModule/ModulePartition's per-buildcompiled/checkedflags so a reusedConfigurationre-evaluates mtimes. That reset recursed intocfg.dependencies— but dependencyConfigurationobjects are shared across the build DAG (diamond deps point at the sameConfiguration*), and each is compiled concurrently by its ownBuild()call.A parent/sibling thread's recursive reset could clear a shared dependency's module
compiledatomic after that dependency's module-compile thread had set ittrueand exited, but before an intra-config waiter (its implementation, or a dependent partition) rancompiled.wait(false). The waiter then blocked forever on a flag nothing would re-signal — the build froze mid-compile with no compiler alive. The-rflag only perturbed thread scheduling enough to make the race reliable; the dev server itself spawns afterBuild()returns.Fix
Reset only the current configuration's own modules; never recurse into dependencies. Every config in the tree already gets its own
Build()call (the per-PcmDirbuilder registered indepResults), which resets its own state at the top of that call, sequenced before its compile threads spawn. Cross-config module state is consulted only via PCM file mtimes and thedepResultsfutures — never via these flags — so the narrower reset is correct and removes the data race entirely.Test
Adds
ConcurrentDependencyReset: builds a static-lib dependency fully, then builds a consumer that depends on it while the dependency is already cached indepResults(so it is never rebuilt), and asserts the consumer build leaves the dependency's modulecompiledflag intact. Fails deterministically on the old recursive reset, passes with the fix — no reliance on thread timing.crafter-build test: 12 passed.Resolves #16