Skip to content

fix(mlx): add generation counter to prevent stale session operations#38

Merged
missuo merged 1 commit into
missuo:mainfrom
erning:fix/mlx-session-isolation
Mar 30, 2026
Merged

fix(mlx): add generation counter to prevent stale session operations#38
missuo merged 1 commit into
missuo:mainfrom
erning:fix/mlx-session-isolation

Conversation

@erning

@erning erning commented Mar 30, 2026

Copy link
Copy Markdown
Collaborator

Why

The MLXAsrManager Swift singleton was vulnerable to session cross-talk:
when a new recording session started while the old one was still cleaning
up, the old provider's stop()/cancel() would hit the new session on
the singleton, potentially cancelling or prematurely ending it. The Rust-side
Arc isolation (commit 8b22ea8) mitigated the Rust layer but the Swift
singleton still overwrote shared state.

What changed

  • Added a monotonically increasing generation counter to MLXAsrManager.
  • startSession() increments generation, cancels any in-flight session,
    and returns the generation to the Rust caller.
  • feedAudio(), stop(), cancel() all take a generation parameter —
    calls with a stale generation are silently ignored.
  • The eventTask checks generation to stop forwarding events from
    superseded sessions.
  • Rust MlxProvider stores the generation from connect() and passes it
    through all subsequent FFI calls.

Test plan

  • cargo check --no-default-features — Rust compiles
  • make builds successfully
  • Manual: rapid start/stop recording — new session should not be
    interrupted by old session cleanup

The MLXAsrManager singleton was vulnerable to session cross-talk:
when a new session started while the old one was still cleaning up,
the old provider's stop()/cancel() would hit the new session on the
singleton, potentially cancelling or prematurely ending it.

Add a monotonically increasing generation counter:
- startSession() bumps the counter, cancels any in-flight session,
  and returns the new generation to the caller
- feedAudio(), stop(), cancel() all take a generation parameter and
  are no-ops if it doesn't match the current generation
- The eventTask also checks generation to stop forwarding events
  from a superseded session

The Rust MlxProvider stores the generation from connect() and passes
it through all subsequent FFI calls, so an old provider's close()
can never affect a newer session.
@missuo missuo merged commit 9c18f78 into missuo:main Mar 30, 2026
@erning erning deleted the fix/mlx-session-isolation branch March 30, 2026 11:00
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.

2 participants