From 16e699a76155b8babb51e14d03b1c65eb6c589bb Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 1 Aug 2022 07:59:04 +0100 Subject: [PATCH] Proposing exposing as public api the various arch dependent pause instructions so could be used in app infinite loops. A handful of games do already so we unify it in one place. --- include/SDL_atomic.h | 20 ++++++++++++++++++++ src/atomic/SDL_spinlock.c | 21 +-------------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/include/SDL_atomic.h b/include/SDL_atomic.h index b29ceeac2..2eace2086 100644 --- a/include/SDL_atomic.h +++ b/include/SDL_atomic.h @@ -237,6 +237,26 @@ typedef void (*SDL_KernelMemoryBarrierFunc)(); #endif #endif +/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */ +#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) + #define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */ +#elif (defined(__arm__) && __ARM_ARCH__ >= 7) || defined(__aarch64__) + #define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory") +#elif (defined(__powerpc__) || defined(__powerpc64__)) + #define SDL_CPUPauseInstruction() __asm__ __volatile__("or 27,27,27"); +#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + #define SDL_CPUPauseInstruction() _mm_pause() /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */ +#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) + #define SDL_CPUPauseInstruction() __yield() +#elif defined(__WATCOMC__) && defined(__386__) + /* watcom assembler rejects PAUSE if CPU < i686, and it refuses REP NOP as an invalid combination. Hardcode the bytes. */ + extern __inline void SDL_CPUPauseInstruction(void); + #pragma aux SDL_CPUPauseInstruction = "db 0f3h,90h" +#else + #define SDL_CPUPauseInstruction() +#endif + + /** * \brief A type representing an atomic integer value. It is a struct * so people don't accidentally use numeric operations on it. diff --git a/src/atomic/SDL_spinlock.c b/src/atomic/SDL_spinlock.c index cbe5445f1..965c021e1 100644 --- a/src/atomic/SDL_spinlock.c +++ b/src/atomic/SDL_spinlock.c @@ -158,25 +158,6 @@ SDL_AtomicTryLock(SDL_SpinLock *lock) #endif } -/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */ -#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) - #define PAUSE_INSTRUCTION() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */ -#elif (defined(__arm__) && __ARM_ARCH__ >= 7) || defined(__aarch64__) - #define PAUSE_INSTRUCTION() __asm__ __volatile__("yield" ::: "memory") -#elif (defined(__powerpc__) || defined(__powerpc64__)) - #define PAUSE_INSTRUCTION() __asm__ __volatile__("or 27,27,27"); -#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) - #define PAUSE_INSTRUCTION() _mm_pause() /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */ -#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) - #define PAUSE_INSTRUCTION() __yield() -#elif defined(__WATCOMC__) && defined(__386__) - /* watcom assembler rejects PAUSE if CPU < i686, and it refuses REP NOP as an invalid combination. Hardcode the bytes. */ - extern __inline void PAUSE_INSTRUCTION(void); - #pragma aux PAUSE_INSTRUCTION = "db 0f3h,90h" -#else - #define PAUSE_INSTRUCTION() -#endif - void SDL_AtomicLock(SDL_SpinLock *lock) { @@ -185,7 +166,7 @@ SDL_AtomicLock(SDL_SpinLock *lock) while (!SDL_AtomicTryLock(lock)) { if (iterations < 32) { iterations++; - PAUSE_INSTRUCTION(); + SDL_CPUPauseInstruction(); } else { /* !!! FIXME: this doesn't definitely give up the current timeslice, it does different things on various platforms. */ SDL_Delay(0);