Skip to content

Fix data races in monitor thread, restore-on-exit, add features + tests - #1

Merged
kuy124 merged 3 commits into
mainfrom
fix/concurrency-and-robustness
Sep 22, 2026
Merged

kuy124 merged 3 commits into
mainfrom
fix/concurrency-and-robustness

Conversation

@kuy124

@kuy124 kuy124 commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

The monitor thread shared mutable state with the UI thread, which could crash. Fixed that plus a few other bugs, added the features I wanted, and wrote tests.

Bugs fixed

  • Data race on g_Profiles — the worker iterated the vector while the UI thread resized it. Now the UI thread hands the worker an immutable snapshot.
  • Dangling pointer — g_ActiveProfile pointed into the vector and went stale on reallocation. Now it's a value copy plus an index.
  • Shared state not atomic — the original dev mode, changed flag, and active index are now guarded.

Safety

  • Restore the original resolution on exit and on logoff/shutdown. Previously you could get stuck at the game's resolution.
  • Test mode auto-reverts after 15s. The old code popped a blocking dialog and then immediately killed the revert timer, so it never actually reverted.
  • Single-instance mutex so a double-launch doesn't fight over the display.
  • Atomic config write (temp file + MoveFileEx).
  • Replaced the validation pop-ups with an inline status line.

Features

  • Supported-modes dropdown read live from the monitor.
  • Per-profile icons and a tray "restore now" action.
  • Drag-and-drop an exe onto the window.
  • Dark mode.
  • Optional logging to %APPDATA%.
  • Handle WM_DISPLAYCHANGE, per-monitor-v2 DPI, faster adaptive process polling.

Tests

  • Unit tests (tests/test_main.cpp, 36 checks): config round-trip, atomic write, mode enumeration, process detection, path parsing.
  • GUI test (tests/gui_save_test.ps1): drives the real window and checks Save/Delete/validation produce the right config.
  • Wired into ctest and the build workflow.

Builds clean with -Wall -Wextra -Wpedantic. 36/36 unit tests, 3/3 GUI tests pass.

Thread-safety (fixes crashes / use-after-free):
- UI thread now publishes an immutable profile snapshot that the monitor
  thread reads, instead of both threads mutating the live g_Profiles vector.
- Replace the dangling AppProfile* g_ActiveProfile with a value copy plus an
  atomic index, so vector reallocation can no longer invalidate it.
- Serialize all active-state (original dev mode, changed flag, index) behind
  g_RestoreMutex; make g_ProcessFoundTime/g_ActiveIndex atomic.

Reliability:
- Restore the original resolution when the app exits and on WM_ENDSESSION
  (logoff/shutdown) if a profile change is active.
- Test Display Settings now auto-reverts after 15s via a timer instead of a
  blocking MessageBox, so an unreadable mode can always be recovered.
- Single-instance mutex prevents duplicate tray icons / competing monitors.
- Atomic config save (temp file + MoveFileEx) avoids corruption on crash.
- IsProcessRunning handles an invalid toolhelp snapshot.

UX / correctness:
- Validate Width/Height before save and test; clamp Hz/Delay to >= 0.
- Load the tray/window icon at the proper size via LoadImage and free it.
- Fix signed/unsigned comparisons; handle GetMessage error and join safely.
- Build clean with -Wall -Wextra -Wpedantic.

Docs/build:
- README updated for timed test revert and guaranteed restoration.
- Add .gitignore; document the hardened build command.
UI / UX:
- Add a live 'Supported Modes' dropdown populated from EnumDisplaySettings
  for the selected monitor, so listed modes are guaranteed to be supported.
- Owner-draw profile list showing each target app's extracted icon.
- Drag-and-drop an .exe onto the window to fill the executable path.
- Dark mode toggle (immersive dark title bar + WM_CTLCOLOR* themed controls).
- Optional diagnostic logging to %APPDATA%\AutoResChanger\log.txt.
- Tray menu gains 'Restore resolution now' and 'Open config folder'.

Robustness / performance:
- Single-pass process enumeration per tick (set-based) instead of one
  snapshot per profile; adaptive 1s/2s polling with interruptible sleep.
- Handle WM_DISPLAYCHANGE to re-enumerate monitors and refresh modes.
- Per-monitor-v2 DPI awareness with graceful fallbacks.
- Persist dark-mode/logging prefs; free theme brushes, icons and handles.

Build / docs:
- Add CMakeLists.txt (MinGW + MSVC) and a PowerShell build.ps1.
- Add GitHub Actions workflow that builds and attaches the exe to releases.
- README updated for all new features and build options.
…tatus

UX (non-blocking feedback):
- Replace all MessageBox validation pop-ups (Save/Test/drag-drop) with an
  inline status line that colour-codes info/warn/error/ok and auto-clears.
  This keeps the UI responsive and makes the flows fully automatable.
- Rework Test into a two-phase flow: apply the mode and arm a 15s countdown;
  the button becomes 'Keep This Mode' to confirm, otherwise it auto-reverts.
  Fixes the previous behaviour where the blocking OK box cancelled the timer
  immediately, so it never actually auto-reverted.
- Assign control IDs to the exe/Hz/Delay/restore/enable fields for testability.

Testing:
- tests/test_main.cpp: headless unit tests (36 checks) compiled with
  -DTESTING, which excludes the GUI. Covers GetFileName, ToLowerCopy, config
  save/load round-trip, atomic-write cleanliness, overwrite semantics,
  EnumModesForDevice, GetCurrentRes, process enumeration, and missing-config.
- tests/gui_save_test.ps1: drives the real window via Win32 messages to verify
  the Save/Delete/validation end-to-end flow and config output. Uses WM_SETTEXT
  (marshaled cross-process) so inputs reach the owning process correctly.
- tests/run_tests.ps1: one-shot builder/runner for both suites.
- CMakeLists.txt gains a ctest target; CI workflow builds and runs all tests.

main.cpp is unchanged in behaviour except the dialog/status refactor; the
GUI is now guarded by #ifndef TESTING so the same source backs the tests.
@kuy124 kuy124 changed the title Fix monitor-thread races, harden safety, add features + tests Fix data races in monitor thread, restore-on-exit, add features + tests Sep 22, 2026
@kuy124
kuy124 merged commit 8b7e96b into main Sep 22, 2026
1 check passed
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