ps3_audio: hold cond_lock across sysLwCondWait; check room under the lock

sysLwCondWait() requires the calling thread to own the lwmutex the
lwcond was created with - cond_lock here - and fails at once (EPERM)
otherwise.  Neither wait in this driver ever took it, so on a full
fifo the "bounded wait" in ps3_audio_write() and ps3_audio_wait_
writable() was PS3_AUDIO_WAIT_LAPS immediate failures back to back,
a few microseconds in total, after which the write returned 0 and the
audio was dropped.  Blocking mode never actually blocked.

Wrap the wait in ps3_audio_wait_block(), which locks cond_lock around
it.  The output thread's sysLwCondSignal() does not need the mutex
and is unchanged.

Also take the fifo lock for the room checks in ps3_audio_write() (via
ps3_audio_write_avail(), which already does) instead of reading the
fifo's cursors bare while the output thread moves one of them, and
check fifo_new() in init, which was never checked.

No PS3 toolchain here: syntax-checked against stubbed PSL1GHT
headers, not built or run.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-09-11 02:50:40 +02:00
1 parent c92e020a9f
commit 790438f424
1 file changed
+26 -4
+26 -4
View File
@@ -129,6 +129,13 @@ static void *ps3_audio_init(const char *device,
data->buffer = fifo_new(AUDIO_BLOCK_SAMPLES *
AUDIO_CHANNELS * AUDIO_BLOCKS * sizeof(float));
if (!data->buffer)
{
audioPortClose(data->audio_port);
audioQuit();
free(data);
return NULL;
}
sysLwMutexCreate(&data->lock, &lock_attr);
sysLwMutexCreate(&data->cond_lock, &cond_lock_attr);
@@ -147,13 +154,28 @@ static void *ps3_audio_init(const char *device,
return data;
}
static size_t ps3_audio_write_avail(void *data);
/* Sleep on the condition the output thread signals after each block it
* takes. sysLwCondWait() requires the lwcond's mutex - cond_lock, the
* one it was created with - to be held by the caller; called without
* it, it fails at once (EPERM) instead of sleeping, so the bounded
* waits below became a few microseconds of spinning and then gave up,
* returning 0 and dropping the audio, whenever the fifo was full. */
static void ps3_audio_wait_block(ps3_audio_t *aud)
{
sysLwMutexLock(&aud->cond_lock, PS3_SYS_NO_TIMEOUT);
sysLwCondWait(&aud->cond, PS3_AUDIO_WAIT_US);
sysLwMutexUnlock(&aud->cond_lock);
}
static ssize_t ps3_audio_write(void *data, const void *s, size_t len)
{
ps3_audio_t *aud = data;
if (aud->nonblock)
{
if (FIFO_WRITE_AVAIL(aud->buffer) < len)
if (ps3_audio_write_avail(aud) < len)
return 0;
}
@@ -164,11 +186,11 @@ static ssize_t ps3_audio_write(void *data, const void *s, size_t len)
* then returns having written nothing rather than holding the
* caller. */
int laps = PS3_AUDIO_WAIT_LAPS;
while (FIFO_WRITE_AVAIL(aud->buffer) < len)
while (ps3_audio_write_avail(aud) < len)
{
if (!aud->started || aud->quit_thread)
return 0;
sysLwCondWait(&aud->cond, PS3_AUDIO_WAIT_US);
ps3_audio_wait_block(aud);
if (--laps < 0)
return 0;
}
@@ -280,7 +302,7 @@ static size_t ps3_audio_wait_writable(void *data, size_t len)
/* Timed and capped, as in the write: no room after this many
* waits is a thread that has stopped consuming, and the pass is
* handed back as no space coming from this call. */
sysLwCondWait(&aud->cond, PS3_AUDIO_WAIT_US);
ps3_audio_wait_block(aud);
if (--laps < 0)
return 0;
}