mem.c revision 193149
1135446Strhodes/* 2193149Sdougb * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1997-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18193149Sdougb/* $Id: mem.c,v 1.145.120.4 2009/02/16 03:17:05 marka Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <stdio.h> 25135446Strhodes#include <stdlib.h> 26135446Strhodes#include <stddef.h> 27135446Strhodes 28135446Strhodes#include <limits.h> 29135446Strhodes 30135446Strhodes#include <isc/magic.h> 31135446Strhodes#include <isc/mem.h> 32135446Strhodes#include <isc/msgs.h> 33170222Sdougb#include <isc/once.h> 34135446Strhodes#include <isc/ondestroy.h> 35135446Strhodes#include <isc/string.h> 36135446Strhodes#include <isc/mutex.h> 37193149Sdougb#include <isc/print.h> 38135446Strhodes#include <isc/util.h> 39193149Sdougb#include <isc/xml.h> 40135446Strhodes 41170222Sdougb#define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l) 42170222Sdougb#define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l) 43170222Sdougb 44135446Strhodes#ifndef ISC_MEM_DEBUGGING 45135446Strhodes#define ISC_MEM_DEBUGGING 0 46135446Strhodes#endif 47135446StrhodesLIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING; 48135446Strhodes 49135446Strhodes/* 50135446Strhodes * Constants. 51135446Strhodes */ 52135446Strhodes 53135446Strhodes#define DEF_MAX_SIZE 1100 54135446Strhodes#define DEF_MEM_TARGET 4096 55193149Sdougb#define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */ 56170222Sdougb#define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */ 57135446Strhodes#define TABLE_INCREMENT 1024 58135446Strhodes#define DEBUGLIST_COUNT 1024 59135446Strhodes 60135446Strhodes/* 61135446Strhodes * Types. 62135446Strhodes */ 63135446Strhodes#if ISC_MEM_TRACKLINES 64135446Strhodestypedef struct debuglink debuglink_t; 65135446Strhodesstruct debuglink { 66135446Strhodes ISC_LINK(debuglink_t) link; 67135446Strhodes const void *ptr[DEBUGLIST_COUNT]; 68135446Strhodes unsigned int size[DEBUGLIST_COUNT]; 69135446Strhodes const char *file[DEBUGLIST_COUNT]; 70135446Strhodes unsigned int line[DEBUGLIST_COUNT]; 71135446Strhodes unsigned int count; 72135446Strhodes}; 73135446Strhodes 74135446Strhodes#define FLARG_PASS , file, line 75135446Strhodes#define FLARG , const char *file, int line 76135446Strhodes#else 77135446Strhodes#define FLARG_PASS 78135446Strhodes#define FLARG 79135446Strhodes#endif 80135446Strhodes 81135446Strhodestypedef struct element element; 82135446Strhodesstruct element { 83135446Strhodes element * next; 84135446Strhodes}; 85135446Strhodes 86135446Strhodestypedef struct { 87170222Sdougb /*! 88135446Strhodes * This structure must be ALIGNMENT_SIZE bytes. 89135446Strhodes */ 90135446Strhodes union { 91135446Strhodes size_t size; 92170222Sdougb isc_mem_t *ctx; 93135446Strhodes char bytes[ALIGNMENT_SIZE]; 94135446Strhodes } u; 95135446Strhodes} size_info; 96135446Strhodes 97135446Strhodesstruct stats { 98135446Strhodes unsigned long gets; 99135446Strhodes unsigned long totalgets; 100135446Strhodes unsigned long blocks; 101135446Strhodes unsigned long freefrags; 102135446Strhodes}; 103135446Strhodes 104135446Strhodes#define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C') 105135446Strhodes#define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC) 106135446Strhodes 107135446Strhodes#if ISC_MEM_TRACKLINES 108135446Strhodestypedef ISC_LIST(debuglink_t) debuglist_t; 109135446Strhodes#endif 110135446Strhodes 111170222Sdougb/* List of all active memory contexts. */ 112170222Sdougb 113170222Sdougbstatic ISC_LIST(isc_mem_t) contexts; 114170222Sdougbstatic isc_once_t once = ISC_ONCE_INIT; 115170222Sdougbstatic isc_mutex_t lock; 116170222Sdougb 117193149Sdougb/*% 118193149Sdougb * Total size of lost memory due to a bug of external library. 119193149Sdougb * Locked by the global lock. 120193149Sdougb */ 121193149Sdougbstatic isc_uint64_t totallost; 122193149Sdougb 123135446Strhodesstruct isc_mem { 124135446Strhodes unsigned int magic; 125135446Strhodes isc_ondestroy_t ondestroy; 126170222Sdougb unsigned int flags; 127135446Strhodes isc_mutex_t lock; 128135446Strhodes isc_memalloc_t memalloc; 129135446Strhodes isc_memfree_t memfree; 130135446Strhodes void * arg; 131135446Strhodes size_t max_size; 132135446Strhodes isc_boolean_t checkfree; 133135446Strhodes struct stats * stats; 134135446Strhodes unsigned int references; 135193149Sdougb char name[16]; 136193149Sdougb void * tag; 137135446Strhodes size_t quota; 138135446Strhodes size_t total; 139135446Strhodes size_t inuse; 140135446Strhodes size_t maxinuse; 141135446Strhodes size_t hi_water; 142135446Strhodes size_t lo_water; 143135446Strhodes isc_boolean_t hi_called; 144135446Strhodes isc_mem_water_t water; 145135446Strhodes void * water_arg; 146135446Strhodes ISC_LIST(isc_mempool_t) pools; 147193149Sdougb unsigned int poolcnt; 148135446Strhodes 149170222Sdougb /* ISC_MEMFLAG_INTERNAL */ 150135446Strhodes size_t mem_target; 151135446Strhodes element ** freelists; 152135446Strhodes element * basic_blocks; 153135446Strhodes unsigned char ** basic_table; 154135446Strhodes unsigned int basic_table_count; 155135446Strhodes unsigned int basic_table_size; 156135446Strhodes unsigned char * lowest; 157135446Strhodes unsigned char * highest; 158135446Strhodes 159135446Strhodes#if ISC_MEM_TRACKLINES 160135446Strhodes debuglist_t * debuglist; 161193149Sdougb unsigned int debuglistcnt; 162135446Strhodes#endif 163135446Strhodes 164135446Strhodes unsigned int memalloc_failures; 165170222Sdougb ISC_LINK(isc_mem_t) link; 166135446Strhodes}; 167135446Strhodes 168135446Strhodes#define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p') 169135446Strhodes#define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC) 170135446Strhodes 171135446Strhodesstruct isc_mempool { 172135446Strhodes /* always unlocked */ 173170222Sdougb unsigned int magic; /*%< magic number */ 174170222Sdougb isc_mutex_t *lock; /*%< optional lock */ 175170222Sdougb isc_mem_t *mctx; /*%< our memory context */ 176170222Sdougb /*%< locked via the memory context's lock */ 177170222Sdougb ISC_LINK(isc_mempool_t) link; /*%< next pool in this mem context */ 178170222Sdougb /*%< optionally locked from here down */ 179170222Sdougb element *items; /*%< low water item list */ 180170222Sdougb size_t size; /*%< size of each item on this pool */ 181170222Sdougb unsigned int maxalloc; /*%< max number of items allowed */ 182170222Sdougb unsigned int allocated; /*%< # of items currently given out */ 183170222Sdougb unsigned int freecount; /*%< # of items on reserved list */ 184170222Sdougb unsigned int freemax; /*%< # of items allowed on free list */ 185170222Sdougb unsigned int fillcount; /*%< # of items to fetch on each fill */ 186170222Sdougb /*%< Stats only. */ 187170222Sdougb unsigned int gets; /*%< # of requests to this pool */ 188170222Sdougb /*%< Debugging only. */ 189135446Strhodes#if ISC_MEMPOOL_NAMES 190170222Sdougb char name[16]; /*%< printed name in stats reports */ 191135446Strhodes#endif 192135446Strhodes}; 193135446Strhodes 194135446Strhodes/* 195135446Strhodes * Private Inline-able. 196135446Strhodes */ 197135446Strhodes 198135446Strhodes#if ! ISC_MEM_TRACKLINES 199135446Strhodes#define ADD_TRACE(a, b, c, d, e) 200135446Strhodes#define DELETE_TRACE(a, b, c, d, e) 201135446Strhodes#else 202135446Strhodes#define ADD_TRACE(a, b, c, d, e) \ 203135446Strhodes do { \ 204135446Strhodes if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \ 205135446Strhodes ISC_MEM_DEBUGRECORD)) != 0 && \ 206135446Strhodes b != NULL) \ 207186462Sdougb add_trace_entry(a, b, c, d, e); \ 208135446Strhodes } while (0) 209135446Strhodes#define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e) 210135446Strhodes 211135446Strhodesstatic void 212135446Strhodesprint_active(isc_mem_t *ctx, FILE *out); 213135446Strhodes 214170222Sdougb/*! 215135446Strhodes * mctx must be locked. 216135446Strhodes */ 217135446Strhodesstatic inline void 218135446Strhodesadd_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size 219135446Strhodes FLARG) 220135446Strhodes{ 221135446Strhodes debuglink_t *dl; 222135446Strhodes unsigned int i; 223135446Strhodes 224135446Strhodes if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) 225135446Strhodes fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 226135446Strhodes ISC_MSG_ADDTRACE, 227135446Strhodes "add %p size %u " 228135446Strhodes "file %s line %u mctx %p\n"), 229135446Strhodes ptr, size, file, line, mctx); 230135446Strhodes 231135446Strhodes if (mctx->debuglist == NULL) 232135446Strhodes return; 233135446Strhodes 234135446Strhodes if (size > mctx->max_size) 235135446Strhodes size = mctx->max_size; 236135446Strhodes 237135446Strhodes dl = ISC_LIST_HEAD(mctx->debuglist[size]); 238135446Strhodes while (dl != NULL) { 239135446Strhodes if (dl->count == DEBUGLIST_COUNT) 240135446Strhodes goto next; 241135446Strhodes for (i = 0; i < DEBUGLIST_COUNT; i++) { 242135446Strhodes if (dl->ptr[i] == NULL) { 243135446Strhodes dl->ptr[i] = ptr; 244135446Strhodes dl->size[i] = size; 245135446Strhodes dl->file[i] = file; 246135446Strhodes dl->line[i] = line; 247135446Strhodes dl->count++; 248135446Strhodes return; 249135446Strhodes } 250135446Strhodes } 251135446Strhodes next: 252135446Strhodes dl = ISC_LIST_NEXT(dl, link); 253135446Strhodes } 254135446Strhodes 255135446Strhodes dl = malloc(sizeof(debuglink_t)); 256135446Strhodes INSIST(dl != NULL); 257135446Strhodes 258135446Strhodes ISC_LINK_INIT(dl, link); 259135446Strhodes for (i = 1; i < DEBUGLIST_COUNT; i++) { 260135446Strhodes dl->ptr[i] = NULL; 261135446Strhodes dl->size[i] = 0; 262135446Strhodes dl->file[i] = NULL; 263135446Strhodes dl->line[i] = 0; 264135446Strhodes } 265135446Strhodes 266135446Strhodes dl->ptr[0] = ptr; 267135446Strhodes dl->size[0] = size; 268135446Strhodes dl->file[0] = file; 269135446Strhodes dl->line[0] = line; 270135446Strhodes dl->count = 1; 271135446Strhodes 272135446Strhodes ISC_LIST_PREPEND(mctx->debuglist[size], dl, link); 273193149Sdougb mctx->debuglistcnt++; 274135446Strhodes} 275135446Strhodes 276135446Strhodesstatic inline void 277135446Strhodesdelete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size, 278135446Strhodes const char *file, unsigned int line) 279135446Strhodes{ 280135446Strhodes debuglink_t *dl; 281135446Strhodes unsigned int i; 282135446Strhodes 283135446Strhodes if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) 284135446Strhodes fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 285135446Strhodes ISC_MSG_DELTRACE, 286135446Strhodes "del %p size %u " 287135446Strhodes "file %s line %u mctx %p\n"), 288135446Strhodes ptr, size, file, line, mctx); 289135446Strhodes 290135446Strhodes if (mctx->debuglist == NULL) 291135446Strhodes return; 292135446Strhodes 293135446Strhodes if (size > mctx->max_size) 294135446Strhodes size = mctx->max_size; 295135446Strhodes 296135446Strhodes dl = ISC_LIST_HEAD(mctx->debuglist[size]); 297135446Strhodes while (dl != NULL) { 298135446Strhodes for (i = 0; i < DEBUGLIST_COUNT; i++) { 299135446Strhodes if (dl->ptr[i] == ptr) { 300135446Strhodes dl->ptr[i] = NULL; 301135446Strhodes dl->size[i] = 0; 302135446Strhodes dl->file[i] = NULL; 303135446Strhodes dl->line[i] = 0; 304135446Strhodes 305135446Strhodes INSIST(dl->count > 0); 306135446Strhodes dl->count--; 307135446Strhodes if (dl->count == 0) { 308135446Strhodes ISC_LIST_UNLINK(mctx->debuglist[size], 309135446Strhodes dl, link); 310135446Strhodes free(dl); 311135446Strhodes } 312135446Strhodes return; 313135446Strhodes } 314135446Strhodes } 315135446Strhodes dl = ISC_LIST_NEXT(dl, link); 316135446Strhodes } 317135446Strhodes 318135446Strhodes /* 319135446Strhodes * If we get here, we didn't find the item on the list. We're 320135446Strhodes * screwed. 321135446Strhodes */ 322135446Strhodes INSIST(dl != NULL); 323135446Strhodes} 324135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 325135446Strhodes 326135446Strhodesstatic inline size_t 327135446Strhodesrmsize(size_t size) { 328135446Strhodes /* 329186462Sdougb * round down to ALIGNMENT_SIZE 330135446Strhodes */ 331135446Strhodes return (size & (~(ALIGNMENT_SIZE - 1))); 332135446Strhodes} 333135446Strhodes 334135446Strhodesstatic inline size_t 335135446Strhodesquantize(size_t size) { 336170222Sdougb /*! 337135446Strhodes * Round up the result in order to get a size big 338135446Strhodes * enough to satisfy the request and be aligned on ALIGNMENT_SIZE 339135446Strhodes * byte boundaries. 340135446Strhodes */ 341135446Strhodes 342170222Sdougb if (size == 0U) 343135446Strhodes return (ALIGNMENT_SIZE); 344135446Strhodes return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1))); 345135446Strhodes} 346135446Strhodes 347135446Strhodesstatic inline isc_boolean_t 348135446Strhodesmore_basic_blocks(isc_mem_t *ctx) { 349135446Strhodes void *new; 350135446Strhodes unsigned char *curr, *next; 351135446Strhodes unsigned char *first, *last; 352135446Strhodes unsigned char **table; 353135446Strhodes unsigned int table_size; 354135446Strhodes size_t increment; 355135446Strhodes int i; 356135446Strhodes 357135446Strhodes /* Require: we hold the context lock. */ 358135446Strhodes 359135446Strhodes /* 360135446Strhodes * Did we hit the quota for this context? 361135446Strhodes */ 362135446Strhodes increment = NUM_BASIC_BLOCKS * ctx->mem_target; 363170222Sdougb if (ctx->quota != 0U && ctx->total + increment > ctx->quota) 364135446Strhodes return (ISC_FALSE); 365135446Strhodes 366135446Strhodes INSIST(ctx->basic_table_count <= ctx->basic_table_size); 367135446Strhodes if (ctx->basic_table_count == ctx->basic_table_size) { 368135446Strhodes table_size = ctx->basic_table_size + TABLE_INCREMENT; 369135446Strhodes table = (ctx->memalloc)(ctx->arg, 370135446Strhodes table_size * sizeof(unsigned char *)); 371135446Strhodes if (table == NULL) { 372135446Strhodes ctx->memalloc_failures++; 373135446Strhodes return (ISC_FALSE); 374135446Strhodes } 375135446Strhodes if (ctx->basic_table_size != 0) { 376135446Strhodes memcpy(table, ctx->basic_table, 377135446Strhodes ctx->basic_table_size * 378135446Strhodes sizeof(unsigned char *)); 379135446Strhodes (ctx->memfree)(ctx->arg, ctx->basic_table); 380135446Strhodes } 381135446Strhodes ctx->basic_table = table; 382135446Strhodes ctx->basic_table_size = table_size; 383135446Strhodes } 384135446Strhodes 385135446Strhodes new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target); 386135446Strhodes if (new == NULL) { 387135446Strhodes ctx->memalloc_failures++; 388135446Strhodes return (ISC_FALSE); 389135446Strhodes } 390135446Strhodes ctx->total += increment; 391135446Strhodes ctx->basic_table[ctx->basic_table_count] = new; 392135446Strhodes ctx->basic_table_count++; 393135446Strhodes 394135446Strhodes curr = new; 395135446Strhodes next = curr + ctx->mem_target; 396135446Strhodes for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { 397135446Strhodes ((element *)curr)->next = (element *)next; 398135446Strhodes curr = next; 399135446Strhodes next += ctx->mem_target; 400135446Strhodes } 401135446Strhodes /* 402135446Strhodes * curr is now pointing at the last block in the 403135446Strhodes * array. 404135446Strhodes */ 405135446Strhodes ((element *)curr)->next = NULL; 406135446Strhodes first = new; 407135446Strhodes last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1; 408135446Strhodes if (first < ctx->lowest || ctx->lowest == NULL) 409135446Strhodes ctx->lowest = first; 410135446Strhodes if (last > ctx->highest) 411135446Strhodes ctx->highest = last; 412135446Strhodes ctx->basic_blocks = new; 413135446Strhodes 414135446Strhodes return (ISC_TRUE); 415135446Strhodes} 416135446Strhodes 417135446Strhodesstatic inline isc_boolean_t 418135446Strhodesmore_frags(isc_mem_t *ctx, size_t new_size) { 419135446Strhodes int i, frags; 420135446Strhodes size_t total_size; 421135446Strhodes void *new; 422135446Strhodes unsigned char *curr, *next; 423135446Strhodes 424170222Sdougb /*! 425135446Strhodes * Try to get more fragments by chopping up a basic block. 426135446Strhodes */ 427135446Strhodes 428135446Strhodes if (ctx->basic_blocks == NULL) { 429135446Strhodes if (!more_basic_blocks(ctx)) { 430135446Strhodes /* 431135446Strhodes * We can't get more memory from the OS, or we've 432135446Strhodes * hit the quota for this context. 433135446Strhodes */ 434135446Strhodes /* 435135446Strhodes * XXXRTH "At quota" notification here. 436135446Strhodes */ 437135446Strhodes return (ISC_FALSE); 438135446Strhodes } 439135446Strhodes } 440135446Strhodes 441135446Strhodes total_size = ctx->mem_target; 442135446Strhodes new = ctx->basic_blocks; 443135446Strhodes ctx->basic_blocks = ctx->basic_blocks->next; 444135446Strhodes frags = total_size / new_size; 445135446Strhodes ctx->stats[new_size].blocks++; 446135446Strhodes ctx->stats[new_size].freefrags += frags; 447135446Strhodes /* 448135446Strhodes * Set up a linked-list of blocks of size 449135446Strhodes * "new_size". 450135446Strhodes */ 451135446Strhodes curr = new; 452135446Strhodes next = curr + new_size; 453135446Strhodes total_size -= new_size; 454135446Strhodes for (i = 0; i < (frags - 1); i++) { 455135446Strhodes ((element *)curr)->next = (element *)next; 456135446Strhodes curr = next; 457135446Strhodes next += new_size; 458135446Strhodes total_size -= new_size; 459135446Strhodes } 460135446Strhodes /* 461135446Strhodes * Add the remaining fragment of the basic block to a free list. 462135446Strhodes */ 463135446Strhodes total_size = rmsize(total_size); 464170222Sdougb if (total_size > 0U) { 465135446Strhodes ((element *)next)->next = ctx->freelists[total_size]; 466135446Strhodes ctx->freelists[total_size] = (element *)next; 467135446Strhodes ctx->stats[total_size].freefrags++; 468135446Strhodes } 469135446Strhodes /* 470135446Strhodes * curr is now pointing at the last block in the 471135446Strhodes * array. 472135446Strhodes */ 473135446Strhodes ((element *)curr)->next = NULL; 474135446Strhodes ctx->freelists[new_size] = new; 475135446Strhodes 476135446Strhodes return (ISC_TRUE); 477135446Strhodes} 478135446Strhodes 479135446Strhodesstatic inline void * 480135446Strhodesmem_getunlocked(isc_mem_t *ctx, size_t size) { 481135446Strhodes size_t new_size = quantize(size); 482135446Strhodes void *ret; 483135446Strhodes 484135446Strhodes if (size >= ctx->max_size || new_size >= ctx->max_size) { 485135446Strhodes /* 486135446Strhodes * memget() was called on something beyond our upper limit. 487135446Strhodes */ 488170222Sdougb if (ctx->quota != 0U && ctx->total + size > ctx->quota) { 489135446Strhodes ret = NULL; 490135446Strhodes goto done; 491135446Strhodes } 492135446Strhodes ret = (ctx->memalloc)(ctx->arg, size); 493135446Strhodes if (ret == NULL) { 494135446Strhodes ctx->memalloc_failures++; 495135446Strhodes goto done; 496135446Strhodes } 497135446Strhodes ctx->total += size; 498135446Strhodes ctx->inuse += size; 499135446Strhodes ctx->stats[ctx->max_size].gets++; 500135446Strhodes ctx->stats[ctx->max_size].totalgets++; 501135446Strhodes /* 502135446Strhodes * If we don't set new_size to size, then the 503135446Strhodes * ISC_MEM_FILL code might write over bytes we 504135446Strhodes * don't own. 505135446Strhodes */ 506135446Strhodes new_size = size; 507135446Strhodes goto done; 508135446Strhodes } 509135446Strhodes 510135446Strhodes /* 511135446Strhodes * If there are no blocks in the free list for this size, get a chunk 512135446Strhodes * of memory and then break it up into "new_size"-sized blocks, adding 513135446Strhodes * them to the free list. 514135446Strhodes */ 515135446Strhodes if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size)) 516135446Strhodes return (NULL); 517135446Strhodes 518135446Strhodes /* 519135446Strhodes * The free list uses the "rounded-up" size "new_size". 520135446Strhodes */ 521135446Strhodes ret = ctx->freelists[new_size]; 522135446Strhodes ctx->freelists[new_size] = ctx->freelists[new_size]->next; 523135446Strhodes 524135446Strhodes /* 525135446Strhodes * The stats[] uses the _actual_ "size" requested by the 526135446Strhodes * caller, with the caveat (in the code above) that "size" >= the 527135446Strhodes * max. size (max_size) ends up getting recorded as a call to 528135446Strhodes * max_size. 529135446Strhodes */ 530135446Strhodes ctx->stats[size].gets++; 531135446Strhodes ctx->stats[size].totalgets++; 532135446Strhodes ctx->stats[new_size].freefrags--; 533135446Strhodes ctx->inuse += new_size; 534135446Strhodes 535135446Strhodes done: 536135446Strhodes 537135446Strhodes#if ISC_MEM_FILL 538135446Strhodes if (ret != NULL) 539135446Strhodes memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */ 540135446Strhodes#endif 541135446Strhodes 542135446Strhodes return (ret); 543135446Strhodes} 544135446Strhodes 545135446Strhodes#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN 546135446Strhodesstatic inline void 547135446Strhodescheck_overrun(void *mem, size_t size, size_t new_size) { 548135446Strhodes unsigned char *cp; 549135446Strhodes 550135446Strhodes cp = (unsigned char *)mem; 551135446Strhodes cp += size; 552135446Strhodes while (size < new_size) { 553135446Strhodes INSIST(*cp == 0xbe); 554135446Strhodes cp++; 555135446Strhodes size++; 556135446Strhodes } 557135446Strhodes} 558135446Strhodes#endif 559135446Strhodes 560135446Strhodesstatic inline void 561135446Strhodesmem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) { 562135446Strhodes size_t new_size = quantize(size); 563135446Strhodes 564135446Strhodes if (size == ctx->max_size || new_size >= ctx->max_size) { 565135446Strhodes /* 566135446Strhodes * memput() called on something beyond our upper limit. 567135446Strhodes */ 568135446Strhodes#if ISC_MEM_FILL 569135446Strhodes memset(mem, 0xde, size); /* Mnemonic for "dead". */ 570135446Strhodes#endif 571135446Strhodes (ctx->memfree)(ctx->arg, mem); 572170222Sdougb INSIST(ctx->stats[ctx->max_size].gets != 0U); 573135446Strhodes ctx->stats[ctx->max_size].gets--; 574135446Strhodes INSIST(size <= ctx->total); 575135446Strhodes ctx->inuse -= size; 576135446Strhodes ctx->total -= size; 577135446Strhodes return; 578135446Strhodes } 579135446Strhodes 580135446Strhodes#if ISC_MEM_FILL 581135446Strhodes#if ISC_MEM_CHECKOVERRUN 582135446Strhodes check_overrun(mem, size, new_size); 583135446Strhodes#endif 584135446Strhodes memset(mem, 0xde, new_size); /* Mnemonic for "dead". */ 585135446Strhodes#endif 586135446Strhodes 587135446Strhodes /* 588135446Strhodes * The free list uses the "rounded-up" size "new_size". 589135446Strhodes */ 590135446Strhodes ((element *)mem)->next = ctx->freelists[new_size]; 591135446Strhodes ctx->freelists[new_size] = (element *)mem; 592135446Strhodes 593135446Strhodes /* 594135446Strhodes * The stats[] uses the _actual_ "size" requested by the 595135446Strhodes * caller, with the caveat (in the code above) that "size" >= the 596135446Strhodes * max. size (max_size) ends up getting recorded as a call to 597135446Strhodes * max_size. 598135446Strhodes */ 599170222Sdougb INSIST(ctx->stats[size].gets != 0U); 600135446Strhodes ctx->stats[size].gets--; 601135446Strhodes ctx->stats[new_size].freefrags++; 602135446Strhodes ctx->inuse -= new_size; 603135446Strhodes} 604135446Strhodes 605170222Sdougb/*! 606135446Strhodes * Perform a malloc, doing memory filling and overrun detection as necessary. 607135446Strhodes */ 608135446Strhodesstatic inline void * 609135446Strhodesmem_get(isc_mem_t *ctx, size_t size) { 610135446Strhodes char *ret; 611135446Strhodes 612135446Strhodes#if ISC_MEM_CHECKOVERRUN 613135446Strhodes size += 1; 614135446Strhodes#endif 615135446Strhodes 616135446Strhodes ret = (ctx->memalloc)(ctx->arg, size); 617135446Strhodes if (ret == NULL) 618186462Sdougb ctx->memalloc_failures++; 619135446Strhodes 620135446Strhodes#if ISC_MEM_FILL 621135446Strhodes if (ret != NULL) 622135446Strhodes memset(ret, 0xbe, size); /* Mnemonic for "beef". */ 623135446Strhodes#else 624135446Strhodes# if ISC_MEM_CHECKOVERRUN 625135446Strhodes if (ret != NULL) 626135446Strhodes ret[size-1] = 0xbe; 627135446Strhodes# endif 628135446Strhodes#endif 629135446Strhodes 630135446Strhodes return (ret); 631135446Strhodes} 632135446Strhodes 633170222Sdougb/*! 634135446Strhodes * Perform a free, doing memory filling and overrun detection as necessary. 635135446Strhodes */ 636135446Strhodesstatic inline void 637135446Strhodesmem_put(isc_mem_t *ctx, void *mem, size_t size) { 638135446Strhodes#if ISC_MEM_CHECKOVERRUN 639135446Strhodes INSIST(((unsigned char *)mem)[size] == 0xbe); 640135446Strhodes#endif 641135446Strhodes#if ISC_MEM_FILL 642135446Strhodes memset(mem, 0xde, size); /* Mnemonic for "dead". */ 643135446Strhodes#else 644135446Strhodes UNUSED(size); 645135446Strhodes#endif 646135446Strhodes (ctx->memfree)(ctx->arg, mem); 647135446Strhodes} 648135446Strhodes 649170222Sdougb/*! 650135446Strhodes * Update internal counters after a memory get. 651135446Strhodes */ 652135446Strhodesstatic inline void 653135446Strhodesmem_getstats(isc_mem_t *ctx, size_t size) { 654135446Strhodes ctx->total += size; 655135446Strhodes ctx->inuse += size; 656135446Strhodes 657135446Strhodes if (size > ctx->max_size) { 658135446Strhodes ctx->stats[ctx->max_size].gets++; 659135446Strhodes ctx->stats[ctx->max_size].totalgets++; 660135446Strhodes } else { 661135446Strhodes ctx->stats[size].gets++; 662135446Strhodes ctx->stats[size].totalgets++; 663135446Strhodes } 664135446Strhodes} 665135446Strhodes 666170222Sdougb/*! 667135446Strhodes * Update internal counters after a memory put. 668135446Strhodes */ 669135446Strhodesstatic inline void 670135446Strhodesmem_putstats(isc_mem_t *ctx, void *ptr, size_t size) { 671135446Strhodes UNUSED(ptr); 672135446Strhodes 673135446Strhodes INSIST(ctx->inuse >= size); 674135446Strhodes ctx->inuse -= size; 675135446Strhodes 676135446Strhodes if (size > ctx->max_size) { 677135446Strhodes INSIST(ctx->stats[ctx->max_size].gets > 0U); 678135446Strhodes ctx->stats[ctx->max_size].gets--; 679135446Strhodes } else { 680135446Strhodes INSIST(ctx->stats[size].gets > 0U); 681135446Strhodes ctx->stats[size].gets--; 682135446Strhodes } 683135446Strhodes} 684135446Strhodes 685135446Strhodes/* 686135446Strhodes * Private. 687135446Strhodes */ 688135446Strhodes 689135446Strhodesstatic void * 690135446Strhodesdefault_memalloc(void *arg, size_t size) { 691135446Strhodes UNUSED(arg); 692135446Strhodes if (size == 0U) 693135446Strhodes size = 1; 694135446Strhodes return (malloc(size)); 695135446Strhodes} 696135446Strhodes 697135446Strhodesstatic void 698135446Strhodesdefault_memfree(void *arg, void *ptr) { 699135446Strhodes UNUSED(arg); 700135446Strhodes free(ptr); 701135446Strhodes} 702135446Strhodes 703170222Sdougbstatic void 704170222Sdougbinitialize_action(void) { 705174187Sdougb RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS); 706174187Sdougb ISC_LIST_INIT(contexts); 707193149Sdougb totallost = 0; 708170222Sdougb} 709170222Sdougb 710135446Strhodes/* 711135446Strhodes * Public. 712135446Strhodes */ 713135446Strhodes 714135446Strhodesisc_result_t 715135446Strhodesisc_mem_createx(size_t init_max_size, size_t target_size, 716135446Strhodes isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 717135446Strhodes isc_mem_t **ctxp) 718135446Strhodes{ 719170222Sdougb return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree, 720170222Sdougb arg, ctxp, ISC_MEMFLAG_DEFAULT)); 721186462Sdougb 722170222Sdougb} 723170222Sdougb 724170222Sdougbisc_result_t 725170222Sdougbisc_mem_createx2(size_t init_max_size, size_t target_size, 726170222Sdougb isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 727170222Sdougb isc_mem_t **ctxp, unsigned int flags) 728170222Sdougb{ 729135446Strhodes isc_mem_t *ctx; 730135446Strhodes isc_result_t result; 731135446Strhodes 732135446Strhodes REQUIRE(ctxp != NULL && *ctxp == NULL); 733135446Strhodes REQUIRE(memalloc != NULL); 734135446Strhodes REQUIRE(memfree != NULL); 735135446Strhodes 736135446Strhodes INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0); 737135446Strhodes 738170222Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 739135446Strhodes 740135446Strhodes ctx = (memalloc)(arg, sizeof(*ctx)); 741135446Strhodes if (ctx == NULL) 742135446Strhodes return (ISC_R_NOMEMORY); 743135446Strhodes 744170222Sdougb if ((flags & ISC_MEMFLAG_NOLOCK) == 0) { 745170222Sdougb result = isc_mutex_init(&ctx->lock); 746170222Sdougb if (result != ISC_R_SUCCESS) { 747170222Sdougb (memfree)(arg, ctx); 748170222Sdougb return (result); 749170222Sdougb } 750153816Sdougb } 751153816Sdougb 752135446Strhodes if (init_max_size == 0U) 753135446Strhodes ctx->max_size = DEF_MAX_SIZE; 754135446Strhodes else 755135446Strhodes ctx->max_size = init_max_size; 756170222Sdougb ctx->flags = flags; 757135446Strhodes ctx->references = 1; 758193149Sdougb memset(ctx->name, 0, sizeof(ctx->name)); 759193149Sdougb ctx->tag = NULL; 760135446Strhodes ctx->quota = 0; 761135446Strhodes ctx->total = 0; 762135446Strhodes ctx->inuse = 0; 763135446Strhodes ctx->maxinuse = 0; 764135446Strhodes ctx->hi_water = 0; 765135446Strhodes ctx->lo_water = 0; 766135446Strhodes ctx->hi_called = ISC_FALSE; 767135446Strhodes ctx->water = NULL; 768135446Strhodes ctx->water_arg = NULL; 769135446Strhodes ctx->magic = MEM_MAGIC; 770135446Strhodes isc_ondestroy_init(&ctx->ondestroy); 771135446Strhodes ctx->memalloc = memalloc; 772135446Strhodes ctx->memfree = memfree; 773135446Strhodes ctx->arg = arg; 774135446Strhodes ctx->stats = NULL; 775135446Strhodes ctx->checkfree = ISC_TRUE; 776135446Strhodes#if ISC_MEM_TRACKLINES 777135446Strhodes ctx->debuglist = NULL; 778193149Sdougb ctx->debuglistcnt = 0; 779135446Strhodes#endif 780135446Strhodes ISC_LIST_INIT(ctx->pools); 781193149Sdougb ctx->poolcnt = 0; 782135446Strhodes ctx->freelists = NULL; 783170222Sdougb ctx->basic_blocks = NULL; 784170222Sdougb ctx->basic_table = NULL; 785170222Sdougb ctx->basic_table_count = 0; 786170222Sdougb ctx->basic_table_size = 0; 787170222Sdougb ctx->lowest = NULL; 788170222Sdougb ctx->highest = NULL; 789135446Strhodes 790135446Strhodes ctx->stats = (memalloc)(arg, 791135446Strhodes (ctx->max_size+1) * sizeof(struct stats)); 792135446Strhodes if (ctx->stats == NULL) { 793135446Strhodes result = ISC_R_NOMEMORY; 794135446Strhodes goto error; 795135446Strhodes } 796135446Strhodes memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats)); 797135446Strhodes 798170222Sdougb if ((flags & ISC_MEMFLAG_INTERNAL) != 0) { 799170222Sdougb if (target_size == 0U) 800170222Sdougb ctx->mem_target = DEF_MEM_TARGET; 801170222Sdougb else 802170222Sdougb ctx->mem_target = target_size; 803170222Sdougb ctx->freelists = (memalloc)(arg, ctx->max_size * 804170222Sdougb sizeof(element *)); 805170222Sdougb if (ctx->freelists == NULL) { 806170222Sdougb result = ISC_R_NOMEMORY; 807170222Sdougb goto error; 808170222Sdougb } 809170222Sdougb memset(ctx->freelists, 0, 810170222Sdougb ctx->max_size * sizeof(element *)); 811135446Strhodes } 812135446Strhodes 813135446Strhodes#if ISC_MEM_TRACKLINES 814135446Strhodes if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) { 815135446Strhodes unsigned int i; 816135446Strhodes 817135446Strhodes ctx->debuglist = (memalloc)(arg, 818135446Strhodes (ctx->max_size+1) * sizeof(debuglist_t)); 819135446Strhodes if (ctx->debuglist == NULL) { 820135446Strhodes result = ISC_R_NOMEMORY; 821135446Strhodes goto error; 822135446Strhodes } 823135446Strhodes for (i = 0; i <= ctx->max_size; i++) 824135446Strhodes ISC_LIST_INIT(ctx->debuglist[i]); 825135446Strhodes } 826135446Strhodes#endif 827135446Strhodes 828135446Strhodes ctx->memalloc_failures = 0; 829135446Strhodes 830170222Sdougb LOCK(&lock); 831170222Sdougb ISC_LIST_INITANDAPPEND(contexts, ctx, link); 832170222Sdougb UNLOCK(&lock); 833170222Sdougb 834135446Strhodes *ctxp = ctx; 835135446Strhodes return (ISC_R_SUCCESS); 836135446Strhodes 837135446Strhodes error: 838153816Sdougb if (ctx != NULL) { 839153816Sdougb if (ctx->stats != NULL) 840135446Strhodes (memfree)(arg, ctx->stats); 841153816Sdougb if (ctx->freelists != NULL) 842135446Strhodes (memfree)(arg, ctx->freelists); 843135446Strhodes#if ISC_MEM_TRACKLINES 844153816Sdougb if (ctx->debuglist != NULL) 845135446Strhodes (ctx->memfree)(ctx->arg, ctx->debuglist); 846135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 847170222Sdougb if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 848170222Sdougb DESTROYLOCK(&ctx->lock); 849135446Strhodes (memfree)(arg, ctx); 850135446Strhodes } 851135446Strhodes 852135446Strhodes return (result); 853135446Strhodes} 854135446Strhodes 855135446Strhodesisc_result_t 856135446Strhodesisc_mem_create(size_t init_max_size, size_t target_size, 857135446Strhodes isc_mem_t **ctxp) 858135446Strhodes{ 859170222Sdougb return (isc_mem_createx2(init_max_size, target_size, 860170222Sdougb default_memalloc, default_memfree, NULL, 861170222Sdougb ctxp, ISC_MEMFLAG_DEFAULT)); 862135446Strhodes} 863135446Strhodes 864170222Sdougbisc_result_t 865170222Sdougbisc_mem_create2(size_t init_max_size, size_t target_size, 866170222Sdougb isc_mem_t **ctxp, unsigned int flags) 867170222Sdougb{ 868170222Sdougb return (isc_mem_createx2(init_max_size, target_size, 869170222Sdougb default_memalloc, default_memfree, NULL, 870170222Sdougb ctxp, flags)); 871170222Sdougb} 872170222Sdougb 873135446Strhodesstatic void 874135446Strhodesdestroy(isc_mem_t *ctx) { 875135446Strhodes unsigned int i; 876135446Strhodes isc_ondestroy_t ondest; 877135446Strhodes 878135446Strhodes ctx->magic = 0; 879135446Strhodes 880170222Sdougb LOCK(&lock); 881170222Sdougb ISC_LIST_UNLINK(contexts, ctx, link); 882193149Sdougb totallost += ctx->inuse; 883170222Sdougb UNLOCK(&lock); 884170222Sdougb 885135446Strhodes INSIST(ISC_LIST_EMPTY(ctx->pools)); 886135446Strhodes 887135446Strhodes#if ISC_MEM_TRACKLINES 888135446Strhodes if (ctx->debuglist != NULL) { 889135446Strhodes if (ctx->checkfree) { 890135446Strhodes for (i = 0; i <= ctx->max_size; i++) { 891135446Strhodes if (!ISC_LIST_EMPTY(ctx->debuglist[i])) 892135446Strhodes print_active(ctx, stderr); 893135446Strhodes INSIST(ISC_LIST_EMPTY(ctx->debuglist[i])); 894135446Strhodes } 895135446Strhodes } else { 896135446Strhodes debuglink_t *dl; 897135446Strhodes 898135446Strhodes for (i = 0; i <= ctx->max_size; i++) 899135446Strhodes for (dl = ISC_LIST_HEAD(ctx->debuglist[i]); 900135446Strhodes dl != NULL; 901135446Strhodes dl = ISC_LIST_HEAD(ctx->debuglist[i])) { 902135446Strhodes ISC_LIST_UNLINK(ctx->debuglist[i], 903186462Sdougb dl, link); 904135446Strhodes free(dl); 905135446Strhodes } 906135446Strhodes } 907135446Strhodes (ctx->memfree)(ctx->arg, ctx->debuglist); 908135446Strhodes } 909135446Strhodes#endif 910135446Strhodes INSIST(ctx->references == 0); 911135446Strhodes 912135446Strhodes if (ctx->checkfree) { 913135446Strhodes for (i = 0; i <= ctx->max_size; i++) { 914135446Strhodes#if ISC_MEM_TRACKLINES 915135446Strhodes if (ctx->stats[i].gets != 0U) 916135446Strhodes print_active(ctx, stderr); 917135446Strhodes#endif 918135446Strhodes INSIST(ctx->stats[i].gets == 0U); 919135446Strhodes } 920135446Strhodes } 921135446Strhodes 922135446Strhodes (ctx->memfree)(ctx->arg, ctx->stats); 923135446Strhodes 924170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 925170222Sdougb for (i = 0; i < ctx->basic_table_count; i++) 926170222Sdougb (ctx->memfree)(ctx->arg, ctx->basic_table[i]); 927170222Sdougb (ctx->memfree)(ctx->arg, ctx->freelists); 928186462Sdougb if (ctx->basic_table != NULL) 929186462Sdougb (ctx->memfree)(ctx->arg, ctx->basic_table); 930170222Sdougb } 931135446Strhodes 932135446Strhodes ondest = ctx->ondestroy; 933135446Strhodes 934170222Sdougb if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 935170222Sdougb DESTROYLOCK(&ctx->lock); 936135446Strhodes (ctx->memfree)(ctx->arg, ctx); 937135446Strhodes 938135446Strhodes isc_ondestroy_notify(&ondest, ctx); 939135446Strhodes} 940135446Strhodes 941135446Strhodesvoid 942135446Strhodesisc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) { 943135446Strhodes REQUIRE(VALID_CONTEXT(source)); 944135446Strhodes REQUIRE(targetp != NULL && *targetp == NULL); 945135446Strhodes 946170222Sdougb MCTXLOCK(source, &source->lock); 947135446Strhodes source->references++; 948170222Sdougb MCTXUNLOCK(source, &source->lock); 949135446Strhodes 950135446Strhodes *targetp = source; 951135446Strhodes} 952135446Strhodes 953135446Strhodesvoid 954135446Strhodesisc_mem_detach(isc_mem_t **ctxp) { 955135446Strhodes isc_mem_t *ctx; 956135446Strhodes isc_boolean_t want_destroy = ISC_FALSE; 957135446Strhodes 958135446Strhodes REQUIRE(ctxp != NULL); 959135446Strhodes ctx = *ctxp; 960135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 961135446Strhodes 962170222Sdougb MCTXLOCK(ctx, &ctx->lock); 963135446Strhodes INSIST(ctx->references > 0); 964135446Strhodes ctx->references--; 965135446Strhodes if (ctx->references == 0) 966135446Strhodes want_destroy = ISC_TRUE; 967170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 968135446Strhodes 969135446Strhodes if (want_destroy) 970135446Strhodes destroy(ctx); 971135446Strhodes 972135446Strhodes *ctxp = NULL; 973135446Strhodes} 974135446Strhodes 975135446Strhodes/* 976135446Strhodes * isc_mem_putanddetach() is the equivalent of: 977135446Strhodes * 978135446Strhodes * mctx = NULL; 979135446Strhodes * isc_mem_attach(ptr->mctx, &mctx); 980135446Strhodes * isc_mem_detach(&ptr->mctx); 981135446Strhodes * isc_mem_put(mctx, ptr, sizeof(*ptr); 982135446Strhodes * isc_mem_detach(&mctx); 983135446Strhodes */ 984135446Strhodes 985135446Strhodesvoid 986135446Strhodesisc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { 987135446Strhodes isc_mem_t *ctx; 988135446Strhodes isc_boolean_t want_destroy = ISC_FALSE; 989170222Sdougb size_info *si; 990170222Sdougb size_t oldsize; 991135446Strhodes 992135446Strhodes REQUIRE(ctxp != NULL); 993135446Strhodes ctx = *ctxp; 994135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 995135446Strhodes REQUIRE(ptr != NULL); 996135446Strhodes 997135446Strhodes /* 998135446Strhodes * Must be before mem_putunlocked() as ctxp is usually within 999135446Strhodes * [ptr..ptr+size). 1000135446Strhodes */ 1001135446Strhodes *ctxp = NULL; 1002135446Strhodes 1003170222Sdougb if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { 1004170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { 1005170222Sdougb si = &(((size_info *)ptr)[-1]); 1006170222Sdougb oldsize = si->u.size - ALIGNMENT_SIZE; 1007170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1008170222Sdougb oldsize -= ALIGNMENT_SIZE; 1009170222Sdougb INSIST(oldsize == size); 1010170222Sdougb } 1011170222Sdougb isc__mem_free(ctx, ptr FLARG_PASS); 1012135446Strhodes 1013170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1014170222Sdougb ctx->references--; 1015170222Sdougb if (ctx->references == 0) 1016170222Sdougb want_destroy = ISC_TRUE; 1017170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1018170222Sdougb if (want_destroy) 1019170222Sdougb destroy(ctx); 1020170222Sdougb 1021170222Sdougb return; 1022170222Sdougb } 1023170222Sdougb 1024170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1025170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1026170222Sdougb mem_putunlocked(ctx, ptr, size); 1027170222Sdougb } else { 1028170222Sdougb mem_put(ctx, ptr, size); 1029170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1030170222Sdougb mem_putstats(ctx, ptr, size); 1031170222Sdougb } 1032170222Sdougb 1033135446Strhodes DELETE_TRACE(ctx, ptr, size, file, line); 1034135446Strhodes INSIST(ctx->references > 0); 1035135446Strhodes ctx->references--; 1036135446Strhodes if (ctx->references == 0) 1037135446Strhodes want_destroy = ISC_TRUE; 1038135446Strhodes 1039170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1040135446Strhodes 1041135446Strhodes if (want_destroy) 1042135446Strhodes destroy(ctx); 1043135446Strhodes} 1044135446Strhodes 1045135446Strhodesvoid 1046135446Strhodesisc_mem_destroy(isc_mem_t **ctxp) { 1047135446Strhodes isc_mem_t *ctx; 1048135446Strhodes 1049135446Strhodes /* 1050135446Strhodes * This routine provides legacy support for callers who use mctxs 1051135446Strhodes * without attaching/detaching. 1052135446Strhodes */ 1053135446Strhodes 1054135446Strhodes REQUIRE(ctxp != NULL); 1055135446Strhodes ctx = *ctxp; 1056135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1057135446Strhodes 1058170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1059135446Strhodes#if ISC_MEM_TRACKLINES 1060135446Strhodes if (ctx->references != 1) 1061135446Strhodes print_active(ctx, stderr); 1062135446Strhodes#endif 1063135446Strhodes REQUIRE(ctx->references == 1); 1064135446Strhodes ctx->references--; 1065170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1066135446Strhodes 1067135446Strhodes destroy(ctx); 1068135446Strhodes 1069135446Strhodes *ctxp = NULL; 1070135446Strhodes} 1071135446Strhodes 1072135446Strhodesisc_result_t 1073135446Strhodesisc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) { 1074135446Strhodes isc_result_t res; 1075135446Strhodes 1076170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1077135446Strhodes res = isc_ondestroy_register(&ctx->ondestroy, task, event); 1078170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1079135446Strhodes 1080135446Strhodes return (res); 1081135446Strhodes} 1082135446Strhodes 1083135446Strhodes 1084135446Strhodesvoid * 1085135446Strhodesisc__mem_get(isc_mem_t *ctx, size_t size FLARG) { 1086135446Strhodes void *ptr; 1087135446Strhodes isc_boolean_t call_water = ISC_FALSE; 1088135446Strhodes 1089135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1090135446Strhodes 1091170222Sdougb if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) 1092170222Sdougb return (isc__mem_allocate(ctx, size FLARG_PASS)); 1093135446Strhodes 1094170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1095170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1096170222Sdougb ptr = mem_getunlocked(ctx, size); 1097170222Sdougb } else { 1098170222Sdougb ptr = mem_get(ctx, size); 1099170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1100170222Sdougb if (ptr != NULL) 1101170222Sdougb mem_getstats(ctx, size); 1102170222Sdougb } 1103170222Sdougb 1104135446Strhodes ADD_TRACE(ctx, ptr, size, file, line); 1105135446Strhodes if (ctx->hi_water != 0U && !ctx->hi_called && 1106135446Strhodes ctx->inuse > ctx->hi_water) { 1107135446Strhodes call_water = ISC_TRUE; 1108135446Strhodes } 1109135446Strhodes if (ctx->inuse > ctx->maxinuse) { 1110135446Strhodes ctx->maxinuse = ctx->inuse; 1111135446Strhodes if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1112135446Strhodes (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) 1113135446Strhodes fprintf(stderr, "maxinuse = %lu\n", 1114135446Strhodes (unsigned long)ctx->inuse); 1115135446Strhodes } 1116170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1117135446Strhodes 1118135446Strhodes if (call_water) 1119135446Strhodes (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); 1120135446Strhodes 1121135446Strhodes return (ptr); 1122135446Strhodes} 1123135446Strhodes 1124135446Strhodesvoid 1125135446Strhodesisc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG) 1126135446Strhodes{ 1127135446Strhodes isc_boolean_t call_water = ISC_FALSE; 1128170222Sdougb size_info *si; 1129170222Sdougb size_t oldsize; 1130135446Strhodes 1131135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1132135446Strhodes REQUIRE(ptr != NULL); 1133135446Strhodes 1134170222Sdougb if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { 1135170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { 1136170222Sdougb si = &(((size_info *)ptr)[-1]); 1137170222Sdougb oldsize = si->u.size - ALIGNMENT_SIZE; 1138170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1139170222Sdougb oldsize -= ALIGNMENT_SIZE; 1140170222Sdougb INSIST(oldsize == size); 1141170222Sdougb } 1142170222Sdougb isc__mem_free(ctx, ptr FLARG_PASS); 1143170222Sdougb return; 1144170222Sdougb } 1145135446Strhodes 1146170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1147170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1148170222Sdougb mem_putunlocked(ctx, ptr, size); 1149170222Sdougb } else { 1150170222Sdougb mem_put(ctx, ptr, size); 1151170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1152170222Sdougb mem_putstats(ctx, ptr, size); 1153170222Sdougb } 1154170222Sdougb 1155135446Strhodes DELETE_TRACE(ctx, ptr, size, file, line); 1156135446Strhodes 1157135446Strhodes /* 1158135446Strhodes * The check against ctx->lo_water == 0 is for the condition 1159135446Strhodes * when the context was pushed over hi_water but then had 1160135446Strhodes * isc_mem_setwater() called with 0 for hi_water and lo_water. 1161135446Strhodes */ 1162186462Sdougb if (ctx->hi_called && 1163135446Strhodes (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1164135446Strhodes if (ctx->water != NULL) 1165135446Strhodes call_water = ISC_TRUE; 1166135446Strhodes } 1167170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1168135446Strhodes 1169135446Strhodes if (call_water) 1170135446Strhodes (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1171135446Strhodes} 1172135446Strhodes 1173186462Sdougbvoid 1174186462Sdougbisc_mem_waterack(isc_mem_t *ctx, int flag) { 1175186462Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1176186462Sdougb 1177186462Sdougb MCTXLOCK(ctx, &ctx->lock); 1178186462Sdougb if (flag == ISC_MEM_LOWATER) 1179186462Sdougb ctx->hi_called = ISC_FALSE; 1180186462Sdougb else if (flag == ISC_MEM_HIWATER) 1181186462Sdougb ctx->hi_called = ISC_TRUE; 1182186462Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1183186462Sdougb} 1184186462Sdougb 1185135446Strhodes#if ISC_MEM_TRACKLINES 1186135446Strhodesstatic void 1187135446Strhodesprint_active(isc_mem_t *mctx, FILE *out) { 1188135446Strhodes if (mctx->debuglist != NULL) { 1189135446Strhodes debuglink_t *dl; 1190135446Strhodes unsigned int i, j; 1191135446Strhodes const char *format; 1192135446Strhodes isc_boolean_t found; 1193135446Strhodes 1194193149Sdougb fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1195135446Strhodes ISC_MSG_DUMPALLOC, 1196135446Strhodes "Dump of all outstanding " 1197135446Strhodes "memory allocations:\n")); 1198135446Strhodes found = ISC_FALSE; 1199135446Strhodes format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1200186462Sdougb ISC_MSG_PTRFILELINE, 1201135446Strhodes "\tptr %p size %u file %s line %u\n"); 1202135446Strhodes for (i = 0; i <= mctx->max_size; i++) { 1203135446Strhodes dl = ISC_LIST_HEAD(mctx->debuglist[i]); 1204186462Sdougb 1205135446Strhodes if (dl != NULL) 1206135446Strhodes found = ISC_TRUE; 1207135446Strhodes 1208135446Strhodes while (dl != NULL) { 1209135446Strhodes for (j = 0; j < DEBUGLIST_COUNT; j++) 1210135446Strhodes if (dl->ptr[j] != NULL) 1211135446Strhodes fprintf(out, format, 1212135446Strhodes dl->ptr[j], 1213135446Strhodes dl->size[j], 1214135446Strhodes dl->file[j], 1215135446Strhodes dl->line[j]); 1216135446Strhodes dl = ISC_LIST_NEXT(dl, link); 1217135446Strhodes } 1218135446Strhodes } 1219135446Strhodes if (!found) 1220193149Sdougb fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1221135446Strhodes ISC_MSG_NONE, "\tNone.\n")); 1222135446Strhodes } 1223135446Strhodes} 1224135446Strhodes#endif 1225135446Strhodes 1226135446Strhodes/* 1227135446Strhodes * Print the stats[] on the stream "out" with suitable formatting. 1228135446Strhodes */ 1229135446Strhodesvoid 1230135446Strhodesisc_mem_stats(isc_mem_t *ctx, FILE *out) { 1231135446Strhodes size_t i; 1232135446Strhodes const struct stats *s; 1233135446Strhodes const isc_mempool_t *pool; 1234135446Strhodes 1235135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1236170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1237135446Strhodes 1238135446Strhodes for (i = 0; i <= ctx->max_size; i++) { 1239135446Strhodes s = &ctx->stats[i]; 1240135446Strhodes 1241135446Strhodes if (s->totalgets == 0U && s->gets == 0U) 1242135446Strhodes continue; 1243135446Strhodes fprintf(out, "%s%5lu: %11lu gets, %11lu rem", 1244135446Strhodes (i == ctx->max_size) ? ">=" : " ", 1245135446Strhodes (unsigned long) i, s->totalgets, s->gets); 1246170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 && 1247170222Sdougb (s->blocks != 0U || s->freefrags != 0U)) 1248135446Strhodes fprintf(out, " (%lu bl, %lu ff)", 1249135446Strhodes s->blocks, s->freefrags); 1250135446Strhodes fputc('\n', out); 1251135446Strhodes } 1252135446Strhodes 1253135446Strhodes /* 1254135446Strhodes * Note that since a pool can be locked now, these stats might be 1255135446Strhodes * somewhat off if the pool is in active use at the time the stats 1256135446Strhodes * are dumped. The link fields are protected by the isc_mem_t's 1257135446Strhodes * lock, however, so walking this list and extracting integers from 1258135446Strhodes * stats fields is always safe. 1259135446Strhodes */ 1260135446Strhodes pool = ISC_LIST_HEAD(ctx->pools); 1261135446Strhodes if (pool != NULL) { 1262193149Sdougb fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1263135446Strhodes ISC_MSG_POOLSTATS, 1264135446Strhodes "[Pool statistics]\n")); 1265135446Strhodes fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n", 1266135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1267135446Strhodes ISC_MSG_POOLNAME, "name"), 1268135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1269135446Strhodes ISC_MSG_POOLSIZE, "size"), 1270135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1271135446Strhodes ISC_MSG_POOLMAXALLOC, "maxalloc"), 1272135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1273135446Strhodes ISC_MSG_POOLALLOCATED, "allocated"), 1274135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1275135446Strhodes ISC_MSG_POOLFREECOUNT, "freecount"), 1276135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1277135446Strhodes ISC_MSG_POOLFREEMAX, "freemax"), 1278135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1279135446Strhodes ISC_MSG_POOLFILLCOUNT, "fillcount"), 1280135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1281135446Strhodes ISC_MSG_POOLGETS, "gets"), 1282135446Strhodes "L"); 1283135446Strhodes } 1284135446Strhodes while (pool != NULL) { 1285135446Strhodes fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n", 1286135446Strhodes pool->name, (unsigned long) pool->size, pool->maxalloc, 1287135446Strhodes pool->allocated, pool->freecount, pool->freemax, 1288135446Strhodes pool->fillcount, pool->gets, 1289135446Strhodes (pool->lock == NULL ? "N" : "Y")); 1290135446Strhodes pool = ISC_LIST_NEXT(pool, link); 1291135446Strhodes } 1292135446Strhodes 1293135446Strhodes#if ISC_MEM_TRACKLINES 1294135446Strhodes print_active(ctx, out); 1295135446Strhodes#endif 1296135446Strhodes 1297170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1298135446Strhodes} 1299135446Strhodes 1300135446Strhodes/* 1301135446Strhodes * Replacements for malloc() and free() -- they implicitly remember the 1302135446Strhodes * size of the object allocated (with some additional overhead). 1303135446Strhodes */ 1304135446Strhodes 1305135446Strhodesstatic void * 1306135446Strhodesisc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) { 1307135446Strhodes size_info *si; 1308135446Strhodes 1309135446Strhodes size += ALIGNMENT_SIZE; 1310170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1311170222Sdougb size += ALIGNMENT_SIZE; 1312170222Sdougb 1313170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) 1314170222Sdougb si = mem_getunlocked(ctx, size); 1315170222Sdougb else 1316170222Sdougb si = mem_get(ctx, size); 1317170222Sdougb 1318135446Strhodes if (si == NULL) 1319135446Strhodes return (NULL); 1320170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1321170222Sdougb si->u.ctx = ctx; 1322170222Sdougb si++; 1323170222Sdougb } 1324135446Strhodes si->u.size = size; 1325135446Strhodes return (&si[1]); 1326135446Strhodes} 1327135446Strhodes 1328135446Strhodesvoid * 1329135446Strhodesisc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) { 1330135446Strhodes size_info *si; 1331170222Sdougb isc_boolean_t call_water = ISC_FALSE; 1332135446Strhodes 1333135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1334135446Strhodes 1335170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1336170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1337170222Sdougb si = isc__mem_allocateunlocked(ctx, size); 1338170222Sdougb } else { 1339170222Sdougb si = isc__mem_allocateunlocked(ctx, size); 1340170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1341170222Sdougb if (si != NULL) 1342170222Sdougb mem_getstats(ctx, si[-1].u.size); 1343170222Sdougb } 1344135446Strhodes 1345135446Strhodes#if ISC_MEM_TRACKLINES 1346135446Strhodes ADD_TRACE(ctx, si, si[-1].u.size, file, line); 1347135446Strhodes#endif 1348170222Sdougb if (ctx->hi_water != 0U && !ctx->hi_called && 1349170222Sdougb ctx->inuse > ctx->hi_water) { 1350170222Sdougb ctx->hi_called = ISC_TRUE; 1351170222Sdougb call_water = ISC_TRUE; 1352170222Sdougb } 1353170222Sdougb if (ctx->inuse > ctx->maxinuse) { 1354170222Sdougb ctx->maxinuse = ctx->inuse; 1355170222Sdougb if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1356170222Sdougb (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) 1357170222Sdougb fprintf(stderr, "maxinuse = %lu\n", 1358170222Sdougb (unsigned long)ctx->inuse); 1359170222Sdougb } 1360170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1361135446Strhodes 1362170222Sdougb if (call_water) 1363170222Sdougb (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); 1364135446Strhodes 1365135446Strhodes return (si); 1366135446Strhodes} 1367135446Strhodes 1368193149Sdougbvoid * 1369193149Sdougbisc__mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG) { 1370193149Sdougb void *new_ptr = NULL; 1371193149Sdougb size_t oldsize, copysize; 1372193149Sdougb 1373193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1374193149Sdougb 1375193149Sdougb /* 1376193149Sdougb * This function emulates the realloc(3) standard library function: 1377193149Sdougb * - if size > 0, allocate new memory; and if ptr is non NULL, copy 1378193149Sdougb * as much of the old contents to the new buffer and free the old one. 1379193149Sdougb * Note that when allocation fails the original pointer is intact; 1380193149Sdougb * the caller must free it. 1381193149Sdougb * - if size is 0 and ptr is non NULL, simply free the given ptr. 1382193149Sdougb * - this function returns: 1383193149Sdougb * pointer to the newly allocated memory, or 1384193149Sdougb * NULL if allocation fails or doesn't happen. 1385193149Sdougb */ 1386193149Sdougb if (size > 0U) { 1387193149Sdougb new_ptr = isc__mem_allocate(ctx, size FLARG_PASS); 1388193149Sdougb if (new_ptr != NULL && ptr != NULL) { 1389193149Sdougb oldsize = (((size_info *)ptr)[-1]).u.size; 1390193149Sdougb INSIST(oldsize >= ALIGNMENT_SIZE); 1391193149Sdougb oldsize -= ALIGNMENT_SIZE; 1392193149Sdougb copysize = oldsize > size ? size : oldsize; 1393193149Sdougb memcpy(new_ptr, ptr, copysize); 1394193149Sdougb isc__mem_free(ctx, ptr FLARG_PASS); 1395193149Sdougb } 1396193149Sdougb } else if (ptr != NULL) 1397193149Sdougb isc__mem_free(ctx, ptr FLARG_PASS); 1398193149Sdougb 1399193149Sdougb return (new_ptr); 1400193149Sdougb} 1401193149Sdougb 1402135446Strhodesvoid 1403135446Strhodesisc__mem_free(isc_mem_t *ctx, void *ptr FLARG) { 1404135446Strhodes size_info *si; 1405135446Strhodes size_t size; 1406170222Sdougb isc_boolean_t call_water= ISC_FALSE; 1407135446Strhodes 1408135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1409135446Strhodes REQUIRE(ptr != NULL); 1410135446Strhodes 1411170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1412170222Sdougb si = &(((size_info *)ptr)[-2]); 1413170222Sdougb REQUIRE(si->u.ctx == ctx); 1414170222Sdougb size = si[1].u.size; 1415170222Sdougb } else { 1416170222Sdougb si = &(((size_info *)ptr)[-1]); 1417170222Sdougb size = si->u.size; 1418170222Sdougb } 1419135446Strhodes 1420170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1421170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1422170222Sdougb mem_putunlocked(ctx, si, size); 1423170222Sdougb } else { 1424170222Sdougb mem_put(ctx, si, size); 1425170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1426170222Sdougb mem_putstats(ctx, si, size); 1427170222Sdougb } 1428135446Strhodes 1429135446Strhodes DELETE_TRACE(ctx, ptr, size, file, line); 1430135446Strhodes 1431170222Sdougb /* 1432170222Sdougb * The check against ctx->lo_water == 0 is for the condition 1433170222Sdougb * when the context was pushed over hi_water but then had 1434170222Sdougb * isc_mem_setwater() called with 0 for hi_water and lo_water. 1435170222Sdougb */ 1436186462Sdougb if (ctx->hi_called && 1437170222Sdougb (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1438170222Sdougb ctx->hi_called = ISC_FALSE; 1439170222Sdougb 1440170222Sdougb if (ctx->water != NULL) 1441170222Sdougb call_water = ISC_TRUE; 1442170222Sdougb } 1443170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1444170222Sdougb 1445170222Sdougb if (call_water) 1446170222Sdougb (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1447135446Strhodes} 1448135446Strhodes 1449135446Strhodes 1450135446Strhodes/* 1451135446Strhodes * Other useful things. 1452135446Strhodes */ 1453135446Strhodes 1454135446Strhodeschar * 1455135446Strhodesisc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) { 1456135446Strhodes size_t len; 1457135446Strhodes char *ns; 1458135446Strhodes 1459135446Strhodes REQUIRE(VALID_CONTEXT(mctx)); 1460135446Strhodes REQUIRE(s != NULL); 1461135446Strhodes 1462135446Strhodes len = strlen(s); 1463135446Strhodes 1464135446Strhodes ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS); 1465135446Strhodes 1466135446Strhodes if (ns != NULL) 1467135446Strhodes strncpy(ns, s, len + 1); 1468135446Strhodes 1469135446Strhodes return (ns); 1470135446Strhodes} 1471135446Strhodes 1472135446Strhodesvoid 1473135446Strhodesisc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) { 1474135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1475170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1476135446Strhodes 1477135446Strhodes ctx->checkfree = flag; 1478135446Strhodes 1479170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1480135446Strhodes} 1481135446Strhodes 1482135446Strhodes/* 1483135446Strhodes * Quotas 1484135446Strhodes */ 1485135446Strhodes 1486135446Strhodesvoid 1487135446Strhodesisc_mem_setquota(isc_mem_t *ctx, size_t quota) { 1488135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1489170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1490135446Strhodes 1491135446Strhodes ctx->quota = quota; 1492135446Strhodes 1493170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1494135446Strhodes} 1495135446Strhodes 1496135446Strhodessize_t 1497135446Strhodesisc_mem_getquota(isc_mem_t *ctx) { 1498135446Strhodes size_t quota; 1499135446Strhodes 1500135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1501170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1502135446Strhodes 1503135446Strhodes quota = ctx->quota; 1504135446Strhodes 1505170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1506135446Strhodes 1507135446Strhodes return (quota); 1508135446Strhodes} 1509135446Strhodes 1510135446Strhodessize_t 1511135446Strhodesisc_mem_inuse(isc_mem_t *ctx) { 1512135446Strhodes size_t inuse; 1513135446Strhodes 1514135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1515170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1516135446Strhodes 1517135446Strhodes inuse = ctx->inuse; 1518135446Strhodes 1519170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1520135446Strhodes 1521135446Strhodes return (inuse); 1522135446Strhodes} 1523135446Strhodes 1524135446Strhodesvoid 1525135446Strhodesisc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, 1526186462Sdougb size_t hiwater, size_t lowater) 1527135446Strhodes{ 1528170222Sdougb isc_boolean_t callwater = ISC_FALSE; 1529170222Sdougb isc_mem_water_t oldwater; 1530170222Sdougb void *oldwater_arg; 1531170222Sdougb 1532135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1533135446Strhodes REQUIRE(hiwater >= lowater); 1534135446Strhodes 1535170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1536170222Sdougb oldwater = ctx->water; 1537170222Sdougb oldwater_arg = ctx->water_arg; 1538135446Strhodes if (water == NULL) { 1539170222Sdougb callwater = ctx->hi_called; 1540135446Strhodes ctx->water = NULL; 1541135446Strhodes ctx->water_arg = NULL; 1542135446Strhodes ctx->hi_water = 0; 1543135446Strhodes ctx->lo_water = 0; 1544135446Strhodes ctx->hi_called = ISC_FALSE; 1545135446Strhodes } else { 1546170222Sdougb if (ctx->hi_called && 1547170222Sdougb (ctx->water != water || ctx->water_arg != water_arg || 1548170222Sdougb ctx->inuse < lowater || lowater == 0U)) 1549170222Sdougb callwater = ISC_TRUE; 1550135446Strhodes ctx->water = water; 1551135446Strhodes ctx->water_arg = water_arg; 1552135446Strhodes ctx->hi_water = hiwater; 1553135446Strhodes ctx->lo_water = lowater; 1554135446Strhodes ctx->hi_called = ISC_FALSE; 1555135446Strhodes } 1556170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1557186462Sdougb 1558170222Sdougb if (callwater && oldwater != NULL) 1559170222Sdougb (oldwater)(oldwater_arg, ISC_MEM_LOWATER); 1560135446Strhodes} 1561135446Strhodes 1562193149Sdougbvoid 1563193149Sdougbisc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) { 1564193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1565193149Sdougb 1566193149Sdougb LOCK(&ctx->lock); 1567193149Sdougb memset(ctx->name, 0, sizeof(ctx->name)); 1568193149Sdougb strncpy(ctx->name, name, sizeof(ctx->name) - 1); 1569193149Sdougb ctx->tag = tag; 1570193149Sdougb UNLOCK(&ctx->lock); 1571193149Sdougb} 1572193149Sdougb 1573193149Sdougbconst char * 1574193149Sdougbisc_mem_getname(isc_mem_t *ctx) { 1575193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1576193149Sdougb 1577193149Sdougb return (ctx->name); 1578193149Sdougb} 1579193149Sdougb 1580193149Sdougbvoid * 1581193149Sdougbisc_mem_gettag(isc_mem_t *ctx) { 1582193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1583193149Sdougb 1584193149Sdougb return (ctx->tag); 1585193149Sdougb} 1586193149Sdougb 1587135446Strhodes/* 1588135446Strhodes * Memory pool stuff 1589135446Strhodes */ 1590135446Strhodes 1591135446Strhodesisc_result_t 1592135446Strhodesisc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) { 1593135446Strhodes isc_mempool_t *mpctx; 1594135446Strhodes 1595135446Strhodes REQUIRE(VALID_CONTEXT(mctx)); 1596135446Strhodes REQUIRE(size > 0U); 1597135446Strhodes REQUIRE(mpctxp != NULL && *mpctxp == NULL); 1598135446Strhodes 1599135446Strhodes /* 1600135446Strhodes * Allocate space for this pool, initialize values, and if all works 1601135446Strhodes * well, attach to the memory context. 1602135446Strhodes */ 1603135446Strhodes mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t)); 1604135446Strhodes if (mpctx == NULL) 1605135446Strhodes return (ISC_R_NOMEMORY); 1606135446Strhodes 1607135446Strhodes mpctx->magic = MEMPOOL_MAGIC; 1608135446Strhodes mpctx->lock = NULL; 1609135446Strhodes mpctx->mctx = mctx; 1610135446Strhodes mpctx->size = size; 1611135446Strhodes mpctx->maxalloc = UINT_MAX; 1612135446Strhodes mpctx->allocated = 0; 1613135446Strhodes mpctx->freecount = 0; 1614135446Strhodes mpctx->freemax = 1; 1615135446Strhodes mpctx->fillcount = 1; 1616135446Strhodes mpctx->gets = 0; 1617135446Strhodes#if ISC_MEMPOOL_NAMES 1618135446Strhodes mpctx->name[0] = 0; 1619135446Strhodes#endif 1620135446Strhodes mpctx->items = NULL; 1621135446Strhodes 1622135446Strhodes *mpctxp = mpctx; 1623135446Strhodes 1624170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1625135446Strhodes ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link); 1626193149Sdougb mctx->poolcnt++; 1627170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1628135446Strhodes 1629135446Strhodes return (ISC_R_SUCCESS); 1630135446Strhodes} 1631135446Strhodes 1632135446Strhodesvoid 1633135446Strhodesisc_mempool_setname(isc_mempool_t *mpctx, const char *name) { 1634135446Strhodes REQUIRE(name != NULL); 1635135446Strhodes 1636135446Strhodes#if ISC_MEMPOOL_NAMES 1637135446Strhodes if (mpctx->lock != NULL) 1638135446Strhodes LOCK(mpctx->lock); 1639135446Strhodes 1640135446Strhodes strncpy(mpctx->name, name, sizeof(mpctx->name) - 1); 1641135446Strhodes mpctx->name[sizeof(mpctx->name) - 1] = '\0'; 1642135446Strhodes 1643135446Strhodes if (mpctx->lock != NULL) 1644135446Strhodes UNLOCK(mpctx->lock); 1645135446Strhodes#else 1646135446Strhodes UNUSED(mpctx); 1647135446Strhodes UNUSED(name); 1648135446Strhodes#endif 1649135446Strhodes} 1650135446Strhodes 1651135446Strhodesvoid 1652135446Strhodesisc_mempool_destroy(isc_mempool_t **mpctxp) { 1653135446Strhodes isc_mempool_t *mpctx; 1654135446Strhodes isc_mem_t *mctx; 1655135446Strhodes isc_mutex_t *lock; 1656135446Strhodes element *item; 1657135446Strhodes 1658135446Strhodes REQUIRE(mpctxp != NULL); 1659135446Strhodes mpctx = *mpctxp; 1660135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1661135446Strhodes#if ISC_MEMPOOL_NAMES 1662135446Strhodes if (mpctx->allocated > 0) 1663135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 1664135446Strhodes "isc_mempool_destroy(): mempool %s " 1665135446Strhodes "leaked memory", 1666135446Strhodes mpctx->name); 1667135446Strhodes#endif 1668135446Strhodes REQUIRE(mpctx->allocated == 0); 1669135446Strhodes 1670135446Strhodes mctx = mpctx->mctx; 1671135446Strhodes 1672135446Strhodes lock = mpctx->lock; 1673135446Strhodes 1674135446Strhodes if (lock != NULL) 1675135446Strhodes LOCK(lock); 1676135446Strhodes 1677135446Strhodes /* 1678135446Strhodes * Return any items on the free list 1679135446Strhodes */ 1680170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1681135446Strhodes while (mpctx->items != NULL) { 1682135446Strhodes INSIST(mpctx->freecount > 0); 1683135446Strhodes mpctx->freecount--; 1684135446Strhodes item = mpctx->items; 1685135446Strhodes mpctx->items = item->next; 1686135446Strhodes 1687170222Sdougb if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1688170222Sdougb mem_putunlocked(mctx, item, mpctx->size); 1689170222Sdougb } else { 1690170222Sdougb mem_put(mctx, item, mpctx->size); 1691170222Sdougb mem_putstats(mctx, item, mpctx->size); 1692170222Sdougb } 1693135446Strhodes } 1694170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1695135446Strhodes 1696135446Strhodes /* 1697135446Strhodes * Remove our linked list entry from the memory context. 1698135446Strhodes */ 1699170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1700135446Strhodes ISC_LIST_UNLINK(mctx->pools, mpctx, link); 1701193149Sdougb mctx->poolcnt--; 1702170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1703135446Strhodes 1704135446Strhodes mpctx->magic = 0; 1705135446Strhodes 1706135446Strhodes isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t)); 1707135446Strhodes 1708135446Strhodes if (lock != NULL) 1709135446Strhodes UNLOCK(lock); 1710135446Strhodes 1711135446Strhodes *mpctxp = NULL; 1712135446Strhodes} 1713135446Strhodes 1714135446Strhodesvoid 1715135446Strhodesisc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) { 1716135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1717135446Strhodes REQUIRE(mpctx->lock == NULL); 1718135446Strhodes REQUIRE(lock != NULL); 1719135446Strhodes 1720135446Strhodes mpctx->lock = lock; 1721135446Strhodes} 1722135446Strhodes 1723135446Strhodesvoid * 1724135446Strhodesisc__mempool_get(isc_mempool_t *mpctx FLARG) { 1725135446Strhodes element *item; 1726135446Strhodes isc_mem_t *mctx; 1727135446Strhodes unsigned int i; 1728135446Strhodes 1729135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1730135446Strhodes 1731135446Strhodes mctx = mpctx->mctx; 1732135446Strhodes 1733135446Strhodes if (mpctx->lock != NULL) 1734135446Strhodes LOCK(mpctx->lock); 1735135446Strhodes 1736135446Strhodes /* 1737135446Strhodes * Don't let the caller go over quota 1738135446Strhodes */ 1739135446Strhodes if (mpctx->allocated >= mpctx->maxalloc) { 1740135446Strhodes item = NULL; 1741135446Strhodes goto out; 1742135446Strhodes } 1743135446Strhodes 1744135446Strhodes /* 1745135446Strhodes * if we have a free list item, return the first here 1746135446Strhodes */ 1747135446Strhodes item = mpctx->items; 1748135446Strhodes if (item != NULL) { 1749135446Strhodes mpctx->items = item->next; 1750135446Strhodes INSIST(mpctx->freecount > 0); 1751135446Strhodes mpctx->freecount--; 1752135446Strhodes mpctx->gets++; 1753135446Strhodes mpctx->allocated++; 1754135446Strhodes goto out; 1755135446Strhodes } 1756135446Strhodes 1757135446Strhodes /* 1758135446Strhodes * We need to dip into the well. Lock the memory context here and 1759135446Strhodes * fill up our free list. 1760135446Strhodes */ 1761170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1762135446Strhodes for (i = 0; i < mpctx->fillcount; i++) { 1763170222Sdougb if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1764170222Sdougb item = mem_getunlocked(mctx, mpctx->size); 1765170222Sdougb } else { 1766170222Sdougb item = mem_get(mctx, mpctx->size); 1767170222Sdougb if (item != NULL) 1768170222Sdougb mem_getstats(mctx, mpctx->size); 1769170222Sdougb } 1770135446Strhodes if (item == NULL) 1771135446Strhodes break; 1772135446Strhodes item->next = mpctx->items; 1773135446Strhodes mpctx->items = item; 1774135446Strhodes mpctx->freecount++; 1775135446Strhodes } 1776170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1777135446Strhodes 1778135446Strhodes /* 1779135446Strhodes * If we didn't get any items, return NULL. 1780135446Strhodes */ 1781135446Strhodes item = mpctx->items; 1782135446Strhodes if (item == NULL) 1783135446Strhodes goto out; 1784135446Strhodes 1785135446Strhodes mpctx->items = item->next; 1786135446Strhodes mpctx->freecount--; 1787135446Strhodes mpctx->gets++; 1788135446Strhodes mpctx->allocated++; 1789135446Strhodes 1790135446Strhodes out: 1791135446Strhodes if (mpctx->lock != NULL) 1792135446Strhodes UNLOCK(mpctx->lock); 1793135446Strhodes 1794135446Strhodes#if ISC_MEM_TRACKLINES 1795135446Strhodes if (item != NULL) { 1796170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1797135446Strhodes ADD_TRACE(mctx, item, mpctx->size, file, line); 1798170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1799135446Strhodes } 1800135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 1801135446Strhodes 1802135446Strhodes return (item); 1803135446Strhodes} 1804135446Strhodes 1805135446Strhodesvoid 1806135446Strhodesisc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) { 1807135446Strhodes isc_mem_t *mctx; 1808135446Strhodes element *item; 1809135446Strhodes 1810135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1811135446Strhodes REQUIRE(mem != NULL); 1812135446Strhodes 1813135446Strhodes mctx = mpctx->mctx; 1814135446Strhodes 1815135446Strhodes if (mpctx->lock != NULL) 1816135446Strhodes LOCK(mpctx->lock); 1817135446Strhodes 1818135446Strhodes INSIST(mpctx->allocated > 0); 1819135446Strhodes mpctx->allocated--; 1820135446Strhodes 1821135446Strhodes#if ISC_MEM_TRACKLINES 1822170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1823135446Strhodes DELETE_TRACE(mctx, mem, mpctx->size, file, line); 1824170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1825135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 1826135446Strhodes 1827135446Strhodes /* 1828135446Strhodes * If our free list is full, return this to the mctx directly. 1829135446Strhodes */ 1830135446Strhodes if (mpctx->freecount >= mpctx->freemax) { 1831170222Sdougb if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1832170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1833170222Sdougb mem_putunlocked(mctx, mem, mpctx->size); 1834170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1835170222Sdougb } else { 1836170222Sdougb mem_put(mctx, mem, mpctx->size); 1837170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1838170222Sdougb mem_putstats(mctx, mem, mpctx->size); 1839170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1840170222Sdougb } 1841135446Strhodes if (mpctx->lock != NULL) 1842135446Strhodes UNLOCK(mpctx->lock); 1843135446Strhodes return; 1844135446Strhodes } 1845135446Strhodes 1846135446Strhodes /* 1847135446Strhodes * Otherwise, attach it to our free list and bump the counter. 1848135446Strhodes */ 1849135446Strhodes mpctx->freecount++; 1850135446Strhodes item = (element *)mem; 1851135446Strhodes item->next = mpctx->items; 1852135446Strhodes mpctx->items = item; 1853135446Strhodes 1854135446Strhodes if (mpctx->lock != NULL) 1855135446Strhodes UNLOCK(mpctx->lock); 1856135446Strhodes} 1857135446Strhodes 1858135446Strhodes/* 1859135446Strhodes * Quotas 1860135446Strhodes */ 1861135446Strhodes 1862135446Strhodesvoid 1863135446Strhodesisc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) { 1864135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1865135446Strhodes 1866135446Strhodes if (mpctx->lock != NULL) 1867135446Strhodes LOCK(mpctx->lock); 1868135446Strhodes 1869135446Strhodes mpctx->freemax = limit; 1870135446Strhodes 1871135446Strhodes if (mpctx->lock != NULL) 1872135446Strhodes UNLOCK(mpctx->lock); 1873135446Strhodes} 1874135446Strhodes 1875135446Strhodesunsigned int 1876135446Strhodesisc_mempool_getfreemax(isc_mempool_t *mpctx) { 1877135446Strhodes unsigned int freemax; 1878135446Strhodes 1879135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1880135446Strhodes 1881135446Strhodes if (mpctx->lock != NULL) 1882135446Strhodes LOCK(mpctx->lock); 1883135446Strhodes 1884135446Strhodes freemax = mpctx->freemax; 1885135446Strhodes 1886135446Strhodes if (mpctx->lock != NULL) 1887135446Strhodes UNLOCK(mpctx->lock); 1888135446Strhodes 1889135446Strhodes return (freemax); 1890135446Strhodes} 1891135446Strhodes 1892135446Strhodesunsigned int 1893135446Strhodesisc_mempool_getfreecount(isc_mempool_t *mpctx) { 1894135446Strhodes unsigned int freecount; 1895135446Strhodes 1896135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1897135446Strhodes 1898135446Strhodes if (mpctx->lock != NULL) 1899135446Strhodes LOCK(mpctx->lock); 1900135446Strhodes 1901135446Strhodes freecount = mpctx->freecount; 1902135446Strhodes 1903135446Strhodes if (mpctx->lock != NULL) 1904135446Strhodes UNLOCK(mpctx->lock); 1905135446Strhodes 1906135446Strhodes return (freecount); 1907135446Strhodes} 1908135446Strhodes 1909135446Strhodesvoid 1910135446Strhodesisc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) { 1911135446Strhodes REQUIRE(limit > 0); 1912135446Strhodes 1913135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1914135446Strhodes 1915135446Strhodes if (mpctx->lock != NULL) 1916135446Strhodes LOCK(mpctx->lock); 1917135446Strhodes 1918135446Strhodes mpctx->maxalloc = limit; 1919135446Strhodes 1920135446Strhodes if (mpctx->lock != NULL) 1921135446Strhodes UNLOCK(mpctx->lock); 1922135446Strhodes} 1923135446Strhodes 1924135446Strhodesunsigned int 1925135446Strhodesisc_mempool_getmaxalloc(isc_mempool_t *mpctx) { 1926135446Strhodes unsigned int maxalloc; 1927135446Strhodes 1928135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1929135446Strhodes 1930135446Strhodes if (mpctx->lock != NULL) 1931135446Strhodes LOCK(mpctx->lock); 1932135446Strhodes 1933135446Strhodes maxalloc = mpctx->maxalloc; 1934135446Strhodes 1935135446Strhodes if (mpctx->lock != NULL) 1936135446Strhodes UNLOCK(mpctx->lock); 1937135446Strhodes 1938135446Strhodes return (maxalloc); 1939135446Strhodes} 1940135446Strhodes 1941135446Strhodesunsigned int 1942135446Strhodesisc_mempool_getallocated(isc_mempool_t *mpctx) { 1943135446Strhodes unsigned int allocated; 1944135446Strhodes 1945135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1946135446Strhodes 1947135446Strhodes if (mpctx->lock != NULL) 1948135446Strhodes LOCK(mpctx->lock); 1949135446Strhodes 1950135446Strhodes allocated = mpctx->allocated; 1951135446Strhodes 1952135446Strhodes if (mpctx->lock != NULL) 1953135446Strhodes UNLOCK(mpctx->lock); 1954135446Strhodes 1955135446Strhodes return (allocated); 1956135446Strhodes} 1957135446Strhodes 1958135446Strhodesvoid 1959135446Strhodesisc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) { 1960135446Strhodes REQUIRE(limit > 0); 1961135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1962135446Strhodes 1963135446Strhodes if (mpctx->lock != NULL) 1964135446Strhodes LOCK(mpctx->lock); 1965135446Strhodes 1966135446Strhodes mpctx->fillcount = limit; 1967135446Strhodes 1968135446Strhodes if (mpctx->lock != NULL) 1969135446Strhodes UNLOCK(mpctx->lock); 1970135446Strhodes} 1971135446Strhodes 1972135446Strhodesunsigned int 1973135446Strhodesisc_mempool_getfillcount(isc_mempool_t *mpctx) { 1974135446Strhodes unsigned int fillcount; 1975135446Strhodes 1976135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1977135446Strhodes 1978135446Strhodes if (mpctx->lock != NULL) 1979135446Strhodes LOCK(mpctx->lock); 1980135446Strhodes 1981135446Strhodes fillcount = mpctx->fillcount; 1982135446Strhodes 1983135446Strhodes if (mpctx->lock != NULL) 1984135446Strhodes UNLOCK(mpctx->lock); 1985135446Strhodes 1986135446Strhodes return (fillcount); 1987135446Strhodes} 1988170222Sdougb 1989170222Sdougbvoid 1990170222Sdougbisc_mem_printactive(isc_mem_t *ctx, FILE *file) { 1991170222Sdougb 1992170222Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1993170222Sdougb REQUIRE(file != NULL); 1994170222Sdougb 1995170222Sdougb#if !ISC_MEM_TRACKLINES 1996170222Sdougb UNUSED(ctx); 1997170222Sdougb UNUSED(file); 1998170222Sdougb#else 1999170222Sdougb print_active(ctx, file); 2000170222Sdougb#endif 2001170222Sdougb} 2002170222Sdougb 2003170222Sdougbvoid 2004170222Sdougbisc_mem_printallactive(FILE *file) { 2005170222Sdougb#if !ISC_MEM_TRACKLINES 2006170222Sdougb UNUSED(file); 2007170222Sdougb#else 2008170222Sdougb isc_mem_t *ctx; 2009170222Sdougb 2010170222Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2011170222Sdougb 2012170222Sdougb LOCK(&lock); 2013170222Sdougb for (ctx = ISC_LIST_HEAD(contexts); 2014170222Sdougb ctx != NULL; 2015170222Sdougb ctx = ISC_LIST_NEXT(ctx, link)) { 2016170222Sdougb fprintf(file, "context: %p\n", ctx); 2017170222Sdougb print_active(ctx, file); 2018170222Sdougb } 2019170222Sdougb UNLOCK(&lock); 2020170222Sdougb#endif 2021170222Sdougb} 2022170222Sdougb 2023186462Sdougbvoid 2024170222Sdougbisc_mem_checkdestroyed(FILE *file) { 2025170222Sdougb 2026170222Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2027170222Sdougb 2028170222Sdougb LOCK(&lock); 2029170222Sdougb if (!ISC_LIST_EMPTY(contexts)) { 2030170222Sdougb#if ISC_MEM_TRACKLINES 2031170222Sdougb isc_mem_t *ctx; 2032170222Sdougb 2033170222Sdougb for (ctx = ISC_LIST_HEAD(contexts); 2034170222Sdougb ctx != NULL; 2035170222Sdougb ctx = ISC_LIST_NEXT(ctx, link)) { 2036170222Sdougb fprintf(file, "context: %p\n", ctx); 2037170222Sdougb print_active(ctx, file); 2038170222Sdougb } 2039170222Sdougb fflush(file); 2040170222Sdougb#endif 2041174187Sdougb INSIST(0); 2042170222Sdougb } 2043170222Sdougb UNLOCK(&lock); 2044170222Sdougb} 2045193149Sdougb 2046193149Sdougbunsigned int 2047193149Sdougbisc_mem_references(isc_mem_t *ctx) { 2048193149Sdougb unsigned int references; 2049193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 2050193149Sdougb 2051193149Sdougb MCTXLOCK(ctx, &ctx->lock); 2052193149Sdougb references = ctx->references; 2053193149Sdougb MCTXUNLOCK(ctx, &ctx->lock); 2054193149Sdougb 2055193149Sdougb return (references); 2056193149Sdougb} 2057193149Sdougb 2058193149Sdougb#ifdef HAVE_LIBXML2 2059193149Sdougb 2060193149Sdougbtypedef struct summarystat { 2061193149Sdougb isc_uint64_t total; 2062193149Sdougb isc_uint64_t inuse; 2063193149Sdougb isc_uint64_t blocksize; 2064193149Sdougb isc_uint64_t contextsize; 2065193149Sdougb} summarystat_t; 2066193149Sdougb 2067193149Sdougbstatic void 2068193149Sdougbrenderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) { 2069193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 2070193149Sdougb 2071193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"); 2072193149Sdougb 2073193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"); 2074193149Sdougb xmlTextWriterWriteFormatString(writer, "%p", ctx); 2075193149Sdougb xmlTextWriterEndElement(writer); /* id */ 2076193149Sdougb 2077193149Sdougb if (ctx->name[0] != 0) { 2078193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); 2079193149Sdougb xmlTextWriterWriteFormatString(writer, "%s", ctx->name); 2080193149Sdougb xmlTextWriterEndElement(writer); /* name */ 2081193149Sdougb } 2082193149Sdougb 2083193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 2084193149Sdougb MCTXLOCK(ctx, &ctx->lock); 2085193149Sdougb 2086193149Sdougb summary->contextsize += sizeof(*ctx) + 2087193149Sdougb (ctx->max_size + 1) * sizeof(struct stats) + 2088193149Sdougb ctx->max_size * sizeof(element *) + 2089193149Sdougb ctx->basic_table_count * sizeof(char *); 2090193149Sdougb#if ISC_MEM_TRACKLINES 2091193149Sdougb if (ctx->debuglist != NULL) { 2092193149Sdougb summary->contextsize += 2093193149Sdougb (ctx->max_size + 1) * sizeof(debuglist_t) + 2094193149Sdougb ctx->debuglistcnt * sizeof(debuglink_t); 2095193149Sdougb } 2096193149Sdougb#endif 2097193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); 2098193149Sdougb xmlTextWriterWriteFormatString(writer, "%d", ctx->references); 2099193149Sdougb xmlTextWriterEndElement(writer); /* references */ 2100193149Sdougb 2101193149Sdougb summary->total += ctx->total; 2102193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"); 2103193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2104193149Sdougb (isc_uint64_t)ctx->total); 2105193149Sdougb xmlTextWriterEndElement(writer); /* total */ 2106193149Sdougb 2107193149Sdougb summary->inuse += ctx->inuse; 2108193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"); 2109193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2110193149Sdougb (isc_uint64_t)ctx->inuse); 2111193149Sdougb xmlTextWriterEndElement(writer); /* inuse */ 2112193149Sdougb 2113193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"); 2114193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2115193149Sdougb (isc_uint64_t)ctx->maxinuse); 2116193149Sdougb xmlTextWriterEndElement(writer); /* maxinuse */ 2117193149Sdougb 2118193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"); 2119193149Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2120193149Sdougb summary->blocksize += ctx->basic_table_count * 2121193149Sdougb NUM_BASIC_BLOCKS * ctx->mem_target; 2122193149Sdougb xmlTextWriterWriteFormatString(writer, 2123193149Sdougb "%" ISC_PRINT_QUADFORMAT "u", 2124193149Sdougb (isc_uint64_t) 2125193149Sdougb ctx->basic_table_count * 2126193149Sdougb NUM_BASIC_BLOCKS * 2127193149Sdougb ctx->mem_target); 2128193149Sdougb } else 2129193149Sdougb xmlTextWriterWriteFormatString(writer, "%s", "-"); 2130193149Sdougb xmlTextWriterEndElement(writer); /* blocksize */ 2131193149Sdougb 2132193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"); 2133193149Sdougb xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt); 2134193149Sdougb xmlTextWriterEndElement(writer); /* pools */ 2135193149Sdougb summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t); 2136193149Sdougb 2137193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"); 2138193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2139193149Sdougb (isc_uint64_t)ctx->hi_water); 2140193149Sdougb xmlTextWriterEndElement(writer); /* hiwater */ 2141193149Sdougb 2142193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"); 2143193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2144193149Sdougb (isc_uint64_t)ctx->lo_water); 2145193149Sdougb xmlTextWriterEndElement(writer); /* lowater */ 2146193149Sdougb 2147193149Sdougb MCTXUNLOCK(ctx, &ctx->lock); 2148193149Sdougb 2149193149Sdougb xmlTextWriterEndElement(writer); /* context */ 2150193149Sdougb} 2151193149Sdougb 2152193149Sdougbvoid 2153193149Sdougbisc_mem_renderxml(xmlTextWriterPtr writer) { 2154193149Sdougb isc_mem_t *ctx; 2155193149Sdougb summarystat_t summary; 2156193149Sdougb isc_uint64_t lost; 2157193149Sdougb 2158193149Sdougb memset(&summary, 0, sizeof(summary)); 2159193149Sdougb 2160193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"); 2161193149Sdougb 2162193149Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2163193149Sdougb 2164193149Sdougb LOCK(&lock); 2165193149Sdougb lost = totallost; 2166193149Sdougb for (ctx = ISC_LIST_HEAD(contexts); 2167193149Sdougb ctx != NULL; 2168193149Sdougb ctx = ISC_LIST_NEXT(ctx, link)) { 2169193149Sdougb renderctx(ctx, &summary, writer); 2170193149Sdougb } 2171193149Sdougb UNLOCK(&lock); 2172193149Sdougb 2173193149Sdougb xmlTextWriterEndElement(writer); /* contexts */ 2174193149Sdougb 2175193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"); 2176193149Sdougb 2177193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"); 2178193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2179193149Sdougb summary.total); 2180193149Sdougb xmlTextWriterEndElement(writer); /* TotalUse */ 2181193149Sdougb 2182193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"); 2183193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2184193149Sdougb summary.inuse); 2185193149Sdougb xmlTextWriterEndElement(writer); /* InUse */ 2186193149Sdougb 2187193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"); 2188193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2189193149Sdougb summary.blocksize); 2190193149Sdougb xmlTextWriterEndElement(writer); /* BlockSize */ 2191193149Sdougb 2192193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"); 2193193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2194193149Sdougb summary.contextsize); 2195193149Sdougb xmlTextWriterEndElement(writer); /* ContextSize */ 2196193149Sdougb 2197193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"); 2198193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2199193149Sdougb lost); 2200193149Sdougb xmlTextWriterEndElement(writer); /* Lost */ 2201193149Sdougb 2202193149Sdougb xmlTextWriterEndElement(writer); /* summary */ 2203193149Sdougb} 2204193149Sdougb 2205193149Sdougb#endif /* HAVE_LIBXML2 */ 2206