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