diff options
author | Nathan Kinder <nkinder@redhat.com> | 2008-10-29 19:16:29 +0000 |
---|---|---|
committer | Nathan Kinder <nkinder@redhat.com> | 2008-10-29 19:16:29 +0000 |
commit | 06e865cf81bb9f877258e91441205a27d619c478 (patch) | |
tree | 2f8261dddd2d84b8564ecf4931f56b35c81f38e8 | |
parent | f25db4aae70b7818cdbdbe71e95345689dc4faf8 (diff) | |
download | ds-06e865cf81bb9f877258e91441205a27d619c478.tar.gz ds-06e865cf81bb9f877258e91441205a27d619c478.tar.xz ds-06e865cf81bb9f877258e91441205a27d619c478.zip |
Resolves: 207457
Summary: Added 64-bit atomic functions for platforms lacking built-ins.
-rw-r--r-- | config.h.in | 10 | ||||
-rwxr-xr-x | configure | 201 | ||||
-rw-r--r-- | configure.ac | 19 | ||||
-rw-r--r-- | ldap/servers/slapd/result.c | 4 | ||||
-rw-r--r-- | ldap/servers/slapd/slapi_counter.c | 186 | ||||
-rw-r--r-- | ldap/servers/snmp/ldap-agent.h | 5 |
6 files changed, 420 insertions, 5 deletions
diff --git a/config.h.in b/config.h.in index 45827279..d3febbb5 100644 --- a/config.h.in +++ b/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 @@ -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 @@ -23391,6 +23391,133 @@ _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 diff --git a/configure.ac b/configure.ac index ca0bd20c..fc8d7246 100644 --- a/configure.ac +++ b/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 diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c index 387353e4..e07ad7a3 100644 --- a/ldap/servers/slapd/result.c +++ b/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; diff --git a/ldap/servers/slapd/slapi_counter.c b/ldap/servers/slapd/slapi_counter.c index d5812dc9..a3886eb3 100644 --- a/ldap/servers/slapd/slapi_counter.c +++ b/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) */ diff --git a/ldap/servers/snmp/ldap-agent.h b/ldap/servers/snmp/ldap-agent.h index cb7a395d..30253d1c 100644 --- a/ldap/servers/snmp/ldap-agent.h +++ b/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 |