Refactor/simplify spinlocking

This commit is contained in:
Aaron Culliney 2019-06-01 07:13:59 -07:00
parent ef3944a4dd
commit 5a8aa065a9
3 changed files with 34 additions and 27 deletions

View File

@ -71,10 +71,10 @@ static AudioBackend_s opensles_audio_backend = { 0 };
// Check and resets underrun condition (readHead has advanced beyond writeHead)
static inline bool _underrun_check_and_manage(SLVoice *voice, OUTPARM unsigned long *workingBytes) {
SPINLOCK_ACQUIRE(&voice->spinLock);
SPIN_LOCK_FULL(&voice->spinLock);
unsigned long readHead = voice->readHead;
unsigned long readWrapCount = voice->readWrapCount;
SPINLOCK_RELINQUISH(&voice->spinLock);
SPIN_UNLOCK_FULL(&voice->spinLock);
assert(readHead < voice->bufferSize);
assert(voice->writeHead < voice->bufferSize);
@ -160,10 +160,10 @@ static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
++newReadWrapCount0;
}
SPINLOCK_ACQUIRE(&voice0->spinLock);
SPIN_LOCK_FULL(&voice0->spinLock);
voice0->readHead = newReadHead0;
voice0->readWrapCount = newReadWrapCount0;
SPINLOCK_RELINQUISH(&voice0->spinLock);
SPIN_UNLOCK_FULL(&voice0->spinLock);
if (voice1) {
memset(voice1->ringBuffer+voice1->readHead, 0x0, ctx->submitSize); // backfill quiet samples
@ -178,10 +178,10 @@ static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
++newReadWrapCount1;
}
SPINLOCK_ACQUIRE(&voice1->spinLock);
SPIN_LOCK_FULL(&voice1->spinLock);
voice1->readHead = newReadHead1;
voice1->readWrapCount = newReadWrapCount1;
SPINLOCK_RELINQUISH(&voice1->spinLock);
SPIN_UNLOCK_FULL(&voice1->spinLock);
}
} while (0);
@ -316,10 +316,10 @@ static long SLUnlockStaticBuffer(AudioBuffer_s *_this, unsigned long audio_bytes
static long SLReplay(AudioBuffer_s *_this) {
SLVoice *voice = (SLVoice*)_this->_internal;
SPINLOCK_ACQUIRE(&voice->spinLock);
SPIN_LOCK_FULL(&voice->spinLock);
voice->readHead = 0;
voice->writeHead = voice->replay_index;
SPINLOCK_RELINQUISH(&voice->spinLock);
SPIN_UNLOCK_FULL(&voice->spinLock);
long err = _SLMaybeSubmitAndStart(voice);
#warning FIXME TODO ... how do we handle mockingboard for new OpenSLES buffer queue codepath?

View File

@ -26,13 +26,13 @@
#define PUBLIC
#define READONLY
#define CALL_ON_UI_THREAD
#define CALL_ON_UI_THREAD // function should only be called on UI thread
#define ASSERT_ON_UI_THREAD() \
assert(video_isRenderThread())
#define ASSERT_NOT_ON_UI_THREAD() \
assert(!video_isRenderThread())
#define CALL_ON_CPU_THREAD
#define CALL_ON_CPU_THREAD // function should only be called on CPU thread
#define ASSERT_ON_CPU_THREAD() \
assert(timing_isCPUThread())
#define ASSERT_NOT_ON_CPU_THREAD() \
@ -117,20 +117,26 @@
#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
#endif
#define SPINLOCK_INIT 0
#define SPINLOCK_ACQUIRED -1
#define SPINLOCK_ACQUIRE(x) \
#define SPINLOCK_INIT 0L
/*
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
"In most cases, these built-in functions are considered a full barrier. That is, no memory operand is moved across
the operation, either forward or backward. Further, instructions are issued as necessary to prevent the processor
from speculating loads across the operation and from queuing stores after the operation."
*/
#define SPIN_LOCK_FULL(x) \
do { \
long val = __sync_sub_and_fetch((x), 1); \
if (val == SPINLOCK_ACQUIRED) { \
long prev = __sync_fetch_and_or((x), 1L); \
if (prev == SPINLOCK_INIT) { \
break; \
} \
__sync_add_and_fetch((x), 1); \
} while (1);
#define SPINLOCK_RELINQUISH(x) \
__sync_add_and_fetch((x), 1);
usleep(1); \
} while (1)
#define SPIN_UNLOCK_FULL(x) \
__sync_fetch_and_and((x), SPINLOCK_INIT)
// cribbed from AOSP and modified with usleep() and to also ignore EAGAIN (should this be a different errno than EINTR)
#define TEMP_FAILURE_RETRY_FOPEN(exp) ({ \

View File

@ -30,7 +30,7 @@ static int32_t cycles_checkpoint_count = 0;
// scaling and speed adjustments
static bool auto_adjust_speed = true;
static bool is_paused = false;
static unsigned long _pause_spinLock = 0;
static unsigned long _pause_spinLock = SPINLOCK_INIT;
double cpu_scale_factor = 1.0;
double cpu_altscale_factor = 1.0;
@ -150,8 +150,9 @@ void timing_toggleCPUSpeed(void) {
}
static void timing_reinitializeAudio(void) {
SPINLOCK_ACQUIRE(&_pause_spinLock);
ASSERT_NOT_ON_CPU_THREAD();
SPIN_LOCK_FULL(&_pause_spinLock);
#if !TESTING
assert(cpu_isPaused());
#endif
@ -159,13 +160,13 @@ static void timing_reinitializeAudio(void) {
emul_pause_audio = false;
emul_resume_audio = false;
emul_video_dirty = false;
SPINLOCK_RELINQUISH(&_pause_spinLock);
SPIN_UNLOCK_FULL(&_pause_spinLock);
}
void cpu_pause(void) {
ASSERT_NOT_ON_CPU_THREAD();
SPINLOCK_ACQUIRE(&_pause_spinLock);
SPIN_LOCK_FULL(&_pause_spinLock);
do {
if (is_paused) {
break;
@ -179,13 +180,13 @@ void cpu_pause(void) {
pthread_mutex_lock(&interface_mutex);
is_paused = true;
} while (0);
SPINLOCK_RELINQUISH(&_pause_spinLock);
SPIN_UNLOCK_FULL(&_pause_spinLock);
}
void cpu_resume(void) {
ASSERT_NOT_ON_CPU_THREAD();
SPINLOCK_ACQUIRE(&_pause_spinLock);
SPIN_LOCK_FULL(&_pause_spinLock);
do {
if (!is_paused) {
break;
@ -200,7 +201,7 @@ void cpu_resume(void) {
is_paused = false;
pthread_mutex_unlock(&interface_mutex);
} while (0);
SPINLOCK_RELINQUISH(&_pause_spinLock);
SPIN_UNLOCK_FULL(&_pause_spinLock);
}
bool cpu_isPaused(void) {