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