Annotation of embedaddon/ntp/lib/isc/mem.c, revision 1.1
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 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>