+4728. [func] Use C11's stdatomic.h instead of isc_atomic
+ where available. [RT #40668]
+
4727. [bug] Retransferring an inline-signed slave using NSEC3
around the time its NSEC3 salt was changed could result
in an infinite signing loop. [RT #45080]
/* Define to 1 if you have the `setresuid' function. */
#undef HAVE_SETRESUID
+/* Define to 1 if you have the <stdatomic.h> header file. */
+#undef HAVE_STDATOMIC_H
+
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
ISC_PLATFORM_HAVECMPXCHG
ISC_PLATFORM_HAVEXADDQ
ISC_PLATFORM_HAVEXADD
+ISC_PLATFORM_HAVESTDATOMIC
ISC_PLATFORM_HAVEIFNAMETOINDEX
ISC_PLATFORM_HAVESTRINGSH
ISC_PLATFORM_BRACEPTHREADONCEINIT
#
# Machine architecture dependent features
#
+for ac_header in stdatomic.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdatomic_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_STDATOMIC_H 1
+_ACEOF
+ ISC_PLATFORM_HAVESTDATOMIC="#define ISC_PLATFORM_HAVESTDATOMIC 1"
+else
+ ISC_PLATFORM_HAVESTDATOMIC="#undef ISC_PLATFORM_HAVESTDATOMIC"
+fi
+
+done
+
+
# Check whether --enable-atomic was given.
if test "${enable_atomic+set}" = set; then :
enableval=$enable_atomic; enable_atomic="$enableval"
esac
;;
no)
+ ISC_PLATFORM_HAVESTDATOMIC="#undef ISC_PLATFORM_HAVESTDATOMIC"
use_atomic=no
arch=noatomic
;;
esac
+
+
ISC_PLATFORM_USEOSFASM="#undef ISC_PLATFORM_USEOSFASM"
ISC_PLATFORM_USEGCCASM="#undef ISC_PLATFORM_USEGCCASM"
ISC_PLATFORM_USESTDASM="#undef ISC_PLATFORM_USESTDASM"
#
# Machine architecture dependent features
#
+AC_CHECK_HEADERS(stdatomic.h,
+ [ISC_PLATFORM_HAVESTDATOMIC="#define ISC_PLATFORM_HAVESTDATOMIC 1"],
+ [ISC_PLATFORM_HAVESTDATOMIC="#undef ISC_PLATFORM_HAVESTDATOMIC"])
+
AC_ARG_ENABLE(atomic,
[ --enable-atomic enable machine specific atomic operations
[[default=autodetect]]],
esac
;;
no)
+ ISC_PLATFORM_HAVESTDATOMIC="#undef ISC_PLATFORM_HAVESTDATOMIC"
use_atomic=no
arch=noatomic
;;
esac
+AC_SUBST(ISC_PLATFORM_HAVESTDATOMIC)
+
ISC_PLATFORM_USEOSFASM="#undef ISC_PLATFORM_USEOSFASM"
ISC_PLATFORM_USEGCCASM="#undef ISC_PLATFORM_USEGCCASM"
ISC_PLATFORM_USESTDASM="#undef ISC_PLATFORM_USESTDASM"
*/
@ISC_PLATFORM_HAVECMPXCHG@
+/*
+ * If <stdatomic.h> is available on this architecture,
+ * ISC_PLATFORM_HAVESTDATOMIC will be defined.
+ */
+@ISC_PLATFORM_HAVESTDATOMIC@
+
/*
* Define if gcc ASM extension is available
*/
#include <isc/types.h>
#include <isc/util.h>
+#if defined(ISC_PLATFORM_HAVESTDATOMIC)
+#include <stdatomic.h>
+#endif
+
/*! \file isc/refcount.h
* \brief Implements a locked reference counter.
*
* Sample implementations
*/
#ifdef ISC_PLATFORM_USETHREADS
-#ifdef ISC_PLATFORM_HAVEXADD
-
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE)) || defined(ISC_PLATFORM_HAVEXADD)
#define ISC_REFCOUNT_HAVEATOMIC 1
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE))
+#define ISC_REFCOUNT_HAVESTDATOMIC 1
+#endif
typedef struct isc_refcount {
+#if defined(ISC_REFCOUNT_HAVESTDATOMIC)
+ atomic_int_fast32_t refs;
+#else
isc_int32_t refs;
+#endif
} isc_refcount_t;
#define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0)
#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
+#if defined(ISC_REFCOUNT_HAVESTDATOMIC)
+
+#define isc_refcount_increment0(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ isc_int32_t prev; \
+ prev = atomic_fetch_add_explicit \
+ (&(rp)->refs, 1, memory_order_relaxed); \
+ if (_tmp != NULL) \
+ *_tmp = prev + 1; \
+ } while (0)
+
+#define isc_refcount_increment(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ isc_int32_t prev; \
+ prev = atomic_fetch_add_explicit \
+ (&(rp)->refs, 1, memory_order_relaxed); \
+ REQUIRE(prev > 0); \
+ if (_tmp != NULL) \
+ *_tmp = prev + 1; \
+ } while (0)
+
+#define isc_refcount_decrement(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ isc_int32_t prev; \
+ prev = atomic_fetch_sub_explicit \
+ (&(rp)->refs, 1, memory_order_relaxed); \
+ REQUIRE(prev > 0); \
+ if (_tmp != NULL) \
+ *_tmp = prev - 1; \
+ } while (0)
+
+#else /* ISC_REFCOUNT_HAVESTDATOMIC */
+
#define isc_refcount_increment0(rp, tp) \
do { \
unsigned int *_tmp = (unsigned int *)(tp); \
*_tmp = prev - 1; \
} while (0)
+#endif /* ISC_REFCOUNT_HAVESTDATOMIC */
+
#else /* ISC_PLATFORM_HAVEXADD */
typedef struct isc_refcount {
UNLOCK(&(rp)->lock); \
} while (0)
-#endif /* ISC_PLATFORM_HAVEXADD */
+#endif /* (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE)) || defined(ISC_PLATFORM_HAVEXADD) */
#else /* ISC_PLATFORM_USETHREADS */
typedef struct isc_refcount {
#include <isc/platform.h>
#include <isc/types.h>
+#if defined(ISC_PLATFORM_HAVESTDATOMIC)
+#include <stdatomic.h>
+#endif
+
ISC_LANG_BEGINDECLS
typedef enum {
} isc_rwlocktype_t;
#ifdef ISC_PLATFORM_USETHREADS
-#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE)) || (defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG))
#define ISC_RWLOCK_USEATOMIC 1
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE))
+#define ISC_RWLOCK_USESTDATOMIC 1
+#endif
#endif
struct isc_rwlock {
isc_mutex_t lock;
isc_int32_t spins;
-#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+#if defined(ISC_RWLOCK_USEATOMIC)
/*
* When some atomic instructions with hardware assistance are
* available, rwlock will use those so that concurrent readers do not
*/
/* Read or modified atomically. */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ atomic_int_fast32_t write_requests;
+ atomic_int_fast32_t write_completions;
+ atomic_int_fast32_t cnt_and_flag;
+#else
isc_int32_t write_requests;
isc_int32_t write_completions;
isc_int32_t cnt_and_flag;
+#endif
/* Locked by lock. */
isc_condition_t readable;
/* Unlocked. */
unsigned int write_quota;
-#else /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+#else /* ISC_RWLOCK_USEATOMIC */
/*%< Locked by lock. */
isc_condition_t readable;
unsigned int read_quota;
unsigned int write_quota;
isc_rwlocktype_t original;
-#endif /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+#endif /* ISC_RWLOCK_USEATOMIC */
};
#else /* ISC_PLATFORM_USETHREADS */
struct isc_rwlock {
REQUIRE(ref != NULL);
ref->refs = n;
-#if defined(ISC_PLATFORM_USETHREADS) && !defined(ISC_PLATFORM_HAVEXADD)
+#if defined(ISC_PLATFORM_USETHREADS) && !defined(ISC_REFCOUNT_HAVEATOMIC)
return (isc_mutex_init(&ref->lock));
#else
return (ISC_R_SUCCESS);
#define RWLOCK_MAX_ADAPTIVE_COUNT 100
#endif
-#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+#if defined(ISC_RWLOCK_USEATOMIC)
static isc_result_t
isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
#endif
static void
print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
-#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+#if defined(ISC_RWLOCK_USEATOMIC)
fprintf(stderr,
isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
ISC_MSG_PRINTLOCK2,
rwl->magic = 0;
rwl->spins = 0;
-#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+#if defined(ISC_RWLOCK_USEATOMIC)
rwl->write_requests = 0;
rwl->write_completions = 0;
rwl->cnt_and_flag = 0;
isc_rwlock_destroy(isc_rwlock_t *rwl) {
REQUIRE(VALID_RWLOCK(rwl));
-#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+#if defined(ISC_RWLOCK_USEATOMIC)
REQUIRE(rwl->write_requests == rwl->write_completions &&
rwl->cnt_and_flag == 0 && rwl->readers_waiting == 0);
#else
DESTROYLOCK(&rwl->lock);
}
-#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+#if defined(ISC_RWLOCK_USEATOMIC)
/*
* When some architecture-dependent atomic operations are available,
UNLOCK(&rwl->lock);
}
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ cntflag = atomic_fetch_add_explicit(&rwl->cnt_and_flag,
+ READER_INCR,
+ memory_order_relaxed);
+#else
cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+#endif
POST(cntflag);
while (1) {
if ((rwl->cnt_and_flag & WRITER_ACTIVE) == 0)
isc_int32_t prev_writer;
/* enter the waiting queue, and wait for our turn */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ prev_writer = atomic_fetch_add_explicit(&rwl->write_requests, 1,
+ memory_order_relaxed);
+#else
prev_writer = isc_atomic_xadd(&rwl->write_requests, 1);
+#endif
while (rwl->write_completions != prev_writer) {
LOCK(&rwl->lock);
if (rwl->write_completions != prev_writer) {
}
while (1) {
- cntflag = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0,
- WRITER_ACTIVE);
- if (cntflag == 0)
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ atomic_int_fast32_t cntflag2 = 0;
+ atomic_compare_exchange_strong_explicit
+ (&rwl->cnt_and_flag, &cntflag2, WRITER_ACTIVE,
+ memory_order_relaxed, memory_order_relaxed);
+#else
+ isc_int32_t cntflag2;
+ cntflag2 = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0,
+ WRITER_ACTIVE);
+#endif
+
+ if (cntflag2 == 0)
break;
/* Another active reader or writer is working. */
return (ISC_R_LOCKBUSY);
/* Otherwise, be ready for reading. */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ cntflag = atomic_fetch_add_explicit(&rwl->cnt_and_flag,
+ READER_INCR,
+ memory_order_relaxed);
+#else
cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+#endif
if ((cntflag & WRITER_ACTIVE) != 0) {
/*
* A writer is working. We lose, and cancel the read
* request.
*/
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ cntflag = atomic_fetch_sub_explicit
+ (&rwl->cnt_and_flag, READER_INCR,
+ memory_order_relaxed);
+#else
cntflag = isc_atomic_xadd(&rwl->cnt_and_flag,
-READER_INCR);
+#endif
/*
* If no other readers are waiting and we've suspended
* new writers in this short period, wake them up.
}
} else {
/* Try locking without entering the waiting queue. */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ atomic_int_fast32_t zero = 0;
+ if (!atomic_compare_exchange_strong_explicit
+ (&rwl->cnt_and_flag, &zero, WRITER_ACTIVE,
+ memory_order_relaxed, memory_order_relaxed))
+ return (ISC_R_LOCKBUSY);
+#else
cntflag = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0,
WRITER_ACTIVE);
if (cntflag != 0)
return (ISC_R_LOCKBUSY);
+#endif
/*
* XXXJT: jump into the queue, possibly breaking the writer
* order.
*/
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ atomic_fetch_sub_explicit(&rwl->write_completions, 1,
+ memory_order_relaxed);
+#else
(void)isc_atomic_xadd(&rwl->write_completions, -1);
+#endif
rwl->write_granted++;
}
isc_result_t
isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
- isc_int32_t prevcnt;
-
REQUIRE(VALID_RWLOCK(rwl));
- /* Try to acquire write access. */
- prevcnt = isc_atomic_cmpxchg(&rwl->cnt_and_flag,
- READER_INCR, WRITER_ACTIVE);
- /*
- * There must have been no writer, and there must have been at least
- * one reader.
- */
- INSIST((prevcnt & WRITER_ACTIVE) == 0 &&
- (prevcnt & ~WRITER_ACTIVE) != 0);
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ {
+ atomic_int_fast32_t reader_incr = READER_INCR;
- if (prevcnt == READER_INCR) {
+ /* Try to acquire write access. */
+ atomic_compare_exchange_strong_explicit
+ (&rwl->cnt_and_flag, &reader_incr, WRITER_ACTIVE,
+ memory_order_relaxed, memory_order_relaxed);
/*
- * We are the only reader and have been upgraded.
- * Now jump into the head of the writer waiting queue.
+ * There must have been no writer, and there must have
+ * been at least one reader.
*/
- (void)isc_atomic_xadd(&rwl->write_completions, -1);
- } else
- return (ISC_R_LOCKBUSY);
+ INSIST((reader_incr & WRITER_ACTIVE) == 0 &&
+ (reader_incr & ~WRITER_ACTIVE) != 0);
- return (ISC_R_SUCCESS);
+ if (reader_incr == READER_INCR) {
+ /*
+ * We are the only reader and have been upgraded.
+ * Now jump into the head of the writer waiting queue.
+ */
+ atomic_fetch_sub_explicit(&rwl->write_completions, 1,
+ memory_order_relaxed);
+ } else
+ return (ISC_R_LOCKBUSY);
+ }
+#else
+ {
+ isc_int32_t prevcnt;
+
+ /* Try to acquire write access. */
+ prevcnt = isc_atomic_cmpxchg(&rwl->cnt_and_flag,
+ READER_INCR, WRITER_ACTIVE);
+ /*
+ * There must have been no writer, and there must have
+ * been at least one reader.
+ */
+ INSIST((prevcnt & WRITER_ACTIVE) == 0 &&
+ (prevcnt & ~WRITER_ACTIVE) != 0);
+
+ if (prevcnt == READER_INCR) {
+ /*
+ * We are the only reader and have been upgraded.
+ * Now jump into the head of the writer waiting queue.
+ */
+ (void)isc_atomic_xadd(&rwl->write_completions, -1);
+ } else
+ return (ISC_R_LOCKBUSY);
+ }
+#endif
+
+ return (ISC_R_SUCCESS);
}
void
REQUIRE(VALID_RWLOCK(rwl));
- /* Become an active reader. */
- prev_readers = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
- /* We must have been a writer. */
- INSIST((prev_readers & WRITER_ACTIVE) != 0);
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ {
+ /* Become an active reader. */
+ prev_readers = atomic_fetch_add_explicit(&rwl->cnt_and_flag,
+ READER_INCR,
+ memory_order_relaxed);
+ /* We must have been a writer. */
+ INSIST((prev_readers & WRITER_ACTIVE) != 0);
+
+ /* Complete write */
+ atomic_fetch_sub_explicit(&rwl->cnt_and_flag, WRITER_ACTIVE,
+ memory_order_relaxed);
+ atomic_fetch_add_explicit(&rwl->write_completions, 1,
+ memory_order_relaxed);
+ }
+#else
+ {
+ /* Become an active reader. */
+ prev_readers = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+ /* We must have been a writer. */
+ INSIST((prev_readers & WRITER_ACTIVE) != 0);
- /* Complete write */
- (void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE);
- (void)isc_atomic_xadd(&rwl->write_completions, 1);
+ /* Complete write */
+ (void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE);
+ (void)isc_atomic_xadd(&rwl->write_completions, 1);
+ }
+#endif
/* Resume other readers */
LOCK(&rwl->lock);
#endif
if (type == isc_rwlocktype_read) {
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ prev_cnt = atomic_fetch_sub_explicit(&rwl->cnt_and_flag,
+ READER_INCR,
+ memory_order_relaxed);
+#else
prev_cnt = isc_atomic_xadd(&rwl->cnt_and_flag, -READER_INCR);
-
+#endif
/*
* If we're the last reader and any writers are waiting, wake
* them up. We need to wake up all of them to ensure the
* Reset the flag, and (implicitly) tell other writers
* we are done.
*/
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ atomic_fetch_sub_explicit(&rwl->cnt_and_flag, WRITER_ACTIVE,
+ memory_order_relaxed);
+ atomic_fetch_add_explicit(&rwl->write_completions, 1,
+ memory_order_relaxed);
+#else
(void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE);
(void)isc_atomic_xadd(&rwl->write_completions, 1);
+#endif
if (rwl->write_granted >= rwl->write_quota ||
rwl->write_requests == rwl->write_completions ||
return (ISC_R_SUCCESS);
}
-#else /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+#else /* ISC_RWLOCK_USEATOMIC */
static isc_result_t
doit(isc_rwlock_t *rwl, isc_rwlocktype_t type, isc_boolean_t nonblock) {
return (ISC_R_SUCCESS);
}
-#endif /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+#endif /* ISC_RWLOCK_USEATOMIC */
#else /* ISC_PLATFORM_USETHREADS */
isc_result_t
#include <isc/stats.h>
#include <isc/util.h>
+#if defined(ISC_PLATFORM_HAVESTDATOMIC)
+#include <stdatomic.h>
+#endif
+
#define ISC_STATS_MAGIC ISC_MAGIC('S', 't', 'a', 't')
#define ISC_STATS_VALID(x) ISC_MAGIC_VALID(x, ISC_STATS_MAGIC)
* increment and store operations, just to make
* the later macros simpler
*/
-#if defined(ISC_PLATFORM_HAVEXADDQ) && defined(ISC_PLATFORM_HAVEATOMICSTOREQ)
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_LONG_LOCK_FREE)) || \
+ (defined(ISC_PLATFORM_HAVEXADDQ) && defined(ISC_PLATFORM_HAVEATOMICSTOREQ))
#define ISC_STATS_HAVEATOMICQ 1
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_LONG_LOCK_FREE))
+#define ISC_STATS_HAVESTDATOMICQ 1
+#endif
#else
#define ISC_STATS_HAVEATOMICQ 0
#endif
* Otherwise, just rely on standard 64-bit data types
* and operations
*/
-#if !ISC_STATS_HAVEATOMICQ && defined(ISC_PLATFORM_HAVEXADD)
+#if !ISC_STATS_HAVEATOMICQ && ((defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE)) || defined(ISC_PLATFORM_HAVEXADD))
#define ISC_STATS_USEMULTIFIELDS 1
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE))
+#define ISC_STATS_HAVESTDATOMIC 1
+#endif
#else
#define ISC_STATS_USEMULTIFIELDS 0
#endif
#if ISC_STATS_USEMULTIFIELDS
typedef struct {
+#if defined(ISC_STATS_HAVESTDATOMIC)
+ atomic_int_fast32_t hi;
+ atomic_int_fast32_t lo;
+#else
isc_uint32_t hi;
isc_uint32_t lo;
+#endif
} isc_stat_t;
#else
+#if defined(ISC_STATS_HAVESTDATOMICQ)
+typedef atomic_int_fast64_t isc_stat_t;
+#else
typedef isc_uint64_t isc_stat_t;
#endif
+#endif
struct isc_stats {
/*% Unlocked */
#endif
#if ISC_STATS_USEMULTIFIELDS
+#if defined(ISC_STATS_HAVESTDATOMIC)
+ prev = atomic_fetch_add_explicit(&stats->counters[counter].lo, 1,
+ memory_order_relaxed);
+#else
prev = isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].lo, 1);
+#endif
/*
* If the lower 32-bit field overflows, increment the higher field.
* Note that it's *theoretically* possible that the lower field
* isc_stats_copy() is called where the whole process is protected
* by the write (exclusive) lock.
*/
- if (prev == (isc_int32_t)0xffffffff)
+ if (prev == (isc_int32_t)0xffffffff) {
+#if defined(ISC_STATS_HAVESTDATOMIC)
+ atomic_fetch_add_explicit(&stats->counters[counter].hi, 1,
+ memory_order_relaxed);
+#else
isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].hi, 1);
+#endif
+ }
#elif ISC_STATS_HAVEATOMICQ
UNUSED(prev);
+#if defined(ISC_STATS_HAVESTDATOMICQ)
+ atomic_fetch_add_explicit(&stats->counters[counter], 1,
+ memory_order_relaxed);
+#else
isc_atomic_xaddq((isc_int64_t *)&stats->counters[counter], 1);
+#endif
#else
UNUSED(prev);
stats->counters[counter]++;
#endif
#if ISC_STATS_USEMULTIFIELDS
+#if defined(ISC_STATS_HAVESTDATOMIC)
+ prev = atomic_fetch_sub_explicit(&stats->counters[counter].lo, 1,
+ memory_order_relaxed);
+#else
prev = isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].lo, -1);
- if (prev == 0)
+#endif
+ if (prev == 0) {
+#if defined(ISC_STATS_HAVESTDATOMIC)
+ atomic_fetch_sub_explicit(&stats->counters[counter].hi, 1,
+ memory_order_relaxed);
+#else
isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].hi,
-1);
+#endif
+ }
#elif ISC_STATS_HAVEATOMICQ
UNUSED(prev);
+#if defined(ISC_STATS_HAVESTDATOMICQ)
+ atomic_fetch_sub_explicit(&stats->counters[counter], 1,
+ memory_order_relaxed);
+#else
isc_atomic_xaddq((isc_int64_t *)&stats->counters[counter], -1);
+#endif
#else
UNUSED(prev);
stats->counters[counter]--;
(isc_uint64_t)(stats->counters[i].hi) << 32 |
stats->counters[i].lo;
#elif ISC_STATS_HAVEATOMICQ
+#if defined(ISC_STATS_HAVESTDATOMICQ)
+ stats->copiedcounters[i] =
+ atomic_load_explicit(&stats->counters[i],
+ memory_order_relaxed);
+#else
/* use xaddq(..., 0) as an atomic load */
stats->copiedcounters[i] =
(isc_uint64_t)isc_atomic_xaddq((isc_int64_t *)&stats->counters[i], 0);
+#endif
#else
stats->copiedcounters[i] = stats->counters[i];
#endif
stats->counters[counter].hi = (isc_uint32_t)((val >> 32) & 0xffffffff);
stats->counters[counter].lo = (isc_uint32_t)(val & 0xffffffff);
#elif ISC_STATS_HAVEATOMICQ
+#if defined(ISC_STATS_HAVESTDATOMICQ)
+ atomic_store_explicit(&stats->counters[counter], val,
+ memory_order_relaxed);
+#else
isc_atomic_storeq((isc_int64_t *)&stats->counters[counter], val);
+#endif
#else
stats->counters[counter] = val;
#endif
isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_write);
#endif
}
-