1 /* $NetBSD: mem.h,v 1.12 2025/01/26 16:25:41 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #pragma once 17 18 /*! \file isc/mem.h */ 19 20 #include <stdbool.h> 21 #include <stdio.h> 22 23 #include <isc/attributes.h> 24 #include <isc/lang.h> 25 #include <isc/mutex.h> 26 #include <isc/overflow.h> 27 #include <isc/types.h> 28 #include <isc/urcu.h> 29 30 ISC_LANG_BEGINDECLS 31 32 /*% 33 * Define ISC_MEM_TRACKLINES=1 to turn on detailed tracing of memory 34 * allocation and freeing by file and line number. 35 */ 36 #ifndef ISC_MEM_TRACKLINES 37 #define ISC_MEM_TRACKLINES 0 38 #endif /* ifndef ISC_MEM_TRACKLINES */ 39 40 extern unsigned int isc_mem_debugging; 41 extern unsigned int isc_mem_defaultflags; 42 43 /*@{*/ 44 #define ISC_MEM_DEBUGTRACE 0x00000001U 45 #define ISC_MEM_DEBUGRECORD 0x00000002U 46 #define ISC_MEM_DEBUGUSAGE 0x00000004U 47 #define ISC_MEM_DEBUGALL \ 48 (ISC_MEM_DEBUGTRACE | ISC_MEM_DEBUGRECORD | ISC_MEM_DEBUGUSAGE) 49 /*!< 50 * The variable isc_mem_debugging holds a set of flags for 51 * turning certain memory debugging options on or off at 52 * runtime. It is initialized to the value ISC_MEM_DEGBUGGING, 53 * which is 0 by default but may be overridden at compile time. 54 * The following flags can be specified: 55 * 56 * \li #ISC_MEM_DEBUGTRACE 57 * Log each allocation and free to isc_lctx. 58 * 59 * \li #ISC_MEM_DEBUGRECORD 60 * Remember each allocation, and match them up on free. 61 * Crash if a free doesn't match an allocation. 62 * 63 * \li #ISC_MEM_DEBUGUSAGE 64 * Every time the memory usage is greater (lower) than hi_water 65 * (lo_water) mark, print the current inuse memory. 66 */ 67 /*@}*/ 68 69 #if ISC_MEM_TRACKLINES 70 #define _ISC_MEM_FILELINE , __FILE__, __LINE__ 71 #define _ISC_MEM_FLARG , const char *, unsigned int 72 #else /* if ISC_MEM_TRACKLINES */ 73 #define _ISC_MEM_FILELINE 74 #define _ISC_MEM_FLARG 75 #endif /* if ISC_MEM_TRACKLINES */ 76 77 /* 78 * Flags for isc_mem_create() calls. 79 */ 80 #define ISC_MEMFLAG_RESERVED1 0x00000001 /* reserved, obsoleted, don't use */ 81 #define ISC_MEMFLAG_RESERVED2 0x00000002 /* reserved, obsoleted, don't use */ 82 #define ISC_MEMFLAG_FILL \ 83 0x00000004 /* fill with pattern after alloc and frees */ 84 85 /*% 86 * Define ISC_MEM_DEFAULTFILL=1 to turn filling the memory with pattern 87 * after alloc and free. 88 */ 89 #if ISC_MEM_DEFAULTFILL 90 #define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_FILL 91 #else /* if !ISC_MEM_USE_INTERNAL_MALLOC */ 92 #define ISC_MEMFLAG_DEFAULT 0 93 #endif /* if !ISC_MEM_USE_INTERNAL_MALLOC */ 94 95 /*% 96 * isc_mem_putanddetach() is a convenience function for use where you 97 * have a structure with an attached memory context. 98 * 99 * Given: 100 * 101 * \code 102 * struct { 103 * ... 104 * isc_mem_t *mctx; 105 * ... 106 * } *ptr; 107 * 108 * isc_mem_t *mctx; 109 * 110 * isc_mem_putanddetach(&ptr->mctx, ptr, sizeof(*ptr)); 111 * \endcode 112 * 113 * is the equivalent of: 114 * 115 * \code 116 * mctx = NULL; 117 * isc_mem_attach(ptr->mctx, &mctx); 118 * isc_mem_detach(&ptr->mctx); 119 * isc_mem_put(mctx, ptr, sizeof(*ptr)); 120 * isc_mem_detach(&mctx); 121 * \endcode 122 */ 123 124 /*% 125 * These functions are actually implemented in isc__mem_<function> 126 * (two underscores). The single-underscore macros are used to pass 127 * __FILE__ and __LINE__, and in the case of the put functions, to 128 * set the pointer being freed to NULL in the calling function. 129 */ 130 131 /*% 132 * The definitions of the macros have been pulled directly from jemalloc.h 133 * and checked for consistency in mem.c. 134 * 135 *\li ISC__MEM_ZERO - fill the memory with zeroes before returning 136 */ 137 138 #define ISC__MEM_ZERO ((int)0x40) 139 140 #define isc_mem_get(c, s) isc__mem_get((c), (s), 0 _ISC_MEM_FILELINE) 141 #define isc_mem_cget(c, n, s) \ 142 isc__mem_get((c), ISC_CHECKED_MUL((n), (s)), \ 143 ISC__MEM_ZERO _ISC_MEM_FILELINE) 144 #define isc_mem_reget(c, p, o, n) \ 145 isc__mem_reget((c), (p), (o), (n), 0 _ISC_MEM_FILELINE) 146 #define isc_mem_creget(c, p, o, n, s) \ 147 isc__mem_reget((c), (p), ISC_CHECKED_MUL((o), (s)), \ 148 ISC_CHECKED_MUL((n), (s)), \ 149 ISC__MEM_ZERO _ISC_MEM_FILELINE) 150 #define isc_mem_allocate(c, s) isc__mem_allocate((c), (s), 0 _ISC_MEM_FILELINE) 151 #define isc_mem_callocate(c, n, s) \ 152 isc__mem_allocate((c), ISC_CHECKED_MUL((n), (s)), \ 153 ISC__MEM_ZERO _ISC_MEM_FILELINE) 154 #define isc_mem_reallocate(c, p, s) \ 155 isc__mem_reallocate((c), (p), (s), 0 _ISC_MEM_FILELINE) 156 #define isc_mem_strdup(c, p) isc__mem_strdup((c), (p)_ISC_MEM_FILELINE) 157 #define isc_mem_strndup(c, p, l) \ 158 isc__mem_strndup((c), (p), (l)_ISC_MEM_FILELINE) 159 #define isc_mempool_get(c) isc__mempool_get((c)_ISC_MEM_FILELINE) 160 161 #define isc_mem_put(c, p, s) \ 162 do { \ 163 isc__mem_put((c), (p), (s), 0 _ISC_MEM_FILELINE); \ 164 (p) = NULL; \ 165 } while (0) 166 #define isc_mem_cput(c, p, n, s) \ 167 do { \ 168 isc__mem_put((c), (p), ISC_CHECKED_MUL((n), (s)), \ 169 ISC__MEM_ZERO _ISC_MEM_FILELINE); \ 170 (p) = NULL; \ 171 } while (0) 172 #define isc_mem_putanddetach(c, p, s) \ 173 do { \ 174 isc__mem_putanddetach((c), (p), (s), 0 _ISC_MEM_FILELINE); \ 175 (p) = NULL; \ 176 } while (0) 177 #define isc_mem_free(c, p) \ 178 do { \ 179 isc__mem_free((c), (p), 0 _ISC_MEM_FILELINE); \ 180 (p) = NULL; \ 181 } while (0) 182 #define isc_mempool_put(c, p) \ 183 do { \ 184 isc__mempool_put((c), (p)_ISC_MEM_FILELINE); \ 185 (p) = NULL; \ 186 } while (0) 187 188 /*@{*/ 189 /* 190 * This is a little hack to help with dynamic link order, 191 * see https://github.com/jemalloc/jemalloc/issues/2566 192 * for more information. 193 */ 194 #if HAVE_JEMALLOC 195 196 /* 197 * cmocka.h has confliction definitions with the jemalloc header but we only 198 * need the mallocx symbol from jemalloc. 199 */ 200 void * 201 mallocx(size_t size, int flags); 202 203 extern volatile void *isc__mem_malloc; 204 205 #define isc_mem_create(cp) \ 206 { \ 207 isc__mem_create((cp)_ISC_MEM_FILELINE); \ 208 isc__mem_malloc = mallocx; \ 209 ISC_INSIST(CMM_ACCESS_ONCE(isc__mem_malloc) != NULL); \ 210 } 211 #else 212 #define isc_mem_create(cp) isc__mem_create((cp)_ISC_MEM_FILELINE) 213 #endif 214 void 215 isc__mem_create(isc_mem_t **_ISC_MEM_FLARG); 216 217 /*!< 218 * \brief Create a memory context. 219 * 220 * Requires: 221 * mctxp != NULL && *mctxp == NULL */ 222 /*@}*/ 223 224 #define isc_mem_create_arena(cp) isc__mem_create_arena((cp)_ISC_MEM_FILELINE) 225 void 226 isc__mem_create_arena(isc_mem_t **_ISC_MEM_FLARG); 227 /*!< 228 * \brief Create a memory context that routs all its operations to a 229 * dedicated jemalloc arena (when available). When jemalloc is not 230 * available, the function is, effectively, an alias to 231 * isc_mem_create(). 232 * 233 * Requires: 234 * mctxp != NULL && *mctxp == NULL */ 235 /*@}*/ 236 237 isc_result_t 238 isc_mem_arena_set_muzzy_decay_ms(isc_mem_t *mctx, const ssize_t decay_ms); 239 240 isc_result_t 241 isc_mem_arena_set_dirty_decay_ms(isc_mem_t *mctx, const ssize_t decay_ms); 242 /*!< 243 * \brief These two functions set the given parameters on the 244 * jemalloc arena associated with the memory context (if there is 245 * one). When jemalloc is not available, these are no-op. 246 * 247 * NOTE: The "muzzy_decay_ms" and "dirty_decay_ms" are the most common 248 * parameters to adjust when the defaults do not work well (per the 249 * official jemalloc tuning guide: 250 * https://github.com/jemalloc/jemalloc/blob/dev/TUNING.md). 251 * 252 * Requires: 253 * mctx - a valid memory context. 254 */ 255 /*@}*/ 256 257 void 258 isc_mem_attach(isc_mem_t *, isc_mem_t **); 259 260 /*@{*/ 261 void 262 isc_mem_attach(isc_mem_t *, isc_mem_t **); 263 #define isc_mem_detach(cp) isc__mem_detach((cp)_ISC_MEM_FILELINE) 264 void 265 isc__mem_detach(isc_mem_t **_ISC_MEM_FLARG); 266 /*!< 267 * \brief Attach to / detach from a memory context. 268 * 269 * This is intended for applications that use multiple memory contexts 270 * in such a way that it is not obvious when the last allocations from 271 * a given context has been freed and destroying the context is safe. 272 * 273 * Most applications do not need to call these functions as they can 274 * simply create a single memory context at the beginning of main() 275 * and destroy it at the end of main(), thereby guaranteeing that it 276 * is not destroyed while there are outstanding allocations. 277 */ 278 /*@}*/ 279 280 #define isc_mem_destroy(cp) isc__mem_destroy((cp)_ISC_MEM_FILELINE) 281 void 282 isc__mem_destroy(isc_mem_t **_ISC_MEM_FLARG); 283 /*%< 284 * Destroy a memory context. 285 */ 286 287 void 288 isc_mem_stats(isc_mem_t *mctx, FILE *out); 289 /*%< 290 * Print memory usage statistics for 'mctx' on the stream 'out'. 291 */ 292 293 void 294 isc_mem_setdestroycheck(isc_mem_t *mctx, bool on); 295 /*%< 296 * If 'on' is true, 'mctx' will check for memory leaks when 297 * destroyed and abort the program if any are present. 298 */ 299 300 size_t 301 isc_mem_inuse(isc_mem_t *mctx); 302 /*%< 303 * Get an estimate of the amount of memory in use in 'mctx', in bytes. 304 * This includes quantization overhead, but does not include memory 305 * allocated from the system but not yet used. 306 */ 307 308 bool 309 isc_mem_isovermem(isc_mem_t *mctx); 310 /*%< 311 * Return true iff the memory context is in "over memory" state, i.e., 312 * a hiwater mark has been set and the used amount of memory has exceeds 313 * the mark. 314 */ 315 316 void 317 isc_mem_clearwater(isc_mem_t *mctx); 318 void 319 isc_mem_setwater(isc_mem_t *mctx, size_t hiwater, size_t lowater); 320 /*%< 321 * Set high and low water marks for this memory context. 322 * 323 * When the memory usage of 'mctx' exceeds 'hiwater', the overmem condition 324 * will be met and isc_mem_isovermem() will return true. 325 * 326 * If the 'hiwater' and 'lowater' is set to 0, the high- and low-water 327 * processing are disabled for this memory context. 328 * 329 * There's a convenient function isc_mem_clearwater(). 330 * 331 * Requires: 332 *\li 'hiwater' >= 'lowater' 333 */ 334 335 void 336 isc_mem_checkdestroyed(FILE *file); 337 /*%< 338 * Check that all memory contexts have been destroyed. 339 * Prints out those that have not been. 340 * Fatally fails if there are still active contexts. 341 */ 342 343 unsigned int 344 isc_mem_references(isc_mem_t *ctx); 345 /*%< 346 * Return the current reference count. 347 */ 348 349 void 350 isc_mem_setname(isc_mem_t *ctx, const char *name); 351 /*%< 352 * Name 'ctx'. 353 * 354 * Notes: 355 * 356 *\li Only the first 15 characters of 'name' will be copied. 357 * 358 * Requires: 359 * 360 *\li 'ctx' is a valid ctx. 361 */ 362 363 const char * 364 isc_mem_getname(isc_mem_t *ctx); 365 /*%< 366 * Get the name of 'ctx', as previously set using isc_mem_setname(). 367 * 368 * Requires: 369 *\li 'ctx' is a valid ctx. 370 * 371 * Returns: 372 *\li A non-NULL pointer to a null-terminated string. 373 * If the ctx has not been named, the string is 374 * empty. 375 */ 376 377 #ifdef HAVE_LIBXML2 378 int 379 isc_mem_renderxml(void *writer0); 380 /*%< 381 * Render all contexts' statistics and status in XML for writer. 382 */ 383 #endif /* HAVE_LIBXML2 */ 384 385 #ifdef HAVE_JSON_C 386 isc_result_t 387 isc_mem_renderjson(void *memobj0); 388 /*%< 389 * Render all contexts' statistics and status in JSON. 390 */ 391 #endif /* HAVE_JSON_C */ 392 393 /* 394 * Memory pools 395 */ 396 397 #define isc_mempool_create(c, s, mp) \ 398 isc__mempool_create((c), (s), (mp)_ISC_MEM_FILELINE) 399 void 400 isc__mempool_create(isc_mem_t *restrict mctx, const size_t element_size, 401 isc_mempool_t **mpctxp _ISC_MEM_FLARG); 402 /*%< 403 * Create a memory pool. 404 * 405 * Requires: 406 *\li mctx is a valid memory context. 407 *\li size > 0 408 *\li mpctxp != NULL and *mpctxp == NULL 409 * 410 * Defaults: 411 *\li freemax = 1 412 *\li fillcount = 1 413 * 414 * Returns: 415 *\li #ISC_R_NOMEMORY -- not enough memory to create pool 416 *\li #ISC_R_SUCCESS -- all is well. 417 */ 418 419 #define isc_mempool_destroy(mp) isc__mempool_destroy((mp)_ISC_MEM_FILELINE) 420 void 421 isc__mempool_destroy(isc_mempool_t **restrict mpctxp _ISC_MEM_FLARG); 422 /*%< 423 * Destroy a memory pool. 424 * 425 * Requires: 426 *\li mpctxp != NULL && *mpctxp is a valid pool. 427 *\li The pool has no un"put" allocations outstanding 428 */ 429 430 void 431 isc_mempool_setname(isc_mempool_t *restrict mpctx, const char *name); 432 /*%< 433 * Associate a name with a memory pool. At most 15 characters may be 434 *used. 435 * 436 * Requires: 437 *\li mpctx is a valid pool. 438 *\li name != NULL; 439 */ 440 441 /* 442 * The following functions get/set various parameters. Note that due to 443 * the unlocked nature of pools these are potentially random values 444 *unless the imposed externally provided locking protocols are followed. 445 * 446 * Also note that the quota limits will not always take immediate 447 * effect. 448 * 449 * All functions require (in addition to other requirements): 450 * mpctx is a valid memory pool 451 */ 452 453 unsigned int 454 isc_mempool_getfreemax(isc_mempool_t *restrict mpctx); 455 /*%< 456 * Returns the maximum allowed size of the free list. 457 */ 458 459 void 460 isc_mempool_setfreemax(isc_mempool_t *restrict mpctx, const unsigned int limit); 461 /*%< 462 * Sets the maximum allowed size of the free list. 463 */ 464 465 unsigned int 466 isc_mempool_getfreecount(isc_mempool_t *restrict mpctx); 467 /*%< 468 * Returns current size of the free list. 469 */ 470 471 unsigned int 472 isc_mempool_getallocated(isc_mempool_t *restrict mpctx); 473 /*%< 474 * Returns the number of items allocated from this pool. 475 */ 476 477 unsigned int 478 isc_mempool_getfillcount(isc_mempool_t *restrict mpctx); 479 /*%< 480 * Returns the number of items allocated as a block from the parent 481 * memory context when the free list is empty. 482 */ 483 484 void 485 isc_mempool_setfillcount(isc_mempool_t *restrict mpctx, 486 const unsigned int limit); 487 /*%< 488 * Sets the fillcount. 489 * 490 * Additional requirements: 491 *\li limit > 0 492 */ 493 494 #if defined(UNIT_TESTING) && defined(malloc) 495 /* 496 * cmocka.h redefined malloc as a macro, we #undef it 497 * to avoid replacing ISC_ATTR_MALLOC with garbage. 498 */ 499 #pragma push_macro("malloc") 500 #undef malloc 501 #define POP_MALLOC_MACRO 1 502 #endif 503 504 /* 505 * Pseudo-private functions for use via macros. Do not call directly. 506 */ 507 void 508 isc__mem_putanddetach(isc_mem_t **, void *, size_t, int _ISC_MEM_FLARG); 509 void 510 isc__mem_put(isc_mem_t *, void *, size_t, int _ISC_MEM_FLARG); 511 void 512 isc__mem_free(isc_mem_t *, void *, int _ISC_MEM_FLARG); 513 514 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(isc__mem_put, 2) 515 void * 516 isc__mem_get(isc_mem_t *, size_t, int _ISC_MEM_FLARG); 517 518 ISC_ATTR_DEALLOCATOR_IDX(isc__mem_put, 2) 519 void * 520 isc__mem_reget(isc_mem_t *, void *, size_t, size_t, int _ISC_MEM_FLARG); 521 522 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(isc__mem_free, 2) 523 void * 524 isc__mem_allocate(isc_mem_t *, size_t, int _ISC_MEM_FLARG); 525 526 ISC_ATTR_DEALLOCATOR_IDX(isc__mem_free, 2) 527 void * 528 isc__mem_reallocate(isc_mem_t *, void *, size_t, int _ISC_MEM_FLARG); 529 530 ISC_ATTR_RETURNS_NONNULL 531 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(isc__mem_free, 2) 532 char * 533 isc__mem_strdup(isc_mem_t *, const char *_ISC_MEM_FLARG); 534 535 ISC_ATTR_RETURNS_NONNULL 536 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(isc__mem_free, 2) 537 char * 538 isc__mem_strndup(isc_mem_t *, const char *, size_t _ISC_MEM_FLARG); 539 540 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(isc__mempool_put, 2) 541 void * 542 isc__mempool_get(isc_mempool_t *_ISC_MEM_FLARG); 543 544 void 545 isc__mempool_put(isc_mempool_t *, void *_ISC_MEM_FLARG); 546 547 #ifdef POP_MALLOC_MACRO 548 /* 549 * Restore cmocka.h macro for malloc. 550 */ 551 #pragma pop_macro("malloc") 552 #endif 553 554 ISC_LANG_ENDDECLS 555