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