1/* $NetBSD: mem.c,v 1.2.6.2 2012/12/15 05:40:06 riz 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 (/*CONSTCOND*/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 FLARG_PASS); 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 FLARG_PASS); 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 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1598 INSIST(oldsize >= ALIGNMENT_SIZE); 1599 oldsize -= ALIGNMENT_SIZE; 1600 } 1601 copysize = (oldsize > size) ? size : oldsize; 1602 memcpy(new_ptr, ptr, copysize); 1603 isc__mem_free(ctx0, ptr FLARG_PASS); 1604 } 1605 } else if (ptr != NULL) 1606 isc__mem_free(ctx0, ptr FLARG_PASS); 1607 1608 return (new_ptr); 1609} 1610 1611ISC_MEMFUNC_SCOPE void 1612isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) { 1613 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1614 size_info *si; 1615 size_t size; 1616 isc_boolean_t call_water= ISC_FALSE; 1617 1618 REQUIRE(VALID_CONTEXT(ctx)); 1619 REQUIRE(ptr != NULL); 1620 1621 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1622 si = &(((size_info *)ptr)[-2]); 1623 REQUIRE(si->u.ctx == ctx); 1624 size = si[1].u.size; 1625 } else { 1626 si = &(((size_info *)ptr)[-1]); 1627 size = si->u.size; 1628 } 1629 1630 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1631 MCTXLOCK(ctx, &ctx->lock); 1632 mem_putunlocked(ctx, si, size); 1633 } else { 1634 mem_put(ctx, si, size); 1635 MCTXLOCK(ctx, &ctx->lock); 1636 mem_putstats(ctx, si, size); 1637 } 1638 1639 DELETE_TRACE(ctx, ptr, size, file, line); 1640 1641 /* 1642 * The check against ctx->lo_water == 0 is for the condition 1643 * when the context was pushed over hi_water but then had 1644 * isc_mem_setwater() called with 0 for hi_water and lo_water. 1645 */ 1646 if (ctx->is_overmem && 1647 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1648 ctx->is_overmem = ISC_FALSE; 1649 } 1650 1651 if (ctx->hi_called && 1652 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1653 ctx->hi_called = ISC_FALSE; 1654 1655 if (ctx->water != NULL) 1656 call_water = ISC_TRUE; 1657 } 1658 MCTXUNLOCK(ctx, &ctx->lock); 1659 1660 if (call_water) 1661 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1662} 1663 1664 1665/* 1666 * Other useful things. 1667 */ 1668 1669ISC_MEMFUNC_SCOPE char * 1670isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) { 1671 isc__mem_t *mctx = (isc__mem_t *)mctx0; 1672 size_t len; 1673 char *ns; 1674 1675 REQUIRE(VALID_CONTEXT(mctx)); 1676 REQUIRE(s != NULL); 1677 1678 len = strlen(s); 1679 1680 ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS); 1681 1682 if (ns != NULL) 1683 strncpy(ns, s, len + 1); 1684 1685 return (ns); 1686} 1687 1688ISC_MEMFUNC_SCOPE void 1689isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) { 1690 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1691 1692 REQUIRE(VALID_CONTEXT(ctx)); 1693 MCTXLOCK(ctx, &ctx->lock); 1694 1695 ctx->checkfree = flag; 1696 1697 MCTXUNLOCK(ctx, &ctx->lock); 1698} 1699 1700/* 1701 * Quotas 1702 */ 1703 1704ISC_MEMFUNC_SCOPE void 1705isc__mem_setquota(isc_mem_t *ctx0, size_t quota) { 1706 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1707 1708 REQUIRE(VALID_CONTEXT(ctx)); 1709 MCTXLOCK(ctx, &ctx->lock); 1710 1711 ctx->quota = quota; 1712 1713 MCTXUNLOCK(ctx, &ctx->lock); 1714} 1715 1716ISC_MEMFUNC_SCOPE size_t 1717isc__mem_getquota(isc_mem_t *ctx0) { 1718 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1719 size_t quota; 1720 1721 REQUIRE(VALID_CONTEXT(ctx)); 1722 MCTXLOCK(ctx, &ctx->lock); 1723 1724 quota = ctx->quota; 1725 1726 MCTXUNLOCK(ctx, &ctx->lock); 1727 1728 return (quota); 1729} 1730 1731ISC_MEMFUNC_SCOPE size_t 1732isc__mem_inuse(isc_mem_t *ctx0) { 1733 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1734 size_t inuse; 1735 1736 REQUIRE(VALID_CONTEXT(ctx)); 1737 MCTXLOCK(ctx, &ctx->lock); 1738 1739 inuse = ctx->inuse; 1740 1741 MCTXUNLOCK(ctx, &ctx->lock); 1742 1743 return (inuse); 1744} 1745 1746ISC_MEMFUNC_SCOPE void 1747isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg, 1748 size_t hiwater, size_t lowater) 1749{ 1750 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1751 isc_boolean_t callwater = ISC_FALSE; 1752 isc_mem_water_t oldwater; 1753 void *oldwater_arg; 1754 1755 REQUIRE(VALID_CONTEXT(ctx)); 1756 REQUIRE(hiwater >= lowater); 1757 1758 MCTXLOCK(ctx, &ctx->lock); 1759 oldwater = ctx->water; 1760 oldwater_arg = ctx->water_arg; 1761 if (water == NULL) { 1762 callwater = ctx->hi_called; 1763 ctx->water = NULL; 1764 ctx->water_arg = NULL; 1765 ctx->hi_water = 0; 1766 ctx->lo_water = 0; 1767 ctx->hi_called = ISC_FALSE; 1768 } else { 1769 if (ctx->hi_called && 1770 (ctx->water != water || ctx->water_arg != water_arg || 1771 ctx->inuse < lowater || lowater == 0U)) 1772 callwater = ISC_TRUE; 1773 ctx->water = water; 1774 ctx->water_arg = water_arg; 1775 ctx->hi_water = hiwater; 1776 ctx->lo_water = lowater; 1777 ctx->hi_called = ISC_FALSE; 1778 } 1779 MCTXUNLOCK(ctx, &ctx->lock); 1780 1781 if (callwater && oldwater != NULL) 1782 (oldwater)(oldwater_arg, ISC_MEM_LOWATER); 1783} 1784 1785ISC_MEMFUNC_SCOPE isc_boolean_t 1786isc__mem_isovermem(isc_mem_t *ctx0) { 1787 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1788 1789 REQUIRE(VALID_CONTEXT(ctx)); 1790 1791 /* 1792 * We don't bother to lock the context because 100% accuracy isn't 1793 * necessary (and even if we locked the context the returned value 1794 * could be different from the actual state when it's used anyway) 1795 */ 1796 return (ctx->is_overmem); 1797} 1798 1799ISC_MEMFUNC_SCOPE void 1800isc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) { 1801 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1802 1803 REQUIRE(VALID_CONTEXT(ctx)); 1804 1805 LOCK(&ctx->lock); 1806 memset(ctx->name, 0, sizeof(ctx->name)); 1807 strncpy(ctx->name, name, sizeof(ctx->name) - 1); 1808 ctx->tag = tag; 1809 UNLOCK(&ctx->lock); 1810} 1811 1812ISC_MEMFUNC_SCOPE const char * 1813isc__mem_getname(isc_mem_t *ctx0) { 1814 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1815 1816 REQUIRE(VALID_CONTEXT(ctx)); 1817 1818 return (ctx->name); 1819} 1820 1821ISC_MEMFUNC_SCOPE void * 1822isc__mem_gettag(isc_mem_t *ctx0) { 1823 isc__mem_t *ctx = (isc__mem_t *)ctx0; 1824 1825 REQUIRE(VALID_CONTEXT(ctx)); 1826 1827 return (ctx->tag); 1828} 1829 1830/* 1831 * Memory pool stuff 1832 */ 1833 1834ISC_MEMFUNC_SCOPE isc_result_t 1835isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) { 1836 isc__mem_t *mctx = (isc__mem_t *)mctx0; 1837 isc__mempool_t *mpctx; 1838 1839 REQUIRE(VALID_CONTEXT(mctx)); 1840 REQUIRE(size > 0U); 1841 REQUIRE(mpctxp != NULL && *mpctxp == NULL); 1842 1843 /* 1844 * Allocate space for this pool, initialize values, and if all works 1845 * well, attach to the memory context. 1846 */ 1847 mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t)); 1848 if (mpctx == NULL) 1849 return (ISC_R_NOMEMORY); 1850 1851 mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods; 1852 mpctx->common.impmagic = MEMPOOL_MAGIC; 1853 mpctx->common.magic = ISCAPI_MPOOL_MAGIC; 1854 mpctx->lock = NULL; 1855 mpctx->mctx = mctx; 1856 mpctx->size = size; 1857 mpctx->maxalloc = UINT_MAX; 1858 mpctx->allocated = 0; 1859 mpctx->freecount = 0; 1860 mpctx->freemax = 1; 1861 mpctx->fillcount = 1; 1862 mpctx->gets = 0; 1863#if ISC_MEMPOOL_NAMES 1864 mpctx->name[0] = 0; 1865#endif 1866 mpctx->items = NULL; 1867 1868 *mpctxp = (isc_mempool_t *)mpctx; 1869 1870 MCTXLOCK(mctx, &mctx->lock); 1871 ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link); 1872 mctx->poolcnt++; 1873 MCTXUNLOCK(mctx, &mctx->lock); 1874 1875 return (ISC_R_SUCCESS); 1876} 1877 1878ISC_MEMFUNC_SCOPE void 1879isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) { 1880 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1881 1882 REQUIRE(name != NULL); 1883 REQUIRE(VALID_MEMPOOL(mpctx)); 1884 1885#if ISC_MEMPOOL_NAMES 1886 if (mpctx->lock != NULL) 1887 LOCK(mpctx->lock); 1888 1889 strncpy(mpctx->name, name, sizeof(mpctx->name) - 1); 1890 mpctx->name[sizeof(mpctx->name) - 1] = '\0'; 1891 1892 if (mpctx->lock != NULL) 1893 UNLOCK(mpctx->lock); 1894#else 1895 UNUSED(mpctx); 1896 UNUSED(name); 1897#endif 1898} 1899 1900ISC_MEMFUNC_SCOPE void 1901isc__mempool_destroy(isc_mempool_t **mpctxp) { 1902 isc__mempool_t *mpctx; 1903 isc__mem_t *mctx; 1904 isc_mutex_t *lock; 1905 element *item; 1906 1907 REQUIRE(mpctxp != NULL); 1908 mpctx = (isc__mempool_t *)*mpctxp; 1909 REQUIRE(VALID_MEMPOOL(mpctx)); 1910#if ISC_MEMPOOL_NAMES 1911 if (mpctx->allocated > 0) 1912 UNEXPECTED_ERROR(__FILE__, __LINE__, 1913 "isc__mempool_destroy(): mempool %s " 1914 "leaked memory", 1915 mpctx->name); 1916#endif 1917 REQUIRE(mpctx->allocated == 0); 1918 1919 mctx = mpctx->mctx; 1920 1921 lock = mpctx->lock; 1922 1923 if (lock != NULL) 1924 LOCK(lock); 1925 1926 /* 1927 * Return any items on the free list 1928 */ 1929 MCTXLOCK(mctx, &mctx->lock); 1930 while (mpctx->items != NULL) { 1931 INSIST(mpctx->freecount > 0); 1932 mpctx->freecount--; 1933 item = mpctx->items; 1934 mpctx->items = item->next; 1935 1936 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1937 mem_putunlocked(mctx, item, mpctx->size); 1938 } else { 1939 mem_put(mctx, item, mpctx->size); 1940 mem_putstats(mctx, item, mpctx->size); 1941 } 1942 } 1943 MCTXUNLOCK(mctx, &mctx->lock); 1944 1945 /* 1946 * Remove our linked list entry from the memory context. 1947 */ 1948 MCTXLOCK(mctx, &mctx->lock); 1949 ISC_LIST_UNLINK(mctx->pools, mpctx, link); 1950 mctx->poolcnt--; 1951 MCTXUNLOCK(mctx, &mctx->lock); 1952 1953 mpctx->common.impmagic = 0; 1954 mpctx->common.magic = 0; 1955 1956 isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t)); 1957 1958 if (lock != NULL) 1959 UNLOCK(lock); 1960 1961 *mpctxp = NULL; 1962} 1963 1964ISC_MEMFUNC_SCOPE void 1965isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) { 1966 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1967 1968 REQUIRE(VALID_MEMPOOL(mpctx)); 1969 REQUIRE(mpctx->lock == NULL); 1970 REQUIRE(lock != NULL); 1971 1972 mpctx->lock = lock; 1973} 1974 1975ISC_MEMFUNC_SCOPE void * 1976isc___mempool_get(isc_mempool_t *mpctx0 FLARG) { 1977 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1978 element *item; 1979 isc__mem_t *mctx; 1980 unsigned int i; 1981 1982 REQUIRE(VALID_MEMPOOL(mpctx)); 1983 1984 mctx = mpctx->mctx; 1985 1986 if (mpctx->lock != NULL) 1987 LOCK(mpctx->lock); 1988 1989 /* 1990 * Don't let the caller go over quota 1991 */ 1992 if (mpctx->allocated >= mpctx->maxalloc) { 1993 item = NULL; 1994 goto out; 1995 } 1996 1997 /* 1998 * if we have a free list item, return the first here 1999 */ 2000 item = mpctx->items; 2001 if (item != NULL) { 2002 mpctx->items = item->next; 2003 INSIST(mpctx->freecount > 0); 2004 mpctx->freecount--; 2005 mpctx->gets++; 2006 mpctx->allocated++; 2007 goto out; 2008 } 2009 2010 /* 2011 * We need to dip into the well. Lock the memory context here and 2012 * fill up our free list. 2013 */ 2014 MCTXLOCK(mctx, &mctx->lock); 2015 for (i = 0; i < mpctx->fillcount; i++) { 2016 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2017 item = mem_getunlocked(mctx, mpctx->size); 2018 } else { 2019 item = mem_get(mctx, mpctx->size); 2020 if (item != NULL) 2021 mem_getstats(mctx, mpctx->size); 2022 } 2023 if (item == NULL) 2024 break; 2025 item->next = mpctx->items; 2026 mpctx->items = item; 2027 mpctx->freecount++; 2028 } 2029 MCTXUNLOCK(mctx, &mctx->lock); 2030 2031 /* 2032 * If we didn't get any items, return NULL. 2033 */ 2034 item = mpctx->items; 2035 if (item == NULL) 2036 goto out; 2037 2038 mpctx->items = item->next; 2039 mpctx->freecount--; 2040 mpctx->gets++; 2041 mpctx->allocated++; 2042 2043 out: 2044 if (mpctx->lock != NULL) 2045 UNLOCK(mpctx->lock); 2046 2047#if ISC_MEM_TRACKLINES 2048 if (item != NULL) { 2049 MCTXLOCK(mctx, &mctx->lock); 2050 ADD_TRACE(mctx, item, mpctx->size, file, line); 2051 MCTXUNLOCK(mctx, &mctx->lock); 2052 } 2053#endif /* ISC_MEM_TRACKLINES */ 2054 2055 return (item); 2056} 2057 2058ISC_MEMFUNC_SCOPE void 2059isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) { 2060 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2061 isc__mem_t *mctx; 2062 element *item; 2063 2064 REQUIRE(VALID_MEMPOOL(mpctx)); 2065 REQUIRE(mem != NULL); 2066 2067 mctx = mpctx->mctx; 2068 2069 if (mpctx->lock != NULL) 2070 LOCK(mpctx->lock); 2071 2072 INSIST(mpctx->allocated > 0); 2073 mpctx->allocated--; 2074 2075#if ISC_MEM_TRACKLINES 2076 MCTXLOCK(mctx, &mctx->lock); 2077 DELETE_TRACE(mctx, mem, mpctx->size, file, line); 2078 MCTXUNLOCK(mctx, &mctx->lock); 2079#endif /* ISC_MEM_TRACKLINES */ 2080 2081 /* 2082 * If our free list is full, return this to the mctx directly. 2083 */ 2084 if (mpctx->freecount >= mpctx->freemax) { 2085 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2086 MCTXLOCK(mctx, &mctx->lock); 2087 mem_putunlocked(mctx, mem, mpctx->size); 2088 MCTXUNLOCK(mctx, &mctx->lock); 2089 } else { 2090 mem_put(mctx, mem, mpctx->size); 2091 MCTXLOCK(mctx, &mctx->lock); 2092 mem_putstats(mctx, mem, mpctx->size); 2093 MCTXUNLOCK(mctx, &mctx->lock); 2094 } 2095 if (mpctx->lock != NULL) 2096 UNLOCK(mpctx->lock); 2097 return; 2098 } 2099 2100 /* 2101 * Otherwise, attach it to our free list and bump the counter. 2102 */ 2103 mpctx->freecount++; 2104 item = (element *)mem; 2105 item->next = mpctx->items; 2106 mpctx->items = item; 2107 2108 if (mpctx->lock != NULL) 2109 UNLOCK(mpctx->lock); 2110} 2111 2112/* 2113 * Quotas 2114 */ 2115 2116ISC_MEMFUNC_SCOPE void 2117isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) { 2118 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2119 2120 REQUIRE(VALID_MEMPOOL(mpctx)); 2121 2122 if (mpctx->lock != NULL) 2123 LOCK(mpctx->lock); 2124 2125 mpctx->freemax = limit; 2126 2127 if (mpctx->lock != NULL) 2128 UNLOCK(mpctx->lock); 2129} 2130 2131ISC_MEMFUNC_SCOPE unsigned int 2132isc__mempool_getfreemax(isc_mempool_t *mpctx0) { 2133 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2134 unsigned int freemax; 2135 2136 REQUIRE(VALID_MEMPOOL(mpctx)); 2137 2138 if (mpctx->lock != NULL) 2139 LOCK(mpctx->lock); 2140 2141 freemax = mpctx->freemax; 2142 2143 if (mpctx->lock != NULL) 2144 UNLOCK(mpctx->lock); 2145 2146 return (freemax); 2147} 2148 2149ISC_MEMFUNC_SCOPE unsigned int 2150isc__mempool_getfreecount(isc_mempool_t *mpctx0) { 2151 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2152 unsigned int freecount; 2153 2154 REQUIRE(VALID_MEMPOOL(mpctx)); 2155 2156 if (mpctx->lock != NULL) 2157 LOCK(mpctx->lock); 2158 2159 freecount = mpctx->freecount; 2160 2161 if (mpctx->lock != NULL) 2162 UNLOCK(mpctx->lock); 2163 2164 return (freecount); 2165} 2166 2167ISC_MEMFUNC_SCOPE void 2168isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) { 2169 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2170 2171 REQUIRE(limit > 0); 2172 2173 REQUIRE(VALID_MEMPOOL(mpctx)); 2174 2175 if (mpctx->lock != NULL) 2176 LOCK(mpctx->lock); 2177 2178 mpctx->maxalloc = limit; 2179 2180 if (mpctx->lock != NULL) 2181 UNLOCK(mpctx->lock); 2182} 2183 2184ISC_MEMFUNC_SCOPE unsigned int 2185isc__mempool_getmaxalloc(isc_mempool_t *mpctx0) { 2186 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2187 unsigned int maxalloc; 2188 2189 REQUIRE(VALID_MEMPOOL(mpctx)); 2190 2191 if (mpctx->lock != NULL) 2192 LOCK(mpctx->lock); 2193 2194 maxalloc = mpctx->maxalloc; 2195 2196 if (mpctx->lock != NULL) 2197 UNLOCK(mpctx->lock); 2198 2199 return (maxalloc); 2200} 2201 2202ISC_MEMFUNC_SCOPE unsigned int 2203isc__mempool_getallocated(isc_mempool_t *mpctx0) { 2204 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2205 unsigned int allocated; 2206 2207 REQUIRE(VALID_MEMPOOL(mpctx)); 2208 2209 if (mpctx->lock != NULL) 2210 LOCK(mpctx->lock); 2211 2212 allocated = mpctx->allocated; 2213 2214 if (mpctx->lock != NULL) 2215 UNLOCK(mpctx->lock); 2216 2217 return (allocated); 2218} 2219 2220ISC_MEMFUNC_SCOPE void 2221isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) { 2222 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2223 2224 REQUIRE(limit > 0); 2225 REQUIRE(VALID_MEMPOOL(mpctx)); 2226 2227 if (mpctx->lock != NULL) 2228 LOCK(mpctx->lock); 2229 2230 mpctx->fillcount = limit; 2231 2232 if (mpctx->lock != NULL) 2233 UNLOCK(mpctx->lock); 2234} 2235 2236ISC_MEMFUNC_SCOPE unsigned int 2237isc__mempool_getfillcount(isc_mempool_t *mpctx0) { 2238 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2239 2240 unsigned int fillcount; 2241 2242 REQUIRE(VALID_MEMPOOL(mpctx)); 2243 2244 if (mpctx->lock != NULL) 2245 LOCK(mpctx->lock); 2246 2247 fillcount = mpctx->fillcount; 2248 2249 if (mpctx->lock != NULL) 2250 UNLOCK(mpctx->lock); 2251 2252 return (fillcount); 2253} 2254 2255#ifdef USE_MEMIMPREGISTER 2256isc_result_t 2257isc__mem_register() { 2258 return (isc_mem_register(isc__mem_create2)); 2259} 2260#endif 2261 2262#ifdef BIND9 2263ISC_MEMFUNC_SCOPE void 2264isc__mem_printactive(isc_mem_t *ctx0, FILE *file) { 2265 isc__mem_t *ctx = (isc__mem_t *)ctx0; 2266 2267 REQUIRE(VALID_CONTEXT(ctx)); 2268 REQUIRE(file != NULL); 2269 2270#if !ISC_MEM_TRACKLINES 2271 UNUSED(ctx); 2272 UNUSED(file); 2273#else 2274 print_active(ctx, file); 2275#endif 2276} 2277 2278ISC_MEMFUNC_SCOPE void 2279isc__mem_printallactive(FILE *file) { 2280#if !ISC_MEM_TRACKLINES 2281 UNUSED(file); 2282#else 2283 isc__mem_t *ctx; 2284 2285 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2286 2287 LOCK(&lock); 2288 for (ctx = ISC_LIST_HEAD(contexts); 2289 ctx != NULL; 2290 ctx = ISC_LIST_NEXT(ctx, link)) { 2291 fprintf(file, "context: %p\n", ctx); 2292 print_active(ctx, file); 2293 } 2294 UNLOCK(&lock); 2295#endif 2296} 2297 2298ISC_MEMFUNC_SCOPE void 2299isc__mem_checkdestroyed(FILE *file) { 2300 2301 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2302 2303 LOCK(&lock); 2304 if (!ISC_LIST_EMPTY(contexts)) { 2305#if ISC_MEM_TRACKLINES 2306 isc__mem_t *ctx; 2307 2308 for (ctx = ISC_LIST_HEAD(contexts); 2309 ctx != NULL; 2310 ctx = ISC_LIST_NEXT(ctx, link)) { 2311 fprintf(file, "context: %p\n", ctx); 2312 print_active(ctx, file); 2313 } 2314 fflush(file); 2315#endif 2316 INSIST(0); 2317 } 2318 UNLOCK(&lock); 2319} 2320 2321ISC_MEMFUNC_SCOPE unsigned int 2322isc_mem_references(isc_mem_t *ctx0) { 2323 isc__mem_t *ctx = (isc__mem_t *)ctx0; 2324 unsigned int references; 2325 2326 REQUIRE(VALID_CONTEXT(ctx)); 2327 2328 MCTXLOCK(ctx, &ctx->lock); 2329 references = ctx->references; 2330 MCTXUNLOCK(ctx, &ctx->lock); 2331 2332 return (references); 2333} 2334 2335#ifdef HAVE_LIBXML2 2336 2337typedef struct summarystat { 2338 isc_uint64_t total; 2339 isc_uint64_t inuse; 2340 isc_uint64_t blocksize; 2341 isc_uint64_t contextsize; 2342} summarystat_t; 2343 2344static void 2345renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) { 2346 REQUIRE(VALID_CONTEXT(ctx)); 2347 2348 xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"); 2349 2350 xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"); 2351 xmlTextWriterWriteFormatString(writer, "%p", ctx); 2352 xmlTextWriterEndElement(writer); /* id */ 2353 2354 if (ctx->name[0] != 0) { 2355 xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); 2356 xmlTextWriterWriteFormatString(writer, "%s", ctx->name); 2357 xmlTextWriterEndElement(writer); /* name */ 2358 } 2359 2360 REQUIRE(VALID_CONTEXT(ctx)); 2361 MCTXLOCK(ctx, &ctx->lock); 2362 2363 summary->contextsize += sizeof(*ctx) + 2364 (ctx->max_size + 1) * sizeof(struct stats) + 2365 ctx->max_size * sizeof(element *) + 2366 ctx->basic_table_count * sizeof(char *); 2367#if ISC_MEM_TRACKLINES 2368 if (ctx->debuglist != NULL) { 2369 summary->contextsize += 2370 (ctx->max_size + 1) * sizeof(debuglist_t) + 2371 ctx->debuglistcnt * sizeof(debuglink_t); 2372 } 2373#endif 2374 xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); 2375 xmlTextWriterWriteFormatString(writer, "%d", ctx->references); 2376 xmlTextWriterEndElement(writer); /* references */ 2377 2378 summary->total += ctx->total; 2379 xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"); 2380 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2381 (isc_uint64_t)ctx->total); 2382 xmlTextWriterEndElement(writer); /* total */ 2383 2384 summary->inuse += ctx->inuse; 2385 xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"); 2386 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2387 (isc_uint64_t)ctx->inuse); 2388 xmlTextWriterEndElement(writer); /* inuse */ 2389 2390 xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"); 2391 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2392 (isc_uint64_t)ctx->maxinuse); 2393 xmlTextWriterEndElement(writer); /* maxinuse */ 2394 2395 xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"); 2396 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2397 summary->blocksize += ctx->basic_table_count * 2398 NUM_BASIC_BLOCKS * ctx->mem_target; 2399 xmlTextWriterWriteFormatString(writer, 2400 "%" ISC_PRINT_QUADFORMAT "u", 2401 (isc_uint64_t) 2402 ctx->basic_table_count * 2403 NUM_BASIC_BLOCKS * 2404 ctx->mem_target); 2405 } else 2406 xmlTextWriterWriteFormatString(writer, "%s", "-"); 2407 xmlTextWriterEndElement(writer); /* blocksize */ 2408 2409 xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"); 2410 xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt); 2411 xmlTextWriterEndElement(writer); /* pools */ 2412 summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t); 2413 2414 xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"); 2415 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2416 (isc_uint64_t)ctx->hi_water); 2417 xmlTextWriterEndElement(writer); /* hiwater */ 2418 2419 xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"); 2420 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2421 (isc_uint64_t)ctx->lo_water); 2422 xmlTextWriterEndElement(writer); /* lowater */ 2423 2424 MCTXUNLOCK(ctx, &ctx->lock); 2425 2426 xmlTextWriterEndElement(writer); /* context */ 2427} 2428 2429void 2430isc_mem_renderxml(xmlTextWriterPtr writer) { 2431 isc__mem_t *ctx; 2432 summarystat_t summary; 2433 isc_uint64_t lost; 2434 2435 memset(&summary, 0, sizeof(summary)); 2436 2437 xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"); 2438 2439 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2440 2441 LOCK(&lock); 2442 lost = totallost; 2443 for (ctx = ISC_LIST_HEAD(contexts); 2444 ctx != NULL; 2445 ctx = ISC_LIST_NEXT(ctx, link)) { 2446 renderctx(ctx, &summary, writer); 2447 } 2448 UNLOCK(&lock); 2449 2450 xmlTextWriterEndElement(writer); /* contexts */ 2451 2452 xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"); 2453 2454 xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"); 2455 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2456 summary.total); 2457 xmlTextWriterEndElement(writer); /* TotalUse */ 2458 2459 xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"); 2460 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2461 summary.inuse); 2462 xmlTextWriterEndElement(writer); /* InUse */ 2463 2464 xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"); 2465 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2466 summary.blocksize); 2467 xmlTextWriterEndElement(writer); /* BlockSize */ 2468 2469 xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"); 2470 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2471 summary.contextsize); 2472 xmlTextWriterEndElement(writer); /* ContextSize */ 2473 2474 xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"); 2475 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2476 lost); 2477 xmlTextWriterEndElement(writer); /* Lost */ 2478 2479 xmlTextWriterEndElement(writer); /* summary */ 2480} 2481 2482#endif /* HAVE_LIBXML2 */ 2483#endif /* BIND9 */ 2484