diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3f683d05e0..048b9ccf78 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -503,6 +503,29 @@ unit:rwlock:sid:amd64: dependencies: - rwlock:sid:amd64 +# Jobs for mutex-based atomics on Debian SID (amd64) +mutexatomics:sid:amd64: + variables: + CC: gcc + CFLAGS: "-Wall -Wextra -O2 -g -DISC_MEM_USE_INTERNAL_MALLOC=0" + EXTRA_CONFIGURE: "--with-libidn2 --enable-mutex-atomics" + <<: *debian_sid_amd64_image + <<: *build_job + +system:mutexatomics:sid:amd64: + <<: *debian_sid_amd64_image + <<: *system_test_job + dependencies: + - mutexatomics:sid:amd64 + allow_failure: true + +unit:mutexatomics:sid:amd64: + <<: *debian_sid_amd64_image + <<: *unit_test_job + dependencies: + - mutexatomics:sid:amd64 + allow_failure: true + # Jobs for Clang builds on Debian Stretch (amd64) clang:stretch:amd64: diff --git a/CHANGES b/CHANGES index 1474ddd9b5..1c76d006df 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +5263. [cleanup] Use atomics and isc_refcount_t wherever possible. + [GL #1038] + 5262. [func] Removed support for the legacy GeoIP API. [GL #1112] 5261. [cleanup] Remove SO_BSDCOMPAT socket option usage. diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index e518ab3720..b01d15b58c 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -156,8 +156,8 @@ static unsigned char *gsalt = saltbuf; static size_t salt_length = 0; static isc_task_t *master = NULL; static unsigned int ntasks = 0; -static atomic_bool shuttingdown = ATOMIC_VAR_INIT(false); -static atomic_bool finished = ATOMIC_VAR_INIT(false); +static atomic_bool shuttingdown; +static atomic_bool finished; static bool nokeys = false; static bool removefile = false; static bool generateds = false; @@ -3216,6 +3216,9 @@ main(int argc, char *argv[]) { bool set_iter = false; bool nonsecify = false; + atomic_init(&shuttingdown, false); + atomic_init(&finished, false); + /* Unused letters: Bb G J q Yy (and F is reserved). */ #define CMDLINE_FLAGS \ "3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:M:n:N:o:O:PpQRr:s:ST:tuUv:VX:xzZ:" 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/dns/cache.c b/lib/dns/cache.c index 3fddd9c830..731b79a560 100644 --- a/lib/dns/cache.c +++ b/lib/dns/cache.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -130,9 +131,9 @@ struct dns_cache { isc_mem_t *mctx; /* Main cache memory */ isc_mem_t *hmctx; /* Heap memory */ char *name; + isc_refcount_t references; /* Locked by 'lock'. */ - int references; int live_tasks; dns_rdataclass_t rdclass; dns_db_t *db; @@ -214,7 +215,7 @@ dns_cache_create(isc_mem_t *cmctx, isc_mem_t *hmctx, isc_taskmgr_t *taskmgr, isc_mutex_init(&cache->lock); isc_mutex_init(&cache->filelock); - cache->references = 1; + isc_refcount_init(&cache->references, 1); cache->live_tasks = 0; cache->rdclass = rdclass; cache->serve_stale_ttl = 0; @@ -337,7 +338,7 @@ cache_free(dns_cache_t *cache) { int i; REQUIRE(VALID_CACHE(cache)); - REQUIRE(cache->references == 0); + REQUIRE(isc_refcount_current(&cache->references) == 0); isc_mem_setwater(cache->mctx, NULL, NULL, 0, 0); @@ -402,9 +403,7 @@ dns_cache_attach(dns_cache_t *cache, dns_cache_t **targetp) { REQUIRE(VALID_CACHE(cache)); REQUIRE(targetp != NULL && *targetp == NULL); - LOCK(&cache->lock); - cache->references++; - UNLOCK(&cache->lock); + isc_refcount_increment(&cache->references); *targetp = cache; } @@ -417,18 +416,12 @@ dns_cache_detach(dns_cache_t **cachep) { REQUIRE(cachep != NULL); cache = *cachep; REQUIRE(VALID_CACHE(cache)); - - LOCK(&cache->lock); - REQUIRE(cache->references > 0); - cache->references--; - if (cache->references == 0) { - cache->cleaner.overmem = false; - free_cache = true; - } - *cachep = NULL; - if (free_cache) { + if (isc_refcount_decrement(&cache->references) == 1) { + LOCK(&cache->lock); + free_cache = true; + cache->cleaner.overmem = false; /* * When the cache is shut down, dump it to a file if one is * specified. @@ -447,12 +440,13 @@ dns_cache_detach(dns_cache_t **cachep) { isc_task_shutdown(cache->cleaner.task); free_cache = false; } + UNLOCK(&cache->lock); } - UNLOCK(&cache->lock); - if (free_cache) + if (free_cache) { cache_free(cache); + } } void @@ -1030,8 +1024,9 @@ cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) { cache->live_tasks--; INSIST(cache->live_tasks == 0); - if (cache->references == 0) + if (isc_refcount_current(&cache->references) == 0) { should_free = true; + } /* Make sure we don't reschedule anymore. */ (void)isc_task_purge(task, NULL, DNS_EVENT_CACHECLEAN, NULL); diff --git a/lib/dns/dbtable.c b/lib/dns/dbtable.c index e3ca6a7866..177830db92 100644 --- a/lib/dns/dbtable.c +++ b/lib/dns/dbtable.c @@ -25,10 +25,9 @@ struct dns_dbtable { unsigned int magic; isc_mem_t * mctx; dns_rdataclass_t rdclass; - isc_mutex_t lock; isc_rwlock_t tree_lock; - /* Locked by lock. */ - unsigned int references; + /* Protected by atomics */ + isc_refcount_t references; /* Locked by tree_lock. */ dns_rbt_t * rbt; dns_db_t * default_db; @@ -65,8 +64,6 @@ dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, if (result != ISC_R_SUCCESS) goto clean1; - isc_mutex_init(&dbtable->lock); - result = isc_rwlock_init(&dbtable->tree_lock, 0, 0); if (result != ISC_R_SUCCESS) goto clean3; @@ -76,15 +73,13 @@ dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_mem_attach(mctx, &dbtable->mctx); dbtable->rdclass = rdclass; dbtable->magic = DBTABLE_MAGIC; - dbtable->references = 1; + isc_refcount_init(&dbtable->references, 1); *dbtablep = dbtable; return (ISC_R_SUCCESS); clean3: - isc_mutex_destroy(&dbtable->lock); - dns_rbt_destroy(&dbtable->rbt); clean1: @@ -120,13 +115,7 @@ dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp) { REQUIRE(VALID_DBTABLE(source)); REQUIRE(targetp != NULL && *targetp == NULL); - LOCK(&source->lock); - - INSIST(source->references > 0); - source->references++; - INSIST(source->references != 0); - - UNLOCK(&source->lock); + isc_refcount_increment(&source->references); *targetp = source; } @@ -134,25 +123,15 @@ dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp) { void dns_dbtable_detach(dns_dbtable_t **dbtablep) { dns_dbtable_t *dbtable; - bool free_dbtable = false; REQUIRE(dbtablep != NULL); dbtable = *dbtablep; REQUIRE(VALID_DBTABLE(dbtable)); - - LOCK(&dbtable->lock); - - INSIST(dbtable->references > 0); - dbtable->references--; - if (dbtable->references == 0) - free_dbtable = true; - - UNLOCK(&dbtable->lock); - - if (free_dbtable) - dbtable_free(dbtable); - *dbtablep = NULL; + + if (isc_refcount_decrement(&dbtable->references) == 1) { + dbtable_free(dbtable); + } } isc_result_t diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index a5dd6d75b4..7411dd5b27 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -174,7 +174,7 @@ struct dispsocket { */ struct dispportentry { in_port_t port; - unsigned int refs; + isc_refcount_t refs; ISC_LINK(struct dispportentry) link; }; @@ -578,7 +578,7 @@ new_portentry(dns_dispatch_t *disp, in_port_t port) { return (portentry); portentry->port = port; - portentry->refs = 1; + isc_refcount_init(&portentry->refs, 1); ISC_LINK_INIT(portentry, link); qid = DNS_QID(disp); LOCK(&qid->lock); @@ -598,26 +598,25 @@ deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { dns_qid_t *qid; REQUIRE(disp->port_table != NULL); - REQUIRE(portentry != NULL && portentry->refs > 0); + REQUIRE(portentry != NULL && isc_refcount_current(&portentry->refs) > 0); - qid = DNS_QID(disp); - LOCK(&qid->lock); - portentry->refs--; - - if (portentry->refs == 0) { + if (isc_refcount_decrement(&portentry->refs) == 1) { + qid = DNS_QID(disp); + LOCK(&qid->lock); ISC_LIST_UNLINK(disp->port_table[portentry->port % DNS_DISPATCH_PORTTABLESIZE], portentry, link); isc_mempool_put(disp->portpool, portentry); + UNLOCK(&qid->lock); } /* + * XXXWPK TODO: is it really necessary? * Set '*portentryp' to NULL inside the lock so that * dispsock->portentry does not change in socket_search. */ *portentryp = NULL; - UNLOCK(&qid->lock); } /*% @@ -736,9 +735,7 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, break; } } else { - LOCK(&qid->lock); - portentry->refs++; - UNLOCK(&qid->lock); + isc_refcount_increment(&portentry->refs); } break; } else if (result == ISC_R_NOPERM) { diff --git a/lib/dns/ecdb.c b/lib/dns/ecdb.c index 97711956b8..fc349e82c6 100644 --- a/lib/dns/ecdb.c +++ b/lib/dns/ecdb.c @@ -11,6 +11,7 @@ #include +#include #include #include #include @@ -43,8 +44,10 @@ typedef struct dns_ecdb { dns_db_t common; isc_mutex_t lock; + /* Protected by atomics */ + isc_refcount_t references; + /* Locked */ - unsigned int references; ISC_LIST(struct dns_ecdbnode) nodes; } dns_ecdb_t; @@ -58,7 +61,9 @@ typedef struct dns_ecdbnode { /* Locked */ ISC_LIST(struct rdatasetheader) rdatasets; - unsigned int references; + + /* Protected by atomics */ + isc_refcount_t references; } dns_ecdbnode_t; typedef struct rdatasetheader { @@ -156,9 +161,7 @@ attach(dns_db_t *source, dns_db_t **targetp) { REQUIRE(VALID_ECDB(ecdb)); REQUIRE(targetp != NULL && *targetp == NULL); - LOCK(&ecdb->lock); - ecdb->references++; - UNLOCK(&ecdb->lock); + isc_refcount_increment(&ecdb->references); *targetp = source; } @@ -172,6 +175,7 @@ destroy_ecdb(dns_ecdb_t **ecdbp) { dns_name_free(&ecdb->common.origin, mctx); isc_mutex_destroy(&ecdb->lock); + isc_refcount_destroy(&ecdb->references); ecdb->common.impmagic = 0; ecdb->common.magic = 0; @@ -191,9 +195,10 @@ detach(dns_db_t **dbp) { REQUIRE(VALID_ECDB(ecdb)); LOCK(&ecdb->lock); - ecdb->references--; - if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes)) + if (isc_refcount_decrement(&ecdb->references) == 1 && + ISC_LIST_EMPTY(ecdb->nodes)) { need_destroy = true; + } UNLOCK(&ecdb->lock); if (need_destroy) @@ -211,11 +216,7 @@ attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) { REQUIRE(VALID_ECDBNODE(node)); REQUIRE(targetp != NULL && *targetp == NULL); - LOCK(&node->lock); - INSIST(node->references > 0); - node->references++; - INSIST(node->references != 0); /* Catch overflow. */ - UNLOCK(&node->lock); + isc_refcount_increment(&node->references); *targetp = node; } @@ -231,8 +232,10 @@ destroynode(dns_ecdbnode_t *node) { LOCK(&ecdb->lock); ISC_LIST_UNLINK(ecdb->nodes, node, link); - if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes)) + if (isc_refcount_current(&ecdb->references) == 0 && + ISC_LIST_EMPTY(ecdb->nodes)) { need_destroydb = true; + } UNLOCK(&ecdb->lock); dns_name_free(&node->name, mctx); @@ -248,6 +251,7 @@ destroynode(dns_ecdbnode_t *node) { } isc_mutex_destroy(&node->lock); + isc_refcount_destroy(&node->references); node->magic = 0; isc_mem_put(mctx, node, sizeof(*node)); @@ -260,26 +264,16 @@ static void detachnode(dns_db_t *db, dns_dbnode_t **nodep) { dns_ecdb_t *ecdb = (dns_ecdb_t *)db; dns_ecdbnode_t *node; - bool need_destroy = false; REQUIRE(VALID_ECDB(ecdb)); REQUIRE(nodep != NULL); node = (dns_ecdbnode_t *)*nodep; REQUIRE(VALID_ECDBNODE(node)); - - UNUSED(ecdb); /* in case REQUIRE() is empty */ - - LOCK(&node->lock); - INSIST(node->references > 0); - node->references--; - if (node->references == 0) - need_destroy = true; - UNLOCK(&node->lock); - - if (need_destroy) - destroynode(node); - *nodep = NULL; + + if (isc_refcount_decrement(&node->references) == 1) { + destroynode(node); + } } static isc_result_t @@ -362,7 +356,7 @@ findnode(dns_db_t *db, const dns_name_t *name, bool create, return (result); } node->ecdb= ecdb; - node->references = 1; + isc_refcount_init(&node->references, 1); ISC_LIST_INIT(node->rdatasets); ISC_LINK_INIT(node, link); @@ -413,8 +407,7 @@ bind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node, rdataset->privateuint4 = 0; rdataset->private5 = NULL; - INSIST(node->references > 0); - node->references++; + isc_refcount_increment(&node->references); } static isc_result_t @@ -618,7 +611,7 @@ dns_ecdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, isc_mutex_init(&ecdb->lock); - ecdb->references = 1; + isc_refcount_init(&ecdb->references, 1); ISC_LIST_INIT(ecdb->nodes); ecdb->common.mctx = NULL; diff --git a/lib/dns/include/dns/nta.h b/lib/dns/include/dns/nta.h index cce47b0a44..3bd5d9f9fc 100644 --- a/lib/dns/include/dns/nta.h +++ b/lib/dns/include/dns/nta.h @@ -50,8 +50,9 @@ struct dns_ntatable { isc_taskmgr_t *taskmgr; isc_timermgr_t *timermgr; isc_task_t *task; + /* Protected by atomics */ + isc_refcount_t references; /* Locked by rwlock. */ - uint32_t references; dns_rbt_t *table; }; diff --git a/lib/dns/include/dns/tsig.h b/lib/dns/include/dns/tsig.h index 62660fd676..1aeaa3461b 100644 --- a/lib/dns/include/dns/tsig.h +++ b/lib/dns/include/dns/tsig.h @@ -67,7 +67,7 @@ struct dns_tsig_keyring { unsigned int generated; unsigned int maxgenerated; ISC_LIST(dns_tsigkey_t) lru; - unsigned int references; + isc_refcount_t references; }; struct dns_tsigkey { diff --git a/lib/dns/lib.c b/lib/dns/lib.c index 4454fcff5f..e2b92a99d7 100644 --- a/lib/dns/lib.c +++ b/lib/dns/lib.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -43,8 +44,7 @@ static isc_once_t init_once = ISC_ONCE_INIT; static isc_mem_t *dns_g_mctx = NULL; static dns_dbimplementation_t *dbimp = NULL; static bool initialize_done = false; -static isc_mutex_t reflock; -static unsigned int references = 0; +static isc_refcount_t references; static void initialize(void) { @@ -52,6 +52,8 @@ initialize(void) { REQUIRE(initialize_done == false); + isc_refcount_init(&references, 0); + result = isc_mem_create(0, 0, &dns_g_mctx); if (result != ISC_R_SUCCESS) return; @@ -64,8 +66,6 @@ initialize(void) { if (result != ISC_R_SUCCESS) goto cleanup_db; - isc_mutex_init(&reflock); - initialize_done = true; return; @@ -93,29 +93,23 @@ dns_lib_init(void) { if (!initialize_done) return (ISC_R_FAILURE); - LOCK(&reflock); - references++; - UNLOCK(&reflock); + isc_refcount_increment(&references); return (ISC_R_SUCCESS); } void dns_lib_shutdown(void) { - bool cleanup_ok = false; + if (isc_refcount_decrement(&references) == 1) { + dst_lib_destroy(); - LOCK(&reflock); - if (--references == 0) - cleanup_ok = true; - UNLOCK(&reflock); + isc_refcount_destroy(&references); - if (!cleanup_ok) - return; - - dst_lib_destroy(); - - if (dbimp != NULL) - dns_ecdb_unregister(&dbimp); - if (dns_g_mctx != NULL) - isc_mem_detach(&dns_g_mctx); + if (dbimp != NULL) { + dns_ecdb_unregister(&dbimp); + } + if (dns_g_mctx != NULL) { + isc_mem_detach(&dns_g_mctx); + } + } } diff --git a/lib/dns/master.c b/lib/dns/master.c index 80450f0fd7..3a38873c95 100644 --- a/lib/dns/master.c +++ b/lib/dns/master.c @@ -14,11 +14,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -136,11 +138,13 @@ struct dns_loadctx { /* Which fixed buffers we are using? */ unsigned int loop_cnt; /*% records per quantum, * 0 => all. */ - bool canceled; - isc_mutex_t lock; isc_result_t result; + + /* Atomic */ + isc_refcount_t references; + atomic_bool canceled; + /* locked by lock */ - uint32_t references; dns_incctx_t *inc; uint32_t resign; isc_stdtime_t now; @@ -389,11 +393,7 @@ dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) { REQUIRE(target != NULL && *target == NULL); REQUIRE(DNS_LCTX_VALID(source)); - LOCK(&source->lock); - INSIST(source->references > 0); - source->references++; - INSIST(source->references != 0); /* Overflow? */ - UNLOCK(&source->lock); + isc_refcount_increment(&source->references); *target = source; } @@ -401,22 +401,16 @@ dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) { void dns_loadctx_detach(dns_loadctx_t **lctxp) { dns_loadctx_t *lctx; - bool need_destroy = false; REQUIRE(lctxp != NULL); lctx = *lctxp; REQUIRE(DNS_LCTX_VALID(lctx)); - LOCK(&lctx->lock); - INSIST(lctx->references > 0); - lctx->references--; - if (lctx->references == 0) - need_destroy = true; - UNLOCK(&lctx->lock); - - if (need_destroy) - loadctx_destroy(lctx); *lctxp = NULL; + + if (isc_refcount_decrement(&lctx->references) == 1) { + loadctx_destroy(lctx); + } } static void @@ -461,7 +455,6 @@ loadctx_destroy(dns_loadctx_t *lctx) { if (lctx->task != NULL) isc_task_detach(&lctx->task); - isc_mutex_destroy(&lctx->lock); mctx = NULL; isc_mem_attach(lctx->mctx, &mctx); isc_mem_detach(&lctx->mctx); @@ -532,7 +525,6 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, lctx = isc_mem_get(mctx, sizeof(*lctx)); if (lctx == NULL) return (ISC_R_NOMEMORY); - isc_mutex_init(&lctx->lock); lctx->inc = NULL; result = incctx_create(mctx, origin, &lctx->inc); @@ -613,10 +605,12 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, isc_task_attach(task, &lctx->task); lctx->done = done; lctx->done_arg = done_arg; - lctx->canceled = false; + atomic_init(&lctx->canceled, false); lctx->mctx = NULL; isc_mem_attach(mctx, &lctx->mctx); - lctx->references = 1; /* Implicit attach. */ + + isc_refcount_init(&lctx->references, 1); /* Implicit attach. */ + lctx->magic = DNS_LCTX_MAGIC; *lctxp = lctx; return (ISC_R_SUCCESS); @@ -3099,10 +3093,11 @@ load_quantum(isc_task_t *task, isc_event_t *event) { lctx = event->ev_arg; REQUIRE(DNS_LCTX_VALID(lctx)); - if (lctx->canceled) + if (atomic_load_acquire(&lctx->canceled)) { result = ISC_R_CANCELED; - else + } else { result = (lctx->load)(lctx); + } if (result == DNS_R_CONTINUE) { event->ev_arg = lctx; isc_task_send(task, &event); @@ -3130,9 +3125,7 @@ void dns_loadctx_cancel(dns_loadctx_t *lctx) { REQUIRE(DNS_LCTX_VALID(lctx)); - LOCK(&lctx->lock); - lctx->canceled = true; - UNLOCK(&lctx->lock); + atomic_store_release(&lctx->canceled, true); } void diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c index 64e7ee494f..4177adff75 100644 --- a/lib/dns/masterdump.c +++ b/lib/dns/masterdump.c @@ -15,11 +15,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -221,10 +223,10 @@ struct dns_dumpctx { unsigned int magic; isc_mem_t *mctx; isc_mutex_t lock; - unsigned int references; - bool canceled; - bool first; - bool do_date; + isc_refcount_t references; + atomic_bool canceled; + bool first; + bool do_date; isc_stdtime_t now; FILE *f; dns_db_t *db; @@ -1291,11 +1293,7 @@ dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) { REQUIRE(DNS_DCTX_VALID(source)); REQUIRE(target != NULL && *target == NULL); - LOCK(&source->lock); - INSIST(source->references > 0); - source->references++; - INSIST(source->references != 0); /* Overflow? */ - UNLOCK(&source->lock); + isc_refcount_increment(&source->references); *target = source; } @@ -1303,7 +1301,6 @@ dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) { void dns_dumpctx_detach(dns_dumpctx_t **dctxp) { dns_dumpctx_t *dctx; - bool need_destroy = false; REQUIRE(dctxp != NULL); dctx = *dctxp; @@ -1311,14 +1308,9 @@ dns_dumpctx_detach(dns_dumpctx_t **dctxp) { *dctxp = NULL; - LOCK(&dctx->lock); - INSIST(dctx->references != 0); - dctx->references--; - if (dctx->references == 0) - need_destroy = true; - UNLOCK(&dctx->lock); - if (need_destroy) + if (isc_refcount_decrement(&dctx->references) == 1) { dumpctx_destroy(dctx); + } } dns_dbversion_t * @@ -1337,9 +1329,7 @@ void dns_dumpctx_cancel(dns_dumpctx_t *dctx) { REQUIRE(DNS_DCTX_VALID(dctx)); - LOCK(&dctx->lock); - dctx->canceled = true; - UNLOCK(&dctx->lock); + atomic_store_release(&dctx->canceled, true); } static isc_result_t @@ -1421,10 +1411,11 @@ dump_quantum(isc_task_t *task, isc_event_t *event) { REQUIRE(event != NULL); dctx = event->ev_arg; REQUIRE(DNS_DCTX_VALID(dctx)); - if (dctx->canceled) + if (atomic_load_acquire(&dctx->canceled)) { result = ISC_R_CANCELED; - else + } else { result = dumptostreaminc(dctx); + } if (result == DNS_R_CONTINUE) { event->ev_arg = dctx; isc_task_send(task, &event); @@ -1478,7 +1469,7 @@ dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, dctx->task = NULL; dctx->nodes = 0; dctx->first = true; - dctx->canceled = false; + atomic_init(&dctx->canceled, false); dctx->file = NULL; dctx->tmpfile = NULL; dctx->format = format; @@ -1540,7 +1531,8 @@ dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, else if (!dns_db_iscache(db)) dns_db_currentversion(dctx->db, &dctx->version); isc_mem_attach(mctx, &dctx->mctx); - dctx->references = 1; + + isc_refcount_init(&dctx->references, 1); dctx->magic = DNS_DCTX_MAGIC; *dctxp = dctx; return (ISC_R_SUCCESS); diff --git a/lib/dns/nta.c b/lib/dns/nta.c index 444684c2e9..c495c3cff4 100644 --- a/lib/dns/nta.c +++ b/lib/dns/nta.c @@ -133,7 +133,7 @@ dns_ntatable_create(dns_view_t *view, ntatable->taskmgr = taskmgr; ntatable->view = view; - ntatable->references = 1; + isc_refcount_init(&ntatable->references, 1); ntatable->magic = NTATABLE_MAGIC; *ntatablep = ntatable; @@ -157,20 +157,13 @@ dns_ntatable_attach(dns_ntatable_t *source, dns_ntatable_t **targetp) { REQUIRE(VALID_NTATABLE(source)); REQUIRE(targetp != NULL && *targetp == NULL); - RWLOCK(&source->rwlock, isc_rwlocktype_write); - - INSIST(source->references > 0); - source->references++; - INSIST(source->references != 0); - - RWUNLOCK(&source->rwlock, isc_rwlocktype_write); + isc_refcount_increment(&source->references); *targetp = source; } void dns_ntatable_detach(dns_ntatable_t **ntatablep) { - bool destroy = false; dns_ntatable_t *ntatable; REQUIRE(ntatablep != NULL && VALID_NTATABLE(*ntatablep)); @@ -178,16 +171,10 @@ dns_ntatable_detach(dns_ntatable_t **ntatablep) { ntatable = *ntatablep; *ntatablep = NULL; - RWLOCK(&ntatable->rwlock, isc_rwlocktype_write); - INSIST(ntatable->references > 0); - ntatable->references--; - if (ntatable->references == 0) - destroy = true; - RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write); - - if (destroy) { + if (isc_refcount_decrement(&ntatable->references) == 1) { dns_rbt_destroy(&ntatable->table); isc_rwlock_destroy(&ntatable->rwlock); + isc_refcount_destroy(&ntatable->references); if (ntatable->task != NULL) isc_task_detach(&ntatable->task); ntatable->timermgr = NULL; diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 5fb8c8653c..37efaa3af6 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -268,12 +268,15 @@ struct fetchctx { isc_mem_t * mctx; isc_stdtime_t now; + /* Atomic */ + isc_refcount_t references; + + /*% Locked by appropriate bucket lock. */ fetchstate state; - bool want_shutdown; - bool cloned; - bool spilled; - unsigned int references; + bool want_shutdown; + bool cloned; + bool spilled; isc_event_t control_event; ISC_LINK(struct fetchctx) link; ISC_LIST(dns_fetchevent_t) events; @@ -434,7 +437,7 @@ typedef struct fctxbucket { isc_task_t * task; isc_mutex_t lock; ISC_LIST(fetchctx_t) fctxs; - bool exiting; + atomic_bool exiting; isc_mem_t * mctx; } fctxbucket_t; @@ -472,7 +475,6 @@ struct dns_resolver { unsigned int magic; isc_mem_t * mctx; isc_mutex_t lock; - isc_mutex_t nlock; isc_mutex_t primelock; dns_rdataclass_t rdclass; isc_socketmgr_t * socketmgr; @@ -516,12 +518,14 @@ struct dns_resolver { unsigned int retryinterval; /* in milliseconds */ unsigned int nonbackofftries; + /* Atomic */ + isc_refcount_t references; + atomic_bool exiting; + /* Locked by lock. */ - unsigned int references; - bool exiting; isc_eventlist_t whenshutdown; unsigned int activebuckets; - bool priming; + bool priming; unsigned int spillat; /* clients-per-query */ unsigned int zspill; /* fetches-per-zone */ @@ -529,8 +533,9 @@ struct dns_resolver { /* Locked by primelock. */ dns_fetch_t * primefetch; - /* Locked by nlock. */ - unsigned int nfctx; + + /* Atomic. */ + isc_refcount_t nfctx; }; #define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!') @@ -1641,7 +1646,8 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) { fctx->spilled && (count < fctx->res->spillatmax || fctx->res->spillatmax == 0)) { LOCK(&fctx->res->lock); - if (count == fctx->res->spillat && !fctx->res->exiting) { + if (count == fctx->res->spillat && + !atomic_load_acquire(&fctx->res->exiting)) { old_spillat = fctx->res->spillat; fctx->res->spillat += 5; if (fctx->res->spillat > fctx->res->spillatmax && @@ -3067,7 +3073,7 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 && fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) { - if (fctx->references == 0) { + if (isc_refcount_current(&fctx->references) == 0) { bucket_empty = fctx_unlink(fctx); dodestroy = true; } @@ -4282,24 +4288,26 @@ fctx_unlink(fetchctx_t *fctx) { REQUIRE(ISC_LIST_EMPTY(fctx->finds)); REQUIRE(ISC_LIST_EMPTY(fctx->altfinds)); REQUIRE(fctx->pending == 0); - REQUIRE(fctx->references == 0); REQUIRE(ISC_LIST_EMPTY(fctx->validators)); FCTXTRACE("unlink"); + isc_refcount_destroy(&fctx->references); + res = fctx->res; bucketnum = fctx->bucketnum; ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link); - LOCK(&res->nlock); - res->nfctx--; - UNLOCK(&res->nlock); + isc_refcount_decrement(&res->nfctx); + dec_stats(res, dns_resstatscounter_nfetch); - if (res->buckets[bucketnum].exiting && + if (atomic_load_acquire(&res->buckets[bucketnum].exiting) && ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs)) + { return (true); + } return (false); } @@ -4317,12 +4325,13 @@ fctx_destroy(fetchctx_t *fctx) { REQUIRE(ISC_LIST_EMPTY(fctx->finds)); REQUIRE(ISC_LIST_EMPTY(fctx->altfinds)); REQUIRE(fctx->pending == 0); - REQUIRE(fctx->references == 0); REQUIRE(ISC_LIST_EMPTY(fctx->validators)); REQUIRE(!ISC_LINK_LINKED(fctx, link)); FCTXTRACE("destroy"); + isc_refcount_destroy(&fctx->references); + /* * Free bad. */ @@ -4527,8 +4536,11 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { fctx_sendevents(fctx, ISC_R_CANCELED, __LINE__); } - if (fctx->references == 0 && fctx->pending == 0 && - fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) { + if (isc_refcount_current(&fctx->references) == 0 && + fctx->pending == 0 && + fctx->nqueries == 0 && + ISC_LIST_EMPTY(fctx->validators)) + { bucket_empty = fctx_unlink(fctx); dodestroy = true; } @@ -4577,7 +4589,7 @@ fctx_start(isc_task_t *task, isc_event_t *event) { INSIST(fctx->pending == 0); INSIST(fctx->nqueries == 0); INSIST(ISC_LIST_EMPTY(fctx->validators)); - if (fctx->references == 0) { + if (isc_refcount_current(&fctx->references) == 0) { /* * It's now safe to destroy this fctx. */ @@ -4669,7 +4681,9 @@ fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, ISC_LIST_PREPEND(fctx->events, event, ev_link); else ISC_LIST_APPEND(fctx->events, event, ev_link); - fctx->references++; + + fctx_increference(fctx); + fctx->client = client; fetch->magic = DNS_FETCH_MAGIC; @@ -4762,7 +4776,7 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, * using it. */ fctx->res = res; - fctx->references = 0; + isc_refcount_init(&fctx->references, 0); fctx->bucketnum = bucketnum; fctx->dbucketnum = RES_NOBUCKET; fctx->state = fetchstate_init; @@ -5011,9 +5025,8 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link); - LOCK(&res->nlock); - res->nfctx++; - UNLOCK(&res->nlock); + isc_refcount_increment(&res->nfctx); + inc_stats(res, dns_resstatscounter_nfetch); *fctxp = fctx; @@ -5311,7 +5324,9 @@ maybe_destroy(fetchctx_t *fctx, bool locked) { dns_validator_cancel(validator); } - if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators)) { + if (isc_refcount_current(&fctx->references) == 0 && + ISC_LIST_EMPTY(fctx->validators)) + { bucket_empty = fctx_unlink(fctx); dodestroy = true; } @@ -7009,9 +7024,7 @@ static void fctx_increference(fetchctx_t *fctx) { REQUIRE(VALID_FCTX(fctx)); - LOCK(&fctx->res->buckets[fctx->bucketnum].lock); - fctx->references++; - UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); + isc_refcount_increment(&fctx->references); } static bool @@ -7020,9 +7033,7 @@ fctx_decreference(fetchctx_t *fctx) { REQUIRE(VALID_FCTX(fctx)); - INSIST(fctx->references > 0); - fctx->references--; - if (fctx->references == 0) { + if (isc_refcount_decrement(&fctx->references) == 1) { /* * No one cares about the result of this fetch anymore. */ @@ -7051,8 +7062,6 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx; isc_result_t result; bool bucket_empty; - bool locked = false; - unsigned int bucketnum; dns_rdataset_t nameservers; dns_fixedname_t fixed; dns_name_t *domain; @@ -7073,8 +7082,6 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { dns_rdataset_init(&nameservers); - bucketnum = fctx->bucketnum; - /* * Note: fevent->rdataset must be disassociated and * isc_event_free(&event) be called before resuming @@ -7184,23 +7191,20 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { } fctx_done(fctx, result, __LINE__); } else { - LOCK(&res->buckets[bucketnum].lock); - locked = true; - fctx->references++; + fctx_increference(fctx); } } cleanup: INSIST(event == NULL); INSIST(fevent == NULL); - if (dns_rdataset_isassociated(&nameservers)) + if (dns_rdataset_isassociated(&nameservers)) { dns_rdataset_disassociate(&nameservers); - if (!locked) - LOCK(&res->buckets[bucketnum].lock); + } bucket_empty = fctx_decreference(fctx); - UNLOCK(&res->buckets[bucketnum].lock); - if (bucket_empty) + if (bucket_empty) { empty_bucket(res); + } } static inline void @@ -7359,7 +7363,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { rctx_respinit(task, devent, query, fctx, &rctx); - if (fctx->res->exiting) { + if (atomic_load_acquire(&fctx->res->exiting)) { result = ISC_R_SHUTTINGDOWN; FCTXTRACE("resolver shutting down"); rctx_done(&rctx, result); @@ -9395,9 +9399,7 @@ rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo) { } fctx_done(fctx, result, __LINE__); - LOCK(&fctx->res->buckets[fctx->bucketnum].lock); bucket_empty = fctx_decreference(fctx); - UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); if (bucket_empty) { empty_bucket(fctx->res); } @@ -9812,16 +9814,15 @@ destroy(dns_resolver_t *res) { unsigned int i; alternate_t *a; - REQUIRE(res->references == 0); + REQUIRE(atomic_load(&res->references) == 0); REQUIRE(!res->priming); REQUIRE(res->primefetch == NULL); RTRACE("destroy"); - INSIST(res->nfctx == 0); + isc_refcount_destroy(&res->nfctx); isc_mutex_destroy(&res->primelock); - isc_mutex_destroy(&res->nlock); isc_mutex_destroy(&res->lock); for (i = 0; i < res->nbuckets; i++) { INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs)); @@ -9910,7 +9911,7 @@ spillattimer_countdown(isc_task_t *task, isc_event_t *event) { UNUSED(task); LOCK(&res->lock); - INSIST(!res->exiting); + INSIST(!atomic_load_acquire(&res->exiting)); if (res->spillat > res->spillatmin) { res->spillat--; logit = true; @@ -10038,7 +10039,7 @@ dns_resolver_create(dns_view_t *view, isc_mem_setname(res->buckets[i].mctx, name, NULL); isc_task_setname(res->buckets[i].task, name, res); ISC_LIST_INIT(res->buckets[i].fctxs); - res->buckets[i].exiting = false; + atomic_init(&res->buckets[i].exiting, false); buckets_created++; } @@ -10074,16 +10075,16 @@ dns_resolver_create(dns_view_t *view, res->querydscp4 = -1; res->querydscp6 = -1; - res->references = 1; - res->exiting = false; + isc_refcount_init(&res->references, 1); + atomic_init(&res->exiting, false); res->frozen = false; ISC_LIST_INIT(res->whenshutdown); res->priming = false; res->primefetch = NULL; - res->nfctx = 0; + + isc_refcount_init(&res->nfctx, 0); isc_mutex_init(&res->lock); - isc_mutex_init(&res->nlock); isc_mutex_init(&res->primelock); task = NULL; @@ -10132,7 +10133,6 @@ dns_resolver_create(dns_view_t *view, cleanup_primelock: isc_mutex_destroy(&res->primelock); - isc_mutex_destroy(&res->nlock); isc_mutex_destroy(&res->lock); if (res->dispatches6 != NULL) @@ -10229,7 +10229,8 @@ dns_resolver_prime(dns_resolver_t *res) { LOCK(&res->lock); - if (!res->exiting && !res->priming) { + /* XXXOND: cas needs to be used here */ + if (!atomic_load_acquire(&res->exiting) && !res->priming) { INSIST(res->primefetch == NULL); res->priming = true; want_priming = true; @@ -10295,13 +10296,9 @@ dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) { REQUIRE(targetp != NULL && *targetp == NULL); RRTRACE(source, "attach"); - LOCK(&source->lock); - REQUIRE(!source->exiting); - INSIST(source->references > 0); - source->references++; - INSIST(source->references != 0); - UNLOCK(&source->lock); + REQUIRE(!atomic_load_acquire(&source->exiting)); + isc_refcount_increment(&source->references); *targetp = source; } @@ -10321,7 +10318,7 @@ dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task, LOCK(&res->lock); - if (res->exiting && res->activebuckets == 0) { + if (atomic_load_acquire(&res->exiting) && res->activebuckets == 0) { /* * We're already shutdown. Send the event. */ @@ -10342,16 +10339,14 @@ dns_resolver_shutdown(dns_resolver_t *res) { unsigned int i; fetchctx_t *fctx; isc_result_t result; + bool is_false = false; REQUIRE(VALID_RESOLVER(res)); RTRACE("shutdown"); - LOCK(&res->lock); - - if (!res->exiting) { + if (atomic_compare_exchange_strong(&res->exiting, &is_false, true)) { RTRACE("exiting"); - res->exiting = true; for (i = 0; i < res->nbuckets; i++) { LOCK(&res->buckets[i].lock); @@ -10367,7 +10362,7 @@ dns_resolver_shutdown(dns_resolver_t *res) { dns_dispatchset_cancelall(res->dispatches6, res->buckets[i].task); } - res->buckets[i].exiting = true; + atomic_store(&res->buckets[i].exiting, true); if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) { INSIST(res->activebuckets > 0); res->activebuckets--; @@ -10381,14 +10376,11 @@ dns_resolver_shutdown(dns_resolver_t *res) { NULL, true); RUNTIME_CHECK(result == ISC_R_SUCCESS); } - - UNLOCK(&res->lock); } void dns_resolver_detach(dns_resolver_t **resp) { dns_resolver_t *res; - bool need_destroy = false; REQUIRE(resp != NULL); res = *resp; @@ -10396,21 +10388,13 @@ dns_resolver_detach(dns_resolver_t **resp) { RTRACE("detach"); - LOCK(&res->lock); - - INSIST(res->references > 0); - res->references--; - if (res->references == 0) { - INSIST(res->exiting && res->activebuckets == 0); - need_destroy = true; - } - - UNLOCK(&res->lock); - - if (need_destroy) - destroy(res); - *resp = NULL; + + if (isc_refcount_decrement(&res->references) == 1) { + INSIST(atomic_load_acquire(&res->exiting)); + INSIST(res->activebuckets == 0); + destroy(res); + } } static inline bool @@ -10599,7 +10583,7 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, UNLOCK(&res->lock); LOCK(&res->buckets[bucketnum].lock); - if (res->buckets[bucketnum].exiting) { + if (atomic_load(&res->buckets[bucketnum].exiting)) { result = ISC_R_SHUTTINGDOWN; goto unlock; } @@ -10767,11 +10751,10 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) { RUNTIME_CHECK(event->fetch != fetch); } } + UNLOCK(&res->buckets[bucketnum].lock); bucket_empty = fctx_decreference(fctx); - UNLOCK(&res->buckets[bucketnum].lock); - isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch)); *fetchp = NULL; @@ -10865,11 +10848,7 @@ dns_resolver_setlamettl(dns_resolver_t *resolver, uint32_t lame_ttl) { unsigned int dns_resolver_nrunning(dns_resolver_t *resolver) { - unsigned int n; - LOCK(&resolver->nlock); - n = resolver->nfctx; - UNLOCK(&resolver->nlock); - return (n); + return (isc_refcount_current(&resolver->nfctx)); } isc_result_t diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c index 6be15d8720..4325819e98 100644 --- a/lib/dns/sdb.c +++ b/lib/dns/sdb.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -56,9 +57,9 @@ struct dns_sdb { char *zone; dns_sdbimplementation_t *implementation; void *dbdata; - isc_mutex_t lock; - /* Locked */ - unsigned int references; + + /* Atomic */ + isc_refcount_t references; }; struct dns_sdblookup { @@ -69,10 +70,10 @@ struct dns_sdblookup { ISC_LIST(isc_buffer_t) buffers; dns_name_t *name; ISC_LINK(dns_sdblookup_t) link; - isc_mutex_t lock; dns_rdatacallbacks_t callbacks; - /* Locked */ - unsigned int references; + + /* Atomic */ + isc_refcount_t references; }; typedef struct dns_sdblookup dns_sdbnode_t; @@ -529,10 +530,7 @@ attach(dns_db_t *source, dns_db_t **targetp) { REQUIRE(VALID_SDB(sdb)); - LOCK(&sdb->lock); - REQUIRE(sdb->references > 0); - sdb->references++; - UNLOCK(&sdb->lock); + isc_refcount_increment(&sdb->references); *targetp = source; } @@ -552,7 +550,6 @@ destroy(dns_sdb_t *sdb) { } isc_mem_free(mctx, sdb->zone); - isc_mutex_destroy(&sdb->lock); sdb->common.magic = 0; sdb->common.impmagic = 0; @@ -566,20 +563,14 @@ destroy(dns_sdb_t *sdb) { static void detach(dns_db_t **dbp) { dns_sdb_t *sdb = (dns_sdb_t *)(*dbp); - bool need_destroy = false; REQUIRE(VALID_SDB(sdb)); - LOCK(&sdb->lock); - REQUIRE(sdb->references > 0); - sdb->references--; - if (sdb->references == 0) - need_destroy = true; - UNLOCK(&sdb->lock); - - if (need_destroy) - destroy(sdb); *dbp = NULL; + + if (isc_refcount_decrement(&sdb->references) == 1) { + destroy(sdb); + } } static isc_result_t @@ -661,9 +652,10 @@ createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) { ISC_LIST_INIT(node->buffers); ISC_LINK_INIT(node, link); node->name = NULL; - isc_mutex_init(&node->lock); dns_rdatacallbacks_init(&node->callbacks); - node->references = 1; + + isc_refcount_init(&node->references, 1); + node->magic = SDBLOOKUP_MAGIC; *nodep = node; @@ -702,7 +694,7 @@ destroynode(dns_sdbnode_t *node) { dns_name_free(node->name, mctx); isc_mem_put(mctx, node->name, sizeof(dns_name_t)); } - isc_mutex_destroy(&node->lock); + node->magic = 0; isc_mem_put(mctx, node, sizeof(dns_sdbnode_t)); detach((dns_db_t **) (void *)&sdb); @@ -1001,11 +993,7 @@ attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) { UNUSED(sdb); - LOCK(&node->lock); - INSIST(node->references > 0); - node->references++; - INSIST(node->references != 0); /* Catch overflow. */ - UNLOCK(&node->lock); + isc_refcount_increment(&node->references); *targetp = source; } @@ -1014,7 +1002,6 @@ static void detachnode(dns_db_t *db, dns_dbnode_t **targetp) { dns_sdb_t *sdb = (dns_sdb_t *)db; dns_sdbnode_t *node; - bool need_destroy = false; REQUIRE(VALID_SDB(sdb)); REQUIRE(targetp != NULL && *targetp != NULL); @@ -1023,17 +1010,11 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) { node = (dns_sdbnode_t *)(*targetp); - LOCK(&node->lock); - INSIST(node->references > 0); - node->references--; - if (node->references == 0) - need_destroy = true; - UNLOCK(&node->lock); - - if (need_destroy) - destroynode(node); - *targetp = NULL; + + if (isc_refcount_decrement(&node->references) == 1) { + destroynode(node); + } } static isc_result_t @@ -1323,8 +1304,6 @@ dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, isc_mem_attach(mctx, &sdb->common.mctx); - isc_mutex_init(&sdb->lock); - result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin); if (result != ISC_R_SUCCESS) goto cleanup_lock; @@ -1351,7 +1330,7 @@ dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, goto cleanup_zonestr; } - sdb->references = 1; + isc_refcount_init(&sdb->references, 1); sdb->common.magic = DNS_DB_MAGIC; sdb->common.impmagic = SDB_MAGIC; @@ -1365,7 +1344,6 @@ dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, cleanup_origin: dns_name_free(&sdb->common.origin, mctx); cleanup_lock: - isc_mutex_destroy(&sdb->lock); isc_mem_put(mctx, sdb, sizeof(dns_sdb_t)); isc_mem_detach(&mctx); diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c index 39f3032148..b0658b39df 100644 --- a/lib/dns/sdlz.c +++ b/lib/dns/sdlz.c @@ -98,9 +98,11 @@ struct dns_sdlz_db { dns_db_t common; void *dbdata; dns_sdlzimplementation_t *dlzimp; - isc_mutex_t refcnt_lock; + + /* Atomic */ + isc_refcount_t references; + /* Locked */ - unsigned int references; dns_dbversion_t *future_version; int dummy_version; }; @@ -113,10 +115,10 @@ struct dns_sdlzlookup { ISC_LIST(isc_buffer_t) buffers; dns_name_t *name; ISC_LINK(dns_sdlzlookup_t) link; - isc_mutex_t lock; dns_rdatacallbacks_t callbacks; - /* Locked */ - unsigned int references; + + /* Atomic */ + isc_refcount_t references; }; typedef struct dns_sdlzlookup dns_sdlznode_t; @@ -318,47 +320,33 @@ attach(dns_db_t *source, dns_db_t **targetp) { REQUIRE(VALID_SDLZDB(sdlz)); - LOCK(&sdlz->refcnt_lock); - REQUIRE(sdlz->references > 0); - sdlz->references++; - UNLOCK(&sdlz->refcnt_lock); + isc_refcount_increment(&sdlz->references); *targetp = source; } static void destroy(dns_sdlz_db_t *sdlz) { - isc_mem_t *mctx; - mctx = sdlz->common.mctx; - sdlz->common.magic = 0; sdlz->common.impmagic = 0; - isc_mutex_destroy(&sdlz->refcnt_lock); + dns_name_free(&sdlz->common.origin, sdlz->common.mctx); - dns_name_free(&sdlz->common.origin, mctx); - - isc_mem_put(mctx, sdlz, sizeof(dns_sdlz_db_t)); - isc_mem_detach(&mctx); + isc_refcount_destroy(&sdlz->references); + isc_mem_putanddetach(&sdlz->common.mctx, sdlz, sizeof(dns_sdlz_db_t)); } static void detach(dns_db_t **dbp) { dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)(*dbp); - bool need_destroy = false; REQUIRE(VALID_SDLZDB(sdlz)); - LOCK(&sdlz->refcnt_lock); - REQUIRE(sdlz->references > 0); - sdlz->references--; - if (sdlz->references == 0) - need_destroy = true; - UNLOCK(&sdlz->refcnt_lock); - - if (need_destroy) - destroy(sdlz); *dbp = NULL; + + if (isc_refcount_decrement(&sdlz->references) == 1) { + destroy(sdlz); + } } static isc_result_t @@ -476,9 +464,9 @@ createnode(dns_sdlz_db_t *sdlz, dns_sdlznode_t **nodep) { ISC_LIST_INIT(node->buffers); ISC_LINK_INIT(node, link); node->name = NULL; - isc_mutex_init(&node->lock); dns_rdatacallbacks_init(&node->callbacks); - node->references = 1; + + isc_refcount_init(&node->references, 1); node->magic = SDLZLOOKUP_MAGIC; *nodep = node; @@ -518,7 +506,8 @@ destroynode(dns_sdlznode_t *node) { dns_name_free(node->name, mctx); isc_mem_put(mctx, node->name, sizeof(dns_name_t)); } - isc_mutex_destroy(&node->lock); + isc_refcount_destroy(&node->references); + node->magic = 0; isc_mem_put(mctx, node, sizeof(dns_sdlznode_t)); db = &sdlz->common; @@ -652,6 +641,7 @@ getnodedata(dns_db_t *db, const dns_name_t *name, bool create, result = ISC_R_SUCCESS; if (result != ISC_R_SUCCESS) { + isc_refcount_decrement(&node->references); destroynode(node); return (result); } @@ -665,6 +655,7 @@ getnodedata(dns_db_t *db, const dns_name_t *name, bool create, if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) { + isc_refcount_decrement(&node->references); destroynode(node); return (result); } @@ -673,18 +664,9 @@ getnodedata(dns_db_t *db, const dns_name_t *name, bool create, if (node->name == NULL) { node->name = isc_mem_get(sdlz->common.mctx, sizeof(dns_name_t)); - if (node->name == NULL) { - destroynode(node); - return (ISC_R_NOMEMORY); - } dns_name_init(node->name, NULL); result = dns_name_dup(name, sdlz->common.mctx, node->name); - if (result != ISC_R_SUCCESS) { - isc_mem_put(sdlz->common.mctx, node->name, - sizeof(dns_name_t)); - destroynode(node); - return (result); - } + RUNTIME_CHECK(result == ISC_R_SUCCESS); } *nodep = node; @@ -734,11 +716,7 @@ attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) { UNUSED(sdlz); - LOCK(&node->lock); - INSIST(node->references > 0); - node->references++; - INSIST(node->references != 0); /* Catch overflow. */ - UNLOCK(&node->lock); + isc_refcount_increment(&node->references); *targetp = source; } @@ -747,7 +725,6 @@ static void detachnode(dns_db_t *db, dns_dbnode_t **targetp) { dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; dns_sdlznode_t *node; - bool need_destroy = false; REQUIRE(VALID_SDLZDB(sdlz)); REQUIRE(targetp != NULL && *targetp != NULL); @@ -755,18 +732,11 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) { UNUSED(sdlz); node = (dns_sdlznode_t *)(*targetp); - - LOCK(&node->lock); - INSIST(node->references > 0); - node->references--; - if (node->references == 0) - need_destroy = true; - UNLOCK(&node->lock); - - if (need_destroy) - destroynode(node); - *targetp = NULL; + + if (isc_refcount_decrement(&node->references) == 1) { + destroynode(node); + } } static isc_result_t @@ -989,7 +959,7 @@ findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, * and try again. */ if (i < nlabels) { - destroynode(node); + detachnode(db, &node); node = NULL; continue; } @@ -1035,10 +1005,12 @@ findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, xresult = dns_name_copy(xname, foundname, NULL); if (xresult != ISC_R_SUCCESS) { - if (node != NULL) - destroynode(node); - if (dns_rdataset_isassociated(rdataset)) + if (node != NULL) { + detachnode(db, &node); + } + if (dns_rdataset_isassociated(rdataset)) { dns_rdataset_disassociate(rdataset); + } return (DNS_R_BADDB); } } @@ -1349,6 +1321,7 @@ dbiterator_destroy(dns_dbiterator_t **iteratorp) { dns_sdlznode_t *node; node = ISC_LIST_HEAD(sdlziter->nodelist); ISC_LIST_UNLINK(sdlziter->nodelist, node, link); + isc_refcount_decrement(&node->references); destroynode(node); } @@ -1543,9 +1516,6 @@ dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata, if (result != ISC_R_SUCCESS) goto mem_cleanup; - /* initialize the reference count mutex */ - isc_mutex_init(&sdlzdb->refcnt_lock); - /* set the rest of the database structure attributes */ sdlzdb->dlzimp = imp; sdlzdb->common.methods = &sdlzdb_methods; @@ -1553,7 +1523,7 @@ dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata, sdlzdb->common.rdclass = rdclass; sdlzdb->common.mctx = NULL; sdlzdb->dbdata = dbdata; - sdlzdb->references = 1; + isc_refcount_init(&sdlzdb->references, 1); /* attach to the memory context */ isc_mem_attach(mctx, &sdlzdb->common.mctx); @@ -1999,17 +1969,9 @@ dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name, if (result != ISC_R_SUCCESS) return (result); sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t)); - if (sdlznode->name == NULL) { - destroynode(sdlznode); - return (ISC_R_NOMEMORY); - } dns_name_init(sdlznode->name, NULL); result = dns_name_dup(newname, mctx, sdlznode->name); - if (result != ISC_R_SUCCESS) { - isc_mem_put(mctx, sdlznode->name, sizeof(dns_name_t)); - destroynode(sdlznode); - return (result); - } + RUNTIME_CHECK(result == ISC_R_SUCCESS); ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link); if (allnodes->origin == NULL && dns_name_equal(newname, &sdlz->common.origin)) diff --git a/lib/dns/ssu.c b/lib/dns/ssu.c index 73e8da4e2a..0e93a657dc 100644 --- a/lib/dns/ssu.c +++ b/lib/dns/ssu.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -51,8 +52,7 @@ struct dns_ssurule { struct dns_ssutable { unsigned int magic; isc_mem_t *mctx; - unsigned int references; - isc_mutex_t lock; + isc_refcount_t references; dns_dlzdb_t *dlzdatabase; ISC_LIST(dns_ssurule_t) rules; }; @@ -65,10 +65,7 @@ dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **tablep) { REQUIRE(mctx != NULL); table = isc_mem_get(mctx, sizeof(dns_ssutable_t)); - if (table == NULL) - return (ISC_R_NOMEMORY); - isc_mutex_init(&table->lock); - table->references = 1; + isc_refcount_init(&table->references, 1); table->mctx = NULL; isc_mem_attach(mctx, &table->mctx); ISC_LIST_INIT(table->rules); @@ -101,7 +98,7 @@ destroy(dns_ssutable_t *table) { rule->magic = 0; isc_mem_put(mctx, rule, sizeof(dns_ssurule_t)); } - isc_mutex_destroy(&table->lock); + isc_refcount_destroy(&table->references); table->magic = 0; isc_mem_putanddetach(&table->mctx, table, sizeof(dns_ssutable_t)); } @@ -111,13 +108,7 @@ dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp) { REQUIRE(VALID_SSUTABLE(source)); REQUIRE(targetp != NULL && *targetp == NULL); - LOCK(&source->lock); - - INSIST(source->references > 0); - source->references++; - INSIST(source->references != 0); - - UNLOCK(&source->lock); + isc_refcount_increment(&source->references); *targetp = source; } @@ -125,23 +116,15 @@ dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp) { void dns_ssutable_detach(dns_ssutable_t **tablep) { dns_ssutable_t *table; - bool done = false; REQUIRE(tablep != NULL); table = *tablep; REQUIRE(VALID_SSUTABLE(table)); - - LOCK(&table->lock); - - INSIST(table->references > 0); - if (--table->references == 0) - done = true; - UNLOCK(&table->lock); - *tablep = NULL; - if (done) + if (isc_refcount_decrement(&table->references) == 1) { destroy(table); + } } isc_result_t diff --git a/lib/dns/stats.c b/lib/dns/stats.c index c5f9121320..f57e6552b7 100644 --- a/lib/dns/stats.c +++ b/lib/dns/stats.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -64,15 +65,11 @@ enum { }; struct dns_stats { - /*% Unlocked */ unsigned int magic; dns_statstype_t type; isc_mem_t *mctx; - isc_mutex_t lock; isc_stats_t *counters; - - /*% Locked by lock */ - unsigned int references; + isc_refcount_t references; }; typedef struct rdatadumparg { @@ -99,9 +96,7 @@ dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp) { REQUIRE(DNS_STATS_VALID(stats)); REQUIRE(statsp != NULL && *statsp == NULL); - LOCK(&stats->lock); - stats->references++; - UNLOCK(&stats->lock); + isc_refcount_increment(&stats->references); *statsp = stats; } @@ -115,13 +110,8 @@ dns_stats_detach(dns_stats_t **statsp) { stats = *statsp; *statsp = NULL; - LOCK(&stats->lock); - stats->references--; - UNLOCK(&stats->lock); - - if (stats->references == 0) { + if (isc_refcount_decrement(&stats->references) == 1) { isc_stats_detach(&stats->counters); - isc_mutex_destroy(&stats->lock); isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); } } @@ -141,9 +131,7 @@ create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters, return (ISC_R_NOMEMORY); stats->counters = NULL; - stats->references = 1; - - isc_mutex_init(&stats->lock); + isc_refcount_init(&stats->references, 1); result = isc_stats_create(mctx, &stats->counters, ncounters); if (result != ISC_R_SUCCESS) @@ -158,7 +146,6 @@ create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters, return (ISC_R_SUCCESS); clean_mutex: - isc_mutex_destroy(&stats->lock); isc_mem_put(mctx, stats, sizeof(*stats)); return (result); diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index 29ccd33ef0..8e41bd963a 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -611,21 +611,15 @@ dns_tsigkeyring_dumpanddetach(dns_tsig_keyring_t **ringp, FILE *fp) { dns_rbtnode_t *node; dns_tsigkey_t *tkey; dns_tsig_keyring_t *ring; - unsigned int references; REQUIRE(ringp != NULL && *ringp != NULL); ring = *ringp; *ringp = NULL; - RWLOCK(&ring->lock, isc_rwlocktype_write); - INSIST(ring->references > 0); - ring->references--; - references = ring->references; - RWUNLOCK(&ring->lock, isc_rwlocktype_write); - - if (references != 0) + if (isc_refcount_decrement(&ring->references) > 1) { return (DNS_R_CONTINUE); + } isc_stdtime_get(&now); dns_name_init(&foundname, NULL); @@ -1804,7 +1798,7 @@ dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) { ring->maxgenerated = DNS_TSIG_MAXGENERATEDKEYS; ISC_LIST_INIT(ring->lru); isc_mem_attach(mctx, &ring->mctx); - ring->references = 1; + isc_refcount_init(&ring->references, 1); *ringp = ring; return (ISC_R_SUCCESS); @@ -1829,18 +1823,14 @@ dns_tsigkeyring_attach(dns_tsig_keyring_t *source, dns_tsig_keyring_t **target) REQUIRE(source != NULL); REQUIRE(target != NULL && *target == NULL); - RWLOCK(&source->lock, isc_rwlocktype_write); - INSIST(source->references > 0); - source->references++; - INSIST(source->references > 0); + isc_refcount_increment(&source->references); + *target = source; - RWUNLOCK(&source->lock, isc_rwlocktype_write); } void dns_tsigkeyring_detach(dns_tsig_keyring_t **ringp) { dns_tsig_keyring_t *ring; - unsigned int references; REQUIRE(ringp != NULL); REQUIRE(*ringp != NULL); @@ -1848,14 +1838,9 @@ dns_tsigkeyring_detach(dns_tsig_keyring_t **ringp) { ring = *ringp; *ringp = NULL; - RWLOCK(&ring->lock, isc_rwlocktype_write); - INSIST(ring->references > 0); - ring->references--; - references = ring->references; - RWUNLOCK(&ring->lock, isc_rwlocktype_write); - - if (references == 0) + if (isc_refcount_decrement(&ring->references) == 1) { destroyring(ring); + } } void diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 9706d9e2b2..25c8fcfa2a 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -17392,7 +17392,7 @@ dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, RWLOCK(&zmgr->urlock, isc_rwlocktype_read); for (i = 0; i < UNREACH_CACHE_SIZE; i++) { - if (zmgr->unreachable[i].expire >= seconds && + if (atomic_load(&zmgr->unreachable[i].expire) >= seconds && isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) { atomic_store_relaxed(&zmgr->unreachable[i].last, diff --git a/lib/dns/zt.c b/lib/dns/zt.c index cb97bcac8a..ab8bc818fc 100644 --- a/lib/dns/zt.c +++ b/lib/dns/zt.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -45,10 +46,13 @@ struct dns_zt { dns_zt_allloaded_t loaddone; void * loaddone_arg; struct zt_load_params *loadparams; + + /* Atomic */ + atomic_bool flush; + isc_refcount_t references; + isc_refcount_t loads_pending; + /* Locked by lock. */ - bool flush; - uint32_t references; - unsigned int loads_pending; dns_rbt_t *table; }; @@ -93,14 +97,14 @@ dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) { zt->mctx = NULL; isc_mem_attach(mctx, &zt->mctx); - zt->references = 1; - zt->flush = false; + isc_refcount_init(&zt->references, 1); + atomic_init(&zt->flush, false); zt->rdclass = rdclass; zt->magic = ZTMAGIC; zt->loaddone = NULL; zt->loaddone_arg = NULL; zt->loadparams = NULL; - zt->loads_pending = 0; + isc_refcount_init(&zt->loads_pending, 0); *ztp = zt; return (ISC_R_SUCCESS); @@ -209,13 +213,7 @@ dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) { REQUIRE(VALID_ZT(zt)); REQUIRE(ztp != NULL && *ztp == NULL); - RWLOCK(&zt->rwlock, isc_rwlocktype_write); - - INSIST(zt->references > 0); - zt->references++; - INSIST(zt->references != 0); - - RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); + isc_refcount_increment(&zt->references); *ztp = zt; } @@ -228,8 +226,9 @@ flush(dns_zone_t *zone, void *uap) { static void zt_destroy(dns_zt_t *zt) { - if (zt->flush) + if (atomic_load_acquire(&zt->flush)) { (void)dns_zt_apply(zt, false, NULL, flush, NULL); + } dns_rbt_destroy(&zt->table); isc_rwlock_destroy(&zt->rwlock); zt->magic = 0; @@ -238,28 +237,20 @@ zt_destroy(dns_zt_t *zt) { static void zt_flushanddetach(dns_zt_t **ztp, bool need_flush) { - bool destroy = false; dns_zt_t *zt; REQUIRE(ztp != NULL && VALID_ZT(*ztp)); zt = *ztp; - - RWLOCK(&zt->rwlock, isc_rwlocktype_write); - - INSIST(zt->references > 0); - zt->references--; - if (zt->references == 0) - destroy = true; - if (need_flush) - zt->flush = true; - - RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); - - if (destroy) - zt_destroy(zt); - *ztp = NULL; + + if (need_flush) { + atomic_store_release(&zt->flush, true); + } + + if (isc_refcount_decrement(&zt->references) == 1) { + zt_destroy(zt); + } } void @@ -309,11 +300,15 @@ dns_zt_asyncload(dns_zt_t *zt, bool newonly, } zt->loadparams->dl = doneloading; zt->loadparams->newonly = newonly; + RWLOCK(&zt->rwlock, isc_rwlocktype_write); - INSIST(zt->loads_pending == 0); + + INSIST(isc_refcount_current(&zt->loads_pending) == 0); + result = dns_zt_apply(zt, false, NULL, asyncload, zt); - pending = zt->loads_pending; + pending = isc_refcount_current(&zt->loads_pending); + if (pending != 0) { zt->loaddone = alldone; zt->loaddone_arg = arg; @@ -340,15 +335,16 @@ asyncload(dns_zone_t *zone, void *zt_) { isc_result_t result; struct dns_zt *zt = (dns_zt_t*) zt_; REQUIRE(zone != NULL); - INSIST(zt->references > 0); - zt->references++; - zt->loads_pending++; + + isc_refcount_increment(&zt->references); + + isc_refcount_increment(&zt->loads_pending); result = dns_zone_asyncload(zone, zt->loadparams->newonly, *zt->loadparams->dl, zt); if (result != ISC_R_SUCCESS) { - zt->references--; - zt->loads_pending--; - INSIST(zt->references > 0); + + isc_refcount_decrement(&zt->references); + isc_refcount_decrement(&zt->loads_pending); } return (ISC_R_SUCCESS); } @@ -537,7 +533,6 @@ dns_zt_apply(dns_zt_t *zt, bool stop, isc_result_t *sub, */ static isc_result_t doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) { - bool destroy = false; dns_zt_allloaded_t alldone = NULL; void *arg = NULL; @@ -546,28 +541,21 @@ doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) { REQUIRE(VALID_ZT(zt)); - RWLOCK(&zt->rwlock, isc_rwlocktype_write); - INSIST(zt->loads_pending != 0); - INSIST(zt->references != 0); - zt->references--; - if (zt->references == 0) - destroy = true; - zt->loads_pending--; - if (zt->loads_pending == 0) { + if (isc_refcount_decrement(&zt->loads_pending) == 1) { alldone = zt->loaddone; arg = zt->loaddone_arg; zt->loaddone = NULL; zt->loaddone_arg = NULL; isc_mem_put(zt->mctx, zt->loadparams, sizeof(struct zt_load_params)); zt->loadparams = NULL; + if (alldone != NULL) { + alldone(arg); + } } - RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); - if (alldone != NULL) - alldone(arg); - - if (destroy) + if (isc_refcount_decrement(&zt->references) == 1) { zt_destroy(zt); + } return (ISC_R_SUCCESS); } diff --git a/lib/isc/counter.c b/lib/isc/counter.c index d0a16c5278..b5bbe46fd1 100644 --- a/lib/isc/counter.c +++ b/lib/isc/counter.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #define COUNTER_MAGIC ISC_MAGIC('C', 'n', 't', 'r') @@ -26,7 +27,7 @@ struct isc_counter { unsigned int magic; isc_mem_t *mctx; - atomic_uint_fast32_t references; + isc_refcount_t references; atomic_uint_fast32_t limit; atomic_uint_fast32_t used; }; @@ -44,9 +45,9 @@ isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp) { counter->mctx = NULL; isc_mem_attach(mctx, &counter->mctx); - atomic_store(&counter->references, 1); - atomic_store(&counter->limit, limit); - atomic_store(&counter->used, 0); + isc_refcount_init(&counter->references, 1); + atomic_init(&counter->limit, limit); + atomic_init(&counter->used, 0); counter->magic = COUNTER_MAGIC; *counterp = counter; @@ -55,22 +56,21 @@ isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp) { isc_result_t isc_counter_increment(isc_counter_t *counter) { - isc_result_t result = ISC_R_SUCCESS; + uint32_t used = atomic_fetch_add_relaxed(&counter->used, 1) + 1; + uint32_t limit = atomic_load_acquire(&counter->limit); - uint32_t used = atomic_fetch_add(&counter->used, 1) + 1; - if (atomic_load(&counter->limit) != 0 && - used >= atomic_load(&counter->limit)) { - result = ISC_R_QUOTA; + if (limit != 0 && used >= limit) { + return (ISC_R_QUOTA); } - return (result); + return (ISC_R_SUCCESS); } unsigned int isc_counter_used(isc_counter_t *counter) { REQUIRE(VALID_COUNTER(counter)); - return (atomic_load(&counter->used)); + return (atomic_load_acquire(&counter->used)); } void @@ -85,7 +85,7 @@ isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp) { REQUIRE(VALID_COUNTER(source)); REQUIRE(targetp != NULL && *targetp == NULL); - INSIST(atomic_fetch_add(&source->references, 1) > 0); + isc_refcount_increment(&source->references); *targetp = source; } @@ -99,7 +99,6 @@ destroy(isc_counter_t *counter) { void isc_counter_detach(isc_counter_t **counterp) { isc_counter_t *counter; - uint32_t oldrefs; REQUIRE(counterp != NULL && *counterp != NULL); counter = *counterp; @@ -107,10 +106,7 @@ isc_counter_detach(isc_counter_t **counterp) { *counterp = NULL; - oldrefs = atomic_fetch_sub(&counter->references, 1); - INSIST(oldrefs > 0); - - if (oldrefs == 1) { + if (isc_refcount_decrement(&counter->references) == 1) { destroy(counter); } } 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/isc/quota.c b/lib/isc/quota.c index 4ce36ddf82..2480fb8ad5 100644 --- a/lib/isc/quota.c +++ b/lib/isc/quota.c @@ -21,27 +21,27 @@ void isc_quota_init(isc_quota_t *quota, unsigned int max) { - atomic_store("a->max, max); - atomic_store("a->used, 0); - atomic_store("a->soft, 0); + atomic_init("a->max, max); + atomic_init("a->used, 0); + atomic_init("a->soft, 0); } void isc_quota_destroy(isc_quota_t *quota) { INSIST(atomic_load("a->used) == 0); - atomic_store("a->max, 0); - atomic_store("a->used, 0); - atomic_store("a->soft, 0); + atomic_store_release("a->max, 0); + atomic_store_release("a->used, 0); + atomic_store_release("a->soft, 0); } void isc_quota_soft(isc_quota_t *quota, unsigned int soft) { - atomic_store("a->soft, soft); + atomic_store_release("a->soft, soft); } void isc_quota_max(isc_quota_t *quota, unsigned int max) { - atomic_store("a->max, max); + atomic_store_release("a->max, max); } unsigned int @@ -62,9 +62,9 @@ isc_quota_getused(isc_quota_t *quota) { isc_result_t isc_quota_reserve(isc_quota_t *quota) { isc_result_t result; - uint32_t max = atomic_load("a->max); - uint32_t soft = atomic_load("a->soft); - uint32_t used = atomic_fetch_add("a->used, 1); + uint32_t max = atomic_load_acquire("a->max); + uint32_t soft = atomic_load_acquire("a->soft); + uint32_t used = atomic_fetch_add_relaxed("a->used, 1); if (max == 0 || used < max) { if (soft == 0 || used < soft) { result = ISC_R_SUCCESS; @@ -72,7 +72,7 @@ isc_quota_reserve(isc_quota_t *quota) { result = ISC_R_SOFTQUOTA; } } else { - INSIST(atomic_fetch_sub("a->used, 1) > 0); + INSIST(atomic_fetch_sub_release("a->used, 1) > 0); result = ISC_R_QUOTA; } return (result); @@ -80,7 +80,7 @@ isc_quota_reserve(isc_quota_t *quota) { void isc_quota_release(isc_quota_t *quota) { - INSIST(atomic_fetch_sub("a->used, 1) > 0); + INSIST(atomic_fetch_sub_release("a->used, 1) > 0); } static isc_result_t @@ -93,7 +93,7 @@ doattach(isc_quota_t *quota, isc_quota_t **p, bool force) { *p = quota; } else if (result == ISC_R_QUOTA && force) { /* attach anyway */ - atomic_fetch_add("a->used, 1); + atomic_fetch_add_relaxed("a->used, 1); *p = quota; result = ISC_R_SUCCESS; } diff --git a/lib/isc/stats.c b/lib/isc/stats.c index 123c6dff97..aa20f75402 100644 --- a/lib/isc/stats.c +++ b/lib/isc/stats.c @@ -37,7 +37,7 @@ typedef atomic_int_fast64_t isc_stat_t; struct isc_stats { unsigned int magic; isc_mem_t *mctx; - isc_refcount_t refs; + isc_refcount_t references; int ncounters; isc_stat_t *counters; }; @@ -50,7 +50,7 @@ create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) { stats = isc_mem_get(mctx, sizeof(*stats)); stats->counters = isc_mem_get(mctx, sizeof(isc_stat_t) * ncounters); - isc_refcount_init(&stats->refs, 1); + isc_refcount_init(&stats->references, 1); memset(stats->counters, 0, sizeof(isc_stat_t) * ncounters); stats->mctx = NULL; isc_mem_attach(mctx, &stats->mctx); @@ -66,7 +66,7 @@ isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp) { REQUIRE(ISC_STATS_VALID(stats)); REQUIRE(statsp != NULL && *statsp == NULL); - isc_refcount_increment(&stats->refs); + isc_refcount_increment(&stats->references); *statsp = stats; } @@ -79,7 +79,7 @@ isc_stats_detach(isc_stats_t **statsp) { stats = *statsp; *statsp = NULL; - if (isc_refcount_decrement(&stats->refs) == 1) { + if (isc_refcount_decrement(&stats->references) == 1) { isc_mem_put(stats->mctx, stats->counters, sizeof(isc_stat_t) * stats->ncounters); isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); diff --git a/lib/isc/task.c b/lib/isc/task.c index 000721fc16..b97ba306b6 100644 --- a/lib/isc/task.c +++ b/lib/isc/task.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -101,7 +102,7 @@ struct isc__task { isc_mutex_t lock; /* Locked by task lock. */ task_state_t state; - unsigned int references; + isc_refcount_t references; isc_eventlist_t events; isc_eventlist_t on_shutdown; unsigned int nevents; @@ -228,7 +229,7 @@ task_finished(isc__task_t *task) { REQUIRE(EMPTY(task->events)); REQUIRE(task->nevents == 0); REQUIRE(EMPTY(task->on_shutdown)); - REQUIRE(task->references == 0); + REQUIRE(atomic_load(&task->references) == 0); REQUIRE(task->state == task_state_done); XTRACE("task_finished"); @@ -295,7 +296,8 @@ isc_task_create_bound(isc_taskmgr_t *manager0, unsigned int quantum, isc_mutex_init(&task->lock); task->state = task_state_idle; - task->references = 1; + + isc_refcount_init(&task->references, 1); INIT_LIST(task->events); INIT_LIST(task->on_shutdown); task->nevents = 0; @@ -345,9 +347,7 @@ isc_task_attach(isc_task_t *source0, isc_task_t **targetp) { XTTRACE(source, "isc_task_attach"); - LOCK(&source->lock); - source->references++; - UNLOCK(&source->lock); + isc_refcount_increment(&source->references); *targetp = (isc_task_t *)source; } @@ -420,12 +420,11 @@ task_detach(isc__task_t *task) { * Caller must be holding the task lock. */ - REQUIRE(task->references > 0); - XTRACE("detach"); - task->references--; - if (task->references == 0 && task->state == task_state_idle) { + if (isc_refcount_decrement(&task->references) == 1 && + task->state == task_state_idle) + { INSIST(EMPTY(task->events)); /* * There are no references to this task, and no @@ -1140,7 +1139,7 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) { dispatch_count++; } - if (task->references == 0 && + if (isc_refcount_current(&task->references) == 0 && EMPTY(task->events) && !TASK_SHUTTINGDOWN(task)) { bool was_idle; @@ -1177,7 +1176,7 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) { * right now. */ XTRACE("empty"); - if (task->references == 0 && + if (isc_refcount_current(&task->references) == 0 && TASK_SHUTTINGDOWN(task)) { /* * The task is done. @@ -1244,7 +1243,8 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) { * we're stuck. Automatically drop privileges at that * point and continue with the regular ready queue. */ - if (manager->mode != isc_taskmgrmode_normal && + if (atomic_load_relaxed(&manager->mode) != + isc_taskmgrmode_normal && atomic_load_explicit(&manager->tasks_running, memory_order_acquire) == 0) { @@ -1257,7 +1257,8 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) { * we'll end up in a deadlock over queue locks. * */ - if (manager->mode != isc_taskmgrmode_normal && + if (atomic_load(&manager->mode) != + isc_taskmgrmode_normal && atomic_load_explicit(&manager->tasks_running, memory_order_acquire) == 0) { @@ -1361,10 +1362,10 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, manager->queues = isc_mem_get(mctx, workers * sizeof(isc__taskqueue_t)); RUNTIME_CHECK(manager->queues != NULL); - manager->tasks_running = 0; - manager->tasks_ready = 0; - manager->curq = 0; - manager->exiting = false; + atomic_init(&manager->tasks_running, 0); + atomic_init(&manager->tasks_ready, 0); + atomic_init(&manager->curq, 0); + atomic_init(&manager->exiting, false); manager->excl = NULL; manager->halted = 0; atomic_store_relaxed(&manager->exclusive_req, false); @@ -1530,8 +1531,8 @@ void isc__taskmgr_resume(isc_taskmgr_t *manager0) { isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; LOCK(&manager->halt_lock); - if (manager->pause_req) { - manager->pause_req = false; + if (atomic_load(&manager->pause_req)) { + atomic_store(&manager->pause_req, false); while (manager->halted > 0) { BROADCAST(&manager->halt_cond); WAIT(&manager->halt_cond, &manager->halt_lock); @@ -1732,8 +1733,8 @@ isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, void *writer0) { TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references")); - TRY0(xmlTextWriterWriteFormatString(writer, "%d", - task->references)); + TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIuFAST32, + isc_refcount_current(&task->references))); TRY0(xmlTextWriterEndElement(writer)); /* references */ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id")); @@ -1843,7 +1844,7 @@ isc_taskmgr_renderjson(isc_taskmgr_t *mgr0, void *tasks0) { json_object_object_add(taskobj, "name", obj); } - obj = json_object_new_int(task->references); + obj = json_object_new_int(isc_refcount_current(&task->references)); CHECKMEM(obj); json_object_object_add(taskobj, "references", obj); diff --git a/lib/isc/timer.c b/lib/isc/timer.c index 729fcb5608..b5455688f2 100644 --- a/lib/isc/timer.c +++ b/lib/isc/timer.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -61,8 +62,8 @@ struct isc__timer { isc_timer_t common; isc__timermgr_t * manager; isc_mutex_t lock; + isc_refcount_t references; /*! Locked by timer lock. */ - unsigned int references; isc_time_t idle; /*! Locked by manager lock. */ isc_timertype_t type; @@ -284,7 +285,7 @@ isc_timer_create(isc_timermgr_t *manager0, isc_timertype_t type, return (ISC_R_NOMEMORY); timer->manager = manager; - timer->references = 1; + isc_refcount_init(&timer->references, 1); if (type == isc_timertype_once && !isc_interval_iszero(interval)) { result = isc_time_add(&now, interval, &timer->idle); @@ -479,10 +480,7 @@ isc_timer_attach(isc_timer_t *timer0, isc_timer_t **timerp) { REQUIRE(VALID_TIMER(timer)); REQUIRE(timerp != NULL && *timerp == NULL); - - LOCK(&timer->lock); - timer->references++; - UNLOCK(&timer->lock); + isc_refcount_increment(&timer->references); *timerp = (isc_timer_t *)timer; } @@ -490,7 +488,6 @@ isc_timer_attach(isc_timer_t *timer0, isc_timer_t **timerp) { void isc_timer_detach(isc_timer_t **timerp) { isc__timer_t *timer; - bool free_timer = false; /* * Detach *timerp from its timer. @@ -500,15 +497,9 @@ isc_timer_detach(isc_timer_t **timerp) { timer = (isc__timer_t *)*timerp; REQUIRE(VALID_TIMER(timer)); - LOCK(&timer->lock); - REQUIRE(timer->references > 0); - timer->references--; - if (timer->references == 0) - free_timer = true; - UNLOCK(&timer->lock); - - if (free_timer) + if (isc_refcount_decrement(&timer->references) == 1) { destroy(timer); + } *timerp = NULL; } diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c index 7cf2e0426f..995261ede0 100644 --- a/lib/isc/win32/socket.c +++ b/lib/isc/win32/socket.c @@ -232,7 +232,7 @@ struct isc_socket { /* Locked by socket lock. */ ISC_LINK(isc_socket_t) link; - unsigned int references; /* EXTERNAL references */ + isc_refcount_t references; /* EXTERNAL references */ SOCKET fd; /* file handle */ int pf; /* protocol family */ char name[16]; @@ -392,7 +392,8 @@ sock_dump(isc_socket_t *sock) { printf("\n\t\tSock Dump\n"); printf("\t\tfd: %Iu\n", sock->fd); - printf("\t\treferences: %u\n", sock->references); + printf("\t\treferences: %" PRIuFAST32 "\n", + isc_refcount_current(sock->references)); printf("\t\tpending_accept: %u\n", sock->pending_accept); printf("\t\tconnecting: %u\n", sock->pending_connect); printf("\t\tconnected: %u\n", sock->connected); @@ -1320,7 +1321,7 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, return (ISC_R_NOMEMORY); sock->magic = 0; - sock->references = 0; + isc_refcount_init(&sock->references, 0); sock->manager = manager; sock->type = type; @@ -1449,7 +1450,7 @@ maybe_free_socket(isc_socket_t **socketp, int lineno) { || sock->pending_recv > 0 || sock->pending_send > 0 || sock->pending_accept > 0 - || sock->references > 0 + || isc_refcount_current(sock->references) > 0 || sock->pending_connect == 1 || !ISC_LIST_EMPTY(sock->recv_list) || !ISC_LIST_EMPTY(sock->send_list) @@ -1538,11 +1539,11 @@ socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, if (result != ISC_R_SUCCESS) { socket_log(__LINE__, sock, NULL, EVENT, - "closed %d %d %d " + "closed %d %d %" PRIuFAST32 " " "con_reset_fix_failed", sock->pending_recv, sock->pending_send, - sock->references); + isc_refcount_current(sock->references)); closesocket(sock->fd); _set_state(sock, SOCK_CLOSED); sock->fd = INVALID_SOCKET; @@ -1590,10 +1591,11 @@ socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, result = make_nonblock(sock->fd); if (result != ISC_R_SUCCESS) { + socket_log(__LINE__, sock, NULL, EVENT, - "closed %d %d %d make_nonblock_failed", - sock->pending_recv, sock->pending_send, - sock->references); + "closed %d %d %" PRIuFAST32 " make_nonblock_failed", + sock->pending_recv, sock->pending_send, + isc_refcount_current(sock->references)); closesocket(sock->fd); sock->fd = INVALID_SOCKET; free_socket(&sock, __LINE__); @@ -1647,7 +1649,7 @@ socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, #endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */ _set_state(sock, SOCK_OPEN); - sock->references = 1; + isc_refcount_init(&sock->references, 1); *socketp = sock; iocompletionport_update(sock); @@ -1723,9 +1725,10 @@ isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) { LOCK(&sock->lock); CONSISTENT(sock); - sock->references++; UNLOCK(&sock->lock); + isc_refcount_increment(&sock->references); + *socketp = sock; } @@ -1736,6 +1739,7 @@ isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) { void isc_socket_detach(isc_socket_t **socketp) { isc_socket_t *sock; + uint32_t refs; REQUIRE(socketp != NULL); sock = *socketp; @@ -1743,21 +1747,21 @@ isc_socket_detach(isc_socket_t **socketp) { LOCK(&sock->lock); CONSISTENT(sock); - REQUIRE(sock->references > 0); - sock->references--; + + references = isc_refcount_decrement(&socket->references); socket_log(__LINE__, sock, NULL, EVENT, - "detach_socket %d %d %d", - sock->pending_recv, sock->pending_send, - sock->references); + "detach_socket %d %d %" PRIuFAST32, + sock->pending_recv, sock->pending_send, + isc_refcount_current(sock->references)); - if (sock->references == 0 && sock->fd != INVALID_SOCKET) { + if (references == 1 && sock->fd != INVALID_SOCKET) { closesocket(sock->fd); sock->fd = INVALID_SOCKET; _set_state(sock, SOCK_CLOSED); } - maybe_free_socket(&sock, __LINE__); + maybe_free_socket(&sock, __LINE__); /* Also unlocks the socket lock */ *socketp = NULL; } @@ -2415,7 +2419,7 @@ SocketIoThread(LPVOID ThreadContext) { if (acceptdone_is_active(sock, lpo->adev)) { closesocket(lpo->adev->newsocket->fd); lpo->adev->newsocket->fd = INVALID_SOCKET; - lpo->adev->newsocket->references--; + isc_refcount_decrement(&lpo->adev->newsocket->references); free_socket(&lpo->adev->newsocket, __LINE__); lpo->adev->result = isc_result; socket_log(__LINE__, sock, NULL, EVENT, @@ -3109,7 +3113,7 @@ isc_socket_accept(isc_socket_t *sock, UNLOCK(&sock->lock); return (ISC_R_SHUTTINGDOWN); } - nsock->references++; + isc_refcount_decrement(&nsock->references); adev->ev_sender = ntask; adev->newsocket = nsock; @@ -3446,7 +3450,7 @@ isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) { if ((task == NULL) || (task == current_task)) { - dev->newsocket->references--; + isc_refcount_decrement(&dev->newsocket->references); closesocket(dev->newsocket->fd); dev->newsocket->fd = INVALID_SOCKET; free_socket(&dev->newsocket, __LINE__); @@ -3670,8 +3674,8 @@ isc_socketmgr_renderxml(isc_socketmgr_t *mgr, void *writer0) TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references")); - TRY0(xmlTextWriterWriteFormatString(writer, "%d", - sock->references)); + TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIuFAST32, + isc_refcount_current(sock->references))); TRY0(xmlTextWriterEndElement(writer)); TRY0(xmlTextWriterWriteElement(writer, ISC_XMLCHAR "type", @@ -3791,7 +3795,7 @@ isc_socketmgr_renderjson(isc_socketmgr_t *mgr, void *stats0) { json_object_object_add(entry, "name", obj); } - obj = json_object_new_int(sock->references); + obj = json_object_new_int(isc_refcount_current(&sock->references)); CHECKMEM(obj); json_object_object_add(entry, "references", obj); diff --git a/lib/ns/client.c b/lib/ns/client.c index c07e57cad1..dd054422e5 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -489,7 +489,7 @@ exit_check(ns_client_t *client) { } if (! (client->nsends == 0 && client->nrecvs == 0 && - client->references == 0)) + isc_refcount_current(&client->references) == 0)) { /* * Still waiting for I/O cancel completion. @@ -3175,7 +3175,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { client->nrecvs = 0; client->nupdates = 0; client->nctls = 0; - client->references = 0; + isc_refcount_init(&client->references, 0); client->attributes = 0; client->view = NULL; client->dispatch = NULL; @@ -3546,26 +3546,28 @@ client_udprecv(ns_client_t *client) { void ns_client_attach(ns_client_t *source, ns_client_t **targetp) { + uint32_t oldrefs; REQUIRE(NS_CLIENT_VALID(source)); REQUIRE(targetp != NULL && *targetp == NULL); - source->references++; + oldrefs = isc_refcount_increment(&source->references); ns_client_log(source, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), - "ns_client_attach: ref = %d", source->references); + "ns_client_attach: ref = %d", oldrefs+1); *targetp = source; } void ns_client_detach(ns_client_t **clientp) { + int32_t oldrefs; ns_client_t *client = *clientp; + oldrefs = isc_refcount_decrement(&client->references); + INSIST(oldrefs > 0); - client->references--; - INSIST(client->references >= 0); *clientp = NULL; ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), - "ns_client_detach: ref = %d", client->references); + "ns_client_detach: ref = %d", oldrefs-1); (void)exit_check(client); } @@ -3924,7 +3926,7 @@ ns__clientmgr_getclient(ns_clientmgr_t *manager, ns_interface_t *ifp, INSIST(client->recursionquota == NULL); client->dscp = ifp->dscp; - client->references++; + isc_refcount_increment(&client->references); if (tcp) { client->attributes |= NS_CLIENTATTR_TCP; diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index 110d25e953..02531f2118 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -101,7 +101,7 @@ struct ns_client { int nrecvs; int nupdates; int nctls; - int references; + isc_refcount_t references; bool tcpactive; bool needshutdown; /* * Used by clienttest to get diff --git a/lib/ns/include/ns/interfacemgr.h b/lib/ns/include/ns/interfacemgr.h index 6bbb0e67f3..82d76f9e41 100644 --- a/lib/ns/include/ns/interfacemgr.h +++ b/lib/ns/include/ns/interfacemgr.h @@ -68,7 +68,7 @@ struct ns_interface { unsigned int magic; /*%< Magic number. */ ns_interfacemgr_t * mgr; /*%< Interface manager. */ isc_mutex_t lock; - int references; /*%< Locked */ + isc_refcount_t references; unsigned int generation; /*%< Generation number. */ isc_sockaddr_t addr; /*%< Address and port. */ unsigned int flags; /*%< Interface characteristics */ diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index 2601fb800a..abb6be2795 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -64,7 +64,7 @@ /*% nameserver interface manager structure */ struct ns_interfacemgr { unsigned int magic; /*%< Magic number. */ - int references; + isc_refcount_t references; isc_mutex_t lock; isc_mem_t * mctx; /*%< Memory context. */ ns_server_t * sctx; /*%< Server context. */ @@ -253,9 +253,9 @@ ns_interfacemgr_create(isc_mem_t *mctx, mgr->task = NULL; if (mgr->route != NULL) isc_task_attach(task, &mgr->task); - mgr->references = (mgr->route != NULL) ? 2 : 1; + isc_refcount_init(&mgr->references, (mgr->route != NULL) ? 2 : 1); #else - mgr->references = 1; + isc_refcount_init(&mgr->references, 1); #endif mgr->magic = IFMGR_MAGIC; *mgrp = mgr; @@ -332,27 +332,18 @@ ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) { void ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) { REQUIRE(NS_INTERFACEMGR_VALID(source)); - LOCK(&source->lock); - INSIST(source->references > 0); - source->references++; - UNLOCK(&source->lock); + INSIST(isc_refcount_increment(&source->references) > 0); *target = source; } void ns_interfacemgr_detach(ns_interfacemgr_t **targetp) { - isc_result_t need_destroy = false; ns_interfacemgr_t *target = *targetp; REQUIRE(target != NULL); REQUIRE(NS_INTERFACEMGR_VALID(target)); - LOCK(&target->lock); - REQUIRE(target->references > 0); - target->references--; - if (target->references == 0) - need_destroy = true; - UNLOCK(&target->lock); - if (need_destroy) + if (isc_refcount_decrement(&target->references) == 1) { ns_interfacemgr_destroy(target); + } *targetp = NULL; } @@ -435,7 +426,7 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, ns_interfacemgr_attach(mgr, &ifp->mgr); ISC_LIST_APPEND(mgr->interfaces, ifp, link); - ifp->references = 1; + isc_refcount_init(&ifp->references, 1); ifp->magic = IFACE_MAGIC; *ifpret = ifp; @@ -667,27 +658,18 @@ ns_interface_destroy(ns_interface_t *ifp) { void ns_interface_attach(ns_interface_t *source, ns_interface_t **target) { REQUIRE(NS_INTERFACE_VALID(source)); - LOCK(&source->lock); - INSIST(source->references > 0); - source->references++; - UNLOCK(&source->lock); + isc_refcount_increment(&source->references); *target = source; } void ns_interface_detach(ns_interface_t **targetp) { - isc_result_t need_destroy = false; ns_interface_t *target = *targetp; REQUIRE(target != NULL); REQUIRE(NS_INTERFACE_VALID(target)); - LOCK(&target->lock); - REQUIRE(target->references > 0); - target->references--; - if (target->references == 0) - need_destroy = true; - UNLOCK(&target->lock); - if (need_destroy) + if (isc_refcount_decrement(&target->references) == 1) { ns_interface_destroy(target); + } *targetp = NULL; } diff --git a/lib/ns/lib.c b/lib/ns/lib.c index d2ef669b29..66e9025c06 100644 --- a/lib/ns/lib.c +++ b/lib/ns/lib.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -38,8 +39,7 @@ LIBNS_EXTERNAL_DATA unsigned int ns_pps = 0U; static isc_once_t init_once = ISC_ONCE_INIT; static isc_mem_t *ns_g_mctx = NULL; static bool initialize_done = false; -static isc_mutex_t reflock; -static unsigned int references = 0; +static isc_refcount_t references; static void initialize(void) { @@ -51,8 +51,7 @@ initialize(void) { if (result != ISC_R_SUCCESS) return; - isc_mutex_init(&reflock); - + isc_refcount_init(&references, 0); initialize_done = true; return; } @@ -73,25 +72,16 @@ ns_lib_init(void) { if (!initialize_done) return (ISC_R_FAILURE); - LOCK(&reflock); - references++; - UNLOCK(&reflock); + isc_refcount_increment(&references); return (ISC_R_SUCCESS); } void ns_lib_shutdown(void) { - bool cleanup_ok = false; - - LOCK(&reflock); - if (--references == 0) - cleanup_ok = true; - UNLOCK(&reflock); - - if (!cleanup_ok) - return; - - if (ns_g_mctx != NULL) - isc_mem_detach(&ns_g_mctx); + if (isc_refcount_decrement(&references) == 1) { + if (ns_g_mctx != NULL) { + isc_mem_detach(&ns_g_mctx); + } + } } diff --git a/lib/ns/query.c b/lib/ns/query.c index 9c8086cfc9..39709bba83 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -5691,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, @@ -5738,11 +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 = 0; +#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 " @@ -5755,12 +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 = 0; +#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/lib/ns/stats.c b/lib/ns/stats.c index 8a39a84940..b3769aece5 100644 --- a/lib/ns/stats.c +++ b/lib/ns/stats.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -25,11 +26,8 @@ struct ns_stats { /*% Unlocked */ unsigned int magic; isc_mem_t *mctx; - isc_mutex_t lock; isc_stats_t *counters; - - /*% Locked by lock */ - unsigned int references; + isc_refcount_t references; }; void @@ -37,9 +35,7 @@ ns_stats_attach(ns_stats_t *stats, ns_stats_t **statsp) { REQUIRE(NS_STATS_VALID(stats)); REQUIRE(statsp != NULL && *statsp == NULL); - LOCK(&stats->lock); - stats->references++; - UNLOCK(&stats->lock); + isc_refcount_increment(&stats->references); *statsp = stats; } @@ -53,13 +49,9 @@ ns_stats_detach(ns_stats_t **statsp) { stats = *statsp; *statsp = NULL; - LOCK(&stats->lock); - stats->references--; - UNLOCK(&stats->lock); - - if (stats->references == 0) { + if (isc_refcount_decrement(&stats->references) == 1) { isc_stats_detach(&stats->counters); - isc_mutex_destroy(&stats->lock); + isc_refcount_destroy(&stats->references); isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); } } @@ -72,17 +64,14 @@ ns_stats_create(isc_mem_t *mctx, int ncounters, ns_stats_t **statsp) { REQUIRE(statsp != NULL && *statsp == NULL); stats = isc_mem_get(mctx, sizeof(*stats)); - if (stats == NULL) - return (ISC_R_NOMEMORY); - stats->counters = NULL; - stats->references = 1; - isc_mutex_init(&stats->lock); + isc_refcount_init(&stats->references, 1); result = isc_stats_create(mctx, &stats->counters, ncounters); - if (result != ISC_R_SUCCESS) - goto clean_mutex; + if (result != ISC_R_SUCCESS) { + goto clean_mem; + } stats->magic = NS_STATS_MAGIC; stats->mctx = NULL; @@ -91,8 +80,7 @@ ns_stats_create(isc_mem_t *mctx, int ncounters, ns_stats_t **statsp) { return (ISC_R_SUCCESS); - clean_mutex: - isc_mutex_destroy(&stats->lock); + clean_mem: isc_mem_put(mctx, stats, sizeof(*stats)); return (result); 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