atomic: Spin locks now try to use the x86 PAUSE instruction for short waits.
authorRyan C. Gordon <icculus@icculus.org>
Mon, 25 Jun 2018 15:58:35 -0400
changeset 120382d871b0d5c34
parent 12037 5b86833971fb
child 12039 ecc19ca324f7
atomic: Spin locks now try to use the x86 PAUSE instruction for short waits.

Fixes Bugzilla #4151.
src/atomic/SDL_spinlock.c
     1.1 --- a/src/atomic/SDL_spinlock.c	Mon Jun 25 13:14:52 2018 -0400
     1.2 +++ b/src/atomic/SDL_spinlock.c	Mon Jun 25 15:58:35 2018 -0400
     1.3 @@ -32,6 +32,10 @@
     1.4  #include <atomic.h>
     1.5  #endif
     1.6  
     1.7 +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
     1.8 +#include <xmmintrin.h>
     1.9 +#endif
    1.10 +
    1.11  #if defined(__WATCOMC__) && defined(__386__)
    1.12  SDL_COMPILE_TIME_ASSERT(locksize, 4==sizeof(SDL_SpinLock));
    1.13  extern _inline int _SDL_xchg_watcom(volatile int *a, int v);
    1.14 @@ -116,12 +120,31 @@
    1.15  #endif
    1.16  }
    1.17  
    1.18 +/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
    1.19 +#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
    1.20 +    #define PAUSE_INSTRUCTION() __asm__ __volatile__("rep nop\n")
    1.21 +#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
    1.22 +    #define PAUSE_INSRUCTION() _mm_pause()  /* this is actually "rep nop" and not a SIMD instruction. */
    1.23 +#elif defined(__WATCOMC__) && defined(__386__)
    1.24 +    extern _inline void PAUSE_INSTRUCTION(void);
    1.25 +    #pragma aux PAUSE_INSTRUCTION = "rep nop"
    1.26 +#else
    1.27 +    #define PAUSE_INSTRUCTION()
    1.28 +#endif
    1.29 +
    1.30  void
    1.31  SDL_AtomicLock(SDL_SpinLock *lock)
    1.32  {
    1.33 +    int iterations = 0;
    1.34      /* FIXME: Should we have an eventual timeout? */
    1.35      while (!SDL_AtomicTryLock(lock)) {
    1.36 -        SDL_Delay(0);
    1.37 +        if (iterations < 32) {
    1.38 +            iterations++;
    1.39 +            PAUSE_INSTRUCTION();
    1.40 +        } else {
    1.41 +            /* !!! FIXME: this doesn't definitely give up the current timeslice, it does different things on various platforms. */
    1.42 +            SDL_Delay(0);
    1.43 +        }
    1.44      }
    1.45  }
    1.46