fix: serialize Performance tab system-mutations through the operation lock#1432
Merged
Conversation
… lock Every mutating command on the Performance tab (Apply power plan / visual effects / Game Mode / Xbox Game Bar / GPU / processor state, plus Restore All, Trim RAM, Create Restore Point, Toggle Hibernation) is async and awaits real system work, but nothing serialized them against each other. In the worst case, pressing Restore All while an Apply's registry write was still in flight let Restore All null the in-memory snapshot and delete the persisted baseline, leaving a tweak applied with nothing to revert it. Each of these ten commands now acquires the app-wide OperationLockService SystemModification lock (the same lock SFC/DISM and the Environment Variables editor use) immediately after its confirmation dialog. If another system-modification operation is running, the command reports the contention and bails before touching the system. Toggle-based commands re-sync from the live profile on that early return so the UI never shows an unapplied change. Adds regression tests pinning the guard on Restore All, Trim RAM and Apply power plan (dialog stubbed to Yes + lock held -> command bails at the guard, snapshot preserved).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Every system-mutating command on the Performance tab is
asyncand awaits real system work (registry writes,powercfg,EmptyWorkingSetacross all processes), but nothing serialized them against each other. The snapshot'sSemaphoreSlimguards only the load-modify of the_snapshotfield — not the full apply→revert sequence.Worst case: pressing Restore All while an Apply's registry write was still in flight let Restore All null
_snapshotand delete the persisted baseline, leaving a tweak applied with nothing to revert it. Other tabs that mutate the same system state (Tweaks, Cleanup's SFC/DISM) could interleave too.Fix
All ten mutating commands (Apply power plan / visual effects / Game Mode / Xbox Game Bar / GPU / processor state, plus Restore All, Trim RAM, Create Restore Point, Toggle Hibernation) now acquire the app-wide
OperationLockServiceSystemModificationlock — the same lock SFC/DISM and the Environment Variables editor already use — immediately after the confirmation dialog. If another system-modification operation holds it, the command reportsCannot start — <op> is already running.and bails before touching the system. Toggle-based commands re-sync from the live profile on that early return so the UI never shows an unapplied change.This also aligns the tab with its sibling
EnvironmentVariablesViewModel, which already wraps every mutation in the same guard.Tests
Three regression tests pin the guard (dialog stubbed to Yes +
SystemModificationlock held → command bails at the guard, snapshot preserved), mirroringShortcutCleanerViewModelTests.DeleteSelected_WhenDiskLocked_DoesNotDelete:RestoreAll_WhenSystemModificationLocked_BailsAtGuard(asserts_snapshotsurvives)TrimRam_WhenSystemModificationLocked_BailsAtGuardApplyPowerPlan_WhenSystemModificationLocked_BailsAtGuardRegression test red before fix / green after: without the guard the commands proceed past the (absent) lock check and set a success/other status —
Assert.Contains("already running")fails; with the guard they short-circuit and it passes. (dotnet testis not run locally; verified via CI.)Regression sweep
dotnet buildmain + tests: 0 warnings / 0 errors.