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