Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -65,7 +66,7 @@ struct PlayingAudio
RefCountPtr<DynamicAudioEventRTS> 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<PlayingStatus> m_status; // This member is adjusted by another running thread.
Short m_framesFaded;
Bool m_fade;
volatile Bool m_rerequestOnNextUpdate;
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<volatile long*>(&playing->m_status), PS_Stopping, PS_Playing);
advancePlayingStatus(playing, PS_Playing, PS_Stopping);
// Advance from Stopping to Stopped
const long prevStatus = InterlockedCompareExchange(reinterpret_cast<volatile long*>(&playing->m_status), PS_Stopped, PS_Stopping);
const PlayingStatus prevStatus = advancePlayingStatus(playing, PS_Stopping, PS_Stopped);
if (prevStatus != PS_Stopping) {
return;
}
Expand Down Expand Up @@ -1597,7 +1605,7 @@ void MilesAudioManager::notifyOfAudioCompletion( UnsignedInt handle, UnsignedInt
}

// it will be cleaned up on the next frame update
InterlockedCompareExchange(reinterpret_cast<volatile long*>(&playing->m_status), PS_Stopping, PS_Playing);
advancePlayingStatus(playing, PS_Playing, PS_Stopping);
}

//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -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<volatile long*>(&playing->m_status), PS_Stopping, PS_Playing);
advancePlayingStatus(playing, PS_Playing, PS_Stopping);
return true;
}

Expand Down
13 changes: 5 additions & 8 deletions Core/Libraries/Source/WWVegas/WWLib/mpsc_intrusive_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<void* volatile*>(&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
Expand All @@ -54,8 +52,7 @@ class MPSCIntrusiveQueue
// suffer ABA.
T* Flush()
{
T* list = static_cast<T*>(InterlockedExchangePointer(
reinterpret_cast<void* volatile*>(&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;
Expand All @@ -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<T*> m_head;
};
Loading