From eb13718c5e94f183e25b747c952c17405be11693 Mon Sep 17 00:00:00 2001 From: Aaron Culliney Date: Sun, 25 Mar 2018 15:54:23 -0700 Subject: [PATCH] Introduce CPU thread function annotation and enforcement --- src/audio/mockingboard.c | 8 ++++---- src/audio/soundcore.c | 12 ++++++------ src/audio/speaker.c | 8 ++++---- src/audio/speaker.h | 6 +++--- src/common.h | 12 ++++++++++++ src/meta/debugger.c | 6 +----- src/timing.c | 18 +++++++++++------- src/timing.h | 5 +++++ src/video/gltouchjoy_kpad.c | 2 +- src/video/video.c | 4 ++-- 10 files changed, 49 insertions(+), 32 deletions(-) diff --git a/src/audio/mockingboard.c b/src/audio/mockingboard.c index e5671167..bba293b0 100644 --- a/src/audio/mockingboard.c +++ b/src/audio/mockingboard.c @@ -1848,7 +1848,7 @@ static void MB_DSUninit() void MB_Initialize() { #if 1 // APPLE2IX - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); memset(SSI263Voice, 0x0, sizeof(AudioBuffer_s *) * 64); #endif LOG("MB_Initialize: g_bDisableDirectSound=%d, g_bDisableDirectSoundMockingboard=%d\n", g_bDisableDirectSound, g_bDisableDirectSoundMockingboard); @@ -1901,11 +1901,11 @@ void MB_Initialize() #if 1 // APPLE2IX // HACK functions for "soft" destroying backend audio resource (but keeping current state) void MB_SoftDestroy(void) { - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); MB_DSUninit(); } void MB_SoftInitialize(void) { - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); MB_DSInit(); } #endif @@ -1928,7 +1928,7 @@ void MB_Reinitialize() void MB_Destroy() { #if 1 // APPLE2IX - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); #endif MB_DSUninit(); diff --git a/src/audio/soundcore.c b/src/audio/soundcore.c index 9678a880..58032f34 100644 --- a/src/audio/soundcore.c +++ b/src/audio/soundcore.c @@ -40,7 +40,7 @@ static AudioBackend_s *currentBackend = NULL; long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) { // CPU thread owns audio lifecycle (see note above) - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); if (!audio_isAvailable) { *audioBuffer = NULL; @@ -69,7 +69,7 @@ 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); + ASSERT_ON_CPU_THREAD(); if (audioContext) { audioContext->DestroySoundBuffer(audioContext, audioBuffer); } @@ -77,7 +77,7 @@ void audio_destroySoundBuffer(INOUT AudioBuffer_s **audioBuffer) { bool audio_init(void) { // CPU thread owns audio lifecycle (see note above) - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); if (audio_isAvailable) { return true; } @@ -101,7 +101,7 @@ bool audio_init(void) { void audio_shutdown(void) { // CPU thread owns audio lifecycle (see note above) - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); if (!audio_isAvailable) { return; } @@ -115,7 +115,7 @@ void audio_pause(void) { #if TARGET_OS_MAC || TARGET_OS_PHONE # warning FIXME TODO : this assert is firing on iOS port ... but the assert is valid ... fix soon #else - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); #endif if (!audio_isAvailable) { return; @@ -125,7 +125,7 @@ void audio_pause(void) { void audio_resume(void) { // CPU thread owns audio lifecycle (see note above) - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); if (!audio_isAvailable) { return; } diff --git a/src/audio/speaker.c b/src/audio/speaker.c index c7c569fe..a2cb9d1c 100644 --- a/src/audio/speaker.c +++ b/src/audio/speaker.c @@ -369,7 +369,7 @@ static unsigned long _submit_samples_buffer(const unsigned long num_channel_samp // speaker public API functions void speaker_destroy(void) { - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); speaker_isAvailable = false; audio_destroySoundBuffer(&speakerBuffer); FREE(samples_buffer); @@ -377,7 +377,7 @@ void speaker_destroy(void) { } void speaker_init(void) { - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); long err = 0; speaker_isAvailable = false; @@ -443,7 +443,7 @@ void speaker_flush(void) { return; } - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); if (is_fullspeed) { cycles_quiet_time = cycles_count_total; @@ -512,7 +512,7 @@ double speaker_cyclesPerSample(void) { GLUE_C_READ(speaker_toggle) { - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); timing_checkpoint_cycles(); diff --git a/src/audio/speaker.h b/src/audio/speaker.h index a9d67315..789227ed 100644 --- a/src/audio/speaker.h +++ b/src/audio/speaker.h @@ -16,10 +16,10 @@ // between speaker and mockingboard #define SPKR_DATA_INIT (SHRT_MAX>>3) // 0x0FFF -void speaker_init(void); -void speaker_destroy(void); +void speaker_init(void) CALL_ON_CPU_THREAD; +void speaker_destroy(void) CALL_ON_CPU_THREAD; void speaker_reset(void); -void speaker_flush(void); +void speaker_flush(void) CALL_ON_CPU_THREAD; bool speaker_isActive(void); /* diff --git a/src/common.h b/src/common.h index a6d505d8..5b6fe674 100644 --- a/src/common.h +++ b/src/common.h @@ -26,6 +26,18 @@ #define PUBLIC #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 #include "config.h" #endif diff --git a/src/meta/debugger.c b/src/meta/debugger.c index afef41d0..861ecb47 100644 --- a/src/meta/debugger.c +++ b/src/meta/debugger.c @@ -1185,11 +1185,7 @@ static int begin_cpu_stepping() { ------------------------------------------------------------------------- */ bool c_debugger_should_break() { - if (pthread_self() != cpu_thread_id) { - // OOPS ... - LOG("should only call this from cpu thread, bailing..."); - assert(false); - } + ASSERT_ON_CPU_THREAD(); bool break_stepping = false; if (at_haltpt()) { diff --git a/src/timing.c b/src/timing.c index b2981a2c..5d952221 100644 --- a/src/timing.c +++ b/src/timing.c @@ -140,7 +140,7 @@ static #endif void reinitialize(void) { #if !TESTING - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); #endif cycles_count_total = 0; @@ -178,7 +178,7 @@ void timing_toggleCPUSpeed(void) { static void timing_reinitializeAudio(void) { SPINLOCK_ACQUIRE(&_pause_spinLock); - assert(pthread_self() != cpu_thread_id); + ASSERT_NOT_ON_CPU_THREAD(); #if !TESTING assert(cpu_isPaused()); #endif @@ -189,7 +189,7 @@ static void timing_reinitializeAudio(void) { } void cpu_pause(void) { - assert(pthread_self() != cpu_thread_id); + ASSERT_NOT_ON_CPU_THREAD(); SPINLOCK_ACQUIRE(&_pause_spinLock); do { @@ -209,7 +209,7 @@ void cpu_pause(void) { } void cpu_resume(void) { - assert(pthread_self() != cpu_thread_id); + ASSERT_NOT_ON_CPU_THREAD(); SPINLOCK_ACQUIRE(&_pause_spinLock); do { @@ -242,7 +242,7 @@ bool timing_shouldAutoAdjustSpeed(void) { static void *cpu_thread(void *dummyptr) { #ifndef NDEBUG // Spamsung Galaxy Y running Gingerbread triggers this, wTf?! - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); #endif LOG("cpu_thread : initialized..."); @@ -514,6 +514,10 @@ cpu_runloop: return NULL; } +bool timing_isCPUThread(void) { + return pthread_self() == cpu_thread_id; +} + void timing_startCPU(void) { cpu_shutting_down = false; 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) { - assert(pthread_self() == cpu_thread_id); + ASSERT_ON_CPU_THREAD(); timing_checkpoint_cycles(); 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 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; assert(d >= 0); diff --git a/src/timing.h b/src/timing.h index 15baa782..1ae684c6 100644 --- a/src/timing.h +++ b/src/timing.h @@ -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_add(struct timespec start, unsigned long nsecs); +/* + * True if current thread is the CPU thread. + */ +bool timing_isCPUThread(void); + /* * start CPU thread */ diff --git a/src/video/gltouchjoy_kpad.c b/src/video/gltouchjoy_kpad.c index 23fc88c4..bd24b5de 100644 --- a/src/video/gltouchjoy_kpad.c +++ b/src/video/gltouchjoy_kpad.c @@ -129,7 +129,7 @@ static inline void _touch_sourceBegin(volatile int *source) { } static void touchkpad_keyboardReadCallback(void) { - assert(pthread_self() == cpu_thread_id); + ASSERT_CALL_ON_CPU_THREAD(); // HACK FIXME TODO : // diff --git a/src/video/video.c b/src/video/video.c index 01e182a9..0984ea0f 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -28,7 +28,7 @@ static pthread_t render_thread_id = 0; void video_init(void) { 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()); render_thread_id = pthread_self(); @@ -58,7 +58,7 @@ void video_shutdown(void) { } void video_render(void) { - assert(pthread_self() == render_thread_id); + ASSERT_ON_UI_THREAD(); currentBackend->render(); }