postgres.git / summary / log / commit / refs

commit    bb65cb8cdf864e61bc939d3c4b28bbd43d926700
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Sat Jan 07 20:39:05 2012 +0000
First released in: 9.2.0, 8.3.18, 8.4.11, 9.0.7, 9.1.3

    Use __sync_lock_test_and_set() for spinlocks on ARM, if available.
    
    Historically we've used the SWPB instruction for TAS() on ARM, but this
    is deprecated and not available on ARMv6 and later.  Instead, make use
    of a GCC builtin if available.  We'll still fall back to SWPB if not,
    so as not to break existing ports using older GCC versions.
    
    Eventually we might want to try using __sync_lock_test_and_set() on some
    other architectures too, but for now that seems to present only risk and
    not reward.
    
    Back-patch to all supported versions, since people might want to use any
    of them on more recent ARM chips.
    
    Martin Pitt


configure | 65 ++++++++++++++++++++++++++++++++++++++++++++ configure.in | 11 ++++++++ src/include/pg_config.h.in | 3 ++ src/include/storage/s_lock.h | 25 +++++++++++++++-- 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/configure b/configure index ef9e409a416..f38556b9867 100755 --- a/configure +++ b/configure @@ -22108,6 +22108,71 @@ fi done +{ $as_echo "$as_me:$LINENO: checking for builtin locking functions" >&5 +$as_echo_n "checking for builtin locking functions... " >&6; } +if test "${pgac_cv_gcc_int_atomics+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int lock = 0; + __sync_lock_test_and_set(&lock, 1); + __sync_lock_release(&lock); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + pgac_cv_gcc_int_atomics="yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + pgac_cv_gcc_int_atomics="no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $pgac_cv_gcc_int_atomics" >&5 +$as_echo "$pgac_cv_gcc_int_atomics" >&6; } +if test x"$pgac_cv_gcc_int_atomics" = x"yes"; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GCC_INT_ATOMICS 1 +_ACEOF + +fi + # # Pthreads diff --git a/configure.in b/configure.in index a34623a999d..8bbf0154cc0 100644 --- a/configure.in +++ b/configure.in @@ -1403,6 +1403,17 @@ AC_CHECK_FUNCS(atexit, [], [AC_CHECK_FUNCS(on_exit, [], [AC_MSG_ERROR([neither atexit() nor on_exit() found])])]) +AC_CACHE_CHECK([for builtin locking functions], pgac_cv_gcc_int_atomics, +[AC_TRY_LINK([], + [int lock = 0; + __sync_lock_test_and_set(&lock, 1); + __sync_lock_release(&lock);], + [pgac_cv_gcc_int_atomics="yes"], + [pgac_cv_gcc_int_atomics="no"])]) +if test x"$pgac_cv_gcc_int_atomics" = x"yes"; then + AC_DEFINE(HAVE_GCC_INT_ATOMICS, 1, [Define to 1 if you have __sync_lock_test_and_set(int *) and friends.]) +fi + # # Pthreads diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index fd169b682fb..05efca70fd7 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -173,6 +173,9 @@ /* Define to 1 if your compiler understands __FUNCTION__. */ #undef HAVE_FUNCNAME__FUNCTION +/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */ +#undef HAVE_GCC_INT_ATOMICS + /* Define to 1 if you have the `getaddrinfo' function. */ #undef HAVE_GETADDRINFO diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h index 4104cf6c4ca..886f5887f1c 100644 --- a/src/include/storage/s_lock.h +++ b/src/include/storage/s_lock.h @@ -252,13 +252,33 @@ tas(volatile slock_t *lock) #endif /* __ia64__ || __ia64 */ +/* + * On ARM, we use __sync_lock_test_and_set(int *, int) if available, and if + * not fall back on the SWPB instruction. SWPB does not work on ARMv6 or + * later, so the compiler builtin is preferred if available. Note also that + * the int-width variant of the builtin works on more chips than other widths. + */ #if defined(__arm__) || defined(__arm) #define HAS_TEST_AND_SET -typedef unsigned char slock_t; - #define TAS(lock) tas(lock) +#ifdef HAVE_GCC_INT_ATOMICS + +typedef int slock_t; + +static __inline__ int +tas(volatile slock_t *lock) +{ + return __sync_lock_test_and_set(lock, 1); +} + +#define S_UNLOCK(lock) __sync_lock_release(lock) + +#else /* !HAVE_GCC_INT_ATOMICS */ + +typedef unsigned char slock_t; + static __inline__ int tas(volatile slock_t *lock) { @@ -272,6 +292,7 @@ tas(volatile slock_t *lock) return (int) _res; } +#endif /* HAVE_GCC_INT_ATOMICS */ #endif /* __arm__ */ [parent: 1f996adab3ec]