Make HasUsedToolsThisTurn volatile for ARM memory model safety#344
Make HasUsedToolsThisTurn volatile for ARM memory model safety#344
Conversation
The field is read by the watchdog timer thread and SDK background threads while being written from the UI thread. Previously it had inconsistent synchronization: 5 sites used Volatile.Read/Write while 16 used plain access. Fix: Declare the field volatile and remove the now-redundant Volatile.Read/Write calls (which would generate CS0420 warnings). Also remove a duplicate write in the reconnect path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #344 Review — Make HasUsedToolsThisTurn volatile for ARM memory model safetyCI Status: No CI checks on this branch (all 2401 existing tests pass per PR description) ✅ No consensus bugs foundAll three completed models agree the PR is correct:
One harmless nit (no action needed): the first assertion in the test — ✅ ApproveClean mechanical fix. The volatile declaration is the right approach for this pattern (directional bool: SDK threads write |
_activeSessionName is read by WsBridge background threads (SyncRemoteSessions), restore background threads, and SDK event handlers, while being written by the UI thread (SetActiveSession, CloseSession, RenameSession). Without volatile, writes may not be visible to other threads on ARM (iOS/Android) due to CPU memory reordering. Changes: - CopilotService: private string? -> private volatile string? - DemoService: same change for consistency - VolatileFieldGuardTests: 2 reflection-based regression tests verifying the volatile modifier is present (same pattern as PR PureWeen#344) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Problem `_activeSessionName` is a plain `string?` accessed from multiple threads without memory barriers: | Thread | Operation | Location | |--------|-----------|----------| | UI thread | Write (SetActiveSession, CloseSession, RenameSession) | CopilotService.cs | | WsBridge background | Read + conditional write (SyncRemoteSessions) | Bridge.cs:532 | | Restore background | Conditional write (`??=`) | Persistence.cs:380 | | SDK event handler | Read comparison | Events.cs:876 | | SaveActiveSessionsToDisk | Read | Persistence.cs:457 | On ARM (iOS/Android), without `volatile`, writes may sit in a CPU store buffer and never become visible to reads on other cores — causing stale active session name in bridge sync, persistence, and event handling. ## Fix ```diff - private string? _activeSessionName; + private volatile string? _activeSessionName; ``` Applied to both `CopilotService` and `DemoService`. All compound patterns (`??=`, compare-then-swap in Close/Rename) are either on the UI thread or benign (first-write-wins on restore/bridge sync). ## Testing - 2 new reflection-based guard tests in `VolatileFieldGuardTests.cs` verify the `volatile` modifier is present (same pattern as PR #344 for `HasUsedToolsThisTurn`) - All existing tests pass Closes #348 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…een#344) ## Problem `HasUsedToolsThisTurn` on `SessionState` is read by the watchdog timer thread and SDK background threads while being written from the UI thread and SDK event handlers. It had **inconsistent synchronization**: 5 sites used `Volatile.Read/Write` while 16 used plain access. On ARM (iOS/Android), plain writes from the UI thread may not be immediately visible to background thread reads. This is a theoretical data race that could cause the watchdog to use incorrect timeouts (120s vs 600s). Identified during code review of PR PureWeen#342 (INV-7 from the processing-state-safety skill). ## Fix - Declare the field `volatile bool` — all reads/writes automatically have correct memory barriers - Remove the 5 now-redundant `Volatile.Read/Write` calls (would generate CS0420 warnings) - Remove a duplicate write in the reconnect path (line ~2613 was redundant with ~2639) - Replace the `HasUsedToolsThisTurn_VolatileConsistency` test with `HasUsedToolsThisTurn_IsDeclaredVolatile` that uses reflection to verify the volatile modifier ## Testing All 2401 tests pass. No CS0420 warnings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…reWeen#349) ## Problem `_activeSessionName` is a plain `string?` accessed from multiple threads without memory barriers: | Thread | Operation | Location | |--------|-----------|----------| | UI thread | Write (SetActiveSession, CloseSession, RenameSession) | CopilotService.cs | | WsBridge background | Read + conditional write (SyncRemoteSessions) | Bridge.cs:532 | | Restore background | Conditional write (`??=`) | Persistence.cs:380 | | SDK event handler | Read comparison | Events.cs:876 | | SaveActiveSessionsToDisk | Read | Persistence.cs:457 | On ARM (iOS/Android), without `volatile`, writes may sit in a CPU store buffer and never become visible to reads on other cores — causing stale active session name in bridge sync, persistence, and event handling. ## Fix ```diff - private string? _activeSessionName; + private volatile string? _activeSessionName; ``` Applied to both `CopilotService` and `DemoService`. All compound patterns (`??=`, compare-then-swap in Close/Rename) are either on the UI thread or benign (first-write-wins on restore/bridge sync). ## Testing - 2 new reflection-based guard tests in `VolatileFieldGuardTests.cs` verify the `volatile` modifier is present (same pattern as PR PureWeen#344 for `HasUsedToolsThisTurn`) - All existing tests pass Closes PureWeen#348 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Problem
HasUsedToolsThisTurnonSessionStateis read by the watchdog timer thread and SDK background threads while being written from the UI thread and SDK event handlers. It had inconsistent synchronization: 5 sites usedVolatile.Read/Writewhile 16 used plain access.On ARM (iOS/Android), plain writes from the UI thread may not be immediately visible to background thread reads. This is a theoretical data race that could cause the watchdog to use incorrect timeouts (120s vs 600s).
Identified during code review of PR #342 (INV-7 from the processing-state-safety skill).
Fix
volatile bool— all reads/writes automatically have correct memory barriersVolatile.Read/Writecalls (would generate CS0420 warnings)HasUsedToolsThisTurn_VolatileConsistencytest withHasUsedToolsThisTurn_IsDeclaredVolatilethat uses reflection to verify the volatile modifierTesting
All 2401 tests pass. No CS0420 warnings.