Merge branch '2433-improve-memory-contention' into 'main'

Resolve "investigate and improve lock contention around mctx"

Closes #2433

See merge request isc-projects/bind9!4659
This commit is contained in:
Ondřej Surý 2021-02-18 20:08:09 +00:00
commit 3547c0c1ff
31 changed files with 825 additions and 1498 deletions

View file

@ -896,7 +896,7 @@ unit:gcc:focal:amd64:
gcc:asan:
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0"
CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined"
LDFLAGS: "-fsanitize=address,undefined"
EXTRA_CONFIGURE: "--with-libidn2"
<<: *base_image
@ -923,7 +923,7 @@ unit:gcc:asan:
clang:asan:
variables:
CC: ${CLANG}
CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0"
CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined"
LDFLAGS: "-fsanitize=address,undefined"
EXTRA_CONFIGURE: "--with-libidn2"
<<: *base_image
@ -954,7 +954,7 @@ gcc:tsan:
<<: *build_job
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -fsanitize=thread -DISC_MEM_USE_INTERNAL_MALLOC=0"
CFLAGS: "${CFLAGS_COMMON} -fsanitize=thread"
LDFLAGS: "-fsanitize=thread"
EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock"
@ -981,7 +981,7 @@ clang:tsan:
<<: *build_job
variables:
CC: "${CLANG}"
CFLAGS: "${CFLAGS_COMMON} -fsanitize=thread -DISC_MEM_USE_INTERNAL_MALLOC=0"
CFLAGS: "${CFLAGS_COMMON} -fsanitize=thread"
LDFLAGS: "-fsanitize=thread"
EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock"
@ -1008,7 +1008,7 @@ unit:clang:tsan:
gcc:mutexatomics:
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -DISC_MEM_USE_INTERNAL_MALLOC=0"
CFLAGS: "${CFLAGS_COMMON}"
EXTRA_CONFIGURE: "--with-libidn2 --enable-mutex-atomics"
<<: *base_image
<<: *build_job

View file

@ -1,3 +1,11 @@
5585. [func] Implementations of memory contexts and memory pools were
refactored to reduce lock contention for shared memory
contexts by replacing mutexes with atomic operations.
The internal memory allocator was simplified so that it
is only a thin wrapper around the system allocator.
Since this change makes the "-M external" named option
redundant, the latter was removed. [GL #2433]
5584. [bug] Rollback setting IP_DONTFRAG option on the UDP sockets.
[GL #2487]

View file

@ -1401,7 +1401,7 @@ setup_libs(void) {
}
isc_mem_create(&mctx);
isc_mem_setname(mctx, "dig", NULL);
isc_mem_setname(mctx, "dig");
isc_log_create(mctx, &lctx, &logconfig);
isc_log_setcontext(lctx);

View file

@ -440,8 +440,7 @@ static struct flag_def {
{ "size", ISC_MEM_DEBUGSIZE, false },
{ "mctx", ISC_MEM_DEBUGCTX, false },
{ NULL, 0, false } },
mem_context_flags[] = { { "external", ISC_MEMFLAG_INTERNAL, true },
{ "fill", ISC_MEMFLAG_FILL, false },
mem_context_flags[] = { { "fill", ISC_MEMFLAG_FILL, false },
{ "nofill", ISC_MEMFLAG_FILL, true },
{ NULL, 0, false } };
@ -1525,15 +1524,6 @@ main(int argc, char *argv[]) {
pk11_result_register();
#endif /* if USE_PKCS11 */
#if !ISC_MEM_DEFAULTFILL
/*
* Update the default flags to remove ISC_MEMFLAG_FILL
* before we parse the command line. If disabled here,
* it can be turned back on with -M fill.
*/
isc_mem_defaultflags &= ~ISC_MEMFLAG_FILL;
#endif /* if !ISC_MEM_DEFAULTFILL */
parse_command_line(argc, argv);
#ifdef ENABLE_AFL
@ -1564,7 +1554,7 @@ main(int argc, char *argv[]) {
}
isc_mem_create(&named_g_mctx);
isc_mem_setname(named_g_mctx, "main", NULL);
isc_mem_setname(named_g_mctx, "main");
setup();

View file

@ -4617,9 +4617,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
* memory.
*/
isc_mem_create(&cmctx);
isc_mem_setname(cmctx, "cache", NULL);
isc_mem_setname(cmctx, "cache");
isc_mem_create(&hmctx);
isc_mem_setname(hmctx, "cache_heap", NULL);
isc_mem_setname(hmctx, "cache_heap");
CHECK(dns_cache_create(cmctx, hmctx, named_g_taskmgr,
named_g_timermgr, view->rdclass,
cachename, "rbt", 0, NULL,

View file

@ -236,7 +236,7 @@ sub construct_ns_command {
$command .= "--tool=memcheck --track-origins=yes --leak-check=full ";
}
$command .= "$NAMED -m none -M external ";
$command .= "$NAMED -m none ";
} else {
if ($taskset) {
$command = "taskset $taskset $NAMED ";

View file

@ -158,7 +158,7 @@ AC_ARG_ENABLE([developer],
AS_IF([test "$enable_developer" = "yes"],
[DEVELOPER_MODE=yes
STD_CPPFLAGS="$STD_CPPFLAGS -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1"
STD_CPPFLAGS="$STD_CPPFLAGS -DISC_MEM_DEFAULTFILL=1 -DISC_MEM_TRACKLINES=1 -DISC_LIST_CHECKINIT=1"
test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes
test "${enable_querytrace+set}" = set || enable_querytrace=yes
test "${with_cmocka+set}" = set || with_cmocka=yes
@ -1580,6 +1580,12 @@ test -z "$with_dlz_stub" && with_dlz_stub=no
AC_CHECK_HEADERS([glob.h])
#
# Support for constructor and destructor attributes
#
AX_GCC_FUNC_ATTRIBUTE([constructor])
AX_GCC_FUNC_ATTRIBUTE([destructor])
#
# Files to configure. These are listed here because we used to
# specify them as arguments to AC_OUTPUT.

View file

@ -201,7 +201,7 @@ dst_lib_init(isc_mem_t *mctx, const char *engine) {
RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
RETERR(dst__openssl_init(mctx, engine));
RETERR(dst__openssl_init(engine));
RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
#if USE_OPENSSL
RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1],

View file

@ -201,7 +201,7 @@ struct dst_func {
* Initializers
*/
isc_result_t
dst__openssl_init(isc_mem_t *, const char *engine);
dst__openssl_init(const char *engine);
#define dst__pkcs11_init pk11_initialize
isc_result_t

View file

@ -39,8 +39,6 @@
#include "dst_internal.h"
#include "dst_openssl.h"
static isc_mem_t *dst__mctx = NULL;
#if !defined(OPENSSL_NO_ENGINE)
#include <openssl/engine.h>
#endif /* if !defined(OPENSSL_NO_ENGINE) */
@ -67,36 +65,12 @@ enable_fips_mode(void) {
}
isc_result_t
dst__openssl_init(isc_mem_t *mctx, const char *engine) {
isc_result_t result;
REQUIRE(dst__mctx == NULL);
isc_mem_attach(mctx, &dst__mctx);
#if defined(OPENSSL_NO_ENGINE)
UNUSED(engine);
#endif /* if defined(OPENSSL_NO_ENGINE) */
dst__openssl_init(const char *engine) {
isc_result_t result = ISC_R_SUCCESS;
enable_fips_mode();
isc_tls_initialize();
#if !defined(OPENSSL_NO_ENGINE)
#if !defined(CONF_MFLAGS_DEFAULT_SECTION)
OPENSSL_config(NULL);
#else /* if !defined(CONF_MFLAGS_DEFAULT_SECTION) */
/*
* OPENSSL_config() can only be called a single time as of
* 1.0.2e so do the steps individually.
*/
OPENSSL_load_builtin_modules();
ENGINE_load_builtin_engines();
ERR_clear_error();
CONF_modules_load_file(NULL, NULL,
CONF_MFLAGS_DEFAULT_SECTION |
CONF_MFLAGS_IGNORE_MISSING_FILE);
#endif /* if !defined(CONF_MFLAGS_DEFAULT_SECTION) */
if (engine != NULL && *engine == '\0') {
engine = NULL;
}
@ -114,54 +88,26 @@ dst__openssl_init(isc_mem_t *mctx, const char *engine) {
}
}
#endif /* !defined(OPENSSL_NO_ENGINE) */
/* Protect ourselves against unseeded PRNG */
if (RAND_status() != 1) {
FATAL_ERROR(__FILE__, __LINE__,
"OpenSSL pseudorandom number generator "
"cannot be initialized (see the `PRNG not "
"seeded' message in the OpenSSL FAQ)");
}
return (ISC_R_SUCCESS);
#if !defined(OPENSSL_NO_ENGINE)
cleanup_rm:
if (e != NULL) {
ENGINE_free(e);
}
e = NULL;
#else
UNUSED(engine);
#endif /* if !defined(OPENSSL_NO_ENGINE) */
return (result);
}
void
dst__openssl_destroy(void) {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
/*
* Sequence taken from apps_shutdown() in <apps/apps.h>.
*/
CONF_modules_free();
OBJ_cleanup();
EVP_cleanup();
#if !defined(OPENSSL_NO_ENGINE)
if (e != NULL) {
ENGINE_free(e);
}
e = NULL;
ENGINE_cleanup();
#endif /* if !defined(OPENSSL_NO_ENGINE) */
CRYPTO_cleanup_all_ex_data();
ERR_clear_error();
#ifdef DNS_CRYPTO_LEAKS
CRYPTO_mem_leaks_fp(stderr);
#endif /* ifdef DNS_CRYPTO_LEAKS */
#endif
isc_tls_destroy();
isc_mem_detach(&dst__mctx);
}
static isc_result_t

View file

@ -10409,7 +10409,7 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr,
* enabling threads because it will be require more memory.
*/
isc_mem_create(&res->buckets[i].mctx);
isc_mem_setname(res->buckets[i].mctx, name, NULL);
isc_mem_setname(res->buckets[i].mctx, name);
isc_task_setname(res->buckets[i].task, name, res);
ISC_LIST_INIT(res->buckets[i].fctxs);
atomic_init(&res->buckets[i].exiting, false);

View file

@ -828,7 +828,7 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr,
isc_mem_create(&mctx);
result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
isc_mem_setname(mctx, "ADB", NULL);
isc_mem_setname(mctx, "ADB");
isc_mem_detach(&mctx);
if (result != ISC_R_SUCCESS) {
dns_resolver_shutdown(view->resolver);

View file

@ -18358,7 +18358,7 @@ mctxinit(void **target, void *arg) {
REQUIRE(target != NULL && *target == NULL);
isc_mem_create(&mctx);
isc_mem_setname(mctx, "zonemgr-pool", NULL);
isc_mem_setname(mctx, "zonemgr-pool");
*target = mctx;
return (ISC_R_SUCCESS);

View file

@ -33,33 +33,9 @@ typedef void (*isc_mem_water_t)(void *, int);
* allocation and freeing by file and line number.
*/
#ifndef ISC_MEM_TRACKLINES
#define ISC_MEM_TRACKLINES 1
#define ISC_MEM_TRACKLINES 0
#endif /* ifndef ISC_MEM_TRACKLINES */
/*%
* Define ISC_MEM_CHECKOVERRUN=1 to turn on checks for using memory outside
* the requested space. This will increase the size of each allocation.
*
* If we are performing a Coverity static analysis then ISC_MEM_CHECKOVERRUN
* can hide bugs that would otherwise discovered so force to zero.
*/
#ifdef __COVERITY__
#undef ISC_MEM_CHECKOVERRUN
#define ISC_MEM_CHECKOVERRUN 0
#endif /* ifdef __COVERITY__ */
#ifndef ISC_MEM_CHECKOVERRUN
#define ISC_MEM_CHECKOVERRUN 1
#endif /* ifndef ISC_MEM_CHECKOVERRUN */
/*%
* Define ISC_MEMPOOL_NAMES=1 to make memory pools store a symbolic
* name so that the leaking pool can be more readily identified in
* case of a memory leak.
*/
#ifndef ISC_MEMPOOL_NAMES
#define ISC_MEMPOOL_NAMES 1
#endif /* ifndef ISC_MEMPOOL_NAMES */
LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_debugging;
LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_defaultflags;
@ -106,31 +82,22 @@ LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_defaultflags;
#define _ISC_MEM_FLARG
#endif /* if ISC_MEM_TRACKLINES */
/*!
* Define ISC_MEM_USE_INTERNAL_MALLOC=1 to use the internal malloc()
* implementation in preference to the system one. The internal malloc()
* is very space-efficient, and quite fast on uniprocessor systems. It
* performs poorly on multiprocessor machines.
* JT: we can overcome the performance issue on multiprocessor machines
* by carefully separating memory contexts.
*/
#ifndef ISC_MEM_USE_INTERNAL_MALLOC
#define ISC_MEM_USE_INTERNAL_MALLOC 1
#endif /* ifndef ISC_MEM_USE_INTERNAL_MALLOC */
/*
* Flags for isc_mem_create() calls.
*/
#define ISC_MEMFLAG_RESERVED 0x00000001 /* reserved, obsoleted, don't use */
#define ISC_MEMFLAG_INTERNAL 0x00000002 /* use internal malloc */
#define ISC_MEMFLAG_RESERVED1 0x00000001 /* reserved, obsoleted, don't use */
#define ISC_MEMFLAG_RESERVED2 0x00000002 /* reserved, obsoleted, don't use */
#define ISC_MEMFLAG_FILL \
0x00000004 /* fill with pattern after alloc and frees */
#if !ISC_MEM_USE_INTERNAL_MALLOC
#define ISC_MEMFLAG_DEFAULT 0
/*%
* Define ISC_MEM_DEFAULTFILL=1 to turn filling the memory with pattern
* after alloc and free.
*/
#if ISC_MEM_DEFAULTFILL
#define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_FILL
#else /* if !ISC_MEM_USE_INTERNAL_MALLOC */
#define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_INTERNAL | ISC_MEMFLAG_FILL
#define ISC_MEMFLAG_DEFAULT 0
#endif /* if !ISC_MEM_USE_INTERNAL_MALLOC */
/*%
@ -162,52 +129,6 @@ LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_defaultflags;
* \endcode
*/
/*% memory and memory pool methods */
typedef struct isc_memmethods {
void *(*memget)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG);
void (*memput)(isc_mem_t *mctx, void *ptr, size_t size _ISC_MEM_FLARG);
void (*memputanddetach)(isc_mem_t **mctxp, void *ptr,
size_t size _ISC_MEM_FLARG);
void *(*memallocate)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG);
void *(*memreallocate)(isc_mem_t *mctx, void *ptr,
size_t size _ISC_MEM_FLARG);
char *(*memstrdup)(isc_mem_t *mctx, const char *s _ISC_MEM_FLARG);
char *(*memstrndup)(isc_mem_t *mctx, const char *s,
size_t size _ISC_MEM_FLARG);
void (*memfree)(isc_mem_t *mctx, void *ptr _ISC_MEM_FLARG);
} isc_memmethods_t;
/*%
* This structure is actually just the common prefix of a memory context
* implementation's version of an isc_mem_t.
* \brief
* Direct use of this structure by clients is forbidden. mctx implementations
* may change the structure. 'magic' must be ISCAPI_MCTX_MAGIC for any of the
* isc_mem_ routines to work. mctx implementations must maintain all mctx
* invariants.
*/
struct isc_mem {
unsigned int impmagic;
unsigned int magic;
isc_memmethods_t *methods;
};
#define ISCAPI_MCTX_MAGIC ISC_MAGIC('A', 'm', 'c', 'x')
#define ISCAPI_MCTX_VALID(m) ((m) != NULL && (m)->magic == ISCAPI_MCTX_MAGIC)
/*%
* This is the common prefix of a memory pool context. The same note as
* that for the mem structure applies.
*/
struct isc_mempool {
unsigned int impmagic;
unsigned int magic;
};
#define ISCAPI_MPOOL_MAGIC ISC_MAGIC('A', 'm', 'p', 'l')
#define ISCAPI_MPOOL_VALID(mp) \
((mp) != NULL && (mp)->magic == ISCAPI_MPOOL_MAGIC)
/*%
* These functions are actually implemented in isc__mem_<function>
* (two underscores). The single-underscore macros are used to pass
@ -324,6 +245,19 @@ isc_mem_total(isc_mem_t *mctx);
* not yet used.
*/
size_t
isc_mem_malloced(isc_mem_t *ctx);
/*%<
* Get an estimate of the amount of memory allocated in 'mctx', in bytes.
*/
size_t
isc_mem_maxmalloced(isc_mem_t *ctx);
/*%<
* Get an estimate of the largest amount of memory that has been
* allocated in 'mctx' at any time.
*/
bool
isc_mem_isovermem(isc_mem_t *mctx);
/*%<
@ -339,13 +273,13 @@ isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg,
* Set high and low water marks for this memory context.
*
* When the memory usage of 'mctx' exceeds 'hiwater',
* '(water)(water_arg, #ISC_MEM_HIWATER)' will be called. 'water' needs to
* call isc_mem_waterack() with #ISC_MEM_HIWATER to acknowledge the state
* change. 'water' may be called multiple times.
* '(water)(water_arg, #ISC_MEM_HIWATER)' will be called. 'water' needs
*to call isc_mem_waterack() with #ISC_MEM_HIWATER to acknowledge the
*state change. 'water' may be called multiple times.
*
* When the usage drops below 'lowater', 'water' will again be called, this
* time with #ISC_MEM_LOWATER. 'water' need to calls isc_mem_waterack() with
* #ISC_MEM_LOWATER to acknowledge the change.
* When the usage drops below 'lowater', 'water' will again be called,
*this time with #ISC_MEM_LOWATER. 'water' need to calls
*isc_mem_waterack() with #ISC_MEM_LOWATER to acknowledge the change.
*
* static void
* water(void *arg, int mark) {
@ -390,7 +324,7 @@ isc_mem_references(isc_mem_t *ctx);
*/
void
isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag);
isc_mem_setname(isc_mem_t *ctx, const char *name);
/*%<
* Name 'ctx'.
*
@ -398,8 +332,6 @@ isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag);
*
*\li Only the first 15 characters of 'name' will be copied.
*
*\li 'tag' is for debugging purposes only.
*
* Requires:
*
*\li 'ctx' is a valid ctx.
@ -419,21 +351,6 @@ isc_mem_getname(isc_mem_t *ctx);
* empty.
*/
void *
isc_mem_gettag(isc_mem_t *ctx);
/*%<
* Get the tag value for 'task', as previously set using isc_mem_setname().
*
* Requires:
*\li 'ctx' is a valid ctx.
*
* Notes:
*\li This function is for debugging purposes only.
*
* Requires:
*\li 'ctx' is a valid task.
*/
#ifdef HAVE_LIBXML2
int
isc_mem_renderxml(void *writer0);
@ -487,7 +404,8 @@ isc_mempool_destroy(isc_mempool_t **mpctxp);
void
isc_mempool_setname(isc_mempool_t *mpctx, const char *name);
/*%<
* Associate a name with a memory pool. At most 15 characters may be used.
* Associate a name with a memory pool. At most 15 characters may be
*used.
*
* Requires:
*\li mpctx is a valid pool.
@ -499,15 +417,15 @@ isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
/*%<
* Associate a lock with this memory pool.
*
* This lock is used when getting or putting items using this memory pool,
* and it is also used to set or get internal state via the isc_mempool_get*()
* and isc_mempool_set*() set of functions.
* This lock is used when getting or putting items using this memory
*pool, and it is also used to set or get internal state via the
*isc_mempool_get*() and isc_mempool_set*() set of functions.
*
* Multiple pools can each share a single lock. For instance, if "manager"
* type object contained pools for various sizes of events, and each of
* these pools used a common lock. Note that this lock must NEVER be used
* by other than mempool routines once it is given to a pool, since that can
* easily cause double locking.
* Multiple pools can each share a single lock. For instance, if
*"manager" type object contained pools for various sizes of events, and
*each of these pools used a common lock. Note that this lock must
*NEVER be used by other than mempool routines once it is given to a
*pool, since that can easily cause double locking.
*
* Requires:
*
@ -517,19 +435,19 @@ isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
*
*\li No previous lock is assigned to this pool.
*
*\li The lock is initialized before calling this function via the normal
* means of doing that.
*\li The lock is initialized before calling this function via the
*normal means of doing that.
*/
/*
* The following functions get/set various parameters. Note that due to
* the unlocked nature of pools these are potentially random values unless
* the imposed externally provided locking protocols are followed.
* the unlocked nature of pools these are potentially random values
*unless the imposed externally provided locking protocols are followed.
*
* Also note that the quota limits will not always take immediate effect.
* For instance, setting "maxalloc" to a number smaller than the currently
* allocated count is permitted. New allocations will be refused until
* the count drops below this threshold.
* Also note that the quota limits will not always take immediate
*effect. For instance, setting "maxalloc" to a number smaller than the
*currently allocated count is permitted. New allocations will be
*refused until the count drops below this threshold.
*
* All functions require (in addition to other requirements):
* mpctx is a valid memory pool
@ -577,8 +495,8 @@ isc_mempool_getallocated(isc_mempool_t *mpctx);
unsigned int
isc_mempool_getfillcount(isc_mempool_t *mpctx);
/*%<
* Returns the number of items allocated as a block from the parent memory
* context when the free list is empty.
* Returns the number of items allocated as a block from the parent
* memory context when the free list is empty.
*/
void

View file

@ -19,12 +19,6 @@
typedef struct ssl_ctx_st isc_tlsctx_t;
void
isc_tls_initialize(void);
void
isc_tls_destroy(void);
void
isc_tlsctx_free(isc_tlsctx_t **ctpx);
/*%

View file

@ -48,6 +48,16 @@
#define ISC_NONSTRING
#endif /* __GNUC__ */
#if HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR && HAVE_FUNC_ATTRIBUTE_DESTRUCTOR
#define ISC_CONSTRUCTOR(priority) __attribute__((constructor(priority)))
#define ISC_DESTRUCTOR(priority) __attribute__((destructor(priority)))
#elif WIN32
#define ISC_CONSTRUCTOR(priority)
#define ISC_DESTRUCTOR(priority)
#else
#error Either __attribute__((constructor|destructor))__ or DllMain support needed to compile BIND 9.
#endif
/*%
* The opposite: silent warnings about stored values which are never read.
*/

View file

@ -13,6 +13,12 @@
#include <isc/bind9.h>
#include <isc/lib.h>
#include <isc/mem.h>
#include <isc/tls.h>
#include <isc/util.h>
#include "mem_p.h"
#include "tls_p.h"
/***
*** Functions
@ -22,3 +28,20 @@ void
isc_lib_register(void) {
isc_bind9 = false;
}
void
isc__initialize(void) ISC_CONSTRUCTOR(101);
void
isc__shutdown(void) ISC_DESTRUCTOR(101);
void
isc__initialize(void) {
isc__mem_initialize();
isc__tls_initialize();
}
void
isc__shutdown(void) {
isc__tls_shutdown();
isc__mem_shutdown();
}

File diff suppressed because it is too large Load diff

View file

@ -9,8 +9,11 @@
* information regarding copyright ownership.
*/
#ifndef ISC_MEM_P_H
#define ISC_MEM_P_H
#pragma once
#include <stdio.h>
#include <isc/mem.h>
/*! \file */
@ -21,4 +24,11 @@ isc__mem_printactive(isc_mem_t *mctx, FILE *file);
* a single memory context.
*/
#endif /* ISC_MEM_P_H */
void
isc__mem_checkdestroyed(void);
void
isc__mem_initialize(void);
void
isc__mem_shutdown(void);

View file

@ -216,8 +216,6 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) {
isc__nm_winsock_initialize();
#endif /* WIN32 */
isc_tls_initialize();
mgr = isc_mem_get(mctx, sizeof(*mgr));
*mgr = (isc_nm_t){ .nworkers = workers };
@ -374,8 +372,6 @@ nm_destroy(isc_nm_t **mgr0) {
mgr->nworkers * sizeof(isc__networker_t));
isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
isc_tls_destroy();
#ifdef WIN32
isc__nm_winsock_destroy();
#endif /* WIN32 */

View file

@ -999,7 +999,7 @@ processbuffer(isc_nmsocket_t *sock) {
len += 2;
sock->buf_len -= len;
if (len > 0) {
if (sock->buf_len > 0) {
memmove(sock->buf, sock->buf + len, sock->buf_len);
}

View file

@ -398,6 +398,7 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
REQUIRE(VALID_NM(mgr));
REQUIRE(local != NULL);
REQUIRE(peer != NULL);
REQUIRE(sslctx != NULL);
sa_family = peer->addr.type.sa.sa_family;
@ -1147,7 +1148,7 @@ processbuffer(isc_nmsocket_t *sock) {
len += 2;
sock->buf_len -= len;
if (len > 0) {
if (sock->buf_len > 0) {
memmove(sock->buf, sock->buf + len, sock->buf_len);
}
@ -1656,6 +1657,16 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
csock->tls.state = TLS_STATE_NONE;
csock->tls.ssl = SSL_new(ssock->tls.ctx);
if (csock->tls.ssl == NULL) {
char errbuf[256];
unsigned long err = ERR_get_error();
ERR_error_string_n(err, errbuf, sizeof(errbuf));
fprintf(stderr, "%s:SSL_new(%p) -> %s\n", __func__,
ssock->tls.ctx, errbuf);
}
RUNTIME_CHECK(csock->tls.ssl != NULL);
r = BIO_new_bio_pair(&csock->tls.ssl_wbio, TLS_BUF_SIZE,

View file

@ -19,6 +19,7 @@
#include <isc/buffer.h>
#include <isc/hash.h>
#include <isc/hp.h>
#include <isc/mem.h>
#include <isc/os.h>
#include <isc/socket.h>
@ -85,6 +86,8 @@ create_managers(unsigned int workers) {
workers = atoi(p);
}
isc_hp_init(ISC_MAX(ISC_MIN(workers, 256), 128));
netmgr = isc_nm_start(test_mctx, workers);
CHECK(isc_taskmgr_create(test_mctx, workers, 0, netmgr, &taskmgr));
CHECK(isc_task_create(taskmgr, 0, &maintask));

View file

@ -22,6 +22,7 @@
#define UNIT_TESTING
#include <cmocka.h>
#include <isc/atomic.h>
#include <isc/file.h>
#include <isc/mem.h>
#include <isc/mutex.h>
@ -372,17 +373,22 @@ isc_mem_traceflag_test(void **state) {
#define NUM_ITEMS 1024 /* 768 */
#define ITEM_SIZE 65534
static atomic_size_t mem_size;
static isc_threadresult_t
mem_thread(isc_threadarg_t arg) {
isc_mem_t *mctx = (isc_mem_t *)arg;
void *items[NUM_ITEMS];
size_t size = *((size_t *)arg);
size_t size = atomic_load(&mem_size);
while (!atomic_compare_exchange_weak(&mem_size, &size, size / 2))
;
for (int i = 0; i < ITERS; i++) {
for (int j = 0; j < NUM_ITEMS; j++) {
items[j] = isc_mem_get(test_mctx, size);
items[j] = isc_mem_get(mctx, size);
}
for (int j = 0; j < NUM_ITEMS; j++) {
isc_mem_put(test_mctx, items[j], size);
isc_mem_put(mctx, items[j], size);
}
}
@ -396,16 +402,16 @@ isc_mem_benchmark(void **state) {
isc_time_t ts1, ts2;
double t;
isc_result_t result;
size_t size = ITEM_SIZE;
UNUSED(state);
atomic_init(&mem_size, ITEM_SIZE);
result = isc_time_now(&ts1);
assert_int_equal(result, ISC_R_SUCCESS);
for (int i = 0; i < nthreads; i++) {
isc_thread_create(mem_thread, &size, &threads[i]);
size = size / 2;
isc_thread_create(mem_thread, test_mctx, &threads[i]);
}
for (int i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);
@ -446,7 +452,6 @@ isc_mempool_benchmark(void **state) {
isc_time_t ts1, ts2;
double t;
isc_result_t result;
size_t size = ITEM_SIZE;
isc_mempool_t *mp = NULL;
isc_mutex_t mplock;
@ -466,7 +471,6 @@ isc_mempool_benchmark(void **state) {
for (int i = 0; i < nthreads; i++) {
isc_thread_create(mempool_thread, mp, &threads[i]);
size = size / 2;
}
for (int i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);

View file

@ -217,8 +217,13 @@ nm_setup(void **state) {
int tlsdns_listen_sock = -1;
isc_nm_t **nm = NULL;
isc_tlsctx_createserver(NULL, NULL, &tlsdns_listen_ctx);
isc_tlsctx_createclient(&tlsdns_connect_ctx);
if (isc_tlsctx_createserver(NULL, NULL, &tlsdns_listen_ctx) !=
ISC_R_SUCCESS) {
return (-1);
}
if (isc_tlsctx_createclient(&tlsdns_connect_ctx) != ISC_R_SUCCESS) {
return (-1);
}
tlsdns_listen_addr = (isc_sockaddr_t){ .length = 0 };
tlsdns_listen_sock = setup_ephemeral_port(&tlsdns_listen_addr,

View file

@ -9,8 +9,10 @@
* information regarding copyright ownership.
*/
#include <openssl/conf.h>
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include <openssl/rand.h>
#include <isc/atomic.h>
#include <isc/log.h>
@ -22,12 +24,14 @@
#include <isc/util.h>
#include "openssl_shim.h"
#include "tls_p.h"
static isc_once_t init_once = ISC_ONCE_INIT;
static isc_once_t shut_once = ISC_ONCE_INIT;
static atomic_bool init_done = ATOMIC_VAR_INIT(false);
static atomic_bool shut_done = ATOMIC_VAR_INIT(false);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static isc_mem_t *isc__tls_mctx = NULL;
static isc_mutex_t *locks = NULL;
static int nlocks;
@ -49,50 +53,104 @@ isc__tls_set_thread_id(CRYPTO_THREADID *id) {
#endif
static void
isc__tls_initialize(void) {
tls_initialize(void) {
REQUIRE(!atomic_load(&init_done));
RUNTIME_CHECK(OPENSSL_init_ssl(0, NULL) == 1);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
isc_mem_create(&isc__tls_mctx);
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
RUNTIME_CHECK(OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN |
OPENSSL_INIT_LOAD_CONFIG,
NULL) == 1);
#else
nlocks = CRYPTO_num_locks();
locks = isc_mem_get(isc__tls_mctx, nlocks * sizeof(locks[0]));
/*
* We can't use isc_mem API here, because it's called too
* early and when the isc_mem_debugging flags are changed
* later and ISC_MEM_DEBUGSIZE or ISC_MEM_DEBUGCTX flags are
* added, neither isc_mem_put() nor isc_mem_free() can be used
* to free up the memory allocated here because the flags were
* not set when calling isc_mem_get() or isc_mem_allocate()
* here.
*
* Actually, since this is a single allocation at library load
* and deallocation at library unload, using the standard
* allocator without the tracking is fine for this purpose.
*/
locks = calloc(nlocks, sizeof(locks[0]));
isc_mutexblock_init(locks, nlocks);
CRYPTO_set_locking_callback(isc__tls_lock_callback);
CRYPTO_THREADID_set_callback(isc__tls_set_thread_id);
CRYPTO_malloc_init();
ERR_load_crypto_strings();
SSL_load_error_strings();
SSL_library_init();
#if !defined(OPENSSL_NO_ENGINE)
ENGINE_load_builtin_engines();
#endif
atomic_store(&init_done, true);
OpenSSL_add_all_algorithms();
OPENSSL_load_builtin_modules();
CONF_modules_load_file(NULL, NULL,
CONF_MFLAGS_DEFAULT_SECTION |
CONF_MFLAGS_IGNORE_MISSING_FILE);
#endif
/* Protect ourselves against unseeded PRNG */
if (RAND_status() != 1) {
FATAL_ERROR(__FILE__, __LINE__,
"OpenSSL pseudorandom number generator "
"cannot be initialized (see the `PRNG not "
"seeded' message in the OpenSSL FAQ)");
}
REQUIRE(atomic_compare_exchange_strong(&init_done, &(bool){ false },
true));
}
void
isc_tls_initialize(void) {
isc_result_t result = isc_once_do(&init_once, isc__tls_initialize);
isc__tls_initialize(void) {
isc_result_t result = isc_once_do(&init_once, tls_initialize);
REQUIRE(result == ISC_R_SUCCESS);
REQUIRE(atomic_load(&init_done));
}
void
isc_tls_destroy(void) {
static void
tls_shutdown(void) {
REQUIRE(atomic_load(&init_done));
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
REQUIRE(!atomic_load(&shut_done));
#if OPENSSL_VERSION_NUMBER < 0x10100000L
CONF_modules_unload(1);
OBJ_cleanup();
EVP_cleanup();
#if !defined(OPENSSL_NO_ENGINE)
ENGINE_cleanup();
#endif
CRYPTO_cleanup_all_ex_data();
ERR_remove_thread_state(NULL);
RAND_cleanup();
ERR_free_strings();
ERR_remove_thread_state(NULL);
CRYPTO_set_locking_callback(NULL);
if (locks != NULL) {
INSIST(isc__tls_mctx != NULL);
isc_mutexblock_destroy(locks, nlocks);
isc_mem_put(isc__tls_mctx, locks, nlocks * sizeof(locks[0]));
free(locks);
locks = NULL;
}
if (isc__tls_mctx != NULL) {
isc_mem_detach(&isc__tls_mctx);
}
#endif
REQUIRE(atomic_compare_exchange_strong(&shut_done, &(bool){ false },
true));
}
void
isc__tls_shutdown(void) {
isc_result_t result = isc_once_do(&shut_once, tls_shutdown);
REQUIRE(result == ISC_R_SUCCESS);
REQUIRE(atomic_load(&shut_done));
}
void
@ -278,6 +336,7 @@ ssl_error:
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
ISC_LOG_ERROR, "Error initializing TLS context: %s",
errbuf);
if (ctx != NULL) {
SSL_CTX_free(ctx);
}

18
lib/isc/tls_p.h Normal file
View file

@ -0,0 +1,18 @@
/*
* 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 https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#pragma once
void
isc__tls_initialize(void);
void
isc__tls_shutdown(void);

View file

@ -12,6 +12,13 @@
#include <stdio.h>
#include <windows.h>
#include <isc/mem.h>
#include <isc/tls.h>
#include <isc/util.h>
#include "mem_p.h"
#include "tls_p.h"
/*
* Called when we enter the DLL
*/
@ -19,25 +26,35 @@ __declspec(dllexport) BOOL WINAPI
DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
switch (fdwReason) {
/*
* The DLL is loading due to process
* initialization or a call to LoadLibrary.
* The DLL is loading due to process initialization or a call to
* LoadLibrary.
*/
case DLL_PROCESS_ATTACH:
break;
/* The attached process creates a new thread. */
case DLL_THREAD_ATTACH:
break;
/* The thread of the attached process terminates. */
case DLL_THREAD_DETACH:
/*
* Disable DllMain() invocation on Thread creation/destruction
*/
DisableThreadLibraryCalls(hinstDLL);
isc__mem_initialize();
isc__tls_initialize();
break;
/*
* The DLL is unloading from a process due to
* process termination or a call to FreeLibrary.
* The DLL is unloading from a process due to process
* termination or a call to FreeLibrary.
*/
case DLL_PROCESS_DETACH:
isc__tls_shutdown();
isc__mem_shutdown();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
/*
* Calling DllMain when attaching/detaching process has been
* disabled.
*/
INSIST(0);
ISC_UNREACHABLE();
break;
default:

View file

@ -362,16 +362,20 @@ isc_md_get_block_size
isc_md_type_get_size
isc_md_type_get_block_size
isc_md
isc__mem_checkdestroyed
isc__mem_initialize
isc__mem_shutdown
isc_mem_attach
isc_mem_checkdestroyed
isc_mem_create
isc_mem_destroy
isc_mem_detach
isc_mem_getname
isc_mem_gettag
isc_mem_inuse
isc_mem_isovermem
isc_mem_malloced
isc_mem_maxinuse
isc_mem_maxmalloced
isc_mem_references
@IF NOTYET
isc_mem_renderjson
@ -706,8 +710,8 @@ isc_timermgr_create
isc_timermgr_createinctx
isc_timermgr_destroy
isc_timermgr_poke
isc_tls_initialize
isc_tls_destroy
isc__tls_initialize
isc__tls_shutdown
isc_tlsctx_createclient
isc_tlsctx_createserver
isc_tlsctx_free

View file

@ -2506,7 +2506,7 @@ ns_clientmgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr,
for (i = 0; i < npools; i++) {
manager->mctxpool[i] = NULL;
isc_mem_create(&manager->mctxpool[i]);
isc_mem_setname(manager->mctxpool[i], "client", NULL);
isc_mem_setname(manager->mctxpool[i], "client");
}
manager->magic = MANAGER_MAGIC;

View file

@ -1994,6 +1994,7 @@
./lib/isc/tests/uv_wrap.h C 2020,2021
./lib/isc/timer.c C 1998,1999,2000,2001,2002,2004,2005,2007,2008,2009,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021
./lib/isc/tls.c C 2021
./lib/isc/tls_p.h C 2021
./lib/isc/tm.c C 2014,2016,2018,2019,2020,2021
./lib/isc/unix/dir.c C 1999,2000,2001,2004,2005,2007,2008,2009,2011,2012,2016,2017,2018,2019,2020,2021
./lib/isc/unix/errno.c C 2016,2018,2019,2020,2021