]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Use C11's stdatomic.h instead of isc_atomic where available
authorMukund Sivaraman <muks@isc.org>
Tue, 19 Sep 2017 10:12:54 +0000 (15:42 +0530)
committerMukund Sivaraman <muks@isc.org>
Tue, 19 Sep 2017 10:13:45 +0000 (15:43 +0530)
CHANGES
config.h.in
configure
configure.in
lib/isc/include/isc/platform.h.in
lib/isc/include/isc/refcount.h
lib/isc/include/isc/rwlock.h
lib/isc/refcount.c
lib/isc/rwlock.c
lib/isc/stats.c

diff --git a/CHANGES b/CHANGES
index 5ddf3d2146614187f3e7e94488f916b2c3dab1df..10706d629e4b017d1cee0dd355cfa4ce701794bb 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+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]
index 9cb97efadf212db092dd2abcee27239609a5f947..8c669e276afcc90f418b6cbeccbbc12a1bb5f717 100644 (file)
@@ -449,6 +449,9 @@ int sigwait(const unsigned int *set, int *sig);
 /* 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
 
index 4d28ad9ec1144aadd7732e0369be2a9a5a2c796a..25081d21b2cb2fdc5b164004a0112fb71de1e7bf 100755 (executable)
--- a/configure
+++ b/configure
@@ -718,6 +718,7 @@ ISC_PLATFORM_HAVEATOMICSTORE
 ISC_PLATFORM_HAVECMPXCHG
 ISC_PLATFORM_HAVEXADDQ
 ISC_PLATFORM_HAVEXADD
+ISC_PLATFORM_HAVESTDATOMIC
 ISC_PLATFORM_HAVEIFNAMETOINDEX
 ISC_PLATFORM_HAVESTRINGSH
 ISC_PLATFORM_BRACEPTHREADONCEINIT
@@ -20126,6 +20127,21 @@ done
 #
 # 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"
@@ -20201,11 +20217,14 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
                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"
index f71a7fcbbf5b57f80b21d904a9cf638f388946d7..9fa10c48e21445f9c6e765b54e3e2cb1db1bb14e 100644 (file)
@@ -4006,6 +4006,10 @@ AC_CHECK_FUNCS(nanosleep usleep)
 #
 # 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]]],
@@ -4048,11 +4052,14 @@ case "$enable_atomic" in
                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"
index f648dffa5d5736cbd081ec30f539baed31609c73..ef9b255e626f254553d7d32de8b80b55ab124d43 100644 (file)
  */
 @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
  */
index a2b7f5f9a7b2c36b66b042a4d982d16a61afe391..8550ea3db9e7b6f6e0d575d13375315fdd6f53c4 100644 (file)
 #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.
  *
@@ -86,17 +90,59 @@ ISC_LANG_BEGINDECLS
  * 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);      \
@@ -126,6 +172,8 @@ typedef struct isc_refcount {
                        *_tmp = prev - 1;                       \
        } while (0)
 
+#endif /* ISC_REFCOUNT_HAVESTDATOMIC */
+
 #else  /* ISC_PLATFORM_HAVEXADD */
 
 typedef struct isc_refcount {
@@ -176,7 +224,7 @@ 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 {
index 6f8d3788bfb0162e05a03c3ffac1e9e765d0166a..2917174177977d180cd184b902268735fefc71da 100644 (file)
 #include <isc/platform.h>
 #include <isc/types.h>
 
+#if defined(ISC_PLATFORM_HAVESTDATOMIC)
+#include <stdatomic.h>
+#endif
+
 ISC_LANG_BEGINDECLS
 
 typedef enum {
@@ -27,8 +31,11 @@ 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 {
@@ -37,7 +44,7 @@ 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
@@ -52,9 +59,15 @@ struct isc_rwlock {
         */
 
        /* 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;
@@ -67,7 +80,7 @@ struct isc_rwlock {
        /* Unlocked. */
        unsigned int            write_quota;
 
-#else  /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+#else  /* ISC_RWLOCK_USEATOMIC */
 
        /*%< Locked by lock. */
        isc_condition_t         readable;
@@ -89,7 +102,7 @@ struct isc_rwlock {
        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 {
index 3af4d19ed32b676e7a05984630b57dd8f0d12c42..ad1fd5b9455bf7f6cbb54279d47b88481b9f919c 100644 (file)
@@ -21,7 +21,7 @@ isc_refcount_init(isc_refcount_t *ref, unsigned int n) {
        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);
index 57e78b39ec94e456de13b800b63eab1177f0d3f4..e703f8426d7b882da4617188325ad819a87261c2 100644 (file)
@@ -39,7 +39,7 @@
 #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
@@ -50,7 +50,7 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
 
 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,
@@ -105,7 +105,7 @@ isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
        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;
@@ -174,7 +174,7 @@ void
 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
@@ -191,7 +191,7 @@ isc_rwlock_destroy(isc_rwlock_t *rwl) {
        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,
@@ -281,7 +281,13 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
                        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)
@@ -331,7 +337,12 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
                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) {
@@ -344,9 +355,18 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
                }
 
                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. */
@@ -409,14 +429,26 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
                        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.
@@ -432,16 +464,29 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
                }
        } 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++;
        }
@@ -456,31 +501,60 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
 
 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
@@ -489,14 +563,33 @@ isc_rwlock_downgrade(isc_rwlock_t *rwl) {
 
        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);
@@ -517,8 +610,13 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
 #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
@@ -537,8 +635,15 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
                 * 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 ||
@@ -576,7 +681,7 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
        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) {
@@ -782,7 +887,7 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
        return (ISC_R_SUCCESS);
 }
 
-#endif /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+#endif /* ISC_RWLOCK_USEATOMIC */
 #else /* ISC_PLATFORM_USETHREADS */
 
 isc_result_t
index 85f485ce843ab00f99fd187de473f6b951babe82..b9d74966a13a0727b5abf0cb1ba6146b5b9b220b 100644 (file)
 #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 */
@@ -232,7 +252,12 @@ incrementcounter(isc_stats_t *stats, int counter) {
 #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
@@ -241,11 +266,22 @@ incrementcounter(isc_stats_t *stats, int counter) {
         * 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]++;
@@ -265,13 +301,29 @@ decrementcounter(isc_stats_t *stats, int 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]--;
@@ -300,9 +352,15 @@ copy_counters(isc_stats_t *stats) {
                        (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
@@ -373,7 +431,12 @@ isc_stats_set(isc_stats_t *stats, isc_uint64_t val,
        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
@@ -382,4 +445,3 @@ isc_stats_set(isc_stats_t *stats, isc_uint64_t val,
        isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_write);
 #endif
 }
-