Browse Source

Bug 723937 - replication failing on RUV errors

https://bugzilla.redhat.com/show_bug.cgi?id=723937
Resolves: bug 723937
Bug Description: replication failing on RUV errors
Reviewed by: nkinder (Thanks!)
Branch: master
Fix Description: The previous fix broke 32-bit i386 platforms.  The Fedora
build systems use -march=i386.  On those platforms, we have to use our own
assembler code.  The fix is to introduce an AC_LINK_IFELSE test to
compile and link a short program using __sync_bool_compare_and_swap_8
during configure.  If this succeeds, we just use the gcc builtin, otherwise,
we use our own asm code.
Platforms tested: RHEL6 x86_64, RHEL5 i386
Flag Day: no
Doc impact: no
This reverts commit c5bd90755da96f463ba5dfda79793d5d6cee4e53.
Rich Megginson 14 years ago
parent
commit
b9b1b3cdd8
4 changed files with 113 additions and 104 deletions
  1. 1 2
      config.h.in
  2. 26 100
      configure
  3. 11 2
      configure.ac
  4. 75 0
      ldap/servers/slapd/slapi_counter.c

+ 1 - 2
config.h.in

@@ -67,8 +67,7 @@
    don't. */
 #undef HAVE_DECL_STRERROR_R
 
-/* Define to 1 if you have the declaration of `__sync_add_and_fetch', and to 0
-   if you don't. */
+/* do not have 64-bit atomic compare and swap functions provided by gcc */
 #undef HAVE_DECL___SYNC_ADD_AND_FETCH
 
 /* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.

+ 26 - 100
configure

@@ -20751,75 +20751,6 @@ cat >>confdefs.h <<\_ACEOF
 #define ATOMIC_64BIT_OPERATIONS 1
 _ACEOF
 
-        { $as_echo "$as_me:$LINENO: checking whether __sync_add_and_fetch is declared" >&5
-$as_echo_n "checking whether __sync_add_and_fetch is declared... " >&6; }
-if test "${ac_cv_have_decl___sync_add_and_fetch+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.  */
-$ac_includes_default
-int
-main ()
-{
-#ifndef __sync_add_and_fetch
-  (void) __sync_add_and_fetch;
-#endif
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-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_compile") 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_objext; then
-  ac_cv_have_decl___sync_add_and_fetch=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-	ac_cv_have_decl___sync_add_and_fetch=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_have_decl___sync_add_and_fetch" >&5
-$as_echo "$ac_cv_have_decl___sync_add_and_fetch" >&6; }
-if test "x$ac_cv_have_decl___sync_add_and_fetch" = x""yes; then
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL___SYNC_ADD_AND_FETCH 1
-_ACEOF
-
-
-else
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL___SYNC_ADD_AND_FETCH 0
-_ACEOF
-
-
-fi
-
-
         ;;
       x86_64-*-linux*)
 
@@ -20832,38 +20763,34 @@ cat >>confdefs.h <<\_ACEOF
 #define ATOMIC_64BIT_OPERATIONS 1
 _ACEOF
 
-        { $as_echo "$as_me:$LINENO: checking whether __sync_add_and_fetch is declared" >&5
-$as_echo_n "checking whether __sync_add_and_fetch is declared... " >&6; }
-if test "${ac_cv_have_decl___sync_add_and_fetch+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
+        ;;
+    esac
+        { $as_echo "$as_me:$LINENO: checking for GCC provided 64-bit atomic functions ..." >&5
+$as_echo_n "checking for GCC provided 64-bit atomic functions ...... " >&6; }
+    cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-$ac_includes_default
+
 int
 main ()
 {
-#ifndef __sync_add_and_fetch
-  (void) __sync_add_and_fetch;
-#endif
-
+long long ptrval = 0, val = 0, newval = 1; (void)__sync_bool_compare_and_swap_8(&ptrval, val, newval);
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
+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_compile") 2>conftest.er1
+  (eval "$ac_link") 2>conftest.er1
   ac_status=$?
   grep -v '^ *+' conftest.er1 >conftest.err
   rm -f conftest.er1
@@ -20872,37 +20799,36 @@ $as_echo "$ac_try_echo") >&5
   (exit $ac_status); } && {
 	 test -z "$ac_c_werror_flag" ||
 	 test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_have_decl___sync_add_and_fetch=yes
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  have_gcc_64bit_cas=1; { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
 else
   $as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-	ac_cv_have_decl___sync_add_and_fetch=no
+	have_gcc_64bit_cas=; { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_have_decl___sync_add_and_fetch" >&5
-$as_echo "$ac_cv_have_decl___sync_add_and_fetch" >&6; }
-if test "x$ac_cv_have_decl___sync_add_and_fetch" = x""yes; then
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+    if test -n "$have_gcc_64bit_cas" ; then
 
-cat >>confdefs.h <<_ACEOF
+cat >>confdefs.h <<\_ACEOF
 #define HAVE_DECL___SYNC_ADD_AND_FETCH 1
 _ACEOF
 
+    else
 
-else
-  cat >>confdefs.h <<_ACEOF
+cat >>confdefs.h <<\_ACEOF
 #define HAVE_DECL___SYNC_ADD_AND_FETCH 0
 _ACEOF
 
-
-fi
-
-
-        ;;
-    esac
+    fi
     # some programs use the native thread library directly
     THREADLIB=-lpthread
     THREADLIB=$THREADLIB

+ 11 - 2
configure.ac

@@ -401,14 +401,23 @@ case $host in
       i*86-*-linux*)
         AC_DEFINE([CPU_x86], [], [cpu type x86])
         AC_DEFINE([ATOMIC_64BIT_OPERATIONS], [1], [enabling atomic counter])
-        AC_CHECK_DECLS([__sync_add_and_fetch])
         ;;
       x86_64-*-linux*)
         AC_DEFINE([CPU_x86_64], [], [cpu type x86_64])
         AC_DEFINE([ATOMIC_64BIT_OPERATIONS], [1], [enabling atomic counter])
-        AC_CHECK_DECLS([__sync_add_and_fetch])
         ;;
     esac
+    dnl no headers to test for __sync_bool_compare_and_swap_8
+    AC_MSG_CHECKING([for GCC provided 64-bit atomic functions ...])
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],
+                                    [[long long ptrval = 0, val = 0, newval = 1; (void)__sync_bool_compare_and_swap_8(&ptrval, val, newval);]])],
+                   [have_gcc_64bit_cas=1; AC_MSG_RESULT([yes])],
+                   [have_gcc_64bit_cas=; AC_MSG_RESULT([no])])
+    if test -n "$have_gcc_64bit_cas" ; then
+       AC_DEFINE([HAVE_DECL___SYNC_ADD_AND_FETCH], [1], [have 64-bit atomic compare and swap functions provided by gcc])
+    else
+       AC_DEFINE([HAVE_DECL___SYNC_ADD_AND_FETCH], [0], [do not have 64-bit atomic compare and swap functions provided by gcc])
+    fi
     # some programs use the native thread library directly
     THREADLIB=-lpthread
     AC_SUBST([THREADLIB], [$THREADLIB])

+ 75 - 0
ldap/servers/slapd/slapi_counter.c

@@ -292,12 +292,49 @@ PRUint64 slapi_counter_set_value(Slapi_Counter *counter, PRUint64 newvalue)
     return newvalue;
 #else
 #ifdef LINUX
+/* Use our own inline assembly for an atomic set if
+ * the builtins aren't available. */
+#if defined CPU_x86 || !HAVE_DECL___SYNC_ADD_AND_FETCH
+    /*
+     * %0 = counter->value
+     * %1 = newvalue
+     */
+    __asm__ __volatile__(
+#ifdef CPU_x86
+        /* Save the PIC register */
+        " pushl %%ebx;"
+#endif /* CPU_x86 */
+        /* Put value of counter->value in EDX:EAX */
+        "retryset: movl %0, %%eax;"
+        " movl 4%0, %%edx;"
+        /* Put newval in ECX:EBX */
+        " movl %1, %%ebx;"
+        " movl 4+%1, %%ecx;"
+        /* If EDX:EAX and counter-> are the same,
+         * replace *ptr with ECX:EBX */
+        " lock; cmpxchg8b %0;"
+        " jnz retryset;"
+#ifdef CPU_x86
+        /* Restore the PIC register */
+        " popl %%ebx"
+#endif /* CPU_x86 */
+        : "+o" (counter->value)
+        : "m" (newvalue)
+#ifdef CPU_x86
+        : "memory", "eax", "ecx", "edx", "cc");
+#else
+        : "memory", "eax", "ebx", "ecx", "edx", "cc");
+#endif
+
+    return newvalue;
+#else
     while (1) {
         value = counter->value;
         if (__sync_bool_compare_and_swap(&(counter->value), value, newvalue)) {
             return newvalue;
         }
     }
+#endif /* CPU_x86 || !HAVE_DECL___SYNC_ADD_AND_FETCH */
 #elif defined(SOLARIS)
     _sparcv9_AtomicSet(&(counter->value), newvalue);
     return newvalue;
@@ -331,12 +368,50 @@ PRUint64 slapi_counter_get_value(Slapi_Counter *counter)
     slapi_unlock_mutex(counter->lock);
 #else
 #ifdef LINUX
+/* Use our own inline assembly for an atomic get if
+ * the builtins aren't available. */
+#if defined CPU_x86 || !HAVE_DECL___SYNC_ADD_AND_FETCH
+    /*
+     * %0 = counter->value
+     * %1 = value
+     */
+    __asm__ __volatile__(
+#ifdef CPU_x86
+        /* Save the PIC register */
+        " pushl %%ebx;"
+#endif /* CPU_x86 */
+        /* Put value of counter->value in EDX:EAX */
+        "retryget: movl %0, %%eax;"
+        " movl 4%0, %%edx;"
+        /* Copy EDX:EAX to ECX:EBX */
+        " movl %%eax, %%ebx;"
+        " movl %%edx, %%ecx;"
+        /* If EDX:EAX and counter->value are the same,
+         * replace *ptr with ECX:EBX */
+        " lock; cmpxchg8b %0;"
+        " jnz retryget;"
+        /* Put retreived value into value */
+        " movl %%ebx, %1;"
+        " movl %%ecx, 4%1;"
+#ifdef CPU_x86
+        /* Restore the PIC register */
+        " popl %%ebx"
+#endif /* CPU_x86 */
+        : "+o" (counter->value), "=m" (value)
+        : 
+#ifdef CPU_x86
+        : "memory", "eax", "ecx", "edx", "cc");
+#else
+        : "memory", "eax", "ebx", "ecx", "edx", "cc");
+#endif
+#else
     while (1) {
         value = counter->value;
         if (__sync_bool_compare_and_swap(&(counter->value), value, value)) {
             break;
         }
     }
+#endif /* CPU_x86 || !HAVE_DECL___SYNC_ADD_AND_FETCH */
 #elif defined(SOLARIS)
     while (1) {
         value = counter->value;