Przeglądaj źródła

Resolves: 207457
Summary: Added 64-bit atomic functions for platforms lacking built-ins.

Nathan Kinder 17 lat temu
rodzic
commit
06e865cf81

+ 10 - 0
config.h.in

@@ -15,6 +15,12 @@
 /* cpu type sparc */
 #undef CPU_sparc
 
+/* cpu type x86 */
+#undef CPU_x86
+
+/* cpu type x86_64 */
+#undef CPU_x86_64
+
 /* enable ldapi auto bind support in the server */
 #undef ENABLE_AUTOBIND
 
@@ -43,6 +49,10 @@
    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. */
+#undef HAVE_DECL___SYNC_ADD_AND_FETCH
+
 /* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
    */
 #undef HAVE_DIRENT_H

+ 200 - 1
configure

@@ -23358,7 +23358,7 @@ initdir=/rc.d
 # those with our 64 bit compiled product.
 perlexec='/usr/bin/env perl'
 case $host in
-  *-*-linux*)
+  i*86-*-linux*)
 
 cat >>confdefs.h <<\_ACEOF
 #define XP_UNIX 1
@@ -23390,6 +23390,133 @@ cat >>confdefs.h <<\_ACEOF
 _ACEOF
 
 
+cat >>confdefs.h <<\_ACEOF
+#define CPU_x86
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _GNU_SOURCE 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define ATOMIC_64BIT_OPERATIONS 1
+_ACEOF
+
+    echo "$as_me:$LINENO: checking whether __sync_add_and_fetch is declared" >&5
+echo $ECHO_N "checking whether __sync_add_and_fetch is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl___sync_add_and_fetch+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.  */
+$ac_includes_default
+int
+main ()
+{
+#ifndef __sync_add_and_fetch
+  char *p = (char *) __sync_add_and_fetch;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 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_objext'
+  { (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
+  ac_cv_have_decl___sync_add_and_fetch=yes
+else
+  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 conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl___sync_add_and_fetch" >&5
+echo "${ECHO_T}$ac_cv_have_decl___sync_add_and_fetch" >&6
+if test $ac_cv_have_decl___sync_add_and_fetch = 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
+
+
+    platform="linux"
+    # relative to sysconfdir
+    initdir=/rc.d/init.d
+    ;;
+  x86_64-*-linux*)
+
+cat >>confdefs.h <<\_ACEOF
+#define XP_UNIX 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define Linux 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LINUX 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LINUX2_0 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LINUX2_2 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LINUX2_4 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define CPU_x86_64
+_ACEOF
+
+
 cat >>confdefs.h <<\_ACEOF
 #define _GNU_SOURCE 1
 _ACEOF
@@ -23399,6 +23526,78 @@ cat >>confdefs.h <<\_ACEOF
 #define ATOMIC_64BIT_OPERATIONS 1
 _ACEOF
 
+    echo "$as_me:$LINENO: checking whether __sync_add_and_fetch is declared" >&5
+echo $ECHO_N "checking whether __sync_add_and_fetch is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl___sync_add_and_fetch+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.  */
+$ac_includes_default
+int
+main ()
+{
+#ifndef __sync_add_and_fetch
+  char *p = (char *) __sync_add_and_fetch;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 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_objext'
+  { (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
+  ac_cv_have_decl___sync_add_and_fetch=yes
+else
+  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 conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl___sync_add_and_fetch" >&5
+echo "${ECHO_T}$ac_cv_have_decl___sync_add_and_fetch" >&6
+if test $ac_cv_have_decl___sync_add_and_fetch = 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
+
+
     platform="linux"
     # relative to sysconfdir
     initdir=/rc.d/init.d

+ 18 - 1
configure.ac

@@ -294,15 +294,32 @@ initdir=/rc.d
 # those with our 64 bit compiled product.
 perlexec='/usr/bin/env perl'
 case $host in
-  *-*-linux*)
+  i*86-*-linux*)
     AC_DEFINE([XP_UNIX], [1], [UNIX])
     AC_DEFINE([Linux], [1], [Linux])
     AC_DEFINE([LINUX], [1], [Linux])
     AC_DEFINE([LINUX2_0], [1], [Linux 2.0])
     AC_DEFINE([LINUX2_2], [1], [Linux 2.2])
     AC_DEFINE([LINUX2_4], [1], [Linux 2.4])
+    AC_DEFINE([CPU_x86], [], [cpu type x86])
     AC_DEFINE([_GNU_SOURCE], [1], [GNU Source])
     AC_DEFINE([ATOMIC_64BIT_OPERATIONS], [1], [enabling atomic counter])
+    AC_CHECK_DECLS([__sync_add_and_fetch])
+    platform="linux"
+    # relative to sysconfdir
+    initdir=/rc.d/init.d
+    ;;
+  x86_64-*-linux*)
+    AC_DEFINE([XP_UNIX], [1], [UNIX])
+    AC_DEFINE([Linux], [1], [Linux])
+    AC_DEFINE([LINUX], [1], [Linux])
+    AC_DEFINE([LINUX2_0], [1], [Linux 2.0])
+    AC_DEFINE([LINUX2_2], [1], [Linux 2.2])
+    AC_DEFINE([LINUX2_4], [1], [Linux 2.4])
+    AC_DEFINE([CPU_x86_64], [], [cpu type x86_64])
+    AC_DEFINE([_GNU_SOURCE], [1], [GNU Source])
+    AC_DEFINE([ATOMIC_64BIT_OPERATIONS], [1], [enabling atomic counter])
+    AC_CHECK_DECLS([__sync_add_and_fetch])
     platform="linux"
     # relative to sysconfdir
     initdir=/rc.d/init.d

+ 2 - 2
ldap/servers/slapd/result.c

@@ -60,8 +60,8 @@
 
 #include <ssl.h>
 
-Slapi_Counter *num_entries_sent;
-Slapi_Counter *num_bytes_sent;
+static Slapi_Counter *num_entries_sent;
+static Slapi_Counter *num_bytes_sent;
 
 static long	current_conn_count;
 static PRLock	*current_conn_count_mutex;

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

@@ -52,6 +52,24 @@ PRUint64 _sparcv9_AtomicSub_il(PRUint64 *address, PRUint64 val);
 #include <machine/sys/inline.h>
 #endif
 #endif
+
+#if defined LINUX && (defined CPU_x86 || !HAVE_DECL___SYNC_ADD_AND_FETCH)
+/* On systems that don't have the 64-bit GCC atomic builtins, we need to
+ * implement our own atomic functions using inline assembly code. */
+static PRUint64 __sync_add_and_fetch_8(PRUint64 *ptr, PRUint64 addval);
+static PRUint64 __sync_sub_and_fetch_8(PRUint64 *ptr, PRUint64 subval);
+#endif
+
+#if defined LINUX && !HAVE_DECL___SYNC_ADD_AND_FETCH
+/* Systems that have the atomic builtins defined, but don't have
+ * implementations for 64-bit values will automatically try to
+ * call the __sync_*_8 versions we provide.  If the atomic builtins
+ * are not defined at all, we define them here to use our local
+ * functions. */
+#define __sync_add_and_fetch __sync_add_and_fetch_8
+#define __sync_sub_and_fetch __sync_sub_and_fetch_8
+#endif
+
 /*
  * Counter Structure
  */
@@ -271,12 +289,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;
@@ -310,12 +365,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;
@@ -334,3 +427,96 @@ PRUint64 slapi_counter_get_value(Slapi_Counter *counter)
 
     return value;
 }
+
+#if defined LINUX && (defined CPU_x86 || !HAVE_DECL___SYNC_ADD_AND_FETCH)
+/* On systems that don't have the 64-bit GCC atomic builtins, we need to
+ * implement our own atomic add and subtract functions using inline
+ * assembly code. */
+static PRUint64 __sync_add_and_fetch_8(PRUint64 *ptr, PRUint64 addval)
+{
+    PRUint64 retval = 0;
+
+    /*
+     * %0 = *ptr
+     * %1 = retval
+     * %2 = addval
+     */
+    __asm__ __volatile__(
+#ifdef CPU_x86
+        /* Save the PIC register */
+        " pushl %%ebx;"
+#endif /* CPU_x86 */
+        /* Put value of *ptr in EDX:EAX */
+        "retryadd: movl %0, %%eax;"
+        " movl 4%0, %%edx;"
+        /* Put addval in ECX:EBX */
+        " movl %2, %%ebx;"
+        " movl 4%2, %%ecx;"
+        /* Add value from EDX:EAX to value in ECX:EBX */
+        " addl %%eax, %%ebx;"
+        " adcl %%edx, %%ecx;"
+        /* If EDX:EAX and *ptr are the same, replace ptr with ECX:EBX */
+        " lock; cmpxchg8b %0;"
+        " jnz retryadd;"
+        /* Put new value into retval */
+        " movl %%ebx, %1;"
+        " movl %%ecx, 4%1;"
+#ifdef CPU_x86
+        /* Restore the PIC register */
+        " popl %%ebx"
+#endif /* CPU_x86 */
+        : "+o" (*ptr), "=m" (retval)
+        : "m" (addval)
+#ifdef CPU_x86
+        : "memory", "eax", "ecx", "edx", "cc");
+#else
+        : "memory", "eax", "ebx", "ecx", "edx", "cc");
+#endif
+
+    return retval;
+}
+
+static PRUint64 __sync_sub_and_fetch_8(PRUint64 *ptr, PRUint64 subval)
+{
+    PRUint64 retval = 0;
+
+    /*
+     * %0 = *ptr
+     * %1 = retval
+     * %2 = subval
+     */
+    __asm__ __volatile__(
+#ifdef CPU_x86
+        /* Save the PIC register */
+        " pushl %%ebx;"
+#endif /* CPU_x86 */
+        /* Put value of *ptr in EDX:EAX */
+        "retrysub: movl %0, %%eax;"
+        " movl 4%0, %%edx;"
+        /* Copy EDX:EAX to ECX:EBX */
+        " movl %%eax, %%ebx;"
+        " movl %%edx, %%ecx;"
+        /* Subtract subval from value in ECX:EBX */
+        " subl %2, %%ebx;"
+        " sbbl 4%2, %%ecx;"
+        /* If EDX:EAX and ptr are the same, replace *ptr with ECX:EBX */
+        " lock; cmpxchg8b %0;"
+        " jnz retrysub;"
+        /* Put new value into retval */
+        " movl %%ebx, %1;"
+        " movl %%ecx, 4%1;"
+#ifdef CPU_x86
+        /* Restore the PIC register */
+        " popl %%ebx"
+#endif /* CPU_x86 */
+        : "+o" (*ptr), "=m" (retval)
+        : "m" (subval)
+#ifdef CPU_x86 
+        : "memory", "eax", "ecx", "edx", "cc");
+#else
+        : "memory", "eax", "ebx", "ecx", "edx", "cc");
+#endif
+
+    return retval;
+}
+#endif /* LINUX && (defined CPU_x86 || !HAVE_DECL___SYNC_ADD_AND_FETCH) */

+ 4 - 1
ldap/servers/snmp/ldap-agent.h

@@ -79,7 +79,10 @@ extern          "C" {
 
 #ifdef HPUX
 /* HP-UX doesn't define SEM_FAILED like other platforms, so
- *  * we define it ourselves. */
+ * we define it ourselves.  We make this define HP-UX specific
+ * since sem_open() doesn't seem to return the same value on
+ * all platforms in a failure case (it's 1 on some platforms,
+ * and 0 on others). */
 #define SEM_FAILED ((sem_t *)(-1))
 #endif