1/* $NetBSD: mem.c,v 1.5 2020/05/25 20:47:20 christos Exp $ */ 2 3/* 4 * Copyright (C) 2004-2010, 2012 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1997-2003 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20/* Id */ 21 22/*! \file */ 23 24#include <config.h> 25 26#include <stdio.h> 27#include <stdlib.h> 28#include <stddef.h> 29 30#include <limits.h> 31 32#include <isc/magic.h> 33#include <isc/mem.h> 34#include <isc/msgs.h> 35#include <isc/once.h> 36#include <isc/ondestroy.h> 37#include <isc/string.h> 38#include <isc/mutex.h> 39#include <isc/print.h> 40#include <isc/util.h> 41#include <isc/xml.h> 42 43#define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l) 44#define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l) 45 46#ifndef ISC_MEM_DEBUGGING 47#define ISC_MEM_DEBUGGING 0 48#endif 49LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING; 50 51/* 52 * Constants. 53 */ 54 55#define DEF_MAX_SIZE 1100 56#define DEF_MEM_TARGET 4096 57#define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */ 58#define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */ 59#define TABLE_INCREMENT 1024 60#define DEBUGLIST_COUNT 1024 61 62/* 63 * Types. 64 */ 65typedef struct isc__mem isc__mem_t; 66typedef struct isc__mempool isc__mempool_t; 67 68#if ISC_MEM_TRACKLINES 69typedef struct debuglink debuglink_t; 70struct debuglink { 71 ISC_LINK(debuglink_t) link; 72 const void *ptr[DEBUGLIST_COUNT]; 73 unsigned int size[DEBUGLIST_COUNT]; 74 const char *file[DEBUGLIST_COUNT]; 75 unsigned int line[DEBUGLIST_COUNT]; 76 unsigned int count; 77}; 78 79#define FLARG_PASS , file, line 80#define FLARG , const char *file, unsigned int line 81#else 82#define FLARG_PASS 83#define FLARG 84#endif 85 86typedef struct element element; 87struct element { 88 element * next; 89}; 90 91typedef struct { 92 /*! 93 * This structure must be ALIGNMENT_SIZE bytes. 94 */ 95 union { 96 size_t size; 97 isc__mem_t *ctx; 98 char bytes[ALIGNMENT_SIZE]; 99 } u; 100} size_info; 101 102struct stats { 103 unsigned long gets; 104 unsigned long totalgets; 105 unsigned long blocks; 106 unsigned long freefrags; 107}; 108 109#define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C') 110#define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC) 111 112#if ISC_MEM_TRACKLINES 113typedef ISC_LIST(debuglink_t) debuglist_t; 114#endif 115 116/* List of all active memory contexts. */ 117 118static ISC_LIST(isc__mem_t) contexts; 119static isc_once_t once = ISC_ONCE_INIT; 120static isc_mutex_t lock; 121 122/*% 123 * Total size of lost memory due to a bug of external library. 124 * Locked by the global lock. 125 */ 126static isc_uint64_t totallost; 127 128struct isc__mem { 129 isc_mem_t common; 130 isc_ondestroy_t ondestroy; 131 unsigned int flags; 132 isc_mutex_t lock; 133 isc_memalloc_t memalloc; 134 isc_memfree_t memfree; 135 void * arg; 136 size_t max_size; 137 isc_boolean_t checkfree; 138 struct stats * stats; 139 unsigned int references; 140 char name[16]; 141 void * tag; 142 size_t quota; 143 size_t total; 144 size_t inuse; 145 size_t maxinuse; 146 size_t hi_water; 147 size_t lo_water; 148 isc_boolean_t hi_called; 149 isc_boolean_t is_overmem; 150 isc_mem_water_t water; 151 void * water_arg; 152 ISC_LIST(isc__mempool_t) pools; 153 unsigned int poolcnt; 154 155 /* ISC_MEMFLAG_INTERNAL */ 156 size_t mem_target; 157 element ** freelists; 158 element * basic_blocks; 159 unsigned char ** basic_table; 160 unsigned int basic_table_count; 161 unsigned int basic_table_size; 162 unsigned char * lowest; 163 unsigned char * highest; 164 165#if ISC_MEM_TRACKLINES 166 debuglist_t * debuglist; 167 unsigned int debuglistcnt; 168#endif 169 170 unsigned int memalloc_failures; 171 ISC_LINK(isc__mem_t) link; 172}; 173 174#define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p') 175#define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC) 176 177struct isc__mempool { 178 /* always unlocked */ 179 isc_mempool_t common; /*%< common header of mempool's */ 180 isc_mutex_t *lock; /*%< optional lock */ 181 isc__mem_t *mctx; /*%< our memory context */ 182 /*%< locked via the memory context's lock */ 183 ISC_LINK(isc__mempool_t) link; /*%< next pool in this mem context */ 184 /*%< optionally locked from here down */ 185 element *items; /*%< low water item list */ 186 size_t size; /*%< size of each item on this pool */ 187 unsigned int maxalloc; /*%< max number of items allowed */ 188 unsigned int allocated; /*%< # of items currently given out */ 189 unsigned int freecount; /*%< # of items on reserved list */ 190 unsigned int freemax; /*%< # of items allowed on free list */ 191 unsigned int fillcount; /*%< # of items to fetch on each fill */ 192 /*%< Stats only. */ 193 unsigned int gets; /*%< # of requests to this pool */ 194 /*%< Debugging only. */ 195#if ISC_MEMPOOL_NAMES 196 char name[16]; /*%< printed name in stats reports */ 197#endif 198}; 199 200/* 201 * Private Inline-able. 202 */ 203 204#if ! ISC_MEM_TRACKLINES 205#define ADD_TRACE(a, b, c, d, e) 206#define DELETE_TRACE(a, b, c, d, e) 207#else 208#define ADD_TRACE(a, b, c, d, e) \ 209 do { \ 210 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \ 211 ISC_MEM_DEBUGRECORD)) != 0 && \ 212 b != NULL) \ 213 add_trace_entry(a, b, c, d, e); \ 214 } while (0) 215#define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e) 216 217static void 218print_active(isc__mem_t *ctx, FILE *out); 219 220/*% 221 * The following can be either static or public, depending on build environment. 222 */ 223 224#ifdef BIND9 225#define ISC_MEMFUNC_SCOPE 226#else 227#define ISC_MEMFUNC_SCOPE static 228#endif 229 230ISC_MEMFUNC_SCOPE isc_result_t 231isc__mem_createx(size_t init_max_size, size_t target_size, 232 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 233 isc_mem_t **ctxp); 234ISC_MEMFUNC_SCOPE isc_result_t 235isc__mem_createx2(size_t init_max_size, size_t target_size, 236 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 237 isc_mem_t **ctxp, unsigned int flags); 238ISC_MEMFUNC_SCOPE isc_result_t 239isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp); 240ISC_MEMFUNC_SCOPE isc_result_t 241isc__mem_create2(size_t init_max_size, size_t target_size, 242 isc_mem_t **ctxp, unsigned int flags); 243ISC_MEMFUNC_SCOPE void 244isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp); 245ISC_MEMFUNC_SCOPE void 246isc__mem_detach(isc_mem_t **ctxp); 247ISC_MEMFUNC_SCOPE void 248isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG); 249ISC_MEMFUNC_SCOPE void 250isc__mem_destroy(isc_mem_t **ctxp); 251ISC_MEMFUNC_SCOPE isc_result_t 252isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event); 253ISC_MEMFUNC_SCOPE void * 254isc___mem_get(isc_mem_t *ctx, size_t size FLARG); 255ISC_MEMFUNC_SCOPE void 256isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG); 257ISC_MEMFUNC_SCOPE void 258isc__mem_stats(isc_mem_t *ctx, FILE *out); 259ISC_MEMFUNC_SCOPE void * 260isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG); 261ISC_MEMFUNC_SCOPE void * 262isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG); 263ISC_MEMFUNC_SCOPE void 264isc___mem_free(isc_mem_t *ctx, void *ptr FLARG); 265ISC_MEMFUNC_SCOPE char * 266isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG); 267ISC_MEMFUNC_SCOPE void 268isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag); 269ISC_MEMFUNC_SCOPE void 270isc__mem_setquota(isc_mem_t *ctx, size_t quota); 271ISC_MEMFUNC_SCOPE size_t 272isc__mem_getquota(isc_mem_t *ctx); 273ISC_MEMFUNC_SCOPE size_t 274isc__mem_inuse(isc_mem_t *ctx); 275ISC_MEMFUNC_SCOPE isc_boolean_t 276isc__mem_isovermem(isc_mem_t *ctx); 277ISC_MEMFUNC_SCOPE void 278isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, 279 size_t hiwater, size_t lowater); 280ISC_MEMFUNC_SCOPE void 281isc__mem_waterack(isc_mem_t *ctx0, int flag); 282ISC_MEMFUNC_SCOPE void 283isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag); 284ISC_MEMFUNC_SCOPE const char * 285isc__mem_getname(isc_mem_t *ctx); 286ISC_MEMFUNC_SCOPE void * 287isc__mem_gettag(isc_mem_t *ctx); 288ISC_MEMFUNC_SCOPE isc_result_t 289isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp); 290ISC_MEMFUNC_SCOPE void 291isc__mempool_setname(isc_mempool_t *mpctx, const char *name); 292ISC_MEMFUNC_SCOPE void 293isc__mempool_destroy(isc_mempool_t **mpctxp); 294ISC_MEMFUNC_SCOPE void 295isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock); 296ISC_MEMFUNC_SCOPE void * 297isc___mempool_get(isc_mempool_t *mpctx FLARG); 298ISC_MEMFUNC_SCOPE void 299isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG); 300ISC_MEMFUNC_SCOPE void 301isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit); 302ISC_MEMFUNC_SCOPE unsigned int 303isc__mempool_getfreemax(isc_mempool_t *mpctx); 304ISC_MEMFUNC_SCOPE unsigned int 305isc__mempool_getfreecount(isc_mempool_t *mpctx); 306ISC_MEMFUNC_SCOPE void 307isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit); 308ISC_MEMFUNC_SCOPE unsigned int 309isc__mempool_getmaxalloc(isc_mempool_t *mpctx); 310ISC_MEMFUNC_SCOPE unsigned int 311isc__mempool_getallocated(isc_mempool_t *mpctx); 312ISC_MEMFUNC_SCOPE void 313isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit); 314ISC_MEMFUNC_SCOPE unsigned int 315isc__mempool_getfillcount(isc_mempool_t *mpctx); 316#ifdef BIND9 317ISC_MEMFUNC_SCOPE void 318isc__mem_printactive(isc_mem_t *ctx0, FILE *file); 319ISC_MEMFUNC_SCOPE void 320isc__mem_printallactive(FILE *file); 321ISC_MEMFUNC_SCOPE void 322isc__mem_checkdestroyed(FILE *file); 323ISC_MEMFUNC_SCOPE unsigned int 324isc__mem_references(isc_mem_t *ctx0); 325#endif 326 327static struct isc__memmethods { 328 isc_memmethods_t methods; 329 330 /*% 331 * The following are defined just for avoiding unused static functions. 332 */ 333#ifndef BIND9 334 void *createx, *create, *create2, *ondestroy, *stats, 335 *setquota, *getquota, *setname, *getname, *gettag; 336#endif 337} memmethods = { 338 { 339 isc__mem_attach, 340 isc__mem_detach, 341 isc__mem_destroy, 342 isc___mem_get, 343 isc___mem_put, 344 isc___mem_putanddetach, 345 isc___mem_allocate, 346 isc___mem_reallocate, 347 isc___mem_strdup, 348 isc___mem_free, 349 isc__mem_setdestroycheck, 350 isc__mem_setwater, 351 isc__mem_waterack, 352 isc__mem_inuse, 353 isc__mem_isovermem, 354 isc__mempool_create 355 } 356#ifndef BIND9 357 , 358 (void *)isc__mem_createx, (void *)isc__mem_create, 359 (void *)isc__mem_create2, (void *)isc__mem_ondestroy, 360 (void *)isc__mem_stats, (void *)isc__mem_setquota, 361 (void *)isc__mem_getquota, (void *)isc__mem_setname, 362 (void *)isc__mem_getname, (void *)isc__mem_gettag 363#endif 364}; 365 366static struct isc__mempoolmethods { 367 isc_mempoolmethods_t methods; 368 369 /*% 370 * The following are defined just for avoiding unused static functions. 371 */ 372#ifndef BIND9 373 void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount; 374#endif 375} mempoolmethods = { 376 { 377 isc__mempool_destroy, 378 isc___mempool_get, 379 isc___mempool_put, 380 isc__mempool_getallocated, 381 isc__mempool_setmaxalloc, 382 isc__mempool_setfreemax, 383 isc__mempool_setname, 384 isc__mempool_associatelock, 385 isc__mempool_setfillcount 386 } 387#ifndef BIND9 388 , 389 (void *)isc__mempool_getfreemax, (void *)isc__mempool_getfreecount, 390 (void *)isc__mempool_getmaxalloc, (void *)isc__mempool_getfillcount 391#endif 392}; 393 394/*! 395 * mctx must be locked. 396 */ 397static inline void 398add_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size 399 FLARG) 400{ 401 debuglink_t *dl; 402 unsigned int i; 403 unsigned int mysize = size; 404 405 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) 406 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 407 ISC_MSG_ADDTRACE, 408 "add %p size %u " 409 "file %s line %u mctx %p\n"), 410 ptr, size, file, line, mctx); 411 412 if (mctx->debuglist == NULL) 413 return; 414 415 if (mysize > mctx->max_size) 416 mysize = mctx->max_size; 417 418 dl = ISC_LIST_HEAD(mctx->debuglist[mysize]); 419 while (dl != NULL) { 420 if (dl->count == DEBUGLIST_COUNT) 421 goto next; 422 for (i = 0; i < DEBUGLIST_COUNT; i++) { 423 if (dl->ptr[i] == NULL) { 424 dl->ptr[i] = ptr; 425 dl->size[i] = size; 426 dl->file[i] = file; 427 dl->line[i] = line; 428 dl->count++; 429 return; 430 } 431 } 432 next: 433 dl = ISC_LIST_NEXT(dl, link); 434 } 435 436 dl = malloc(sizeof(debuglink_t)); 437 INSIST(dl != NULL); 438 439 ISC_LINK_INIT(dl, link); 440 for (i = 1; i < DEBUGLIST_COUNT; i++) { 441 dl->ptr[i] = NULL; 442 dl->size[i] = 0; 443 dl->file[i] = NULL; 444 dl->line[i] = 0; 445 } 446 447 dl->ptr[0] = ptr; 448 dl->size[0] = size; 449 dl->file[0] = file; 450 dl->line[0] = line; 451 dl->count = 1; 452 453 ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link); 454 mctx->debuglistcnt++; 455} 456 457static inline void 458delete_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size, 459 const char *file, unsigned int line) 460{ 461 debuglink_t *dl; 462 unsigned int i; 463 464 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) 465 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 466 ISC_MSG_DELTRACE, 467 "del %p size %u " 468 "file %s line %u mctx %p\n"), 469 ptr, size, file, line, mctx); 470 471 if (mctx->debuglist == NULL) 472 return; 473 474 if (size > mctx->max_size) 475 size = mctx->max_size; 476 477 dl = ISC_LIST_HEAD(mctx->debuglist[size]); 478 while (dl != NULL) { 479 for (i = 0; i < DEBUGLIST_COUNT; i++) { 480 if (dl->ptr[i] == ptr) { 481 dl->ptr[i] = NULL; 482 dl->size[i] = 0; 483 dl->file[i] = NULL; 484 dl->line[i] = 0; 485 486 INSIST(dl->count > 0); 487 dl->count--; 488 if (dl->count == 0) { 489 ISC_LIST_UNLINK(mctx->debuglist[size], 490 dl, link); 491 free(dl); 492 } 493 return; 494 } 495 } 496 dl = ISC_LIST_NEXT(dl, link); 497 } 498 499 /* 500 * If we get here, we didn't find the item on the list. We're 501 * screwed. 502 */ 503 INSIST(dl != NULL); 504} 505#endif /* ISC_MEM_TRACKLINES */ 506 507static inline size_t 508rmsize(size_t size) { 509 /* 510 * round down to ALIGNMENT_SIZE 511 */ 512 return (size & (~(ALIGNMENT_SIZE - 1))); 513} 514 515static inline size_t 516quantize(size_t size) { 517 /*! 518 * Round up the result in order to get a size big 519 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE 520 * byte boundaries. 521 */ 522 523 if (size == 0U) 524 return (ALIGNMENT_SIZE); 525 return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1))); 526} 527 528static inline isc_boolean_t 529more_basic_blocks(isc__mem_t *ctx) { 530 void *new; 531 unsigned char *curr, *next; 532 unsigned char *first, *last; 533 unsigned char **table; 534 unsigned int table_size; 535 size_t increment; 536 int i; 537 538 /* Require: we hold the context lock. */ 539 540 /* 541 * Did we hit the quota for this context? 542 */ 543 increment = NUM_BASIC_BLOCKS * ctx->mem_target; 544 if (ctx->quota != 0U && ctx->total + increment > ctx->quota) 545 return (ISC_FALSE); 546 547 INSIST(ctx->basic_table_count <= ctx->basic_table_size); 548 if (ctx->basic_table_count == ctx->basic_table_size) { 549 table_size = ctx->basic_table_size + TABLE_INCREMENT; 550 table = (ctx->memalloc)(ctx->arg, 551 table_size * sizeof(unsigned char *)); 552 if (table == NULL) { 553 ctx->memalloc_failures++; 554 return (ISC_FALSE); 555 } 556 if (ctx->basic_table_size != 0) { 557 memcpy(table, ctx->basic_table, 558 ctx->basic_table_size * 559 sizeof(unsigned char *)); 560 (ctx->memfree)(ctx->arg, ctx->basic_table); 561 } 562 ctx->basic_table = table; 563 ctx->basic_table_size = table_size; 564 } 565 566 new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target); 567 if (new == NULL) { 568 ctx->memalloc_failures++; 569 return (ISC_FALSE); 570 } 571 ctx->total += increment; 572 ctx->basic_table[ctx->basic_table_count] = new; 573 ctx->basic_table_count++; 574 575 curr = new; 576 next = curr + ctx->mem_target; 577 for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { 578 ((element *)curr)->next = (element *)next; 579 curr = next; 580 next += ctx->mem_target; 581 } 582 /* 583 * curr is now pointing at the last block in the 584 * array. 585 */ 586 ((element *)curr)->next = NULL; 587 first = new; 588 last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1; 589 if (first < ctx->lowest || ctx->lowest == NULL) 590 ctx->lowest = first; 591 if (last > ctx->highest) 592 ctx->highest = last; 593 ctx->basic_blocks = new; 594 595 return (ISC_TRUE); 596} 597 598static inline isc_boolean_t 599more_frags(isc__mem_t *ctx, size_t new_size) { 600 int i, frags; 601 size_t total_size; 602 void *new; 603 unsigned char *curr, *next; 604 605 /*! 606 * Try to get more fragments by chopping up a basic block. 607 */ 608 609 if (ctx->basic_blocks == NULL) { 610 if (!more_basic_blocks(ctx)) { 611 /* 612 * We can't get more memory from the OS, or we've 613 * hit the quota for this context. 614 */ 615 /* 616 * XXXRTH "At quota" notification here. 617 */ 618 return (ISC_FALSE); 619 } 620 } 621 622 total_size = ctx->mem_target; 623 new = ctx->basic_blocks; 624 ctx->basic_blocks = ctx->basic_blocks->next; 625 frags = total_size / new_size; 626 ctx->stats[new_size].blocks++; 627 ctx->stats[new_size].freefrags += frags; 628 /* 629 * Set up a linked-list of blocks of size 630 * "new_size". 631 */ 632 curr = new; 633 next = curr + new_size; 634 total_size -= new_size; 635 for (i = 0; i < (frags - 1); i++) { 636 ((element *)curr)->next = (element *)next; 637 curr = next; 638 next += new_size; 639 total_size -= new_size; 640 } 641 /* 642 * Add the remaining fragment of the basic block to a free list. 643 */ 644 total_size = rmsize(total_size); 645 if (total_size > 0U) { 646 ((element *)next)->next = ctx->freelists[total_size]; 647 ctx->freelists[total_size] = (element *)next; 648 ctx->stats[total_size].freefrags++; 649 } 650 /* 651 * curr is now pointing at the last block in the 652 * array. 653 */ 654 ((element *)curr)->next = NULL; 655 ctx->freelists[new_size] = new; 656 657 return (ISC_TRUE); 658} 659 660static inline void * 661mem_getunlocked(isc__mem_t *ctx, size_t size) { 662 size_t new_size = quantize(size); 663 void *ret; 664 665 if (size >= ctx->max_size || new_size >= ctx->max_size) { 666 /* 667 * memget() was called on something beyond our upper limit. 668 */ 669 if (ctx->quota != 0U && ctx->total + size > ctx->quota) { 670 ret = NULL; 671 goto done; 672 } 673 ret = (ctx->memalloc)(ctx->arg, size); 674 if (ret == NULL) { 675 ctx->memalloc_failures++; 676 goto done; 677 } 678 ctx->total += size; 679 ctx->inuse += size; 680 ctx->stats[ctx->max_size].gets++; 681 ctx->stats[ctx->max_size].totalgets++; 682 /* 683 * If we don't set new_size to size, then the 684 * ISC_MEM_FILL code might write over bytes we 685 * don't own. 686 */ 687 new_size = size; 688 goto done; 689 } 690 691 /* 692 * If there are no blocks in the free list for this size, get a chunk 693 * of memory and then break it up into "new_size"-sized blocks, adding 694 * them to the free list. 695 */ 696 if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size)) 697 return (NULL); 698 699 /* 700 * The free list uses the "rounded-up" size "new_size". 701 */ 702 ret = ctx->freelists[new_size]; 703 ctx->freelists[new_size] = ctx->freelists[new_size]->next; 704 705 /* 706 * The stats[] uses the _actual_ "size" requested by the 707 * caller, with the caveat (in the code above) that "size" >= the 708 * max. size (max_size) ends up getting recorded as a call to 709 * max_size. 710 */ 711 ctx->stats[size].gets++; 712 ctx->stats[size].totalgets++; 713 ctx->stats[new_size].freefrags--; 714 ctx->inuse += new_size; 715 716 done: 717 718#if ISC_MEM_FILL 719 if (ret != NULL) 720 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */ 721#endif 722 723 return (ret); 724} 725 726#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN 727static inline void 728check_overrun(void *mem, size_t size, size_t new_size) { 729 unsigned char *cp; 730 731 cp = (unsigned char *)mem; 732 cp += size; 733 while (size < new_size) { 734 INSIST(*cp == 0xbe); 735 cp++; 736 size++; 737 } 738} 739#endif 740 741static inline void 742mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) { 743 size_t new_size = quantize(size); 744 745 if (size == ctx->max_size || new_size >= ctx->max_size) { 746 /* 747 * memput() called on something beyond our upper limit. 748 */ 749#if ISC_MEM_FILL 750 memset(mem, 0xde, size); /* Mnemonic for "dead". */ 751#endif 752 (ctx->memfree)(ctx->arg, mem); 753 INSIST(ctx->stats[ctx->max_size].gets != 0U); 754 ctx->stats[ctx->max_size].gets--; 755 INSIST(size <= ctx->total); 756 ctx->inuse -= size; 757 ctx->total -= size; 758 return; 759 } 760 761#if ISC_MEM_FILL 762#if ISC_MEM_CHECKOVERRUN 763 check_overrun(mem, size, new_size); 764#endif 765 memset(mem, 0xde, new_size); /* Mnemonic for "dead". */ 766#endif 767 768 /* 769 * The free list uses the "rounded-up" size "new_size". 770 */ 771 ((element *)mem)->next = ctx->freelists[new_size]; 772 ctx->freelists[new_size] = (element *)mem; 773 774 /* 775 * The stats[] uses the _actual_ "size" requested by the 776 * caller, with the caveat (in the code above) that "size" >= the 777 * max. size (max_size) ends up getting recorded as a call to 778 * max_size. 779 */ 780 INSIST(ctx->stats[size].gets != 0U); 781 ctx->stats[size].gets--; 782 ctx->stats[new_size].freefrags++; 783 ctx->inuse -= new_size; 784} 785 786/*! 787 * Perform a malloc, doing memory filling and overrun detection as necessary. 788 */ 789static inline void * 790mem_get(isc__mem_t *ctx, size_t size) { 791 char *ret; 792 793#if ISC_MEM_CHECKOVERRUN 794 size += 1; 795#endif 796 797 ret = (ctx->memalloc)(ctx->arg, size); 798 if (ret == NULL) 799 ctx->memalloc_failures++; 800 801#if ISC_MEM_FILL 802 if (ret != NULL) 803 memset(ret, 0xbe, size); /* Mnemonic for "beef". */ 804#else 805# if ISC_MEM_CHECKOVERRUN 806 if (ret != NULL) 807 ret[size-1] = 0xbe; 808# endif 809#endif 810 811 return (ret); 812} 813 814/*! 815 * Perform a free, doing memory filling and overrun detection as necessary. 816 */ 817static inline void 818mem_put(isc__mem_t *ctx, void *mem, size_t size) { 819#if ISC_MEM_CHECKOVERRUN 820 INSIST(((unsigned char *)mem)[size] == 0xbe); 821#endif 822#if ISC_MEM_FILL 823 memset(mem, 0xde, size); /* Mnemonic for "dead". */ 824#else 825 UNUSED(size); 826#endif 827 (ctx->memfree)(ctx->arg, mem); 828} 829 830/*! 831 * Update internal counters after a memory get. 832 */ 833static inline void 834mem_getstats(isc__mem_t *ctx, size_t size) { 835 ctx->total += size; 836 ctx->inuse += size; 837 838 if (size > ctx->max_size) { 839 ctx->stats[ctx->max_size].gets++; 840 ctx->stats[ctx->max_size].totalgets++; 841 } else { 842 ctx->stats[size].gets++; 843 ctx->stats[size].totalgets++; 844 } 845} 846 847/*! 848 * Update internal counters after a memory put. 849 */ 850static inline void 851mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) { 852 UNUSED(ptr); 853 854 INSIST(ctx->inuse >= size); 855 ctx->inuse -= size; 856 857 if (size > ctx->max_size) { 858 INSIST(ctx->stats[ctx->max_size].gets > 0U); 859 ctx->stats[ctx->max_size].gets--; 860 } else { 861 INSIST(ctx->stats[size].gets > 0U); 862 ctx->stats[size].gets--; 863 } 864} 865 866/* 867 * Private. 868 */ 869 870static void * 871default_memalloc(void *arg, size_t size) { 872 UNUSED(arg); 873 if (size == 0U) 874 size = 1; 875 return (malloc(size)); 876} 877 878static void 879default_memfree(void *arg, void *ptr) { 880 UNUSED(arg); 881 free(ptr); 882} 883 884static void 885initialize_action(void) { 886 RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS); 887 ISC_LIST_INIT(contexts); 888 totallost = 0; 889} 890 891/* 892 * Public. 893 */ 894 895ISC_MEMFUNC_SCOPE isc_result_t 896isc__mem_createx(size_t init_max_size, size_t target_size, 897 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 898 isc_mem_t **ctxp) 899{ 900 return (isc__mem_createx2(init_max_size, target_size, memalloc, memfree, 901 arg, ctxp, ISC_MEMFLAG_DEFAULT)); 902 903} 904 905ISC_MEMFUNC_SCOPE isc_result_t 906isc__mem_createx2(size_t init_max_size, size_t target_size, 907 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 908 isc_mem_t **ctxp, unsigned int flags) 909{ 910 isc__mem_t *ctx; 911 isc_result_t result; 912 913 REQUIRE(ctxp != NULL && *ctxp == NULL); 914 REQUIRE(memalloc != NULL); 915 REQUIRE(memfree != NULL); 916 917 INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0); 918 919 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 920 921 ctx = (memalloc)(arg, sizeof(*ctx)); 922 if (ctx == NULL) 923 return (ISC_R_NOMEMORY); 924 925 if ((flags & ISC_MEMFLAG_NOLOCK) == 0) { 926 result = isc_mutex_init(&ctx->lock); 927 if (result != ISC_R_SUCCESS) { 928 (memfree)(arg, ctx); 929 return (result); 930 } 931 } 932 933 if (init_max_size == 0U) 934 ctx->max_size = DEF_MAX_SIZE; 935 else 936 ctx->max_size = init_max_size; 937 ctx->flags = flags; 938 ctx->references = 1; 939 memset(ctx->name, 0, sizeof(ctx->name)); 940 ctx->tag = NULL; 941 ctx->quota = 0; 942 ctx->total = 0; 943 ctx->inuse = 0; 944 ctx->maxinuse = 0; 945 ctx->hi_water = 0; 946 ctx->lo_water = 0; 947 ctx->hi_called = ISC_FALSE; 948 ctx->is_overmem = ISC_FALSE; 949 ctx->water = NULL; 950 ctx->water_arg = NULL; 951 ctx->common.impmagic = MEM_MAGIC; 952 ctx->common.magic = ISCAPI_MCTX_MAGIC; 953 ctx->common.methods = (isc_memmethods_t *)&memmethods; 954 isc_ondestroy_init(&ctx->ondestroy); 955 ctx->memalloc = memalloc; 956 ctx->memfree = memfree; 957 ctx->arg = arg; 958 ctx->stats = NULL; 959 ctx->checkfree = ISC_TRUE; 960#if ISC_MEM_TRACKLINES 961 ctx->debuglist = NULL; 962 ctx->debuglistcnt = 0; 963#endif 964 ISC_LIST_INIT(ctx->pools); 965 ctx->poolcnt = 0; 966 ctx->freelists = NULL; 967 ctx->basic_blocks = NULL; 968 ctx->basic_table = NULL; 969 ctx->basic_table_count = 0; 970 ctx->basic_table_size = 0; 971 ctx->lowest = NULL; 972 ctx->highest = NULL; 973 974 ctx->stats = (memalloc)(arg, 975 (ctx->max_size+1) * sizeof(struct stats)); 976 if (ctx->stats == NULL) { 977 result = ISC_R_NOMEMORY; 978 goto error; 979 } 980 memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats)); 981 982 if ((flags & ISC_MEMFLAG_INTERNAL) != 0) { 983 if (target_size == 0U) 984 ctx->mem_target = DEF_MEM_TARGET; 985 else 986 ctx->mem_target = target_size; 987 ctx->freelists = (memalloc)(arg, ctx->max_size * 988 sizeof(element *)); 989 if (ctx->freelists == NULL) { 990 result = ISC_R_NOMEMORY; 991 goto error; 992 } 993 memset(ctx->freelists, 0, 994 ctx->max_size * sizeof(element *)); 995 } 996 997#if ISC_MEM_TRACKLINES 998 if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) { 999 unsigned int i; 1000 1001 ctx->debuglist = (memalloc)(arg, 1002 (ctx->max_size+1) * sizeof(debuglist_t)); 1003 if (ctx->debuglist == NULL) { 1004 result = ISC_R_NOMEMORY; 1005 goto error; 1006 } 1007 for (i = 0; i <= ctx->max_size; i++) 1008 ISC_LIST_INIT(ctx->debuglist[i]); 1009 } 1010#endif 1011 1012 ctx->memalloc_failures = 0; 1013 1014 LOCK(&lock); 1015 ISC_LIST_INITANDAPPEND(contexts, ctx, link); 1016 UNLOCK(&lock); 1017 1018 *ctxp = (isc_mem_t *)ctx; 1019 return (ISC_R_SUCCESS); 1020 1021 error: 1022 if (ctx != NULL) { 1023 if (ctx->stats != NULL) 1024 (memfree)(arg, ctx->stats); 1025 if (ctx->freelists != NULL) 1026 (memfree)(arg, ctx->freelists); 1027#if ISC_MEM_TRACKLINES 1028 if (ctx->debuglist != NULL) 1029 (ctx->memfree)(ctx->arg, ctx->debuglist); 1030#endif /* ISC_MEM_TRACKLINES */ 1031 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 1032 DESTROYLOCK(&ctx->lock); 1033 (memfree)(arg, ctx); 1034 } 1035 1036 return (result); 1037} 1038 1039ISC_MEMFUNC_SCOPE isc_result_t 1040isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) { 1041 return (isc__mem_createx2(init_max_size, target_size, 1042 default_memalloc, default_memfree, NULL, 1043 ctxp, ISC_MEMFLAG_DEFAULT)); 1044} 1045 1046ISC_MEMFUNC_SCOPE isc_result_t 1047isc__mem_create2(size_t init_max_size, size_t target_size, 1048 isc_mem_t **ctxp, unsigned int flags) 1049{ 1050 return (isc__mem_createx2(init_max_size, target_size, 1051 default_memalloc, default_memfree, NULL, 1052 ctxp, flags)); 1053} 1054 1055static void 1056destroy(isc__mem_t *ctx) { 1057 unsigned int i; 1058 isc_ondestroy_t ondest; 1059 1060 LOCK(&lock); 1061 ISC_LIST_UNLINK(contexts, ctx, link); 1062 totallost += ctx->inuse; 1063 UNLOCK(&lock); 1064 1065 ctx->common.impmagic = 0; 1066 ctx->common.magic = 0; 1067 1068 INSIST(ISC_LIST_EMPTY(ctx->pools)); 1069 1070#if ISC_MEM_TRACKLINES 1071 if (ctx->debuglist != NULL) { 1072 if (ctx->checkfree) { 1073 for (i = 0; i <= ctx->max_size; i++) { 1074 if (!ISC_LIST_EMPTY(ctx->debuglist[i])) 1075 print_active(ctx, stderr); 1076 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i])); 1077 } 1078 } else { 1079 debuglink_t *dl; 1080 1081 for (i = 0; i <= ctx->max_size; i++) 1082 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]); 1083 dl != NULL; 1084 dl = ISC_LIST_HEAD(ctx->debuglist[i])) { 1085 ISC_LIST_UNLINK(ctx->debuglist[i], 1086 dl, link); 1087 free(dl); 1088 } 1089 } 1090 (ctx->memfree)(ctx->arg, ctx->debuglist); 1091 } 1092#endif 1093 INSIST(ctx->references == 0); 1094 1095 if (ctx->checkfree) { 1096 for (i = 0; i <= ctx->max_size; i++) { 1097#if ISC_MEM_TRACKLINES 1098 if (ctx->stats[i].gets != 0U) 1099 print_active(ctx, stderr); 1100#endif 1101 INSIST(ctx->stats[i].gets == 0U); 1102 } 1103 } 1104 1105 (ctx->memfree)(ctx->arg, ctx->stats); 1106 1107 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1108 for (i = 0; i < ctx->basic_table_count; i++) 1109 (ctx->memfree)(ctx->arg, ctx->basic_table[i]); 1110 (ctx->memfree)(ctx->arg, ctx->freelists); 1111 if (ctx->basic_table != NULL) 1112 (ctx->memfree)(ctx->arg, ctx->basic_table); 1113 } 1114 1115 ondest = ctx->ondestroy; 1116 1117 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 1118 DESTROYLOCK(&ctx->lock); 1119 (ctx->memfree)(ctx->arg, ctx); 1120 1121 isc_ondestroy_notify(&ondest, ctx); 1122} 1123 1124ISC_MEMFUNC_SCOPE void 1125isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) { 1126 isc__mem_t *source = (isc__mem_t *)source0; 1127 1128 REQUIRE(VALID_CONTEXT(source)); 1129 REQUIRE(targetp != NULL && *targetp == NULL); 1130 1131 MCTXLOCK(source, &source->lock); 1132 source->references++; 1133 MCTXUNLOCK(source, &source->lock); 1134 1135 *targetp = (isc_mem_t *)source; 1136} 1137 1138ISC_MEMFUNC_SCOPE void 1139isc__mem_detach(isc_mem_t **ctxp) { 1140 isc__mem_t *ctx; 1141 isc_boolean_t want_destroy = ISC_FALSE; 1142 1143 REQUIRE(ctxp != NULL); 1144 ctx = (isc__mem_t *)*ctxp; 1145 REQUIRE(VALID_CONTEXT(ctx)); 1146 1147 MCTXLOCK(ctx, &ctx->lock); 1148 INSIST(ctx->references > 0); 1149 ctx->references--; 1150 if (ctx->references == 0) 1151 want_destroy = ISC_TRUE; 1152 MCTXUNLOCK(ctx, &ctx->lock); 1153 1154 if (want_destroy) 1155 destroy(ctx); 1156 1157 *ctxp = NULL; 1158} 1159 1160/* 1161 * isc_mem_putanddetach() is the equivalent of: 1162 * 1163 * mctx = NULL; 1164 * isc_mem_attach(ptr->mctx, &mctx); 1165 * isc_mem_detach(&ptr->mctx); 1166 * isc_mem_put(mctx, ptr, sizeof(*ptr); 1167 * isc_mem_detach(&mctx); 1168 */ 1169 1170ISC_MEMFUNC_SCOPE void 1171isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { 1172 isc__mem_t *ctx; 1173 isc_boolean_t want_destroy = ISC_FALSE; 1174 size_info *si; 1175 size_t oldsize; 1176 1177 REQUIRE(ctxp != NULL); 1178 ctx = (isc__mem_t *)*ctxp; 1179 REQUIRE(VALID_CONTEXT(ctx)); 1180 REQUIRE(ptr != NULL); 1181 1182 /* 1183 * Must be before mem_putunlocked() as ctxp is usually within 1184 * [ptr..ptr+size). 1185 */ 1186 *ctxp = NULL; 1187 1188 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { 1189 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { 1190 si = &(((size_info *)ptr)[-1]); 1191 oldsize = si->u.size - ALIGNMENT_SIZE; 1192 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1193 oldsize -= ALIGNMENT_SIZE; 1194 INSIST(oldsize == size); 1195 } 1196 isc_mem_free((isc_mem_t *)ctx, ptr); 1197 1198 MCTXLOCK(ctx, &ctx->lock); 1199 ctx->references--; 1200 if (ctx->references == 0) 1201 want_destroy = ISC_TRUE; 1202 MCTXUNLOCK(ctx, &ctx->lock); 1203 if (want_destroy) 1204 destroy(ctx); 1205 1206 return; 1207 } 1208 1209 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1210 MCTXLOCK(ctx, &ctx->lock); 1211 mem_putunlocked(ctx, ptr, size); 1212 } else { 1213 mem_put(ctx, ptr, size); 1214 MCTXLOCK(ctx, &ctx->lock); 1215 mem_putstats(ctx, ptr, size); 1216 } 1217 1218 DELETE_TRACE(ctx, ptr, size, file, line); 1219 INSIST(ctx->references > 0); 1220 ctx->references--; 1221 if (ctx->references == 0) 1222 want_destroy = ISC_TRUE; 1223 1224 MCTXUNLOCK(ctx, &ctx->lock); 1225 1226 if (want_destroy) 1227 destroy(ctx); 1228} 1229 1230ISC_MEMFUNC_SCOPE void 1231isc__mem_destroy(isc_mem_t **ctxp) { 1232 isc__mem_t *ctx; 1233 1234 /* 1235 * This routine provides legacy support for callers who use mctxs 1236 * without attaching/detaching. 1237 */ 1238 1239 REQUIRE(ctxp != NULL); 1240 ctx = (isc__mem_t *)*ctxp; 1241 REQUIRE(VALID_CONTEXT(ctx)); 1242 1243 MCTXLOCK(ctx, &ctx->lock); 1244#if ISC_MEM_TRACKLINES 1245 if (ctx->references != 1) 1246 print_active(ctx, stderr); 1247#endif 1248 REQUIRE(ctx->references == 1); 1249 ctx->references--; 1250 MCTXUNLOCK(ctx, &ctx->lock); 1251 1252 destroy(ctx); 1253 1254 *ctxp = NULL; 1255} 1256 1257ISC_MEMFUNC_SCOPE isc_result_t 1258isc__mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) { 1259 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1260 isc_result_t res; 1261 1262 MCTXLOCK(ctx, &ctx->lock); 1263 res = isc_ondestroy_register(&ctx->ondestroy, task, event); 1264 MCTXUNLOCK(ctx, &ctx->lock); 1265 1266 return (res); 1267} 1268 1269ISC_MEMFUNC_SCOPE void * 1270isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) { 1271 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1272 void *ptr; 1273 isc_boolean_t call_water = ISC_FALSE; 1274 1275 REQUIRE(VALID_CONTEXT(ctx)); 1276 1277 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) 1278 return (isc__mem_allocate(ctx0, size FLARG_PASS)); 1279 1280 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1281 MCTXLOCK(ctx, &ctx->lock); 1282 ptr = mem_getunlocked(ctx, size); 1283 } else { 1284 ptr = mem_get(ctx, size); 1285 MCTXLOCK(ctx, &ctx->lock); 1286 if (ptr != NULL) 1287 mem_getstats(ctx, size); 1288 } 1289 1290 ADD_TRACE(ctx, ptr, size, file, line); 1291 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1292 !ctx->is_overmem) { 1293 ctx->is_overmem = ISC_TRUE; 1294 } 1295 if (ctx->hi_water != 0U && !ctx->hi_called && 1296 ctx->inuse > ctx->hi_water) { 1297 call_water = ISC_TRUE; 1298 } 1299 if (ctx->inuse > ctx->maxinuse) { 1300 ctx->maxinuse = ctx->inuse; 1301 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1302 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) 1303 fprintf(stderr, "maxinuse = %lu\n", 1304 (unsigned long)ctx->inuse); 1305 } 1306 MCTXUNLOCK(ctx, &ctx->lock); 1307 1308 if (call_water) 1309 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); 1310 1311 return (ptr); 1312} 1313 1314ISC_MEMFUNC_SCOPE void 1315isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) { 1316 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1317 isc_boolean_t call_water = ISC_FALSE; 1318 size_info *si; 1319 size_t oldsize; 1320 1321 REQUIRE(VALID_CONTEXT(ctx)); 1322 REQUIRE(ptr != NULL); 1323 1324 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { 1325 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { 1326 si = &(((size_info *)ptr)[-1]); 1327 oldsize = si->u.size - ALIGNMENT_SIZE; 1328 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1329 oldsize -= ALIGNMENT_SIZE; 1330 INSIST(oldsize == size); 1331 } 1332 isc_mem_free((isc_mem_t *)ctx, ptr); 1333 return; 1334 } 1335 1336 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1337 MCTXLOCK(ctx, &ctx->lock); 1338 mem_putunlocked(ctx, ptr, size); 1339 } else { 1340 mem_put(ctx, ptr, size); 1341 MCTXLOCK(ctx, &ctx->lock); 1342 mem_putstats(ctx, ptr, size); 1343 } 1344 1345 DELETE_TRACE(ctx, ptr, size, file, line); 1346 1347 /* 1348 * The check against ctx->lo_water == 0 is for the condition 1349 * when the context was pushed over hi_water but then had 1350 * isc_mem_setwater() called with 0 for hi_water and lo_water. 1351 */ 1352 if (ctx->is_overmem && 1353 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1354 ctx->is_overmem = ISC_FALSE; 1355 } 1356 if (ctx->hi_called && 1357 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1358 if (ctx->water != NULL) 1359 call_water = ISC_TRUE; 1360 } 1361 MCTXUNLOCK(ctx, &ctx->lock); 1362 1363 if (call_water) 1364 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1365} 1366 1367ISC_MEMFUNC_SCOPE void 1368isc__mem_waterack(isc_mem_t *ctx0, int flag) { 1369 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1370 1371 REQUIRE(VALID_CONTEXT(ctx)); 1372 1373 MCTXLOCK(ctx, &ctx->lock); 1374 if (flag == ISC_MEM_LOWATER) 1375 ctx->hi_called = ISC_FALSE; 1376 else if (flag == ISC_MEM_HIWATER) 1377 ctx->hi_called = ISC_TRUE; 1378 MCTXUNLOCK(ctx, &ctx->lock); 1379} 1380 1381#if ISC_MEM_TRACKLINES 1382static void 1383print_active(isc__mem_t *mctx, FILE *out) { 1384 if (mctx->debuglist != NULL) { 1385 debuglink_t *dl; 1386 unsigned int i, j; 1387 const char *format; 1388 isc_boolean_t found; 1389 1390 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1391 ISC_MSG_DUMPALLOC, 1392 "Dump of all outstanding " 1393 "memory allocations:\n")); 1394 found = ISC_FALSE; 1395 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1396 ISC_MSG_PTRFILELINE, 1397 "\tptr %p size %u file %s line %u\n"); 1398 for (i = 0; i <= mctx->max_size; i++) { 1399 dl = ISC_LIST_HEAD(mctx->debuglist[i]); 1400 1401 if (dl != NULL) 1402 found = ISC_TRUE; 1403 1404 while (dl != NULL) { 1405 for (j = 0; j < DEBUGLIST_COUNT; j++) 1406 if (dl->ptr[j] != NULL) 1407 fprintf(out, format, 1408 dl->ptr[j], 1409 dl->size[j], 1410 dl->file[j], 1411 dl->line[j]); 1412 dl = ISC_LIST_NEXT(dl, link); 1413 } 1414 } 1415 if (!found) 1416 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1417 ISC_MSG_NONE, "\tNone.\n")); 1418 } 1419} 1420#endif 1421 1422/* 1423 * Print the stats[] on the stream "out" with suitable formatting. 1424 */ 1425ISC_MEMFUNC_SCOPE void 1426isc__mem_stats(isc_mem_t *ctx0, FILE *out) { 1427 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1428 size_t i; 1429 const struct stats *s; 1430 const isc__mempool_t *pool; 1431 1432 REQUIRE(VALID_CONTEXT(ctx)); 1433 MCTXLOCK(ctx, &ctx->lock); 1434 1435 for (i = 0; i <= ctx->max_size; i++) { 1436 s = &ctx->stats[i]; 1437 1438 if (s->totalgets == 0U && s->gets == 0U) 1439 continue; 1440 fprintf(out, "%s%5lu: %11lu gets, %11lu rem", 1441 (i == ctx->max_size) ? ">=" : " ", 1442 (unsigned long) i, s->totalgets, s->gets); 1443 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 && 1444 (s->blocks != 0U || s->freefrags != 0U)) 1445 fprintf(out, " (%lu bl, %lu ff)", 1446 s->blocks, s->freefrags); 1447 fputc('\n', out); 1448 } 1449 1450 /* 1451 * Note that since a pool can be locked now, these stats might be 1452 * somewhat off if the pool is in active use at the time the stats 1453 * are dumped. The link fields are protected by the isc_mem_t's 1454 * lock, however, so walking this list and extracting integers from 1455 * stats fields is always safe. 1456 */ 1457 pool = ISC_LIST_HEAD(ctx->pools); 1458 if (pool != NULL) { 1459 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1460 ISC_MSG_POOLSTATS, 1461 "[Pool statistics]\n")); 1462 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n", 1463 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1464 ISC_MSG_POOLNAME, "name"), 1465 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1466 ISC_MSG_POOLSIZE, "size"), 1467 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1468 ISC_MSG_POOLMAXALLOC, "maxalloc"), 1469 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1470 ISC_MSG_POOLALLOCATED, "allocated"), 1471 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1472 ISC_MSG_POOLFREECOUNT, "freecount"), 1473 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1474 ISC_MSG_POOLFREEMAX, "freemax"), 1475 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1476 ISC_MSG_POOLFILLCOUNT, "fillcount"), 1477 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1478 ISC_MSG_POOLGETS, "gets"), 1479 "L"); 1480 } 1481 while (pool != NULL) { 1482 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n", 1483 pool->name, (unsigned long) pool->size, pool->maxalloc, 1484 pool->allocated, pool->freecount, pool->freemax, 1485 pool->fillcount, pool->gets, 1486 (pool->lock == NULL ? "N" : "Y")); 1487 pool = ISC_LIST_NEXT(pool, link); 1488 } 1489 1490#if ISC_MEM_TRACKLINES 1491 print_active(ctx, out); 1492#endif 1493 1494 MCTXUNLOCK(ctx, &ctx->lock); 1495} 1496 1497/* 1498 * Replacements for malloc() and free() -- they implicitly remember the 1499 * size of the object allocated (with some additional overhead). 1500 */ 1501 1502static void * 1503isc__mem_allocateunlocked(isc_mem_t *ctx0, size_t size) { 1504 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1505 size_info *si; 1506 1507 size += ALIGNMENT_SIZE; 1508 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1509 size += ALIGNMENT_SIZE; 1510 1511 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) 1512 si = mem_getunlocked(ctx, size); 1513 else 1514 si = mem_get(ctx, size); 1515 1516 if (si == NULL) 1517 return (NULL); 1518 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1519 si->u.ctx = ctx; 1520 si++; 1521 } 1522 si->u.size = size; 1523 return (&si[1]); 1524} 1525 1526ISC_MEMFUNC_SCOPE void * 1527isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) { 1528 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1529 size_info *si; 1530 isc_boolean_t call_water = ISC_FALSE; 1531 1532 REQUIRE(VALID_CONTEXT(ctx)); 1533 1534 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1535 MCTXLOCK(ctx, &ctx->lock); 1536 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size); 1537 } else { 1538 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size); 1539 MCTXLOCK(ctx, &ctx->lock); 1540 if (si != NULL) 1541 mem_getstats(ctx, si[-1].u.size); 1542 } 1543 1544#if ISC_MEM_TRACKLINES 1545 ADD_TRACE(ctx, si, si[-1].u.size, file, line); 1546#endif 1547 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1548 !ctx->is_overmem) { 1549 ctx->is_overmem = ISC_TRUE; 1550 } 1551 1552 if (ctx->hi_water != 0U && !ctx->hi_called && 1553 ctx->inuse > ctx->hi_water) { 1554 ctx->hi_called = ISC_TRUE; 1555 call_water = ISC_TRUE; 1556 } 1557 if (ctx->inuse > ctx->maxinuse) { 1558 ctx->maxinuse = ctx->inuse; 1559 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1560 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) 1561 fprintf(stderr, "maxinuse = %lu\n", 1562 (unsigned long)ctx->inuse); 1563 } 1564 MCTXUNLOCK(ctx, &ctx->lock); 1565 1566 if (call_water) 1567 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); 1568 1569 return (si); 1570} 1571 1572ISC_MEMFUNC_SCOPE void * 1573isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) { 1574 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1575 void *new_ptr = NULL; 1576 size_t oldsize, copysize; 1577 1578 REQUIRE(VALID_CONTEXT(ctx)); 1579 1580 /* 1581 * This function emulates the realloc(3) standard library function: 1582 * - if size > 0, allocate new memory; and if ptr is non NULL, copy 1583 * as much of the old contents to the new buffer and free the old one. 1584 * Note that when allocation fails the original pointer is intact; 1585 * the caller must free it. 1586 * - if size is 0 and ptr is non NULL, simply free the given ptr. 1587 * - this function returns: 1588 * pointer to the newly allocated memory, or 1589 * NULL if allocation fails or doesn't happen. 1590 */ 1591 if (size > 0U) { 1592 new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS); 1593 if (new_ptr != NULL && ptr != NULL) { 1594 oldsize = (((size_info *)ptr)[-1]).u.size; 1595 INSIST(oldsize >= ALIGNMENT_SIZE); 1596 oldsize -= ALIGNMENT_SIZE; 1597 copysize = oldsize > size ? size : oldsize; 1598 memcpy(new_ptr, ptr, copysize); 1599 isc__mem_free(ctx0, ptr FLARG_PASS); 1600 } 1601 } else if (ptr != NULL) 1602 isc__mem_free(ctx0, ptr FLARG_PASS); 1603 1604 return (new_ptr); 1605} 1606 1607ISC_MEMFUNC_SCOPE void 1608isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) { 1609 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1610 size_info *si; 1611 size_t size; 1612 isc_boolean_t call_water= ISC_FALSE; 1613 1614 REQUIRE(VALID_CONTEXT(ctx)); 1615 REQUIRE(ptr != NULL); 1616 1617 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1618 si = &(((size_info *)ptr)[-2]); 1619 REQUIRE(si->u.ctx == ctx); 1620 size = si[1].u.size; 1621 } else { 1622 si = &(((size_info *)ptr)[-1]); 1623 size = si->u.size; 1624 } 1625 1626 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1627 MCTXLOCK(ctx, &ctx->lock); 1628 mem_putunlocked(ctx, si, size); 1629 } else { 1630 mem_put(ctx, si, size); 1631 MCTXLOCK(ctx, &ctx->lock); 1632 mem_putstats(ctx, si, size); 1633 } 1634 1635 DELETE_TRACE(ctx, ptr, size, file, line); 1636 1637 /* 1638 * The check against ctx->lo_water == 0 is for the condition 1639 * when the context was pushed over hi_water but then had 1640 * isc_mem_setwater() called with 0 for hi_water and lo_water. 1641 */ 1642 if (ctx->is_overmem && 1643 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1644 ctx->is_overmem = ISC_FALSE; 1645 } 1646 1647 if (ctx->hi_called && 1648 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1649 ctx->hi_called = ISC_FALSE; 1650 1651 if (ctx->water != NULL) 1652 call_water = ISC_TRUE; 1653 } 1654 MCTXUNLOCK(ctx, &ctx->lock); 1655 1656 if (call_water) 1657 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1658} 1659 1660 1661/* 1662 * Other useful things. 1663 */ 1664 1665ISC_MEMFUNC_SCOPE char * 1666isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) { 1667 isc__mem_t *mctx = (isc__mem_t *)mctx0; 1668 size_t len; 1669 char *ns; 1670 1671 REQUIRE(VALID_CONTEXT(mctx)); 1672 REQUIRE(s != NULL); 1673 1674 len = strlen(s); 1675 1676 ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS); 1677 1678 if (ns != NULL) 1679 strncpy(ns, s, len + 1); 1680 1681 return (ns); 1682} 1683 1684ISC_MEMFUNC_SCOPE void 1685isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) { 1686 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1687 1688 REQUIRE(VALID_CONTEXT(ctx)); 1689 MCTXLOCK(ctx, &ctx->lock); 1690 1691 ctx->checkfree = flag; 1692 1693 MCTXUNLOCK(ctx, &ctx->lock); 1694} 1695 1696/* 1697 * Quotas 1698 */ 1699 1700ISC_MEMFUNC_SCOPE void 1701isc__mem_setquota(isc_mem_t *ctx0, size_t quota) { 1702 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1703 1704 REQUIRE(VALID_CONTEXT(ctx)); 1705 MCTXLOCK(ctx, &ctx->lock); 1706 1707 ctx->quota = quota; 1708 1709 MCTXUNLOCK(ctx, &ctx->lock); 1710} 1711 1712ISC_MEMFUNC_SCOPE size_t 1713isc__mem_getquota(isc_mem_t *ctx0) { 1714 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1715 size_t quota; 1716 1717 REQUIRE(VALID_CONTEXT(ctx)); 1718 MCTXLOCK(ctx, &ctx->lock); 1719 1720 quota = ctx->quota; 1721 1722 MCTXUNLOCK(ctx, &ctx->lock); 1723 1724 return (quota); 1725} 1726 1727ISC_MEMFUNC_SCOPE size_t 1728isc__mem_inuse(isc_mem_t *ctx0) { 1729 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1730 size_t inuse; 1731 1732 REQUIRE(VALID_CONTEXT(ctx)); 1733 MCTXLOCK(ctx, &ctx->lock); 1734 1735 inuse = ctx->inuse; 1736 1737 MCTXUNLOCK(ctx, &ctx->lock); 1738 1739 return (inuse); 1740} 1741 1742ISC_MEMFUNC_SCOPE void 1743isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg, 1744 size_t hiwater, size_t lowater) 1745{ 1746 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1747 isc_boolean_t callwater = ISC_FALSE; 1748 isc_mem_water_t oldwater; 1749 void *oldwater_arg; 1750 1751 REQUIRE(VALID_CONTEXT(ctx)); 1752 REQUIRE(hiwater >= lowater); 1753 1754 MCTXLOCK(ctx, &ctx->lock); 1755 oldwater = ctx->water; 1756 oldwater_arg = ctx->water_arg; 1757 if (water == NULL) { 1758 callwater = ctx->hi_called; 1759 ctx->water = NULL; 1760 ctx->water_arg = NULL; 1761 ctx->hi_water = 0; 1762 ctx->lo_water = 0; 1763 ctx->hi_called = ISC_FALSE; 1764 } else { 1765 if (ctx->hi_called && 1766 (ctx->water != water || ctx->water_arg != water_arg || 1767 ctx->inuse < lowater || lowater == 0U)) 1768 callwater = ISC_TRUE; 1769 ctx->water = water; 1770 ctx->water_arg = water_arg; 1771 ctx->hi_water = hiwater; 1772 ctx->lo_water = lowater; 1773 ctx->hi_called = ISC_FALSE; 1774 } 1775 MCTXUNLOCK(ctx, &ctx->lock); 1776 1777 if (callwater && oldwater != NULL) 1778 (oldwater)(oldwater_arg, ISC_MEM_LOWATER); 1779} 1780 1781ISC_MEMFUNC_SCOPE isc_boolean_t 1782isc__mem_isovermem(isc_mem_t *ctx0) { 1783 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1784 1785 REQUIRE(VALID_CONTEXT(ctx)); 1786 1787 /* 1788 * We don't bother to lock the context because 100% accuracy isn't 1789 * necessary (and even if we locked the context the returned value 1790 * could be different from the actual state when it's used anyway) 1791 */ 1792 return (ctx->is_overmem); 1793} 1794 1795ISC_MEMFUNC_SCOPE void 1796isc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) { 1797 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1798 1799 REQUIRE(VALID_CONTEXT(ctx)); 1800 1801 LOCK(&ctx->lock); 1802 memset(ctx->name, 0, sizeof(ctx->name)); 1803 strncpy(ctx->name, name, sizeof(ctx->name) - 1); 1804 ctx->tag = tag; 1805 UNLOCK(&ctx->lock); 1806} 1807 1808ISC_MEMFUNC_SCOPE const char * 1809isc__mem_getname(isc_mem_t *ctx0) { 1810 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1811 1812 REQUIRE(VALID_CONTEXT(ctx)); 1813 1814 return (ctx->name); 1815} 1816 1817ISC_MEMFUNC_SCOPE void * 1818isc__mem_gettag(isc_mem_t *ctx0) { 1819 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1820 1821 REQUIRE(VALID_CONTEXT(ctx)); 1822 1823 return (ctx->tag); 1824} 1825 1826/* 1827 * Memory pool stuff 1828 */ 1829 1830ISC_MEMFUNC_SCOPE isc_result_t 1831isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) { 1832 isc__mem_t *mctx = (isc__mem_t *)mctx0; 1833 isc__mempool_t *mpctx; 1834 1835 REQUIRE(VALID_CONTEXT(mctx)); 1836 REQUIRE(size > 0U); 1837 REQUIRE(mpctxp != NULL && *mpctxp == NULL); 1838 1839 /* 1840 * Allocate space for this pool, initialize values, and if all works 1841 * well, attach to the memory context. 1842 */ 1843 mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t)); 1844 if (mpctx == NULL) 1845 return (ISC_R_NOMEMORY); 1846 1847 mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods; 1848 mpctx->common.impmagic = MEMPOOL_MAGIC; 1849 mpctx->common.magic = ISCAPI_MPOOL_MAGIC; 1850 mpctx->lock = NULL; 1851 mpctx->mctx = mctx; 1852 mpctx->size = size; 1853 mpctx->maxalloc = UINT_MAX; 1854 mpctx->allocated = 0; 1855 mpctx->freecount = 0; 1856 mpctx->freemax = 1; 1857 mpctx->fillcount = 1; 1858 mpctx->gets = 0; 1859#if ISC_MEMPOOL_NAMES 1860 mpctx->name[0] = 0; 1861#endif 1862 mpctx->items = NULL; 1863 1864 *mpctxp = (isc_mempool_t *)mpctx; 1865 1866 MCTXLOCK(mctx, &mctx->lock); 1867 ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link); 1868 mctx->poolcnt++; 1869 MCTXUNLOCK(mctx, &mctx->lock); 1870 1871 return (ISC_R_SUCCESS); 1872} 1873 1874ISC_MEMFUNC_SCOPE void 1875isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) { 1876 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1877 1878 REQUIRE(name != NULL); 1879 REQUIRE(VALID_MEMPOOL(mpctx)); 1880 1881#if ISC_MEMPOOL_NAMES 1882 if (mpctx->lock != NULL) 1883 LOCK(mpctx->lock); 1884 1885 strncpy(mpctx->name, name, sizeof(mpctx->name) - 1); 1886 mpctx->name[sizeof(mpctx->name) - 1] = '\0'; 1887 1888 if (mpctx->lock != NULL) 1889 UNLOCK(mpctx->lock); 1890#else 1891 UNUSED(mpctx); 1892 UNUSED(name); 1893#endif 1894} 1895 1896ISC_MEMFUNC_SCOPE void 1897isc__mempool_destroy(isc_mempool_t **mpctxp) { 1898 isc__mempool_t *mpctx; 1899 isc__mem_t *mctx; 1900 isc_mutex_t *lock; 1901 element *item; 1902 1903 REQUIRE(mpctxp != NULL); 1904 mpctx = (isc__mempool_t *)*mpctxp; 1905 REQUIRE(VALID_MEMPOOL(mpctx)); 1906#if ISC_MEMPOOL_NAMES 1907 if (mpctx->allocated > 0) 1908 UNEXPECTED_ERROR(__FILE__, __LINE__, 1909 "isc__mempool_destroy(): mempool %s " 1910 "leaked memory", 1911 mpctx->name); 1912#endif 1913 REQUIRE(mpctx->allocated == 0); 1914 1915 mctx = mpctx->mctx; 1916 1917 lock = mpctx->lock; 1918 1919 if (lock != NULL) 1920 LOCK(lock); 1921 1922 /* 1923 * Return any items on the free list 1924 */ 1925 MCTXLOCK(mctx, &mctx->lock); 1926 while (mpctx->items != NULL) { 1927 INSIST(mpctx->freecount > 0); 1928 mpctx->freecount--; 1929 item = mpctx->items; 1930 mpctx->items = item->next; 1931 1932 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1933 mem_putunlocked(mctx, item, mpctx->size); 1934 } else { 1935 mem_put(mctx, item, mpctx->size); 1936 mem_putstats(mctx, item, mpctx->size); 1937 } 1938 } 1939 MCTXUNLOCK(mctx, &mctx->lock); 1940 1941 /* 1942 * Remove our linked list entry from the memory context. 1943 */ 1944 MCTXLOCK(mctx, &mctx->lock); 1945 ISC_LIST_UNLINK(mctx->pools, mpctx, link); 1946 mctx->poolcnt--; 1947 MCTXUNLOCK(mctx, &mctx->lock); 1948 1949 mpctx->common.impmagic = 0; 1950 mpctx->common.magic = 0; 1951 1952 isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t)); 1953 1954 if (lock != NULL) 1955 UNLOCK(lock); 1956 1957 *mpctxp = NULL; 1958} 1959 1960ISC_MEMFUNC_SCOPE void 1961isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) { 1962 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1963 1964 REQUIRE(VALID_MEMPOOL(mpctx)); 1965 REQUIRE(mpctx->lock == NULL); 1966 REQUIRE(lock != NULL); 1967 1968 mpctx->lock = lock; 1969} 1970 1971ISC_MEMFUNC_SCOPE void * 1972isc___mempool_get(isc_mempool_t *mpctx0 FLARG) { 1973 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1974 element *item; 1975 isc__mem_t *mctx; 1976 unsigned int i; 1977 1978 REQUIRE(VALID_MEMPOOL(mpctx)); 1979 1980 mctx = mpctx->mctx; 1981 1982 if (mpctx->lock != NULL) 1983 LOCK(mpctx->lock); 1984 1985 /* 1986 * Don't let the caller go over quota 1987 */ 1988 if (mpctx->allocated >= mpctx->maxalloc) { 1989 item = NULL; 1990 goto out; 1991 } 1992 1993 /* 1994 * if we have a free list item, return the first here 1995 */ 1996 item = mpctx->items; 1997 if (item != NULL) { 1998 mpctx->items = item->next; 1999 INSIST(mpctx->freecount > 0); 2000 mpctx->freecount--; 2001 mpctx->gets++; 2002 mpctx->allocated++; 2003 goto out; 2004 } 2005 2006 /* 2007 * We need to dip into the well. Lock the memory context here and 2008 * fill up our free list. 2009 */ 2010 MCTXLOCK(mctx, &mctx->lock); 2011 for (i = 0; i < mpctx->fillcount; i++) { 2012 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2013 item = mem_getunlocked(mctx, mpctx->size); 2014 } else { 2015 item = mem_get(mctx, mpctx->size); 2016 if (item != NULL) 2017 mem_getstats(mctx, mpctx->size); 2018 } 2019 if (item == NULL) 2020 break; 2021 item->next = mpctx->items; 2022 mpctx->items = item; 2023 mpctx->freecount++; 2024 } 2025 MCTXUNLOCK(mctx, &mctx->lock); 2026 2027 /* 2028 * If we didn't get any items, return NULL. 2029 */ 2030 item = mpctx->items; 2031 if (item == NULL) 2032 goto out; 2033 2034 mpctx->items = item->next; 2035 mpctx->freecount--; 2036 mpctx->gets++; 2037 mpctx->allocated++; 2038 2039 out: 2040 if (mpctx->lock != NULL) 2041 UNLOCK(mpctx->lock); 2042 2043#if ISC_MEM_TRACKLINES 2044 if (item != NULL) { 2045 MCTXLOCK(mctx, &mctx->lock); 2046 ADD_TRACE(mctx, item, mpctx->size, file, line); 2047 MCTXUNLOCK(mctx, &mctx->lock); 2048 } 2049#endif /* ISC_MEM_TRACKLINES */ 2050 2051 return (item); 2052} 2053 2054ISC_MEMFUNC_SCOPE void 2055isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) { 2056 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2057 isc__mem_t *mctx; 2058 element *item; 2059 2060 REQUIRE(VALID_MEMPOOL(mpctx)); 2061 REQUIRE(mem != NULL); 2062 2063 mctx = mpctx->mctx; 2064 2065 if (mpctx->lock != NULL) 2066 LOCK(mpctx->lock); 2067 2068 INSIST(mpctx->allocated > 0); 2069 mpctx->allocated--; 2070 2071#if ISC_MEM_TRACKLINES 2072 MCTXLOCK(mctx, &mctx->lock); 2073 DELETE_TRACE(mctx, mem, mpctx->size, file, line); 2074 MCTXUNLOCK(mctx, &mctx->lock); 2075#endif /* ISC_MEM_TRACKLINES */ 2076 2077 /* 2078 * If our free list is full, return this to the mctx directly. 2079 */ 2080 if (mpctx->freecount >= mpctx->freemax) { 2081 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2082 MCTXLOCK(mctx, &mctx->lock); 2083 mem_putunlocked(mctx, mem, mpctx->size); 2084 MCTXUNLOCK(mctx, &mctx->lock); 2085 } else { 2086 mem_put(mctx, mem, mpctx->size); 2087 MCTXLOCK(mctx, &mctx->lock); 2088 mem_putstats(mctx, mem, mpctx->size); 2089 MCTXUNLOCK(mctx, &mctx->lock); 2090 } 2091 if (mpctx->lock != NULL) 2092 UNLOCK(mpctx->lock); 2093 return; 2094 } 2095 2096 /* 2097 * Otherwise, attach it to our free list and bump the counter. 2098 */ 2099 mpctx->freecount++; 2100 item = (element *)mem; 2101 item->next = mpctx->items; 2102 mpctx->items = item; 2103 2104 if (mpctx->lock != NULL) 2105 UNLOCK(mpctx->lock); 2106} 2107 2108/* 2109 * Quotas 2110 */ 2111 2112ISC_MEMFUNC_SCOPE void 2113isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) { 2114 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2115 2116 REQUIRE(VALID_MEMPOOL(mpctx)); 2117 2118 if (mpctx->lock != NULL) 2119 LOCK(mpctx->lock); 2120 2121 mpctx->freemax = limit; 2122 2123 if (mpctx->lock != NULL) 2124 UNLOCK(mpctx->lock); 2125} 2126 2127ISC_MEMFUNC_SCOPE unsigned int 2128isc__mempool_getfreemax(isc_mempool_t *mpctx0) { 2129 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2130 unsigned int freemax; 2131 2132 REQUIRE(VALID_MEMPOOL(mpctx)); 2133 2134 if (mpctx->lock != NULL) 2135 LOCK(mpctx->lock); 2136 2137 freemax = mpctx->freemax; 2138 2139 if (mpctx->lock != NULL) 2140 UNLOCK(mpctx->lock); 2141 2142 return (freemax); 2143} 2144 2145ISC_MEMFUNC_SCOPE unsigned int 2146isc__mempool_getfreecount(isc_mempool_t *mpctx0) { 2147 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2148 unsigned int freecount; 2149 2150 REQUIRE(VALID_MEMPOOL(mpctx)); 2151 2152 if (mpctx->lock != NULL) 2153 LOCK(mpctx->lock); 2154 2155 freecount = mpctx->freecount; 2156 2157 if (mpctx->lock != NULL) 2158 UNLOCK(mpctx->lock); 2159 2160 return (freecount); 2161} 2162 2163ISC_MEMFUNC_SCOPE void 2164isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) { 2165 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2166 2167 REQUIRE(limit > 0); 2168 2169 REQUIRE(VALID_MEMPOOL(mpctx)); 2170 2171 if (mpctx->lock != NULL) 2172 LOCK(mpctx->lock); 2173 2174 mpctx->maxalloc = limit; 2175 2176 if (mpctx->lock != NULL) 2177 UNLOCK(mpctx->lock); 2178} 2179 2180ISC_MEMFUNC_SCOPE unsigned int 2181isc__mempool_getmaxalloc(isc_mempool_t *mpctx0) { 2182 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2183 unsigned int maxalloc; 2184 2185 REQUIRE(VALID_MEMPOOL(mpctx)); 2186 2187 if (mpctx->lock != NULL) 2188 LOCK(mpctx->lock); 2189 2190 maxalloc = mpctx->maxalloc; 2191 2192 if (mpctx->lock != NULL) 2193 UNLOCK(mpctx->lock); 2194 2195 return (maxalloc); 2196} 2197 2198ISC_MEMFUNC_SCOPE unsigned int 2199isc__mempool_getallocated(isc_mempool_t *mpctx0) { 2200 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2201 unsigned int allocated; 2202 2203 REQUIRE(VALID_MEMPOOL(mpctx)); 2204 2205 if (mpctx->lock != NULL) 2206 LOCK(mpctx->lock); 2207 2208 allocated = mpctx->allocated; 2209 2210 if (mpctx->lock != NULL) 2211 UNLOCK(mpctx->lock); 2212 2213 return (allocated); 2214} 2215 2216ISC_MEMFUNC_SCOPE void 2217isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) { 2218 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2219 2220 REQUIRE(limit > 0); 2221 REQUIRE(VALID_MEMPOOL(mpctx)); 2222 2223 if (mpctx->lock != NULL) 2224 LOCK(mpctx->lock); 2225 2226 mpctx->fillcount = limit; 2227 2228 if (mpctx->lock != NULL) 2229 UNLOCK(mpctx->lock); 2230} 2231 2232ISC_MEMFUNC_SCOPE unsigned int 2233isc__mempool_getfillcount(isc_mempool_t *mpctx0) { 2234 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2235 2236 unsigned int fillcount; 2237 2238 REQUIRE(VALID_MEMPOOL(mpctx)); 2239 2240 if (mpctx->lock != NULL) 2241 LOCK(mpctx->lock); 2242 2243 fillcount = mpctx->fillcount; 2244 2245 if (mpctx->lock != NULL) 2246 UNLOCK(mpctx->lock); 2247 2248 return (fillcount); 2249} 2250 2251#ifdef USE_MEMIMPREGISTER 2252isc_result_t 2253isc__mem_register() { 2254 return (isc_mem_register(isc__mem_create2)); 2255} 2256#endif 2257 2258#ifdef BIND9 2259ISC_MEMFUNC_SCOPE void 2260isc__mem_printactive(isc_mem_t *ctx0, FILE *file) { 2261 isc__mem_t *ctx = (isc__mem_t *)ctx0; 2262 2263 REQUIRE(VALID_CONTEXT(ctx)); 2264 REQUIRE(file != NULL); 2265 2266#if !ISC_MEM_TRACKLINES 2267 UNUSED(ctx); 2268 UNUSED(file); 2269#else 2270 print_active(ctx, file); 2271#endif 2272} 2273 2274ISC_MEMFUNC_SCOPE void 2275isc__mem_printallactive(FILE *file) { 2276#if !ISC_MEM_TRACKLINES 2277 UNUSED(file); 2278#else 2279 isc__mem_t *ctx; 2280 2281 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2282 2283 LOCK(&lock); 2284 for (ctx = ISC_LIST_HEAD(contexts); 2285 ctx != NULL; 2286 ctx = ISC_LIST_NEXT(ctx, link)) { 2287 fprintf(file, "context: %p\n", ctx); 2288 print_active(ctx, file); 2289 } 2290 UNLOCK(&lock); 2291#endif 2292} 2293 2294ISC_MEMFUNC_SCOPE void 2295isc__mem_checkdestroyed(FILE *file) { 2296 2297 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2298 2299 LOCK(&lock); 2300 if (!ISC_LIST_EMPTY(contexts)) { 2301#if ISC_MEM_TRACKLINES 2302 isc__mem_t *ctx; 2303 2304 for (ctx = ISC_LIST_HEAD(contexts); 2305 ctx != NULL; 2306 ctx = ISC_LIST_NEXT(ctx, link)) { 2307 fprintf(file, "context: %p\n", ctx); 2308 print_active(ctx, file); 2309 } 2310 fflush(file); 2311#endif 2312 INSIST(0); 2313 } 2314 UNLOCK(&lock); 2315} 2316 2317ISC_MEMFUNC_SCOPE unsigned int 2318isc_mem_references(isc_mem_t *ctx0) { 2319 isc__mem_t *ctx = (isc__mem_t *)ctx0; 2320 unsigned int references; 2321 2322 REQUIRE(VALID_CONTEXT(ctx)); 2323 2324 MCTXLOCK(ctx, &ctx->lock); 2325 references = ctx->references; 2326 MCTXUNLOCK(ctx, &ctx->lock); 2327 2328 return (references); 2329} 2330 2331#ifdef HAVE_LIBXML2 2332 2333typedef struct summarystat { 2334 isc_uint64_t total; 2335 isc_uint64_t inuse; 2336 isc_uint64_t blocksize; 2337 isc_uint64_t contextsize; 2338} summarystat_t; 2339 2340static void 2341renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) { 2342 REQUIRE(VALID_CONTEXT(ctx)); 2343 2344 xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"); 2345 2346 xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"); 2347 xmlTextWriterWriteFormatString(writer, "%p", ctx); 2348 xmlTextWriterEndElement(writer); /* id */ 2349 2350 if (ctx->name[0] != 0) { 2351 xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); 2352 xmlTextWriterWriteFormatString(writer, "%s", ctx->name); 2353 xmlTextWriterEndElement(writer); /* name */ 2354 } 2355 2356 REQUIRE(VALID_CONTEXT(ctx)); 2357 MCTXLOCK(ctx, &ctx->lock); 2358 2359 summary->contextsize += sizeof(*ctx) + 2360 (ctx->max_size + 1) * sizeof(struct stats) + 2361 ctx->max_size * sizeof(element *) + 2362 ctx->basic_table_count * sizeof(char *); 2363#if ISC_MEM_TRACKLINES 2364 if (ctx->debuglist != NULL) { 2365 summary->contextsize += 2366 (ctx->max_size + 1) * sizeof(debuglist_t) + 2367 ctx->debuglistcnt * sizeof(debuglink_t); 2368 } 2369#endif 2370 xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); 2371 xmlTextWriterWriteFormatString(writer, "%d", ctx->references); 2372 xmlTextWriterEndElement(writer); /* references */ 2373 2374 summary->total += ctx->total; 2375 xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"); 2376 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2377 (isc_uint64_t)ctx->total); 2378 xmlTextWriterEndElement(writer); /* total */ 2379 2380 summary->inuse += ctx->inuse; 2381 xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"); 2382 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2383 (isc_uint64_t)ctx->inuse); 2384 xmlTextWriterEndElement(writer); /* inuse */ 2385 2386 xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"); 2387 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2388 (isc_uint64_t)ctx->maxinuse); 2389 xmlTextWriterEndElement(writer); /* maxinuse */ 2390 2391 xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"); 2392 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2393 summary->blocksize += ctx->basic_table_count * 2394 NUM_BASIC_BLOCKS * ctx->mem_target; 2395 xmlTextWriterWriteFormatString(writer, 2396 "%" ISC_PRINT_QUADFORMAT "u", 2397 (isc_uint64_t) 2398 ctx->basic_table_count * 2399 NUM_BASIC_BLOCKS * 2400 ctx->mem_target); 2401 } else 2402 xmlTextWriterWriteFormatString(writer, "%s", "-"); 2403 xmlTextWriterEndElement(writer); /* blocksize */ 2404 2405 xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"); 2406 xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt); 2407 xmlTextWriterEndElement(writer); /* pools */ 2408 summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t); 2409 2410 xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"); 2411 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2412 (isc_uint64_t)ctx->hi_water); 2413 xmlTextWriterEndElement(writer); /* hiwater */ 2414 2415 xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"); 2416 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2417 (isc_uint64_t)ctx->lo_water); 2418 xmlTextWriterEndElement(writer); /* lowater */ 2419 2420 MCTXUNLOCK(ctx, &ctx->lock); 2421 2422 xmlTextWriterEndElement(writer); /* context */ 2423} 2424 2425void 2426isc_mem_renderxml(xmlTextWriterPtr writer) { 2427 isc__mem_t *ctx; 2428 summarystat_t summary; 2429 isc_uint64_t lost; 2430 2431 memset(&summary, 0, sizeof(summary)); 2432 2433 xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"); 2434 2435 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2436 2437 LOCK(&lock); 2438 lost = totallost; 2439 for (ctx = ISC_LIST_HEAD(contexts); 2440 ctx != NULL; 2441 ctx = ISC_LIST_NEXT(ctx, link)) { 2442 renderctx(ctx, &summary, writer); 2443 } 2444 UNLOCK(&lock); 2445 2446 xmlTextWriterEndElement(writer); /* contexts */ 2447 2448 xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"); 2449 2450 xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"); 2451 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2452 summary.total); 2453 xmlTextWriterEndElement(writer); /* TotalUse */ 2454 2455 xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"); 2456 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2457 summary.inuse); 2458 xmlTextWriterEndElement(writer); /* InUse */ 2459 2460 xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"); 2461 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2462 summary.blocksize); 2463 xmlTextWriterEndElement(writer); /* BlockSize */ 2464 2465 xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"); 2466 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2467 summary.contextsize); 2468 xmlTextWriterEndElement(writer); /* ContextSize */ 2469 2470 xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"); 2471 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2472 lost); 2473 xmlTextWriterEndElement(writer); /* Lost */ 2474 2475 xmlTextWriterEndElement(writer); /* summary */ 2476} 2477 2478#endif /* HAVE_LIBXML2 */ 2479#endif /* BIND9 */ 2480