mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-27 18:20:27 +00:00
Merge pull request #11312 from justinweiss/3ds-enable-threading
[3DS] Enable threading and add a threaded audio driver
This commit is contained in:
commit
33a04a794f
@ -685,7 +685,8 @@ endif
|
||||
|
||||
ifeq ($(TARGET), retroarch_3ds)
|
||||
OBJ += audio/drivers/ctr_csnd_audio.o \
|
||||
audio/drivers/ctr_dsp_audio.o
|
||||
audio/drivers/ctr_dsp_audio.o \
|
||||
audio/drivers/ctr_dsp_thread_audio.o \
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_ALSA), 1)
|
||||
|
@ -56,7 +56,8 @@ ifeq ($(GRIFFIN_BUILD), 1)
|
||||
DEFINES += -DHAVE_PATCH -DHAVE_RWAV
|
||||
DEFINES += -DHAVE_SCREENSHOTS
|
||||
DEFINES += -DHAVE_REWIND
|
||||
#DEFINES += -DHAVE_SOCKET_LEGACY -DHAVE_THREADS
|
||||
DEFINES += -DHAVE_THREADS
|
||||
#DEFINES += -DHAVE_SOCKET_LEGACY
|
||||
#-DHAVE_SSL -DHAVE_BUILTINMBEDTLS -DMBEDTLS_SSL_DEBUG_ALL
|
||||
#ssl is currently incompatible with griffin due to use of the "static" flag on repeating functions that will conflict when included in one file
|
||||
else
|
||||
@ -84,7 +85,7 @@ else
|
||||
#HAVE_NETWORKING = 1
|
||||
#HAVE_CHEEVOS = 1
|
||||
#HAVE_SOCKET_LEGACY = 1
|
||||
#HAVE_THREADS = 1
|
||||
HAVE_THREADS = 1
|
||||
#HAVE_SSL = 1
|
||||
#HAVE_BUILTINMBEDTLS = 1
|
||||
|
||||
|
339
audio/drivers/ctr_dsp_thread_audio.c
Normal file
339
audio/drivers/ctr_dsp_thread_audio.c
Normal file
@ -0,0 +1,339 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2020 - Justin Weiss
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <3ds.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <queues/fifo_queue.h>
|
||||
#include <rthreads/rthreads.h>
|
||||
|
||||
#include "../../retroarch.h"
|
||||
#include "../../ctr/ctr_debug.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
fifo_buffer_t* fifo;
|
||||
size_t fifo_size;
|
||||
|
||||
slock_t* fifo_lock;
|
||||
scond_t* fifo_avail;
|
||||
scond_t* fifo_done;
|
||||
sthread_t* thread;
|
||||
|
||||
volatile bool running;
|
||||
|
||||
bool nonblocking;
|
||||
bool playing;
|
||||
retro_time_t frame_time;
|
||||
int channel;
|
||||
ndspWaveBuf dsp_buf;
|
||||
|
||||
uint32_t pos;
|
||||
} ctr_dsp_thread_audio_t;
|
||||
|
||||
// PCM16 stereo
|
||||
#define DSP_BYTES_TO_SAMPLES(bytes) (bytes / (2 * sizeof(uint16_t)))
|
||||
#define DSP_SAMPLES_TO_BYTES(samples) (samples * 2 * sizeof(uint16_t))
|
||||
|
||||
static void ctr_dsp_audio_loop(void* data)
|
||||
{
|
||||
uint32_t pos, buf_pos;
|
||||
ctr_dsp_thread_audio_t *ctr = (ctr_dsp_thread_audio_t*)data;
|
||||
|
||||
if (!ctr)
|
||||
return;
|
||||
|
||||
while (1)
|
||||
{
|
||||
size_t buf_avail, avail, to_write;
|
||||
slock_lock(ctr->fifo_lock);
|
||||
|
||||
do {
|
||||
avail = FIFO_READ_AVAIL(ctr->fifo);
|
||||
|
||||
if (!avail) {
|
||||
scond_wait(ctr->fifo_avail, ctr->fifo_lock);
|
||||
}
|
||||
} while (!avail && ctr->running);
|
||||
|
||||
slock_unlock(ctr->fifo_lock);
|
||||
|
||||
if (!ctr->running)
|
||||
break;
|
||||
|
||||
pos = ctr->pos;
|
||||
buf_pos = DSP_SAMPLES_TO_BYTES(ndspChnGetSamplePos(ctr->channel));
|
||||
|
||||
buf_avail = buf_pos >= pos ? buf_pos - pos : ctr->fifo_size - pos;
|
||||
to_write = MIN(avail, buf_avail);
|
||||
|
||||
slock_lock(ctr->fifo_lock);
|
||||
|
||||
if (to_write > 0) {
|
||||
fifo_read(ctr->fifo, ctr->dsp_buf.data_pcm8 + pos, to_write);
|
||||
DSP_FlushDataCache(ctr->dsp_buf.data_pcm8 + pos, to_write);
|
||||
scond_signal(ctr->fifo_done);
|
||||
}
|
||||
|
||||
slock_unlock(ctr->fifo_lock);
|
||||
|
||||
if (buf_pos == pos) {
|
||||
svcSleepThread(100000);
|
||||
}
|
||||
|
||||
ctr->pos = (pos + to_write) % ctr->fifo_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void ctr_dsp_thread_audio_free(void *data);
|
||||
|
||||
static void *ctr_dsp_thread_audio_init(const char *device, unsigned rate, unsigned latency,
|
||||
unsigned block_frames,
|
||||
unsigned *new_rate)
|
||||
{
|
||||
ctr_dsp_thread_audio_t *ctr = NULL;
|
||||
|
||||
(void)device;
|
||||
(void)rate;
|
||||
|
||||
if (ndspInit() < 0)
|
||||
return NULL;
|
||||
|
||||
ctr = (ctr_dsp_thread_audio_t*)calloc(1, sizeof(ctr_dsp_thread_audio_t));
|
||||
|
||||
if (!ctr)
|
||||
return NULL;
|
||||
|
||||
*new_rate = 32728;
|
||||
|
||||
ctr->running = true;
|
||||
ctr->channel = 0;
|
||||
|
||||
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
|
||||
ndspSetClippingMode(NDSP_CLIP_SOFT); /* ?? */
|
||||
ndspSetOutputCount(2);
|
||||
ndspChnReset(ctr->channel);
|
||||
ndspChnSetFormat(ctr->channel, NDSP_FORMAT_STEREO_PCM16);
|
||||
ndspChnSetInterp(ctr->channel, NDSP_INTERP_NONE);
|
||||
ndspChnSetRate(ctr->channel, 32728.0f);
|
||||
ndspChnWaveBufClear(ctr->channel);
|
||||
|
||||
ctr->fifo_size = DSP_SAMPLES_TO_BYTES((*new_rate * MAX(latency, 8)) / 1000);
|
||||
|
||||
ctr->dsp_buf.data_pcm16 = linearAlloc(ctr->fifo_size);
|
||||
memset(ctr->dsp_buf.data_pcm16, 0, ctr->fifo_size);
|
||||
DSP_FlushDataCache(ctr->dsp_buf.data_pcm16, ctr->fifo_size);
|
||||
|
||||
ctr->dsp_buf.looping = true;
|
||||
ctr->dsp_buf.nsamples = DSP_BYTES_TO_SAMPLES(ctr->fifo_size);
|
||||
ndspChnWaveBufAdd(ctr->channel, &ctr->dsp_buf);
|
||||
|
||||
ctr->fifo = fifo_new(ctr->fifo_size);
|
||||
|
||||
if (!(ctr->fifo_lock = slock_new()) ||
|
||||
!(ctr->fifo_avail = scond_new()) ||
|
||||
!(ctr->fifo_done = scond_new()) ||
|
||||
!(ctr->thread = sthread_create(ctr_dsp_audio_loop, ctr)))
|
||||
{
|
||||
RARCH_LOG("[Audio]: thread creation failed.\n");
|
||||
ctr->running = false;
|
||||
ctr_dsp_thread_audio_free(ctr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctr->pos = 0;
|
||||
ctr->playing = true;
|
||||
|
||||
ctr->frame_time = (retro_time_t)roundf(1000000 * 4481134.0 / (*new_rate * 8192.0));
|
||||
|
||||
ndspSetMasterVol(1.0);
|
||||
|
||||
return ctr;
|
||||
}
|
||||
|
||||
static void ctr_dsp_thread_audio_free(void *data)
|
||||
{
|
||||
ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data;
|
||||
if (!ctr)
|
||||
return;
|
||||
|
||||
if (ctr->running)
|
||||
{
|
||||
ctr->running = false;
|
||||
scond_signal(ctr->fifo_avail);
|
||||
}
|
||||
|
||||
if (ctr->thread)
|
||||
sthread_join(ctr->thread);
|
||||
|
||||
scond_free(ctr->fifo_avail);
|
||||
scond_free(ctr->fifo_done);
|
||||
slock_free(ctr->fifo_lock);
|
||||
|
||||
if (ctr->fifo)
|
||||
{
|
||||
fifo_free(ctr->fifo);
|
||||
ctr->fifo = NULL;
|
||||
}
|
||||
|
||||
ndspChnWaveBufClear(ctr->channel);
|
||||
|
||||
linearFree(ctr->dsp_buf.data_pcm16);
|
||||
|
||||
free(ctr);
|
||||
ndspExit();
|
||||
ctr = NULL;
|
||||
}
|
||||
|
||||
static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t size)
|
||||
{
|
||||
size_t avail, written;
|
||||
ctr_dsp_thread_audio_t * ctr = (ctr_dsp_thread_audio_t*)data;
|
||||
|
||||
if (!ctr || !ctr->running)
|
||||
return 0;
|
||||
|
||||
if (ctr->nonblocking)
|
||||
{
|
||||
slock_lock(ctr->fifo_lock);
|
||||
avail = FIFO_WRITE_AVAIL(ctr->fifo);
|
||||
written = MIN(avail, size);
|
||||
if (written > 0)
|
||||
{
|
||||
fifo_write(ctr->fifo, buf, written);
|
||||
scond_signal(ctr->fifo_avail);
|
||||
}
|
||||
slock_unlock(ctr->fifo_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
written = 0;
|
||||
while (written < size && ctr->running)
|
||||
{
|
||||
slock_lock(ctr->fifo_lock);
|
||||
avail = FIFO_WRITE_AVAIL(ctr->fifo);
|
||||
if (avail == 0)
|
||||
{
|
||||
if (ctr->running)
|
||||
{
|
||||
/* Wait a maximum of one frame, skip the write if the thread is still busy */
|
||||
if (!scond_wait_timeout(ctr->fifo_done, ctr->fifo_lock, ctr->frame_time)) {
|
||||
slock_unlock(ctr->fifo_lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
slock_unlock(ctr->fifo_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t write_amt = MIN(size - written, avail);
|
||||
fifo_write(ctr->fifo, (const char*)buf + written, write_amt);
|
||||
scond_signal(ctr->fifo_avail);
|
||||
slock_unlock(ctr->fifo_lock);
|
||||
written += write_amt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
static bool ctr_dsp_thread_audio_stop(void *data)
|
||||
{
|
||||
ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data;
|
||||
|
||||
if (!ctr)
|
||||
return false;
|
||||
|
||||
ndspSetMasterVol(0.0);
|
||||
ctr->playing = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ctr_dsp_thread_audio_alive(void *data)
|
||||
{
|
||||
ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data;
|
||||
|
||||
if (!ctr)
|
||||
return false;
|
||||
|
||||
return ctr->playing;
|
||||
}
|
||||
|
||||
static bool ctr_dsp_thread_audio_start(void *data, bool is_shutdown)
|
||||
{
|
||||
ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data;
|
||||
|
||||
if (!ctr)
|
||||
return false;
|
||||
|
||||
/* Prevents restarting audio when the menu
|
||||
* is toggled off on shutdown */
|
||||
if (is_shutdown)
|
||||
return true;
|
||||
|
||||
ndspSetMasterVol(1.0);
|
||||
ctr->playing = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ctr_dsp_thread_audio_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data;
|
||||
if (ctr)
|
||||
ctr->nonblocking = state;
|
||||
}
|
||||
|
||||
static bool ctr_dsp_thread_audio_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return false;
|
||||
}
|
||||
|
||||
static size_t ctr_dsp_thread_audio_write_avail(void *data)
|
||||
{
|
||||
size_t val;
|
||||
ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data;
|
||||
|
||||
slock_lock(ctr->fifo_lock);
|
||||
val = FIFO_WRITE_AVAIL(ctr->fifo);
|
||||
slock_unlock(ctr->fifo_lock);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static size_t ctr_dsp_thread_audio_buffer_size(void *data)
|
||||
{
|
||||
ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data;
|
||||
return ctr->fifo_size;
|
||||
}
|
||||
|
||||
audio_driver_t audio_ctr_dsp_thread = {
|
||||
ctr_dsp_thread_audio_init,
|
||||
ctr_dsp_thread_audio_write,
|
||||
ctr_dsp_thread_audio_stop,
|
||||
ctr_dsp_thread_audio_start,
|
||||
ctr_dsp_thread_audio_alive,
|
||||
ctr_dsp_thread_audio_set_nonblock_state,
|
||||
ctr_dsp_thread_audio_free,
|
||||
ctr_dsp_thread_audio_use_float,
|
||||
"dsp_thread",
|
||||
NULL,
|
||||
NULL,
|
||||
ctr_dsp_thread_audio_write_avail,
|
||||
ctr_dsp_thread_audio_buffer_size
|
||||
};
|
@ -482,8 +482,10 @@ static void frontend_ctr_init(void* data)
|
||||
if (csndInit() != 0)
|
||||
audio_ctr_csnd = audio_null;
|
||||
ctr_check_dspfirm();
|
||||
if (ndspInit() != 0)
|
||||
if (ndspInit() != 0) {
|
||||
audio_ctr_dsp = audio_null;
|
||||
audio_ctr_dsp_thread = audio_null;
|
||||
}
|
||||
cfguInit();
|
||||
ptmuInit();
|
||||
mcuHwcInit();
|
||||
|
@ -567,12 +567,6 @@ static bool ctr_frame(void* data, const void* frame,
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!aptMainLoop())
|
||||
{
|
||||
command_event(CMD_EVENT_QUIT, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
state_tmp = hidKeysDown();
|
||||
hidTouchRead(&state_tmp_touch);
|
||||
if((state_tmp & KEY_TOUCH) && (state_tmp_touch.py < 120))
|
||||
|
@ -829,7 +829,11 @@ static bool video_thread_init(thread_video_t *thr,
|
||||
max_size = info.input_scale * RARCH_SCALE_BASE;
|
||||
max_size *= max_size;
|
||||
max_size *= info.rgb32 ? sizeof(uint32_t) : sizeof(uint16_t);
|
||||
#ifdef _3DS
|
||||
thr->frame.buffer = linearMemAlign(max_size, 0x80);
|
||||
#else
|
||||
thr->frame.buffer = (uint8_t*)malloc(max_size);
|
||||
#endif
|
||||
|
||||
if (!thr->frame.buffer)
|
||||
return false;
|
||||
@ -949,7 +953,11 @@ static void video_thread_free(void *data)
|
||||
#if defined(HAVE_MENU)
|
||||
free(thr->texture.frame);
|
||||
#endif
|
||||
#ifdef _3DS
|
||||
linearFree(thr->frame.buffer);
|
||||
#else
|
||||
free(thr->frame.buffer);
|
||||
#endif
|
||||
slock_free(thr->frame.lock);
|
||||
slock_free(thr->lock);
|
||||
scond_free(thr->cond_cmd);
|
||||
|
@ -897,6 +897,7 @@ AUDIO
|
||||
#elif defined(_3DS)
|
||||
#include "../audio/drivers/ctr_csnd_audio.c"
|
||||
#include "../audio/drivers/ctr_dsp_audio.c"
|
||||
#include "../audio/drivers/ctr_dsp_thread_audio.c"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XAUDIO
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include <errno.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#define STACKSIZE (4 * 1024)
|
||||
#define STACKSIZE (32 * 1024)
|
||||
|
||||
#ifndef PTHREAD_SCOPE_PROCESS
|
||||
/* An earlier version of devkitARM does not define the pthread types. Can remove in r54+. */
|
||||
@ -39,10 +39,16 @@ typedef Thread pthread_t;
|
||||
typedef LightLock pthread_mutex_t;
|
||||
typedef void* pthread_mutexattr_t;
|
||||
typedef int pthread_attr_t;
|
||||
typedef LightEvent pthread_cond_t;
|
||||
typedef uint32_t pthread_cond_t;
|
||||
typedef int pthread_condattr_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t semaphore;
|
||||
LightLock lock;
|
||||
uint32_t waiting;
|
||||
} cond_t;
|
||||
|
||||
/* libctru threads return void but pthreads return void pointer */
|
||||
static bool mutex_inited = false;
|
||||
static LightLock safe_double_thread_launch;
|
||||
@ -60,11 +66,18 @@ static INLINE int pthread_create(pthread_t *thread,
|
||||
{
|
||||
s32 prio = 0;
|
||||
Thread new_ctr_thread;
|
||||
int procnum = -2; // use default cpu
|
||||
bool isNew3DS;
|
||||
|
||||
APT_CheckNew3DS(&isNew3DS);
|
||||
|
||||
if (isNew3DS)
|
||||
procnum = 2;
|
||||
|
||||
if (!mutex_inited)
|
||||
{
|
||||
LightLock_Init(&safe_double_thread_launch);
|
||||
mutex_inited = true;
|
||||
LightLock_Init(&safe_double_thread_launch);
|
||||
mutex_inited = true;
|
||||
}
|
||||
|
||||
/*Must wait if attempting to launch 2 threads at once to prevent corruption of function pointer*/
|
||||
@ -73,12 +86,12 @@ static INLINE int pthread_create(pthread_t *thread,
|
||||
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
|
||||
|
||||
start_routine_jump = start_routine;
|
||||
new_ctr_thread = threadCreate(ctr_thread_launcher, arg, STACKSIZE, prio - 1, -1/*No affinity, use any CPU*/, false);
|
||||
new_ctr_thread = threadCreate(ctr_thread_launcher, arg, STACKSIZE, prio - 1, procnum, false);
|
||||
|
||||
if (!new_ctr_thread)
|
||||
{
|
||||
LightLock_Unlock(&safe_double_thread_launch);
|
||||
return EAGAIN;
|
||||
LightLock_Unlock(&safe_double_thread_launch);
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
*thread = (pthread_t)new_ctr_thread;
|
||||
@ -105,7 +118,8 @@ static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
||||
|
||||
static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
{
|
||||
return LightLock_TryLock((LightLock *)mutex);
|
||||
LightLock_Lock((LightLock *)mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
@ -119,6 +133,8 @@ static INLINE void pthread_exit(void *retval)
|
||||
/*Yes the pointer to int cast is not ideal*/
|
||||
/*threadExit((int)retval);*/
|
||||
(void)retval;
|
||||
|
||||
threadExit(0);
|
||||
}
|
||||
|
||||
static INLINE int pthread_detach(pthread_t thread)
|
||||
@ -131,7 +147,12 @@ static INLINE int pthread_detach(pthread_t thread)
|
||||
static INLINE int pthread_join(pthread_t thread, void **retval)
|
||||
{
|
||||
/*retval is ignored*/
|
||||
return threadJoin((Thread)thread, U64_MAX);
|
||||
if(threadJoin((Thread)thread, INT64_MAX))
|
||||
return -1;
|
||||
|
||||
threadFree((Thread)thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
@ -142,51 +163,109 @@ static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
static INLINE int pthread_cond_wait(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex)
|
||||
{
|
||||
LightEvent_Wait((LightEvent *)cond);
|
||||
cond_t *cond_data = (cond_t *)*cond;
|
||||
LightLock_Lock(&cond_data->lock);
|
||||
cond_data->waiting++;
|
||||
LightLock_Unlock(mutex);
|
||||
LightLock_Unlock(&cond_data->lock);
|
||||
svcWaitSynchronization(cond_data->semaphore, INT64_MAX);
|
||||
LightLock_Lock(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex, const struct timespec *abstime)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
struct timespec now = {0};
|
||||
/* Missing clock_gettime*/
|
||||
struct timeval tm;
|
||||
struct timespec now = {0};
|
||||
/* Missing clock_gettime*/
|
||||
struct timeval tm;
|
||||
int retval = 0;
|
||||
|
||||
gettimeofday(&tm, NULL);
|
||||
now.tv_sec = tm.tv_sec;
|
||||
now.tv_nsec = tm.tv_usec * 1000;
|
||||
if (LightEvent_TryWait((LightEvent *)cond) != 0 || now.tv_sec > abstime->tv_sec || (now.tv_sec == abstime->tv_sec && now.tv_nsec > abstime->tv_nsec))
|
||||
break;
|
||||
cond_t *cond_data = (cond_t *)*cond;
|
||||
LightLock_Lock(&cond_data->lock);
|
||||
cond_data->waiting++;
|
||||
|
||||
gettimeofday(&tm, NULL);
|
||||
now.tv_sec = tm.tv_sec;
|
||||
now.tv_nsec = tm.tv_usec * 1000;
|
||||
s64 timeout = (abstime->tv_sec - now.tv_sec) * 1000000000 + (abstime->tv_nsec - now.tv_nsec);
|
||||
|
||||
if (timeout >= 0) {
|
||||
LightLock_Unlock(mutex);
|
||||
LightLock_Unlock(&cond_data->lock);
|
||||
if (svcWaitSynchronization(cond_data->semaphore, timeout))
|
||||
retval = ETIMEDOUT;
|
||||
|
||||
LightLock_Lock(mutex);
|
||||
} else {
|
||||
retval = ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_init(pthread_cond_t *cond,
|
||||
const pthread_condattr_t *attr)
|
||||
{
|
||||
LightEvent_Init((LightEvent *)cond, RESET_ONESHOT);
|
||||
cond_t *cond_data = calloc(1, sizeof(cond_t));
|
||||
if (!cond_data)
|
||||
goto error;
|
||||
|
||||
if (svcCreateSemaphore(&cond_data->semaphore, 0, 1))
|
||||
goto error;
|
||||
|
||||
LightLock_Init(&cond_data->lock);
|
||||
cond_data->waiting = 0;
|
||||
*cond = (pthread_cond_t)cond_data;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
svcCloseHandle(cond_data->semaphore);
|
||||
if (cond_data)
|
||||
free(cond_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
LightEvent_Signal((LightEvent *)cond);
|
||||
int32_t count;
|
||||
cond_t *cond_data = (cond_t *)*cond;
|
||||
LightLock_Lock(&cond_data->lock);
|
||||
if (cond_data->waiting) {
|
||||
cond_data->waiting--;
|
||||
LightLock_Unlock(&cond_data->lock);
|
||||
svcReleaseSemaphore(&count, cond_data->semaphore, 1);
|
||||
} else {
|
||||
LightLock_Unlock(&cond_data->lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
LightEvent_Signal((LightEvent *)cond);
|
||||
int32_t count;
|
||||
cond_t *cond_data = (cond_t *)*cond;
|
||||
LightLock_Lock(&cond_data->lock);
|
||||
while (cond_data->waiting) {
|
||||
cond_data->waiting--;
|
||||
LightLock_Unlock(&cond_data->lock);
|
||||
svcReleaseSemaphore(&count, cond_data->semaphore, 1);
|
||||
LightLock_Lock(&cond_data->lock);
|
||||
}
|
||||
LightLock_Unlock(&cond_data->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
/*nothing to destroy*/
|
||||
if (*cond) {
|
||||
cond_t *cond_data = (cond_t *)*cond;
|
||||
|
||||
svcCloseHandle(cond_data->semaphore);
|
||||
free(cond_data);
|
||||
}
|
||||
*cond = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -379,6 +379,7 @@ static const audio_driver_t *audio_drivers[] = {
|
||||
#ifdef _3DS
|
||||
&audio_ctr_csnd,
|
||||
&audio_ctr_dsp,
|
||||
&audio_ctr_dsp_thread,
|
||||
#endif
|
||||
#ifdef SWITCH
|
||||
&audio_switch,
|
||||
@ -38776,6 +38777,13 @@ static enum runloop_state runloop_check_state(
|
||||
return RUNLOOP_STATE_QUIT;
|
||||
#endif
|
||||
|
||||
#ifdef _3DS
|
||||
/* Should be called once per frame */
|
||||
if (!aptMainLoop())
|
||||
return RUNLOOP_STATE_QUIT;
|
||||
#endif
|
||||
|
||||
|
||||
BIT256_CLEAR_ALL_PTR(¤t_bits);
|
||||
|
||||
p_rarch->input_driver_block_libretro_input = false;
|
||||
|
@ -605,6 +605,7 @@ extern audio_driver_t audio_psp;
|
||||
extern audio_driver_t audio_ps2;
|
||||
extern audio_driver_t audio_ctr_csnd;
|
||||
extern audio_driver_t audio_ctr_dsp;
|
||||
extern audio_driver_t audio_ctr_dsp_thread;
|
||||
extern audio_driver_t audio_switch;
|
||||
extern audio_driver_t audio_switch_thread;
|
||||
extern audio_driver_t audio_switch_libnx_audren;
|
||||
|
Loading…
Reference in New Issue
Block a user