$(libavl_a_SOURCES)
libslapd_la_CPPFLAGS = $(PLUGIN_CPPFLAGS) @sasl_inc@ @db_inc@ @svrcore_inc@ @kerberos_inc@ @pcre_inc@
-if SPARC
-libslapd_la_SOURCES += ldap/servers/slapd/slapi_counter_sunos_sparcv9.S
-endif
libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(NUNC_STANS_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB) $(SYSTEMD_LINK)
case $host in
i*86-*-linux*)
AC_DEFINE([CPU_x86], [], [cpu type x86])
- AC_DEFINE([ATOMIC_64BIT_OPERATIONS], [1], [enabling atomic counter])
;;
x86_64-*-linux*)
- AC_DEFINE([CPU_x86_64], [], [cpu type x86_64])
- AC_DEFINE([ATOMIC_64BIT_OPERATIONS], [1], [enabling atomic counter])
+ AC_DEFINE([CPU_x86_64], [1], [cpu type x86_64])
+
+ # This turns on and off LFDS inside of libsds
+ # wibrown -- 2017-02-21 disabled temporarily
+ # with_atomic_queue="yes"
+ # AC_DEFINE([ATOMIC_QUEUE_OPERATIONS], [1], [enabling atomic queue operations])
;;
aarch64-*-linux*)
AC_DEFINE([CPU_arm], [], [cpu type arm])
AC_DEFINE([CPU_arm], [], [cpu type arm])
;;
esac
- AC_MSG_CHECKING([for GCC provided 64-bit atomic bool cas function ...])
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],
- [[long long ptrval = 0, val = 0, newval = 1; (void)__sync_bool_compare_and_swap_8(&ptrval, val, newval);]])],
- [AC_DEFINE([HAVE_64BIT_ATOMIC_CAS_FUNC], [1], [have 64-bit atomic bool compare and swap function provided by gcc])AC_MSG_RESULT([yes])],
- [AC_MSG_RESULT([no])])
- AC_MSG_CHECKING([for GCC provided 64-bit atomic ops functions ...])
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],
- [[long long ptrval = 0, val = 0; (void)__sync_add_and_fetch_8(&ptrval, val);]])],
- [AC_DEFINE([HAVE_64BIT_ATOMIC_OP_FUNCS], [1], [have 64-bit atomic operation functions provided by gcc])AC_MSG_RESULT([yes])],
- [AC_MSG_RESULT([no])])
# some programs use the native thread library directly
THREADLIB=-lpthread
AC_SUBST([THREADLIB], [$THREADLIB])
AC_DEFINE([_POSIX_C_SOURCE], [199506L], [POSIX revision])
AC_DEFINE([_HPUX_SOURCE], [1], [Source namespace])
AC_DEFINE([_INCLUDE_STDC__SOURCE_199901], [1], [to pick up all of the printf format macros in inttypes.h])
- AC_DEFINE([ATOMIC_64BIT_OPERATIONS], [1], [enabling atomic counter])
# assume 64 bit
initconfigdir="/$PACKAGE_NAME/config"
perlexec='/opt/perl_64/bin/perl'
initdir='$(sysconfdir)/init.d'
case $host in
i?86-*-solaris2.1[[0-9]]*)
-dnl I dont know why i386 need this explicit
+ dnl I dont know why i386 need this explicit
AC_DEFINE([HAVE_GETPEERUCRED], [1], [have getpeerucred])
;;
sparc-*-solaris*)
-dnl includes some assembler stuff in counter.o
- AC_DEFINE([ATOMIC_64BIT_OPERATIONS], [1], [enabling atomic counter])
+ dnl includes some assembler stuff in counter.o
AC_DEFINE([CPU_sparc], [], [cpu type sparc])
TARGET='SPARC'
;;
;;
esac
+AC_MSG_CHECKING([for GCC provided 64-bit atomic operations])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <inttypes.h>
+ ]],
+ [[
+ uint64_t t_counter = 0;
+ uint64_t t_oldval = 0;
+ uint64_t t_newval = 1;
+
+ __atomic_compare_exchange_8(&t_counter, &t_oldval, t_newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ __atomic_add_fetch_8(&t_counter, t_newval, __ATOMIC_SEQ_CST);
+ __atomic_sub_fetch_8(&t_counter, t_newval, __ATOMIC_SEQ_CST);
+ __atomic_load(&t_counter, &t_oldval, __ATOMIC_SEQ_CST);
+ return 0;
+ ]])],
+ [
+ AC_DEFINE([ATOMIC_64BIT_OPERATIONS], [1], [have 64-bit atomic operation functions provided by gcc])
+ AC_MSG_RESULT([yes])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ]
+)
+
# cmd line overrides default setting above
if test -n "$with_initddir" ; then
initdir="$with_initddir"
#include "slap.h"
+#ifndef ATOMIC_64BIT_OPERATIONS
+#include <pthread.h>
+#endif
+
#ifdef HPUX
-#ifdef ATOMIC_64BIT_OPERATIONS
#include <machine/sys/inline.h>
#endif
-#endif
/*
* Counter Structure
*/
typedef struct slapi_counter {
uint64_t value;
+#ifndef ATOMIC_64BIT_OPERATIONS
+ pthread_mutex_t _lock;
+#endif
} slapi_counter;
/*
if (counter != NULL) {
/* Set the value to 0. */
slapi_counter_set_value(counter, 0);
+#ifndef ATOMIC_64BIT_OPERATIONS
+ pthread_mutex_init(&(counter->_lock), NULL);
+#endif
}
}
void slapi_counter_destroy(Slapi_Counter **counter)
{
if ((counter != NULL) && (*counter != NULL)) {
+#ifndef ATOMIC_64BIT_OPERATIONS
+ pthread_mutex_destroy(&((*counter)->_lock));
+#endif
slapi_ch_free((void **)counter);
}
}
uint64_t slapi_counter_add(Slapi_Counter *counter, uint64_t addvalue)
{
uint64_t newvalue = 0;
-#ifdef HPUX
- uint64_t prev = 0;
-#endif
if (counter == NULL) {
return newvalue;
}
-
-#ifndef HPUX
+#ifdef ATOMIC_64BIT_OPERATIONS
newvalue = __atomic_add_fetch_8(&(counter->value), addvalue, __ATOMIC_SEQ_CST);
#else
+#ifdef HPUX
+ uint64_t prev = 0;
/* fetchadd only works with values of 1, 4, 8, and 16. In addition, it requires
* it's argument to be an integer constant. */
if (addvalue == 1) {
_Asm_mov_to_ar(_AREG_CCV, prev);
} while (prev != _Asm_cmpxchg(_FASZ_D, _SEM_ACQ, &(counter->value), newvalue, _LDHINT_NONE));
}
+#else
+ pthread_mutex_lock(&(counter->_lock));
+ counter->value += addvalue;
+ newvalue = counter->value;
+ pthread_mutex_unlock(&(counter->_lock));
+#endif
#endif
return newvalue;
uint64_t slapi_counter_subtract(Slapi_Counter *counter, uint64_t subvalue)
{
uint64_t newvalue = 0;
-#ifdef HPUX
- uint64_t prev = 0;
-#endif
if (counter == NULL) {
return newvalue;
}
-#ifndef HPUX
+#ifdef ATOMIC_64BIT_OPERATIONS
newvalue = __atomic_sub_fetch_8(&(counter->value), subvalue, __ATOMIC_SEQ_CST);
#else
+#ifdef HPUX
+ uint64_t prev = 0;
/* fetchadd only works with values of -1, -4, -8, and -16. In addition, it requires
* it's argument to be an integer constant. */
if (subvalue == 1) {
_Asm_mov_to_ar(_AREG_CCV, prev);
} while (prev != _Asm_cmpxchg(_FASZ_D, _SEM_ACQ, &(counter->value), newvalue, _LDHINT_NONE));
}
+#else
+ pthread_mutex_lock(&(counter->_lock));
+ counter->value -= subvalue;
+ newvalue = counter->value;
+ pthread_mutex_unlock(&(counter->_lock));
+#endif
#endif
return newvalue;
return value;
}
-#ifndef HPUX
-/* Use our own inline assembly for an atomic set if
- * the builtins aren't available. */
-#if !HAVE_64BIT_ATOMIC_CAS_FUNC
- /*
- * %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 /* HAVE_64BIT_ATOMIC_CAS_FUNC */
- while (1) {
- value = __atomic_load_8(&(counter->value), __ATOMIC_SEQ_CST);
- if (__atomic_compare_exchange_8(&(counter->value), &value, newvalue, PR_FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)){
- return newvalue;
- }
- }
-#endif
+#ifdef ATOMIC_64BIT_OPERATIONS
+ __atomic_store_8(&(counter->value), newvalue, __ATOMIC_SEQ_CST);
#else /* HPUX */
+#ifdef HPUX
do {
value = counter->value;
/* Put value in a register for cmpxchg to compare against */
_Asm_mov_to_ar(_AREG_CCV, value);
} while (value != _Asm_cmpxchg(_FASZ_D, _SEM_ACQ, &(counter->value), newvalue, _LDHINT_NONE));
- return newvalue;
+#else
+ pthread_mutex_lock(&(counter->_lock));
+ counter->value = newvalue;
+ pthread_mutex_unlock(&(counter->_lock));
+#endif
#endif
+ return newvalue;
}
/*
return value;
}
-#ifndef HPUX
-/* Use our own inline assembly for an atomic get if
- * the builtins aren't available. */
-#if !HAVE_64BIT_ATOMIC_CAS_FUNC
- /*
- * %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 retrieved 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 /* HAVE_64BIT_ATOMIC_CAS_FUNC */
- while (1) {
- value = __atomic_load_8(&(counter->value), __ATOMIC_SEQ_CST);
- if (__atomic_compare_exchange_8(&(counter->value), &value, value, PR_FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)){
- break;
- }
- }
-#endif
+#ifdef ATOMIC_64BIT_OPERATIONS
+ value = __atomic_load_8(&(counter->value), __ATOMIC_SEQ_CST);
#else /* HPUX */
+#ifdef HPUX
do {
value = counter->value;
/* Put value in a register for cmpxchg to compare against */
_Asm_mov_to_ar(_AREG_CCV, value);
} while (value != _Asm_cmpxchg(_FASZ_D, _SEM_ACQ, &(counter->value), value, _LDHINT_NONE));
+#else
+ pthread_mutex_lock(&(counter->_lock));
+ value = counter->value;
+ pthread_mutex_unlock(&(counter->_lock));
+#endif
#endif
return value;
+++ /dev/null
-! BEGIN COPYRIGHT BLOCK
-! The Original Code is the Netscape Portable Runtime (NSPR).
-!
-! The Initial Developer of the Original Code is
-! Netscape Communications Corporation.
-! Portions created by the Initial Developer are Copyright (C) 1998-2000
-! the Initial Developer. All Rights Reserved.
-!
-! The original code has been modified to support 64-bit atomic increments by
-! Red Hat, Inc. These portions are Copyright (C) 2008 Red Hat, Inc. All Rights
-! reserved.
-!
-! License: GPL (version 3 or any later version).
-! See LICENSE for details.
-! END COPYRIGHT BLOCK
-!
-
-#define _ASM 1 /* force to set an assembler code macro _ASM */
-#include <sys/asm_linkage.h>
-
-! ======================================================================
-!
-! Perform the sequence a = b atomically with respect to other
-! fetch-and-stores to location a in a wait-free fashion.
-!
-! usage : old_val = PR_AtomicSet(address, newval)
-!
-! -----------------------
-! Note on REGISTER USAGE:
-! as this is a LEAF procedure, a new stack frame is not created;
-! we use the caller's stack frame so what would normally be %i (input)
-! registers are actually %o (output registers). Also, we must not
-! overwrite the contents of %l (local) registers as they are not
-! assumed to be volatile during calls.
-! -----------------------
-
- ENTRY(_sparcv9_AtomicSet) ! standard assembler/ELF prologue
-
-retryAS:
- ldx [%o0], %o2 ! set o2 to the current value
- mov %o1, %o3 ! set up the new value
- casx [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
- cmp %o2, %o3 ! see if we set the value
- bne retryAS ! if not, try again
- nop ! empty out the branch pipeline
- retl ! return back to the caller
- mov %o3, %o0 ! set the return code to the prev value
-
- SET_SIZE(_sparcv9_AtomicSet) ! standard assembler/ELF epilogue
-
-!
-! end
-!
-! ======================================================================
-!
-! Perform the sequence a = a + b atomically with respect to other
-! fetch-and-adds to location a in a wait-free fashion.
-!
-! usage : newval = PR_AtomicAdd(address, val)
-! return: the value after addition
-!
- ENTRY(_sparcv9_AtomicAdd) ! standard assembler/ELF prologue
-
-retryAA:
- ldx [%o0], %o2 ! set o2 to the current value
- addx %o2, %o1, %o3 ! calc the new value
- mov %o3, %o4 ! save the return value
- casx [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
- cmp %o2, %o3 ! see if we set the value
- bne retryAA ! if not, try again
- nop ! empty out the branch pipeline
- retl ! return back to the caller
- mov %o4, %o0 ! set the return code to the new value
-
- SET_SIZE(_sparcv9_AtomicAdd) ! standard assembler/ELF epilogue
-
-!
-! end
-!
-! ======================================================================
-!
-! Perform the sequence a = a - b atomically with respect to other
-! fetch-and-subs to location a in a wait-free fashion.
-!
-! usage : newval = PR_AtomicSub(address, val)
-! return: the value after addition
-!
- ENTRY(_sparcv9_AtomicSub) ! standard assembler/ELF prologue
-
-retryAU:
- ldx [%o0], %o2 ! set o2 to the current value
- subx %o2, %o1, %o3 ! calc the new value
- mov %o3, %o4 ! save the return value
- casx [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
- cmp %o2, %o3 ! see if we set the value
- bne retryAU ! if not, try again
- nop ! empty out the branch pipeline
- retl ! return back to the caller
- mov %o4, %o0 ! set the return code to the new value
-
- SET_SIZE(_sparcv9_AtomicSub) ! standard assembler/ELF epilogue
-
-!
-! end
-!
--- /dev/null
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright (C) 2017 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * License: GPL (version 3 or any later version).
+ * See LICENSE for details.
+ * END COPYRIGHT BLOCK **/
+
+#include "../../test_slapd.h"
+
+void
+test_libslapd_counters_atomic_usage(void **state __attribute__((unused))) {
+ Slapi_Counter *tc = slapi_counter_new();
+
+ uint64_t value = 0;
+ /* Check that it starts as 0 */
+ value = slapi_counter_get_value(tc);
+ assert_true(value == 0);
+ /* Increment */
+ slapi_counter_increment(tc);
+ value = slapi_counter_get_value(tc);
+ assert_true(value == 1);
+ /* add */
+ slapi_counter_add(tc, 100);
+ value = slapi_counter_get_value(tc);
+ assert_true(value == 101);
+ /* set */
+ slapi_counter_set_value(tc, 200);
+ value = slapi_counter_get_value(tc);
+ assert_true(value == 200);
+ /* dec */
+ slapi_counter_decrement(tc);
+ value = slapi_counter_get_value(tc);
+ assert_true(value == 199);
+ /* sub */
+ slapi_counter_subtract(tc, 99);
+ value = slapi_counter_get_value(tc);
+ assert_true(value == 100);
+ /* init */
+ slapi_counter_init(tc);
+ value = slapi_counter_get_value(tc);
+ assert_true(value == 0);
+
+
+ slapi_counter_destroy(&tc);
+
+ /* We could attempt a more complex thread test later? */
+
+}
+
+void
+test_libslapd_counters_atomic_overflow(void **state __attribute__((unused))) {
+ Slapi_Counter *tc = slapi_counter_new();
+ /* This is intmax ... */
+ uint32_t value_32 = 0xFFFFFFFF;
+ uint64_t value = 0;
+
+ slapi_counter_set_value(tc, (uint64_t)value_32);
+ value = slapi_counter_get_value(tc);
+ assert_true(value == (uint64_t)value_32);
+
+ slapi_counter_increment(tc);
+ value = slapi_counter_get_value(tc);
+ assert_true(value != 0);
+ assert_true(value > (uint64_t)value_32);
+
+ slapi_counter_destroy(&tc);
+}
+