mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-09-27 09:56:08 +00:00
Safer CPU/audio lifecycle management that appears to fix a deadlock on Kindle Fire 1st Gen
This commit is contained in:
parent
b4f871613d
commit
aa5b9eb971
@ -11,6 +11,9 @@
|
||||
|
||||
/*
|
||||
* Apple //e core sound system support. Source inspired/derived from AppleWin.
|
||||
*
|
||||
* 2015/10/01 AUDIO LIFECYCLE WARNING : CPU thread owns all audio, otherwise bad things may happen in system sound layer
|
||||
* (OpenAL/OpenSLES/ALSA/etc)
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
@ -26,6 +29,8 @@ AudioBackend_s *audio_backend = NULL;
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
|
||||
// CPU thread owns audio lifecycle (see note above)
|
||||
assert(pthread_self() == cpu_thread_id);
|
||||
|
||||
if (!audio_isAvailable) {
|
||||
*audioBuffer = NULL;
|
||||
@ -55,12 +60,15 @@ long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
|
||||
}
|
||||
|
||||
void audio_destroySoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
|
||||
// CPU thread owns audio lifecycle (see note above)
|
||||
assert(pthread_self() == cpu_thread_id);
|
||||
if (audioContext) {
|
||||
audioContext->DestroySoundBuffer(audioContext, audioBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool audio_init(void) {
|
||||
// CPU thread owns audio lifecycle (see note above)
|
||||
assert(pthread_self() == cpu_thread_id);
|
||||
if (audio_isAvailable) {
|
||||
return true;
|
||||
@ -89,6 +97,7 @@ bool audio_init(void) {
|
||||
}
|
||||
|
||||
void audio_shutdown(void) {
|
||||
// CPU thread owns audio lifecycle (see note above)
|
||||
assert(pthread_self() == cpu_thread_id);
|
||||
if (!audio_isAvailable) {
|
||||
return;
|
||||
@ -98,6 +107,9 @@ void audio_shutdown(void) {
|
||||
}
|
||||
|
||||
void audio_pause(void) {
|
||||
// CPU thread owns audio lifecycle (see note above)
|
||||
// Deadlock on Kindle Fire 1st Gen if audio_pause() and audio_resume() happen off CPU thread ...
|
||||
assert(pthread_self() == cpu_thread_id);
|
||||
if (!audio_isAvailable) {
|
||||
return;
|
||||
}
|
||||
@ -105,6 +117,8 @@ void audio_pause(void) {
|
||||
}
|
||||
|
||||
void audio_resume(void) {
|
||||
// CPU thread owns audio lifecycle (see note above)
|
||||
assert(pthread_self() == cpu_thread_id);
|
||||
if (!audio_isAvailable) {
|
||||
return;
|
||||
}
|
||||
|
74
src/timing.c
74
src/timing.c
@ -42,16 +42,6 @@
|
||||
|
||||
#define DISK_MOTOR_QUIET_NSECS 2000000
|
||||
|
||||
#define _LOCK_CPU_THREAD() \
|
||||
if (pthread_self() != cpu_thread_id) { \
|
||||
pthread_mutex_lock(&interface_mutex); \
|
||||
}
|
||||
|
||||
#define _UNLOCK_CPU_THREAD() \
|
||||
if (pthread_self() != cpu_thread_id) { \
|
||||
pthread_mutex_unlock(&interface_mutex); \
|
||||
}
|
||||
|
||||
// VBL constants?
|
||||
#define uCyclesPerLine 65 // 25 cycles of HBL & 40 cycles of HBL'
|
||||
#define uVisibleLinesPerFrame (64*3) // 192
|
||||
@ -68,12 +58,12 @@ static int32_t cycles_checkpoint_count = 0;
|
||||
static unsigned int g_dwCyclesThisFrame = 0;
|
||||
|
||||
// scaling and speed adjustments
|
||||
#if MOBILE_DEVICE
|
||||
static bool is_paused = true;
|
||||
#else
|
||||
static bool is_paused = false;
|
||||
#if !MOBILE_DEVICE
|
||||
static bool auto_adjust_speed = true;
|
||||
#endif
|
||||
static bool is_paused = false;
|
||||
static unsigned long _pause_spinLock = 0;
|
||||
|
||||
double cpu_scale_factor = 1.0;
|
||||
double cpu_altscale_factor = 1.0;
|
||||
bool is_fullspeed = false;
|
||||
@ -82,7 +72,9 @@ bool alt_speed_enabled = false;
|
||||
// misc
|
||||
volatile uint8_t emul_reinitialize = 1;
|
||||
#ifdef AUDIO_ENABLED
|
||||
bool emul_reinitialize_audio = true;
|
||||
static bool emul_reinitialize_audio = true;
|
||||
static bool emul_pause_audio = false;
|
||||
static bool emul_resume_audio = false;
|
||||
#endif
|
||||
static bool cpu_shutting_down = false;
|
||||
pthread_t cpu_thread_id = 0;
|
||||
@ -199,32 +191,56 @@ void timing_toggleCPUSpeed(void) {
|
||||
|
||||
#ifdef AUDIO_ENABLED
|
||||
void timing_reinitializeAudio(void) {
|
||||
assert(cpu_isPaused() || (pthread_self() == cpu_thread_id));
|
||||
SPINLOCK_ACQUIRE(&_pause_spinLock);
|
||||
assert(pthread_self() != cpu_thread_id);
|
||||
assert(cpu_isPaused());
|
||||
emul_reinitialize_audio = true;
|
||||
emul_pause_audio = false;
|
||||
emul_resume_audio = false;
|
||||
SPINLOCK_RELINQUISH(&_pause_spinLock);
|
||||
}
|
||||
#endif
|
||||
|
||||
void cpu_pause(void) {
|
||||
|
||||
assert(pthread_self() != cpu_thread_id);
|
||||
_LOCK_CPU_THREAD();
|
||||
|
||||
SPINLOCK_ACQUIRE(&_pause_spinLock);
|
||||
do {
|
||||
if (is_paused) {
|
||||
break;
|
||||
}
|
||||
|
||||
// CPU thread will be paused when it next tries to acquire interface_mutex
|
||||
#ifdef AUDIO_ENABLED
|
||||
audio_pause();
|
||||
if (!emul_reinitialize_audio) {
|
||||
emul_pause_audio = true;
|
||||
}
|
||||
#endif
|
||||
is_paused = true;
|
||||
pthread_mutex_lock(&interface_mutex);
|
||||
is_paused = true;
|
||||
} while (0);
|
||||
SPINLOCK_RELINQUISH(&_pause_spinLock);
|
||||
}
|
||||
|
||||
void cpu_resume(void) {
|
||||
assert(pthread_self() != cpu_thread_id);
|
||||
assert(cpu_isPaused());
|
||||
is_paused = false;
|
||||
|
||||
SPINLOCK_ACQUIRE(&_pause_spinLock);
|
||||
do {
|
||||
if (!is_paused) {
|
||||
break;
|
||||
}
|
||||
|
||||
// CPU thread will be unblocked to acquire interface_mutex
|
||||
#ifdef AUDIO_ENABLED
|
||||
audio_resume();
|
||||
if (!emul_reinitialize_audio) {
|
||||
emul_resume_audio = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
_UNLOCK_CPU_THREAD();
|
||||
pthread_mutex_unlock(&interface_mutex);
|
||||
is_paused = false;
|
||||
} while (0);
|
||||
SPINLOCK_RELINQUISH(&_pause_spinLock);
|
||||
}
|
||||
|
||||
bool cpu_isPaused(void) {
|
||||
@ -292,7 +308,15 @@ static void *cpu_thread(void *dummyptr) {
|
||||
|
||||
do {
|
||||
// -LOCK----------------------------------------------------------------------------------------- SAMPLE ti
|
||||
if (UNLIKELY(emul_pause_audio)) {
|
||||
emul_pause_audio = false;
|
||||
audio_pause();
|
||||
}
|
||||
pthread_mutex_lock(&interface_mutex);
|
||||
if (UNLIKELY(emul_resume_audio)) {
|
||||
emul_resume_audio = false;
|
||||
audio_resume();
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &ti);
|
||||
|
||||
deltat = timespec_diff(t0, ti, &negative);
|
||||
|
Loading…
Reference in New Issue
Block a user