From 92424e23fac390d39bbcd06b2b9f1c494f64efe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Witold=20Kr=C4=99cicki?= Date: Fri, 17 May 2019 11:35:35 +0200 Subject: [PATCH] Special, for-tests-only, mode with atomics emulated by a mutex-locked variable - useful for finding atomics congestions --- config.h.in | 3 + configure | 54 ++++++++++-- configure.ac | 21 +++++ lib/isc/include/isc/atomic.h | 4 + lib/isc/include/isc/mutexatomic.h | 132 ++++++++++++++++++++++++++++++ lib/ns/query.c | 35 ++++---- util/copyrights | 1 + 7 files changed, 228 insertions(+), 22 deletions(-) create mode 100644 lib/isc/include/isc/mutexatomic.h diff --git a/config.h.in b/config.h.in index de8d128b5b..1f0a9f7d78 100644 --- a/config.h.in +++ b/config.h.in @@ -480,6 +480,9 @@ /* Define to allow building of objects for dlopen(). */ #undef ISC_DLZ_DLOPEN +/* Define to emulate atomic variables with mutexes. */ +#undef ISC_MUTEX_ATOMICS + /* define if the linker supports --wrap option */ #undef LD_WRAP diff --git a/configure b/configure index d1c264bca0..6845ea53db 100755 --- a/configure +++ b/configure @@ -850,6 +850,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -897,6 +898,7 @@ enable_warn_shadow enable_warn_error enable_developer enable_fuzzing +enable_mutex_atomics with_python with_python_install_dir enable_kqueue @@ -1018,6 +1020,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1270,6 +1273,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1407,7 +1419,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1560,6 +1572,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1611,6 +1624,8 @@ Optional Features: --enable-fuzzing= Enable fuzzing using American Fuzzy Lop or libFuzzer (default=no) + --enable-mutex-atomics emulate atomics by mutex-locked variables, useful + for debugging [default=no] --enable-kqueue use BSD kqueue when available [default=yes] --enable-epoll use Linux epoll when available [default=auto] --enable-devpoll use /dev/poll when available [default=yes] @@ -3998,7 +4013,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -4044,7 +4059,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -4068,7 +4083,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -4113,7 +4128,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -4137,7 +4152,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -12314,6 +12329,33 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi +# Check whether --enable-mutex_atomics was given. +if test "${enable_mutex_atomics+set}" = set; then : + enableval=$enable_mutex_atomics; +else + enable_mutex_atomics=no +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to emulate atomics with mutexes" >&5 +$as_echo_n "checking whether to emulate atomics with mutexes... " >&6; } +case "$enable_mutex_atomics" in +yes) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define ISC_MUTEX_ATOMICS 1" >>confdefs.h + + ;; +no) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; +*) + as_fn_error $? "\"--enable-mutex-atomics requires yes or no\"" "$LINENO" 5 + ;; +esac + # # Make very sure that these are the first files processed by # config.status, since we use the processed output as the input for diff --git a/configure.ac b/configure.ac index c50337d324..63e7b30160 100644 --- a/configure.ac +++ b/configure.ac @@ -132,6 +132,27 @@ AS_IF([test "$enable_fuzzing" = "afl"], [AC_MSG_ERROR([set CC=afl- when --enable-fuzzing=afl is used])]) ]) +AC_ARG_ENABLE(mutex_atomics, + AS_HELP_STRING([--enable-mutex-atomics], + [emulate atomics by mutex-locked variables, useful for debugging + [default=no]]), + [], + [enable_mutex_atomics=no]) + +AC_MSG_CHECKING([whether to emulate atomics with mutexes]) +case "$enable_mutex_atomics" in +yes) + AC_MSG_RESULT(yes) + AC_DEFINE(ISC_MUTEX_ATOMICS, 1, [Define to emulate atomic variables with mutexes.]) + ;; +no) + AC_MSG_RESULT(no) + ;; +*) + AC_MSG_ERROR("--enable-mutex-atomics requires yes or no") + ;; +esac + # # Make very sure that these are the first files processed by # config.status, since we use the processed output as the input for diff --git a/lib/isc/include/isc/atomic.h b/lib/isc/include/isc/atomic.h index 8f09ecf8d9..e75ada094b 100644 --- a/lib/isc/include/isc/atomic.h +++ b/lib/isc/include/isc/atomic.h @@ -11,11 +11,15 @@ #pragma once +#ifdef ISC_MUTEX_ATOMICS +#include +#else #if HAVE_STDATOMIC_H #include #else #include #endif +#endif /* * We define a few additional macros to make things easier diff --git a/lib/isc/include/isc/mutexatomic.h b/lib/isc/include/isc/mutexatomic.h new file mode 100644 index 0000000000..31ecd3f2c0 --- /dev/null +++ b/lib/isc/include/isc/mutexatomic.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +#include +#include +#include + +#if !defined(__has_feature) +#define __has_feature(x) 0 +#endif + +#if !defined(__has_extension) +#define __has_extension(x) __has_feature(x) +#endif + +#if !defined(__GNUC_PREREQ__) +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +#define __GNUC_PREREQ__(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +#define __GNUC_PREREQ__(maj, min) 0 +#endif +#endif + +#if !defined(__CLANG_ATOMICS) && !defined(__GNUC_ATOMICS) +#if __has_extension(c_atomic) || __has_extension(cxx_atomic) +#define __CLANG_ATOMICS +#elif __GNUC_PREREQ__(4, 7) +#define __GNUC_ATOMICS +#elif !defined(__GNUC__) +#error "isc/stdatomic.h does not support your compiler" +#endif +#endif + +#ifndef __ATOMIC_RELAXED +#define __ATOMIC_RELAXED 0 +#endif +#ifndef __ATOMIC_CONSUME +#define __ATOMIC_CONSUME 1 +#endif +#ifndef __ATOMIC_ACQUIRE +#define __ATOMIC_ACQUIRE 2 +#endif +#ifndef __ATOMIC_RELEASE +#define __ATOMIC_RELEASE 3 +#endif +#ifndef __ATOMIC_ACQ_REL +#define __ATOMIC_ACQ_REL 4 +#endif +#ifndef __ATOMIC_SEQ_CST +#define __ATOMIC_SEQ_CST 5 +#endif + + +enum memory_order { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST +}; + +typedef enum memory_order memory_order; + +typedef struct atomic_int_fast32 { + isc_mutex_t m; + int32_t v; +} atomic_int_fast32_t; + +typedef struct atomic_int_fast64 { + isc_mutex_t m; + int64_t v; +} atomic_int_fast64_t; + +typedef struct atomic_uint_fast32 { + isc_mutex_t m; + uint32_t v; +} atomic_uint_fast32_t; + +typedef struct atomic_uint_fast64 { + isc_mutex_t m; + uint64_t v; +} atomic_uint_fast64_t; + + +typedef struct atomic_bool_s { + isc_mutex_t m; + bool v; +} atomic_bool; + + +#define atomic_init(obj, desired) \ + { isc_mutex_init(&(obj)->m); isc_mutex_lock(&(obj)->m); (obj)->v = desired; isc_mutex_unlock(&(obj)->m); } +#define atomic_load_explicit(obj, order) \ + ({ typeof((obj)->v) __v; isc_mutex_lock(&(obj)->m); __v= (obj)->v; isc_mutex_unlock(&(obj)->m); __v;} ) +#define atomic_store_explicit(obj, desired, order) \ + {isc_mutex_lock(&(obj)->m); (obj)->v = desired; isc_mutex_unlock(&(obj)->m); } +#define atomic_fetch_add_explicit(obj, arg, order) \ + ({ typeof((obj)->v) __v; isc_mutex_lock(&(obj)->m); __v= (obj)->v; (obj)->v += arg; isc_mutex_unlock(&(obj)->m); __v;} ) +#define atomic_fetch_sub_explicit(obj, arg, order) \ + ({ typeof((obj)->v) __v; isc_mutex_lock(&(obj)->m); __v= (obj)->v; (obj)->v -= arg; isc_mutex_unlock(&(obj)->m); __v;} ) +#define atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, fail) \ + ({ bool __v; isc_mutex_lock(&(obj)->m); __v = ((obj)->v == *expected); *expected = (obj)->v; (obj)->v = __v ? desired : (obj)->v; isc_mutex_unlock(&(obj)->m); __v;} ) +#define atomic_compare_exchange_weak_explicit(obj, expected, desired, succ, fail) \ + ({ bool __v; isc_mutex_lock(&(obj)->m); __v = ((obj)->v == *expected); *expected = (obj)->v; (obj)->v = __v ? desired : (obj)->v; isc_mutex_unlock(&(obj)->m); __v;} ) + + + + +#define atomic_load(obj) \ + atomic_load_explicit(obj, memory_order_seq_cst) +#define atomic_store(obj, arg) \ + atomic_store_explicit(obj, arg, memory_order_seq_cst) +#define atomic_fetch_add(obj, arg) \ + atomic_fetch_add_explicit(obj, arg, memory_order_seq_cst) +#define atomic_fetch_sub(obj, arg) \ + atomic_fetch_sub_explicit(obj, arg, memory_order_seq_cst) +#define atomic_compare_exchange_strong(obj, expected, desired) \ + atomic_compare_exchange_strong_explicit(obj, expected, desired, memory_order_seq_cst, memory_order_seq_cst) +#define atomic_compare_exchange_weak(obj, expected, desired) \ + atomic_compare_exchange_weak_explicit(obj, expected, desired, memory_order_seq_cst, memory_order_seq_cst) diff --git a/lib/ns/query.c b/lib/ns/query.c index abb88fbe33..39709bba83 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -5692,6 +5692,15 @@ recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype, RUNTIME_CHECK(result == ISC_R_SUCCESS); } } +static atomic_uint_fast32_t last_soft, last_hard; +#ifdef ISC_MUTEX_ATOMICS +static isc_once_t last_once = ISC_ONCE_INIT; +static void last_init() { + atomic_init(&last_soft, 0); + atomic_init(&last_hard, 0); +} +#endif + isc_result_t ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, @@ -5739,16 +5748,13 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, } if (result == ISC_R_SOFTQUOTA) { - static atomic_uint_fast32_t last; - static isc_once_t once = ISC_ONCE_INIT; - void __ain() { - atomic_init(&last, 0); - } - isc_once_do(&once, __ain); +#ifdef ISC_MUTEX_ATOMICS + isc_once_do(&last_once, last_init); +#endif isc_stdtime_t now; isc_stdtime_get(&now); - if (now != atomic_load_relaxed(&last)) { - atomic_store_relaxed(&last, now); + if (now != atomic_load_relaxed(&last_soft)) { + atomic_store_relaxed(&last_soft, now); ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, ISC_LOG_WARNING, "recursive-clients soft limit " @@ -5761,17 +5767,14 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, ns_client_killoldestquery(client); result = ISC_R_SUCCESS; } else if (result == ISC_R_QUOTA) { - static atomic_uint_fast32_t last; - static isc_once_t once = ISC_ONCE_INIT; - void __ain() { - atomic_init(&last, 0); - } - isc_once_do(&once, __ain); +#ifdef ISC_MUTEX_ATOMICS + isc_once_do(&last_once, last_init); +#endif isc_stdtime_t now; isc_stdtime_get(&now); - if (now != atomic_load_relaxed(&last)) { + if (now != atomic_load_relaxed(&last_hard)) { ns_server_t *sctx = client->sctx; - atomic_store_relaxed(&last, now); + atomic_store_relaxed(&last_hard, now); ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, ISC_LOG_WARNING, "no more recursive clients " diff --git a/util/copyrights b/util/copyrights index db7f895ff6..acec1e8b93 100644 --- a/util/copyrights +++ b/util/copyrights @@ -2182,6 +2182,7 @@ ./lib/isc/include/isc/md.h C 2018,2019 ./lib/isc/include/isc/mem.h C 1997,1998,1999,2000,2001,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2015,2016,2017,2018,2019 ./lib/isc/include/isc/meminfo.h C 2015,2016,2018,2019 +./lib/isc/include/isc/mutexatomic.h C 2019 ./lib/isc/include/isc/mutexblock.h C 1999,2000,2001,2004,2005,2006,2007,2016,2018,2019 ./lib/isc/include/isc/netaddr.h C 1998,1999,2000,2001,2002,2004,2005,2006,2007,2009,2015,2016,2017,2018,2019 ./lib/isc/include/isc/netscope.h C 2002,2004,2005,2006,2007,2009,2016,2018,2019