Introduce CPU thread function annotation and enforcement

This commit is contained in:
Aaron Culliney 2018-03-25 15:54:23 -07:00
parent 51d2efba03
commit eb13718c5e
10 changed files with 49 additions and 32 deletions

View File

@ -1848,7 +1848,7 @@ static void MB_DSUninit()
void MB_Initialize() void MB_Initialize()
{ {
#if 1 // APPLE2IX #if 1 // APPLE2IX
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
memset(SSI263Voice, 0x0, sizeof(AudioBuffer_s *) * 64); memset(SSI263Voice, 0x0, sizeof(AudioBuffer_s *) * 64);
#endif #endif
LOG("MB_Initialize: g_bDisableDirectSound=%d, g_bDisableDirectSoundMockingboard=%d\n", g_bDisableDirectSound, g_bDisableDirectSoundMockingboard); LOG("MB_Initialize: g_bDisableDirectSound=%d, g_bDisableDirectSoundMockingboard=%d\n", g_bDisableDirectSound, g_bDisableDirectSoundMockingboard);
@ -1901,11 +1901,11 @@ void MB_Initialize()
#if 1 // APPLE2IX #if 1 // APPLE2IX
// HACK functions for "soft" destroying backend audio resource (but keeping current state) // HACK functions for "soft" destroying backend audio resource (but keeping current state)
void MB_SoftDestroy(void) { void MB_SoftDestroy(void) {
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
MB_DSUninit(); MB_DSUninit();
} }
void MB_SoftInitialize(void) { void MB_SoftInitialize(void) {
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
MB_DSInit(); MB_DSInit();
} }
#endif #endif
@ -1928,7 +1928,7 @@ void MB_Reinitialize()
void MB_Destroy() void MB_Destroy()
{ {
#if 1 // APPLE2IX #if 1 // APPLE2IX
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
#endif #endif
MB_DSUninit(); MB_DSUninit();

View File

@ -40,7 +40,7 @@ static AudioBackend_s *currentBackend = NULL;
long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) { long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
// CPU thread owns audio lifecycle (see note above) // CPU thread owns audio lifecycle (see note above)
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
if (!audio_isAvailable) { if (!audio_isAvailable) {
*audioBuffer = NULL; *audioBuffer = NULL;
@ -69,7 +69,7 @@ long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
void audio_destroySoundBuffer(INOUT AudioBuffer_s **audioBuffer) { void audio_destroySoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
// CPU thread owns audio lifecycle (see note above) // CPU thread owns audio lifecycle (see note above)
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
if (audioContext) { if (audioContext) {
audioContext->DestroySoundBuffer(audioContext, audioBuffer); audioContext->DestroySoundBuffer(audioContext, audioBuffer);
} }
@ -77,7 +77,7 @@ void audio_destroySoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
bool audio_init(void) { bool audio_init(void) {
// CPU thread owns audio lifecycle (see note above) // CPU thread owns audio lifecycle (see note above)
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
if (audio_isAvailable) { if (audio_isAvailable) {
return true; return true;
} }
@ -101,7 +101,7 @@ bool audio_init(void) {
void audio_shutdown(void) { void audio_shutdown(void) {
// CPU thread owns audio lifecycle (see note above) // CPU thread owns audio lifecycle (see note above)
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
if (!audio_isAvailable) { if (!audio_isAvailable) {
return; return;
} }
@ -115,7 +115,7 @@ void audio_pause(void) {
#if TARGET_OS_MAC || TARGET_OS_PHONE #if TARGET_OS_MAC || TARGET_OS_PHONE
# warning FIXME TODO : this assert is firing on iOS port ... but the assert is valid ... fix soon # warning FIXME TODO : this assert is firing on iOS port ... but the assert is valid ... fix soon
#else #else
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
#endif #endif
if (!audio_isAvailable) { if (!audio_isAvailable) {
return; return;
@ -125,7 +125,7 @@ void audio_pause(void) {
void audio_resume(void) { void audio_resume(void) {
// CPU thread owns audio lifecycle (see note above) // CPU thread owns audio lifecycle (see note above)
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
if (!audio_isAvailable) { if (!audio_isAvailable) {
return; return;
} }

View File

@ -369,7 +369,7 @@ static unsigned long _submit_samples_buffer(const unsigned long num_channel_samp
// speaker public API functions // speaker public API functions
void speaker_destroy(void) { void speaker_destroy(void) {
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
speaker_isAvailable = false; speaker_isAvailable = false;
audio_destroySoundBuffer(&speakerBuffer); audio_destroySoundBuffer(&speakerBuffer);
FREE(samples_buffer); FREE(samples_buffer);
@ -377,7 +377,7 @@ void speaker_destroy(void) {
} }
void speaker_init(void) { void speaker_init(void) {
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
long err = 0; long err = 0;
speaker_isAvailable = false; speaker_isAvailable = false;
@ -443,7 +443,7 @@ void speaker_flush(void) {
return; return;
} }
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
if (is_fullspeed) { if (is_fullspeed) {
cycles_quiet_time = cycles_count_total; cycles_quiet_time = cycles_count_total;
@ -512,7 +512,7 @@ double speaker_cyclesPerSample(void) {
GLUE_C_READ(speaker_toggle) GLUE_C_READ(speaker_toggle)
{ {
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
timing_checkpoint_cycles(); timing_checkpoint_cycles();

View File

@ -16,10 +16,10 @@
// between speaker and mockingboard // between speaker and mockingboard
#define SPKR_DATA_INIT (SHRT_MAX>>3) // 0x0FFF #define SPKR_DATA_INIT (SHRT_MAX>>3) // 0x0FFF
void speaker_init(void); void speaker_init(void) CALL_ON_CPU_THREAD;
void speaker_destroy(void); void speaker_destroy(void) CALL_ON_CPU_THREAD;
void speaker_reset(void); void speaker_reset(void);
void speaker_flush(void); void speaker_flush(void) CALL_ON_CPU_THREAD;
bool speaker_isActive(void); bool speaker_isActive(void);
/* /*

View File

@ -26,6 +26,18 @@
#define PUBLIC #define PUBLIC
#define READONLY #define READONLY
#define CALL_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 ASSERT_ON_CPU_THREAD() \
assert(timing_isCPUThread())
#define ASSERT_NOT_ON_CPU_THREAD() \
assert(!timing_isCPUThread())
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif

View File

@ -1185,11 +1185,7 @@ static int begin_cpu_stepping() {
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
bool c_debugger_should_break() { bool c_debugger_should_break() {
if (pthread_self() != cpu_thread_id) { ASSERT_ON_CPU_THREAD();
// OOPS ...
LOG("should only call this from cpu thread, bailing...");
assert(false);
}
bool break_stepping = false; bool break_stepping = false;
if (at_haltpt()) { if (at_haltpt()) {

View File

@ -140,7 +140,7 @@ static
#endif #endif
void reinitialize(void) { void reinitialize(void) {
#if !TESTING #if !TESTING
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
#endif #endif
cycles_count_total = 0; cycles_count_total = 0;
@ -178,7 +178,7 @@ void timing_toggleCPUSpeed(void) {
static void timing_reinitializeAudio(void) { static void timing_reinitializeAudio(void) {
SPINLOCK_ACQUIRE(&_pause_spinLock); SPINLOCK_ACQUIRE(&_pause_spinLock);
assert(pthread_self() != cpu_thread_id); ASSERT_NOT_ON_CPU_THREAD();
#if !TESTING #if !TESTING
assert(cpu_isPaused()); assert(cpu_isPaused());
#endif #endif
@ -189,7 +189,7 @@ static void timing_reinitializeAudio(void) {
} }
void cpu_pause(void) { void cpu_pause(void) {
assert(pthread_self() != cpu_thread_id); ASSERT_NOT_ON_CPU_THREAD();
SPINLOCK_ACQUIRE(&_pause_spinLock); SPINLOCK_ACQUIRE(&_pause_spinLock);
do { do {
@ -209,7 +209,7 @@ void cpu_pause(void) {
} }
void cpu_resume(void) { void cpu_resume(void) {
assert(pthread_self() != cpu_thread_id); ASSERT_NOT_ON_CPU_THREAD();
SPINLOCK_ACQUIRE(&_pause_spinLock); SPINLOCK_ACQUIRE(&_pause_spinLock);
do { do {
@ -242,7 +242,7 @@ bool timing_shouldAutoAdjustSpeed(void) {
static void *cpu_thread(void *dummyptr) { static void *cpu_thread(void *dummyptr) {
#ifndef NDEBUG // Spamsung Galaxy Y running Gingerbread triggers this, wTf?! #ifndef NDEBUG // Spamsung Galaxy Y running Gingerbread triggers this, wTf?!
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
#endif #endif
LOG("cpu_thread : initialized..."); LOG("cpu_thread : initialized...");
@ -514,6 +514,10 @@ cpu_runloop:
return NULL; return NULL;
} }
bool timing_isCPUThread(void) {
return pthread_self() == cpu_thread_id;
}
void timing_startCPU(void) { void timing_startCPU(void) {
cpu_shutting_down = false; cpu_shutting_down = false;
int err = TEMP_FAILURE_RETRY(pthread_create(&cpu_thread_id, NULL, (void *)&cpu_thread, (void *)NULL)); int err = TEMP_FAILURE_RETRY(pthread_create(&cpu_thread_id, NULL, (void *)&cpu_thread, (void *)NULL));
@ -533,7 +537,7 @@ void timing_stopCPU(void) {
} }
unsigned int CpuGetCyclesThisVideoFrame(void) { unsigned int CpuGetCyclesThisVideoFrame(void) {
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
timing_checkpoint_cycles(); timing_checkpoint_cycles();
return g_dwCyclesThisFrame + cycles_checkpoint_count; return g_dwCyclesThisFrame + cycles_checkpoint_count;
@ -541,7 +545,7 @@ unsigned int CpuGetCyclesThisVideoFrame(void) {
// Called when an IO-reg is accessed & accurate global cycle count info is needed // Called when an IO-reg is accessed & accurate global cycle count info is needed
void timing_checkpoint_cycles(void) { void timing_checkpoint_cycles(void) {
assert(pthread_self() == cpu_thread_id); ASSERT_ON_CPU_THREAD();
const int32_t d = run_args.cpu65_cycle_count - cycles_checkpoint_count; const int32_t d = run_args.cpu65_cycle_count - cycles_checkpoint_count;
assert(d >= 0); assert(d >= 0);

View File

@ -68,6 +68,11 @@ extern READONLY pthread_t cpu_thread_id;
struct timespec timespec_diff(struct timespec start, struct timespec end, bool *negative); struct timespec timespec_diff(struct timespec start, struct timespec end, bool *negative);
struct timespec timespec_add(struct timespec start, unsigned long nsecs); struct timespec timespec_add(struct timespec start, unsigned long nsecs);
/*
* True if current thread is the CPU thread.
*/
bool timing_isCPUThread(void);
/* /*
* start CPU thread * start CPU thread
*/ */

View File

@ -129,7 +129,7 @@ static inline void _touch_sourceBegin(volatile int *source) {
} }
static void touchkpad_keyboardReadCallback(void) { static void touchkpad_keyboardReadCallback(void) {
assert(pthread_self() == cpu_thread_id); ASSERT_CALL_ON_CPU_THREAD();
// HACK FIXME TODO : // HACK FIXME TODO :
// //

View File

@ -28,7 +28,7 @@ static pthread_t render_thread_id = 0;
void video_init(void) { void video_init(void) {
video_initialized = true; video_initialized = true;
assert(pthread_self() != cpu_thread_id); ASSERT_NOT_ON_CPU_THREAD();
LOG("(re)setting render_thread_id : %lu -> %lu", (unsigned long)render_thread_id, (unsigned long)pthread_self()); LOG("(re)setting render_thread_id : %lu -> %lu", (unsigned long)render_thread_id, (unsigned long)pthread_self());
render_thread_id = pthread_self(); render_thread_id = pthread_self();
@ -58,7 +58,7 @@ void video_shutdown(void) {
} }
void video_render(void) { void video_render(void) {
assert(pthread_self() == render_thread_id); ASSERT_ON_UI_THREAD();
currentBackend->render(); currentBackend->render();
} }