Skip to content

Fix Sendable soundness and process-stop escalation - #38

Merged
rudrankriyam merged 1 commit into
mainfrom
fix/sendable-audit-and-process-stop
Jul 3, 2026
Merged

Fix Sendable soundness and process-stop escalation#38
rudrankriyam merged 1 commit into
mainfrom
fix/sendable-audit-and-process-stop

Conversation

@rudrankriyam

Copy link
Copy Markdown
Owner

What

Two targeted concurrency fixes plus documentation of audited @unchecked Sendable boundaries.

1. ChatterboxRandomGenerator — make @unchecked Sendable sound

CoreAILabCore/Chatterbox/ChatterboxSampling.swift declared @unchecked Sendable on a class with unsynchronized mutable state (state, spareNormal). The mutable state is now held in a single State struct guarded by OSAllocatedUnfairLock (deployment target is 27.0, so it is available everywhere the core builds). nextNormal uses static unlocked helpers so it never re-enters the lock. The draw sequence for a given seed is byte-for-byte unchanged, so seeded determinism is preserved (verified by ChatterboxFunctionContractTests). The uncontended lock cost is negligible next to the sqrt/log/sin math in the noise loop.

2. CoreAIConversionProcessRunner.stop() — SIGKILL escalation, no blocking wait

Previously: SIGINT → SIGTERM, then a synchronous process.waitUntilExit() inside the actor — a child that ignored SIGTERM would wedge the actor forever, and nothing ever sent SIGKILL. Now: SIGINT → 1s grace → SIGTERM → 1s grace → SIGKILL, with all waiting done by non-blocking isRunning polling (50 ms intervals). Polling rather than a second terminationHandler because execute() already owns the handler to feed its termination stream. If the surrounding task is cancelled, the grace period is skipped and escalation proceeds immediately instead of busy-spinning.

3. Documented @unchecked Sendable invariants

  • SendableImageSegmenter (AppleImageSegmenterEngine.swift): actor-confined to AppleImageSegmenterEngine.
  • ScopedResourceLease (AppleDiffusionPipelineEngine.swift): immutable after init; deinit only balances the scoped access.
  • SendableObjectDetector (AppleObjectDetectorEngine.swift): existing comment extended to note actor confinement.

Verification

Full LFS model weights pulled; complete suite run on Xcode 27 beta 2:

xcodebuild -scheme CoreAILabMac -destination 'platform=macOS' test
** TEST SUCCEEDED **
Test run with 291 tests in 33 suites passed after 29.754 seconds.

All 33 suites passed, including the two directly covering this change: ChatterboxFunctionContractTests (seeded-determinism contract) and CoreAIConversionProcessRunnerTests (launch/cancel/child-process lifecycle).

- ChatterboxRandomGenerator: guard the SplitMix64 state and cached
  spare normal with OSAllocatedUnfairLock so the @unchecked Sendable
  conformance is actually sound. Static unlocked helpers keep
  nextNormal from re-entering the lock, and the draw sequence for a
  given seed is unchanged.
- CoreAIConversionProcessRunner.stop(): escalate SIGINT -> SIGTERM ->
  SIGKILL with 1s grace periods, and replace the synchronous
  waitUntilExit() (which could wedge the actor if the child ignored
  SIGTERM) with non-blocking polling. Polling is used because execute()
  already owns the process terminationHandler.
- Document the @unchecked Sendable invariants on SendableImageSegmenter,
  ScopedResourceLease, and SendableObjectDetector.
@rudrankriyam
rudrankriyam merged commit 888addb into main Jul 3, 2026
3 checks passed
@rudrankriyam
rudrankriyam deleted the fix/sendable-audit-and-process-stop branch July 3, 2026 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant