From 1359182457f6202f8078a50584c89b41f68bf6a9 Mon Sep 17 00:00:00 2001 From: CryoTheRenegade Date: Mon, 26 Oct 2026 16:07:13 -0600 Subject: [PATCH 1/2] refactor(atomic): Use std::atomic instead of casting storage for the Interlocked functions PlayingAudio::m_status was a PlayingStatus enum that the audio manager cast to volatile long for InterlockedCompareExchange, and MPSCIntrusiveQueue cast its T* head to void* for the pointer variants. Declare both as std::atomic from atomic_adapter.h, which uses the same Interlocked functions on VC6, so no storage is accessed through another type. A file-static advancePlayingStatus does the compare exchange and returns the previous status, as InterlockedCompareExchange did. Co-Authored-By: Claude Opus 5.5 --- .../Include/MilesAudioDevice/MilesAudioManager.h | 5 ++--- .../MilesAudioDevice/MilesAudioManager.cpp | 16 ++++++++++++---- .../Source/WWVegas/WWLib/mpsc_intrusive_queue.h | 13 +++++-------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h b/Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h index 09f4cb31f43..a83a437c7b6 100644 --- a/Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h +++ b/Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h @@ -24,6 +24,7 @@ #include "Common/GameAudio.h" #include "mss/mss.h" #include "WWLib/mutex.h" +#include "Utility/atomic_adapter.h" class AudioEventRTS; class DynamicAudioEventRTS; @@ -65,7 +66,7 @@ struct PlayingAudio RefCountPtr m_audioEventRTS; void *m_file; // The file that was opened to play this PlayingAudioType m_type; - volatile PlayingStatus m_status; // This member is adjusted by another running thread. + std::atomic m_status; // This member is adjusted by another running thread. Short m_framesFaded; Bool m_fade; volatile Bool m_rerequestOnNextUpdate; @@ -92,8 +93,6 @@ struct PlayingAudio { return m_status == PS_Playing || m_rerequestOnNextUpdate; } - - static_assert(sizeof(m_status) == sizeof(long), "Must be size of long, because it is used with Interlocked functions"); }; struct ProviderInfo diff --git a/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp b/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp index 97be26ca5a4..9316f0da653 100644 --- a/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp +++ b/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp @@ -1074,13 +1074,21 @@ void MilesAudioManager::releasePlayingAudio( PlayingAudio *playing ) delete playing; } +//------------------------------------------------------------------------------------------------- +// Sets the status to 'to' if it is 'from', in one atomic step, and returns the status it had before. +static PlayingStatus advancePlayingStatus( PlayingAudio *playing, PlayingStatus from, PlayingStatus to ) +{ + playing->m_status.compare_exchange_strong(from, to); + return from; +} + //------------------------------------------------------------------------------------------------- void MilesAudioManager::stopPlayingAudio( PlayingAudio *playing ) { // Advance from Playing to Stopping - InterlockedCompareExchange(reinterpret_cast(&playing->m_status), PS_Stopping, PS_Playing); + advancePlayingStatus(playing, PS_Playing, PS_Stopping); // Advance from Stopping to Stopped - const long prevStatus = InterlockedCompareExchange(reinterpret_cast(&playing->m_status), PS_Stopped, PS_Stopping); + const PlayingStatus prevStatus = advancePlayingStatus(playing, PS_Stopping, PS_Stopped); if (prevStatus != PS_Stopping) { return; } @@ -1597,7 +1605,7 @@ void MilesAudioManager::notifyOfAudioCompletion( UnsignedInt handle, UnsignedInt } // it will be cleaned up on the next frame update - InterlockedCompareExchange(reinterpret_cast(&playing->m_status), PS_Stopping, PS_Playing); + advancePlayingStatus(playing, PS_Playing, PS_Stopping); } //------------------------------------------------------------------------------------------------- @@ -2740,7 +2748,7 @@ Bool MilesAudioManager::startNextLoop( PlayingAudio *playing ) if (playing->m_audioEventRTS->getDelay() > MSEC_PER_LOGICFRAME_REAL) { playing->m_rerequestOnNextUpdate = true; - InterlockedCompareExchange(reinterpret_cast(&playing->m_status), PS_Stopping, PS_Playing); + advancePlayingStatus(playing, PS_Playing, PS_Stopping); return true; } diff --git a/Core/Libraries/Source/WWVegas/WWLib/mpsc_intrusive_queue.h b/Core/Libraries/Source/WWVegas/WWLib/mpsc_intrusive_queue.h index 7c2b92a5cf2..dbdc3d58a54 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/mpsc_intrusive_queue.h +++ b/Core/Libraries/Source/WWVegas/WWLib/mpsc_intrusive_queue.h @@ -18,7 +18,7 @@ #pragma once -#include "Utility/interlocked_adapter.h" +#include "Utility/atomic_adapter.h" // Lock-free intrusive queue for multiple producer threads and a single consumer thread, // using the same algorithm as the Win32 InterlockedPushEntrySList/InterlockedFlushSList @@ -38,14 +38,12 @@ class MPSCIntrusiveQueue // head, so its next pointer is never visible while stale. void Push(T* node) { - T* head; + T* head = m_head.load(); do { - head = m_head; node->next = head; } - while (InterlockedCompareExchangePointer( - reinterpret_cast(&m_head), node, head) != head); + while (!m_head.compare_exchange_weak(head, node)); } // Detaches all nodes and returns them linked in push order, or null if the queue is @@ -54,8 +52,7 @@ class MPSCIntrusiveQueue // suffer ABA. T* Flush() { - T* list = static_cast(InterlockedExchangePointer( - reinterpret_cast(&m_head), nullptr)); + T* list = m_head.exchange(nullptr); // The detached chain is in last-in-first-out order, so reverse it. T* reversed = nullptr; @@ -73,5 +70,5 @@ class MPSCIntrusiveQueue MPSCIntrusiveQueue(const MPSCIntrusiveQueue&) CPP_11(= delete); MPSCIntrusiveQueue& operator=(const MPSCIntrusiveQueue&) CPP_11(= delete); - T* volatile m_head; + std::atomic m_head; }; From 4dd1c01bfa063a88180bedf447f2bd743231747f Mon Sep 17 00:00:00 2001 From: Jacob Ledbetter Date: Sun, 8 Nov 2026 11:50:21 -0700 Subject: [PATCH 2/2] style(milesaudiomanager): Attach the pointer symbol to the type in advancePlayingStatus Co-Authored-By: Claude Opus 5.5 --- .../Source/MilesAudioDevice/MilesAudioManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp b/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp index 9316f0da653..7a3390618fb 100644 --- a/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp +++ b/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp @@ -1076,7 +1076,7 @@ void MilesAudioManager::releasePlayingAudio( PlayingAudio *playing ) //------------------------------------------------------------------------------------------------- // Sets the status to 'to' if it is 'from', in one atomic step, and returns the status it had before. -static PlayingStatus advancePlayingStatus( PlayingAudio *playing, PlayingStatus from, PlayingStatus to ) +static PlayingStatus advancePlayingStatus( PlayingAudio* playing, PlayingStatus from, PlayingStatus to ) { playing->m_status.compare_exchange_strong(from, to); return from;