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
This commit is contained in:
Tom Lane 2012-01-07 15:39:16 -05:00
parent a86448e868
commit aa31c350fe
4 changed files with 103 additions and 2 deletions

65
configure vendored
View File

@ -18626,6 +18626,71 @@ _ACEOF
fi
echo "$as_me:$LINENO: checking for builtin locking functions" >&5
echo $ECHO_N "checking for builtin locking functions... $ECHO_C" >&6
if test "${pgac_cv_gcc_int_atomics+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&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 { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
pgac_cv_gcc_int_atomics="yes"
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
pgac_cv_gcc_int_atomics="no"
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
echo "$as_me:$LINENO: result: $pgac_cv_gcc_int_atomics" >&5
echo "${ECHO_T}$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
#

View File

@ -1190,6 +1190,18 @@ AC_CHECK_FUNCS(atexit, [],
AC_FUNC_FSEEKO
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
#

View File

@ -148,6 +148,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

View File

@ -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__ */