[sound] Bring QF into the atomic age

Nuclear powered audio ;)

More seriously, use _Atomic on a few fields that very obviously need it.
That is, channel's buffer pointer (used to signal to the mixer that the
channel is ready for use) and "flow control" flags (stop, done and
pause), and head and tail in the buffer itself. Since QF has been
working without _Atomic (admittedly, thanks to luck and x86's strong
memory model), this should do until proven otherwise. I imagine getting
stream reading out of the RT thread will highlight any issues.
This commit is contained in:
Bill Currie 2022-06-06 11:33:22 +09:00
parent 5ab88b0137
commit 79f3f651a4
2 changed files with 12 additions and 9 deletions

View file

@ -31,6 +31,7 @@
#ifndef __snd_internal_h
#define __snd_internal_h
#include <stdatomic.h>
/** \defgroup sound_render Sound rendering sub-system.
\ingroup sound
@ -142,10 +143,12 @@ struct wavinfo_s {
an ordinary buffer. For streamed sounds, acts as a ring buffer.
*/
struct sfxbuffer_s {
unsigned head; //!< ring buffer head position in sampels
unsigned tail; //!< ring buffer tail position in sampels
unsigned size; //!< size of buffer in frames
_Atomic unsigned head; //!< ring buffer head position in sampels
_Atomic unsigned tail; //!< ring buffer tail position in sampels
// FIXME should pos be atomic? it's primary use is in the mixer but can
// be used for checking the channel's "time"
unsigned pos; //!< position of tail within full stream
unsigned size; //!< size of buffer in frames
unsigned channels; //!< number of channels per frame
unsigned sfx_length; //!< total length of sfx
union { // owning instance
@ -231,7 +234,7 @@ struct sfxblock_s {
/** Representation of a sound being played.
*/
struct channel_s {
sfxbuffer_t *buffer; //!< sound played by this channel
sfxbuffer_t *_Atomic buffer;//!< sound played by this channel
float leftvol; //!< 0-1 volume
float rightvol; //!< 0-1 volume
unsigned end; //!< end time in global paintsamples
@ -239,7 +242,7 @@ struct channel_s {
unsigned loopstart; //!< where to loop, -1 = no looping
int phase; //!< phase shift between l-r in samples
int oldphase; //!< phase shift between l-r in samples
byte pause; //!< don't update the channel at all
_Atomic byte pause; //!< don't update the channel at all
/** signal between main program and mixer thread that the channel is to be
stopped.
- both \c stop and \c done are zero: normal operation
@ -251,8 +254,8 @@ struct channel_s {
can be reused at any time.
*/
//@{
byte stop;
byte done;
_Atomic byte stop;
_Atomic byte done;
//@}
};

View file

@ -122,11 +122,11 @@ SND_PaintChannels (snd_t *snd, unsigned endtime)
// paint in the channels.
ch = snd_channels;
for (i = 0; i < snd_total_channels; i++, ch++) {
if (!(sb = ch->buffer)) {
if (!(sb = ch->buffer) || ch->done) {
// channel is inactive
continue;
}
if (ch->stop || ch->done) {
if (ch->stop) {
ch->done = 1; // acknowledge stopped signal
continue;
}