mem.c revision 218384
1135446Strhodes/* 2214586Sdougb * Copyright (C) 2004-2010 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 18218384Sdougb/* $Id: mem.c,v 1.145.120.9 2010-08-11 23:45:49 tbox 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 75218384Sdougb#define FLARG , const char *file, unsigned 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; 144214586Sdougb isc_boolean_t is_overmem; 145135446Strhodes isc_mem_water_t water; 146135446Strhodes void * water_arg; 147135446Strhodes ISC_LIST(isc_mempool_t) pools; 148193149Sdougb unsigned int poolcnt; 149135446Strhodes 150170222Sdougb /* ISC_MEMFLAG_INTERNAL */ 151135446Strhodes size_t mem_target; 152135446Strhodes element ** freelists; 153135446Strhodes element * basic_blocks; 154135446Strhodes unsigned char ** basic_table; 155135446Strhodes unsigned int basic_table_count; 156135446Strhodes unsigned int basic_table_size; 157135446Strhodes unsigned char * lowest; 158135446Strhodes unsigned char * highest; 159135446Strhodes 160135446Strhodes#if ISC_MEM_TRACKLINES 161135446Strhodes debuglist_t * debuglist; 162193149Sdougb unsigned int debuglistcnt; 163135446Strhodes#endif 164135446Strhodes 165135446Strhodes unsigned int memalloc_failures; 166170222Sdougb ISC_LINK(isc_mem_t) link; 167135446Strhodes}; 168135446Strhodes 169135446Strhodes#define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p') 170135446Strhodes#define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC) 171135446Strhodes 172135446Strhodesstruct isc_mempool { 173135446Strhodes /* always unlocked */ 174170222Sdougb unsigned int magic; /*%< magic number */ 175170222Sdougb isc_mutex_t *lock; /*%< optional lock */ 176170222Sdougb isc_mem_t *mctx; /*%< our memory context */ 177170222Sdougb /*%< locked via the memory context's lock */ 178170222Sdougb ISC_LINK(isc_mempool_t) link; /*%< next pool in this mem context */ 179170222Sdougb /*%< optionally locked from here down */ 180170222Sdougb element *items; /*%< low water item list */ 181170222Sdougb size_t size; /*%< size of each item on this pool */ 182170222Sdougb unsigned int maxalloc; /*%< max number of items allowed */ 183170222Sdougb unsigned int allocated; /*%< # of items currently given out */ 184170222Sdougb unsigned int freecount; /*%< # of items on reserved list */ 185170222Sdougb unsigned int freemax; /*%< # of items allowed on free list */ 186170222Sdougb unsigned int fillcount; /*%< # of items to fetch on each fill */ 187170222Sdougb /*%< Stats only. */ 188170222Sdougb unsigned int gets; /*%< # of requests to this pool */ 189170222Sdougb /*%< Debugging only. */ 190135446Strhodes#if ISC_MEMPOOL_NAMES 191170222Sdougb char name[16]; /*%< printed name in stats reports */ 192135446Strhodes#endif 193135446Strhodes}; 194135446Strhodes 195135446Strhodes/* 196135446Strhodes * Private Inline-able. 197135446Strhodes */ 198135446Strhodes 199135446Strhodes#if ! ISC_MEM_TRACKLINES 200135446Strhodes#define ADD_TRACE(a, b, c, d, e) 201135446Strhodes#define DELETE_TRACE(a, b, c, d, e) 202135446Strhodes#else 203135446Strhodes#define ADD_TRACE(a, b, c, d, e) \ 204135446Strhodes do { \ 205135446Strhodes if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \ 206135446Strhodes ISC_MEM_DEBUGRECORD)) != 0 && \ 207135446Strhodes b != NULL) \ 208186462Sdougb add_trace_entry(a, b, c, d, e); \ 209135446Strhodes } while (0) 210135446Strhodes#define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e) 211135446Strhodes 212135446Strhodesstatic void 213135446Strhodesprint_active(isc_mem_t *ctx, FILE *out); 214135446Strhodes 215170222Sdougb/*! 216135446Strhodes * mctx must be locked. 217135446Strhodes */ 218135446Strhodesstatic inline void 219135446Strhodesadd_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size 220135446Strhodes FLARG) 221135446Strhodes{ 222135446Strhodes debuglink_t *dl; 223135446Strhodes unsigned int i; 224218384Sdougb unsigned int mysize = size; 225135446Strhodes 226135446Strhodes if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) 227135446Strhodes fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 228135446Strhodes ISC_MSG_ADDTRACE, 229135446Strhodes "add %p size %u " 230135446Strhodes "file %s line %u mctx %p\n"), 231135446Strhodes ptr, size, file, line, mctx); 232135446Strhodes 233135446Strhodes if (mctx->debuglist == NULL) 234135446Strhodes return; 235135446Strhodes 236218384Sdougb if (mysize > mctx->max_size) 237218384Sdougb mysize = mctx->max_size; 238135446Strhodes 239218384Sdougb dl = ISC_LIST_HEAD(mctx->debuglist[mysize]); 240135446Strhodes while (dl != NULL) { 241135446Strhodes if (dl->count == DEBUGLIST_COUNT) 242135446Strhodes goto next; 243135446Strhodes for (i = 0; i < DEBUGLIST_COUNT; i++) { 244135446Strhodes if (dl->ptr[i] == NULL) { 245135446Strhodes dl->ptr[i] = ptr; 246135446Strhodes dl->size[i] = size; 247135446Strhodes dl->file[i] = file; 248135446Strhodes dl->line[i] = line; 249135446Strhodes dl->count++; 250135446Strhodes return; 251135446Strhodes } 252135446Strhodes } 253135446Strhodes next: 254135446Strhodes dl = ISC_LIST_NEXT(dl, link); 255135446Strhodes } 256135446Strhodes 257135446Strhodes dl = malloc(sizeof(debuglink_t)); 258135446Strhodes INSIST(dl != NULL); 259135446Strhodes 260135446Strhodes ISC_LINK_INIT(dl, link); 261135446Strhodes for (i = 1; i < DEBUGLIST_COUNT; i++) { 262135446Strhodes dl->ptr[i] = NULL; 263135446Strhodes dl->size[i] = 0; 264135446Strhodes dl->file[i] = NULL; 265135446Strhodes dl->line[i] = 0; 266135446Strhodes } 267135446Strhodes 268135446Strhodes dl->ptr[0] = ptr; 269135446Strhodes dl->size[0] = size; 270135446Strhodes dl->file[0] = file; 271135446Strhodes dl->line[0] = line; 272135446Strhodes dl->count = 1; 273135446Strhodes 274218384Sdougb ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link); 275193149Sdougb mctx->debuglistcnt++; 276135446Strhodes} 277135446Strhodes 278135446Strhodesstatic inline void 279135446Strhodesdelete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size, 280135446Strhodes const char *file, unsigned int line) 281135446Strhodes{ 282135446Strhodes debuglink_t *dl; 283135446Strhodes unsigned int i; 284135446Strhodes 285135446Strhodes if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) 286135446Strhodes fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 287135446Strhodes ISC_MSG_DELTRACE, 288135446Strhodes "del %p size %u " 289135446Strhodes "file %s line %u mctx %p\n"), 290135446Strhodes ptr, size, file, line, mctx); 291135446Strhodes 292135446Strhodes if (mctx->debuglist == NULL) 293135446Strhodes return; 294135446Strhodes 295135446Strhodes if (size > mctx->max_size) 296135446Strhodes size = mctx->max_size; 297135446Strhodes 298135446Strhodes dl = ISC_LIST_HEAD(mctx->debuglist[size]); 299135446Strhodes while (dl != NULL) { 300135446Strhodes for (i = 0; i < DEBUGLIST_COUNT; i++) { 301135446Strhodes if (dl->ptr[i] == ptr) { 302135446Strhodes dl->ptr[i] = NULL; 303135446Strhodes dl->size[i] = 0; 304135446Strhodes dl->file[i] = NULL; 305135446Strhodes dl->line[i] = 0; 306135446Strhodes 307135446Strhodes INSIST(dl->count > 0); 308135446Strhodes dl->count--; 309135446Strhodes if (dl->count == 0) { 310135446Strhodes ISC_LIST_UNLINK(mctx->debuglist[size], 311135446Strhodes dl, link); 312135446Strhodes free(dl); 313135446Strhodes } 314135446Strhodes return; 315135446Strhodes } 316135446Strhodes } 317135446Strhodes dl = ISC_LIST_NEXT(dl, link); 318135446Strhodes } 319135446Strhodes 320135446Strhodes /* 321135446Strhodes * If we get here, we didn't find the item on the list. We're 322135446Strhodes * screwed. 323135446Strhodes */ 324135446Strhodes INSIST(dl != NULL); 325135446Strhodes} 326135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 327135446Strhodes 328135446Strhodesstatic inline size_t 329135446Strhodesrmsize(size_t size) { 330135446Strhodes /* 331186462Sdougb * round down to ALIGNMENT_SIZE 332135446Strhodes */ 333135446Strhodes return (size & (~(ALIGNMENT_SIZE - 1))); 334135446Strhodes} 335135446Strhodes 336135446Strhodesstatic inline size_t 337135446Strhodesquantize(size_t size) { 338170222Sdougb /*! 339135446Strhodes * Round up the result in order to get a size big 340135446Strhodes * enough to satisfy the request and be aligned on ALIGNMENT_SIZE 341135446Strhodes * byte boundaries. 342135446Strhodes */ 343135446Strhodes 344170222Sdougb if (size == 0U) 345135446Strhodes return (ALIGNMENT_SIZE); 346135446Strhodes return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1))); 347135446Strhodes} 348135446Strhodes 349135446Strhodesstatic inline isc_boolean_t 350135446Strhodesmore_basic_blocks(isc_mem_t *ctx) { 351135446Strhodes void *new; 352135446Strhodes unsigned char *curr, *next; 353135446Strhodes unsigned char *first, *last; 354135446Strhodes unsigned char **table; 355135446Strhodes unsigned int table_size; 356135446Strhodes size_t increment; 357135446Strhodes int i; 358135446Strhodes 359135446Strhodes /* Require: we hold the context lock. */ 360135446Strhodes 361135446Strhodes /* 362135446Strhodes * Did we hit the quota for this context? 363135446Strhodes */ 364135446Strhodes increment = NUM_BASIC_BLOCKS * ctx->mem_target; 365170222Sdougb if (ctx->quota != 0U && ctx->total + increment > ctx->quota) 366135446Strhodes return (ISC_FALSE); 367135446Strhodes 368135446Strhodes INSIST(ctx->basic_table_count <= ctx->basic_table_size); 369135446Strhodes if (ctx->basic_table_count == ctx->basic_table_size) { 370135446Strhodes table_size = ctx->basic_table_size + TABLE_INCREMENT; 371135446Strhodes table = (ctx->memalloc)(ctx->arg, 372135446Strhodes table_size * sizeof(unsigned char *)); 373135446Strhodes if (table == NULL) { 374135446Strhodes ctx->memalloc_failures++; 375135446Strhodes return (ISC_FALSE); 376135446Strhodes } 377135446Strhodes if (ctx->basic_table_size != 0) { 378135446Strhodes memcpy(table, ctx->basic_table, 379135446Strhodes ctx->basic_table_size * 380135446Strhodes sizeof(unsigned char *)); 381135446Strhodes (ctx->memfree)(ctx->arg, ctx->basic_table); 382135446Strhodes } 383135446Strhodes ctx->basic_table = table; 384135446Strhodes ctx->basic_table_size = table_size; 385135446Strhodes } 386135446Strhodes 387135446Strhodes new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target); 388135446Strhodes if (new == NULL) { 389135446Strhodes ctx->memalloc_failures++; 390135446Strhodes return (ISC_FALSE); 391135446Strhodes } 392135446Strhodes ctx->total += increment; 393135446Strhodes ctx->basic_table[ctx->basic_table_count] = new; 394135446Strhodes ctx->basic_table_count++; 395135446Strhodes 396135446Strhodes curr = new; 397135446Strhodes next = curr + ctx->mem_target; 398135446Strhodes for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { 399135446Strhodes ((element *)curr)->next = (element *)next; 400135446Strhodes curr = next; 401135446Strhodes next += ctx->mem_target; 402135446Strhodes } 403135446Strhodes /* 404135446Strhodes * curr is now pointing at the last block in the 405135446Strhodes * array. 406135446Strhodes */ 407135446Strhodes ((element *)curr)->next = NULL; 408135446Strhodes first = new; 409135446Strhodes last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1; 410135446Strhodes if (first < ctx->lowest || ctx->lowest == NULL) 411135446Strhodes ctx->lowest = first; 412135446Strhodes if (last > ctx->highest) 413135446Strhodes ctx->highest = last; 414135446Strhodes ctx->basic_blocks = new; 415135446Strhodes 416135446Strhodes return (ISC_TRUE); 417135446Strhodes} 418135446Strhodes 419135446Strhodesstatic inline isc_boolean_t 420135446Strhodesmore_frags(isc_mem_t *ctx, size_t new_size) { 421135446Strhodes int i, frags; 422135446Strhodes size_t total_size; 423135446Strhodes void *new; 424135446Strhodes unsigned char *curr, *next; 425135446Strhodes 426170222Sdougb /*! 427135446Strhodes * Try to get more fragments by chopping up a basic block. 428135446Strhodes */ 429135446Strhodes 430135446Strhodes if (ctx->basic_blocks == NULL) { 431135446Strhodes if (!more_basic_blocks(ctx)) { 432135446Strhodes /* 433135446Strhodes * We can't get more memory from the OS, or we've 434135446Strhodes * hit the quota for this context. 435135446Strhodes */ 436135446Strhodes /* 437135446Strhodes * XXXRTH "At quota" notification here. 438135446Strhodes */ 439135446Strhodes return (ISC_FALSE); 440135446Strhodes } 441135446Strhodes } 442135446Strhodes 443135446Strhodes total_size = ctx->mem_target; 444135446Strhodes new = ctx->basic_blocks; 445135446Strhodes ctx->basic_blocks = ctx->basic_blocks->next; 446135446Strhodes frags = total_size / new_size; 447135446Strhodes ctx->stats[new_size].blocks++; 448135446Strhodes ctx->stats[new_size].freefrags += frags; 449135446Strhodes /* 450135446Strhodes * Set up a linked-list of blocks of size 451135446Strhodes * "new_size". 452135446Strhodes */ 453135446Strhodes curr = new; 454135446Strhodes next = curr + new_size; 455135446Strhodes total_size -= new_size; 456135446Strhodes for (i = 0; i < (frags - 1); i++) { 457135446Strhodes ((element *)curr)->next = (element *)next; 458135446Strhodes curr = next; 459135446Strhodes next += new_size; 460135446Strhodes total_size -= new_size; 461135446Strhodes } 462135446Strhodes /* 463135446Strhodes * Add the remaining fragment of the basic block to a free list. 464135446Strhodes */ 465135446Strhodes total_size = rmsize(total_size); 466170222Sdougb if (total_size > 0U) { 467135446Strhodes ((element *)next)->next = ctx->freelists[total_size]; 468135446Strhodes ctx->freelists[total_size] = (element *)next; 469135446Strhodes ctx->stats[total_size].freefrags++; 470135446Strhodes } 471135446Strhodes /* 472135446Strhodes * curr is now pointing at the last block in the 473135446Strhodes * array. 474135446Strhodes */ 475135446Strhodes ((element *)curr)->next = NULL; 476135446Strhodes ctx->freelists[new_size] = new; 477135446Strhodes 478135446Strhodes return (ISC_TRUE); 479135446Strhodes} 480135446Strhodes 481135446Strhodesstatic inline void * 482135446Strhodesmem_getunlocked(isc_mem_t *ctx, size_t size) { 483135446Strhodes size_t new_size = quantize(size); 484135446Strhodes void *ret; 485135446Strhodes 486135446Strhodes if (size >= ctx->max_size || new_size >= ctx->max_size) { 487135446Strhodes /* 488135446Strhodes * memget() was called on something beyond our upper limit. 489135446Strhodes */ 490170222Sdougb if (ctx->quota != 0U && ctx->total + size > ctx->quota) { 491135446Strhodes ret = NULL; 492135446Strhodes goto done; 493135446Strhodes } 494135446Strhodes ret = (ctx->memalloc)(ctx->arg, size); 495135446Strhodes if (ret == NULL) { 496135446Strhodes ctx->memalloc_failures++; 497135446Strhodes goto done; 498135446Strhodes } 499135446Strhodes ctx->total += size; 500135446Strhodes ctx->inuse += size; 501135446Strhodes ctx->stats[ctx->max_size].gets++; 502135446Strhodes ctx->stats[ctx->max_size].totalgets++; 503135446Strhodes /* 504135446Strhodes * If we don't set new_size to size, then the 505135446Strhodes * ISC_MEM_FILL code might write over bytes we 506135446Strhodes * don't own. 507135446Strhodes */ 508135446Strhodes new_size = size; 509135446Strhodes goto done; 510135446Strhodes } 511135446Strhodes 512135446Strhodes /* 513135446Strhodes * If there are no blocks in the free list for this size, get a chunk 514135446Strhodes * of memory and then break it up into "new_size"-sized blocks, adding 515135446Strhodes * them to the free list. 516135446Strhodes */ 517135446Strhodes if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size)) 518135446Strhodes return (NULL); 519135446Strhodes 520135446Strhodes /* 521135446Strhodes * The free list uses the "rounded-up" size "new_size". 522135446Strhodes */ 523135446Strhodes ret = ctx->freelists[new_size]; 524135446Strhodes ctx->freelists[new_size] = ctx->freelists[new_size]->next; 525135446Strhodes 526135446Strhodes /* 527135446Strhodes * The stats[] uses the _actual_ "size" requested by the 528135446Strhodes * caller, with the caveat (in the code above) that "size" >= the 529135446Strhodes * max. size (max_size) ends up getting recorded as a call to 530135446Strhodes * max_size. 531135446Strhodes */ 532135446Strhodes ctx->stats[size].gets++; 533135446Strhodes ctx->stats[size].totalgets++; 534135446Strhodes ctx->stats[new_size].freefrags--; 535135446Strhodes ctx->inuse += new_size; 536135446Strhodes 537135446Strhodes done: 538135446Strhodes 539135446Strhodes#if ISC_MEM_FILL 540135446Strhodes if (ret != NULL) 541135446Strhodes memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */ 542135446Strhodes#endif 543135446Strhodes 544135446Strhodes return (ret); 545135446Strhodes} 546135446Strhodes 547135446Strhodes#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN 548135446Strhodesstatic inline void 549135446Strhodescheck_overrun(void *mem, size_t size, size_t new_size) { 550135446Strhodes unsigned char *cp; 551135446Strhodes 552135446Strhodes cp = (unsigned char *)mem; 553135446Strhodes cp += size; 554135446Strhodes while (size < new_size) { 555135446Strhodes INSIST(*cp == 0xbe); 556135446Strhodes cp++; 557135446Strhodes size++; 558135446Strhodes } 559135446Strhodes} 560135446Strhodes#endif 561135446Strhodes 562135446Strhodesstatic inline void 563135446Strhodesmem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) { 564135446Strhodes size_t new_size = quantize(size); 565135446Strhodes 566135446Strhodes if (size == ctx->max_size || new_size >= ctx->max_size) { 567135446Strhodes /* 568135446Strhodes * memput() called on something beyond our upper limit. 569135446Strhodes */ 570135446Strhodes#if ISC_MEM_FILL 571135446Strhodes memset(mem, 0xde, size); /* Mnemonic for "dead". */ 572135446Strhodes#endif 573135446Strhodes (ctx->memfree)(ctx->arg, mem); 574170222Sdougb INSIST(ctx->stats[ctx->max_size].gets != 0U); 575135446Strhodes ctx->stats[ctx->max_size].gets--; 576135446Strhodes INSIST(size <= ctx->total); 577135446Strhodes ctx->inuse -= size; 578135446Strhodes ctx->total -= size; 579135446Strhodes return; 580135446Strhodes } 581135446Strhodes 582135446Strhodes#if ISC_MEM_FILL 583135446Strhodes#if ISC_MEM_CHECKOVERRUN 584135446Strhodes check_overrun(mem, size, new_size); 585135446Strhodes#endif 586135446Strhodes memset(mem, 0xde, new_size); /* Mnemonic for "dead". */ 587135446Strhodes#endif 588135446Strhodes 589135446Strhodes /* 590135446Strhodes * The free list uses the "rounded-up" size "new_size". 591135446Strhodes */ 592135446Strhodes ((element *)mem)->next = ctx->freelists[new_size]; 593135446Strhodes ctx->freelists[new_size] = (element *)mem; 594135446Strhodes 595135446Strhodes /* 596135446Strhodes * The stats[] uses the _actual_ "size" requested by the 597135446Strhodes * caller, with the caveat (in the code above) that "size" >= the 598135446Strhodes * max. size (max_size) ends up getting recorded as a call to 599135446Strhodes * max_size. 600135446Strhodes */ 601170222Sdougb INSIST(ctx->stats[size].gets != 0U); 602135446Strhodes ctx->stats[size].gets--; 603135446Strhodes ctx->stats[new_size].freefrags++; 604135446Strhodes ctx->inuse -= new_size; 605135446Strhodes} 606135446Strhodes 607170222Sdougb/*! 608135446Strhodes * Perform a malloc, doing memory filling and overrun detection as necessary. 609135446Strhodes */ 610135446Strhodesstatic inline void * 611135446Strhodesmem_get(isc_mem_t *ctx, size_t size) { 612135446Strhodes char *ret; 613135446Strhodes 614135446Strhodes#if ISC_MEM_CHECKOVERRUN 615135446Strhodes size += 1; 616135446Strhodes#endif 617135446Strhodes 618135446Strhodes ret = (ctx->memalloc)(ctx->arg, size); 619135446Strhodes if (ret == NULL) 620186462Sdougb ctx->memalloc_failures++; 621135446Strhodes 622135446Strhodes#if ISC_MEM_FILL 623135446Strhodes if (ret != NULL) 624135446Strhodes memset(ret, 0xbe, size); /* Mnemonic for "beef". */ 625135446Strhodes#else 626135446Strhodes# if ISC_MEM_CHECKOVERRUN 627135446Strhodes if (ret != NULL) 628135446Strhodes ret[size-1] = 0xbe; 629135446Strhodes# endif 630135446Strhodes#endif 631135446Strhodes 632135446Strhodes return (ret); 633135446Strhodes} 634135446Strhodes 635170222Sdougb/*! 636135446Strhodes * Perform a free, doing memory filling and overrun detection as necessary. 637135446Strhodes */ 638135446Strhodesstatic inline void 639135446Strhodesmem_put(isc_mem_t *ctx, void *mem, size_t size) { 640135446Strhodes#if ISC_MEM_CHECKOVERRUN 641135446Strhodes INSIST(((unsigned char *)mem)[size] == 0xbe); 642135446Strhodes#endif 643135446Strhodes#if ISC_MEM_FILL 644135446Strhodes memset(mem, 0xde, size); /* Mnemonic for "dead". */ 645135446Strhodes#else 646135446Strhodes UNUSED(size); 647135446Strhodes#endif 648135446Strhodes (ctx->memfree)(ctx->arg, mem); 649135446Strhodes} 650135446Strhodes 651170222Sdougb/*! 652135446Strhodes * Update internal counters after a memory get. 653135446Strhodes */ 654135446Strhodesstatic inline void 655135446Strhodesmem_getstats(isc_mem_t *ctx, size_t size) { 656135446Strhodes ctx->total += size; 657135446Strhodes ctx->inuse += size; 658135446Strhodes 659135446Strhodes if (size > ctx->max_size) { 660135446Strhodes ctx->stats[ctx->max_size].gets++; 661135446Strhodes ctx->stats[ctx->max_size].totalgets++; 662135446Strhodes } else { 663135446Strhodes ctx->stats[size].gets++; 664135446Strhodes ctx->stats[size].totalgets++; 665135446Strhodes } 666135446Strhodes} 667135446Strhodes 668170222Sdougb/*! 669135446Strhodes * Update internal counters after a memory put. 670135446Strhodes */ 671135446Strhodesstatic inline void 672135446Strhodesmem_putstats(isc_mem_t *ctx, void *ptr, size_t size) { 673135446Strhodes UNUSED(ptr); 674135446Strhodes 675135446Strhodes INSIST(ctx->inuse >= size); 676135446Strhodes ctx->inuse -= size; 677135446Strhodes 678135446Strhodes if (size > ctx->max_size) { 679135446Strhodes INSIST(ctx->stats[ctx->max_size].gets > 0U); 680135446Strhodes ctx->stats[ctx->max_size].gets--; 681135446Strhodes } else { 682135446Strhodes INSIST(ctx->stats[size].gets > 0U); 683135446Strhodes ctx->stats[size].gets--; 684135446Strhodes } 685135446Strhodes} 686135446Strhodes 687135446Strhodes/* 688135446Strhodes * Private. 689135446Strhodes */ 690135446Strhodes 691135446Strhodesstatic void * 692135446Strhodesdefault_memalloc(void *arg, size_t size) { 693135446Strhodes UNUSED(arg); 694135446Strhodes if (size == 0U) 695135446Strhodes size = 1; 696135446Strhodes return (malloc(size)); 697135446Strhodes} 698135446Strhodes 699135446Strhodesstatic void 700135446Strhodesdefault_memfree(void *arg, void *ptr) { 701135446Strhodes UNUSED(arg); 702135446Strhodes free(ptr); 703135446Strhodes} 704135446Strhodes 705170222Sdougbstatic void 706170222Sdougbinitialize_action(void) { 707174187Sdougb RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS); 708174187Sdougb ISC_LIST_INIT(contexts); 709193149Sdougb totallost = 0; 710170222Sdougb} 711170222Sdougb 712135446Strhodes/* 713135446Strhodes * Public. 714135446Strhodes */ 715135446Strhodes 716135446Strhodesisc_result_t 717135446Strhodesisc_mem_createx(size_t init_max_size, size_t target_size, 718135446Strhodes isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 719135446Strhodes isc_mem_t **ctxp) 720135446Strhodes{ 721170222Sdougb return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree, 722170222Sdougb arg, ctxp, ISC_MEMFLAG_DEFAULT)); 723186462Sdougb 724170222Sdougb} 725170222Sdougb 726170222Sdougbisc_result_t 727170222Sdougbisc_mem_createx2(size_t init_max_size, size_t target_size, 728170222Sdougb isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 729170222Sdougb isc_mem_t **ctxp, unsigned int flags) 730170222Sdougb{ 731135446Strhodes isc_mem_t *ctx; 732135446Strhodes isc_result_t result; 733135446Strhodes 734135446Strhodes REQUIRE(ctxp != NULL && *ctxp == NULL); 735135446Strhodes REQUIRE(memalloc != NULL); 736135446Strhodes REQUIRE(memfree != NULL); 737135446Strhodes 738135446Strhodes INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0); 739135446Strhodes 740170222Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 741135446Strhodes 742135446Strhodes ctx = (memalloc)(arg, sizeof(*ctx)); 743135446Strhodes if (ctx == NULL) 744135446Strhodes return (ISC_R_NOMEMORY); 745135446Strhodes 746170222Sdougb if ((flags & ISC_MEMFLAG_NOLOCK) == 0) { 747170222Sdougb result = isc_mutex_init(&ctx->lock); 748170222Sdougb if (result != ISC_R_SUCCESS) { 749170222Sdougb (memfree)(arg, ctx); 750170222Sdougb return (result); 751170222Sdougb } 752153816Sdougb } 753153816Sdougb 754135446Strhodes if (init_max_size == 0U) 755135446Strhodes ctx->max_size = DEF_MAX_SIZE; 756135446Strhodes else 757135446Strhodes ctx->max_size = init_max_size; 758170222Sdougb ctx->flags = flags; 759135446Strhodes ctx->references = 1; 760193149Sdougb memset(ctx->name, 0, sizeof(ctx->name)); 761193149Sdougb ctx->tag = NULL; 762135446Strhodes ctx->quota = 0; 763135446Strhodes ctx->total = 0; 764135446Strhodes ctx->inuse = 0; 765135446Strhodes ctx->maxinuse = 0; 766135446Strhodes ctx->hi_water = 0; 767135446Strhodes ctx->lo_water = 0; 768135446Strhodes ctx->hi_called = ISC_FALSE; 769214586Sdougb ctx->is_overmem = ISC_FALSE; 770135446Strhodes ctx->water = NULL; 771135446Strhodes ctx->water_arg = NULL; 772135446Strhodes ctx->magic = MEM_MAGIC; 773135446Strhodes isc_ondestroy_init(&ctx->ondestroy); 774135446Strhodes ctx->memalloc = memalloc; 775135446Strhodes ctx->memfree = memfree; 776135446Strhodes ctx->arg = arg; 777135446Strhodes ctx->stats = NULL; 778135446Strhodes ctx->checkfree = ISC_TRUE; 779135446Strhodes#if ISC_MEM_TRACKLINES 780135446Strhodes ctx->debuglist = NULL; 781193149Sdougb ctx->debuglistcnt = 0; 782135446Strhodes#endif 783135446Strhodes ISC_LIST_INIT(ctx->pools); 784193149Sdougb ctx->poolcnt = 0; 785135446Strhodes ctx->freelists = NULL; 786170222Sdougb ctx->basic_blocks = NULL; 787170222Sdougb ctx->basic_table = NULL; 788170222Sdougb ctx->basic_table_count = 0; 789170222Sdougb ctx->basic_table_size = 0; 790170222Sdougb ctx->lowest = NULL; 791170222Sdougb ctx->highest = NULL; 792135446Strhodes 793135446Strhodes ctx->stats = (memalloc)(arg, 794135446Strhodes (ctx->max_size+1) * sizeof(struct stats)); 795135446Strhodes if (ctx->stats == NULL) { 796135446Strhodes result = ISC_R_NOMEMORY; 797135446Strhodes goto error; 798135446Strhodes } 799135446Strhodes memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats)); 800135446Strhodes 801170222Sdougb if ((flags & ISC_MEMFLAG_INTERNAL) != 0) { 802170222Sdougb if (target_size == 0U) 803170222Sdougb ctx->mem_target = DEF_MEM_TARGET; 804170222Sdougb else 805170222Sdougb ctx->mem_target = target_size; 806170222Sdougb ctx->freelists = (memalloc)(arg, ctx->max_size * 807170222Sdougb sizeof(element *)); 808170222Sdougb if (ctx->freelists == NULL) { 809170222Sdougb result = ISC_R_NOMEMORY; 810170222Sdougb goto error; 811170222Sdougb } 812170222Sdougb memset(ctx->freelists, 0, 813170222Sdougb ctx->max_size * sizeof(element *)); 814135446Strhodes } 815135446Strhodes 816135446Strhodes#if ISC_MEM_TRACKLINES 817135446Strhodes if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) { 818135446Strhodes unsigned int i; 819135446Strhodes 820135446Strhodes ctx->debuglist = (memalloc)(arg, 821135446Strhodes (ctx->max_size+1) * sizeof(debuglist_t)); 822135446Strhodes if (ctx->debuglist == NULL) { 823135446Strhodes result = ISC_R_NOMEMORY; 824135446Strhodes goto error; 825135446Strhodes } 826135446Strhodes for (i = 0; i <= ctx->max_size; i++) 827135446Strhodes ISC_LIST_INIT(ctx->debuglist[i]); 828135446Strhodes } 829135446Strhodes#endif 830135446Strhodes 831135446Strhodes ctx->memalloc_failures = 0; 832135446Strhodes 833170222Sdougb LOCK(&lock); 834170222Sdougb ISC_LIST_INITANDAPPEND(contexts, ctx, link); 835170222Sdougb UNLOCK(&lock); 836170222Sdougb 837135446Strhodes *ctxp = ctx; 838135446Strhodes return (ISC_R_SUCCESS); 839135446Strhodes 840135446Strhodes error: 841153816Sdougb if (ctx != NULL) { 842153816Sdougb if (ctx->stats != NULL) 843135446Strhodes (memfree)(arg, ctx->stats); 844153816Sdougb if (ctx->freelists != NULL) 845135446Strhodes (memfree)(arg, ctx->freelists); 846135446Strhodes#if ISC_MEM_TRACKLINES 847153816Sdougb if (ctx->debuglist != NULL) 848135446Strhodes (ctx->memfree)(ctx->arg, ctx->debuglist); 849135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 850170222Sdougb if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 851170222Sdougb DESTROYLOCK(&ctx->lock); 852135446Strhodes (memfree)(arg, ctx); 853135446Strhodes } 854135446Strhodes 855135446Strhodes return (result); 856135446Strhodes} 857135446Strhodes 858135446Strhodesisc_result_t 859135446Strhodesisc_mem_create(size_t init_max_size, size_t target_size, 860135446Strhodes isc_mem_t **ctxp) 861135446Strhodes{ 862170222Sdougb return (isc_mem_createx2(init_max_size, target_size, 863170222Sdougb default_memalloc, default_memfree, NULL, 864170222Sdougb ctxp, ISC_MEMFLAG_DEFAULT)); 865135446Strhodes} 866135446Strhodes 867170222Sdougbisc_result_t 868170222Sdougbisc_mem_create2(size_t init_max_size, size_t target_size, 869170222Sdougb isc_mem_t **ctxp, unsigned int flags) 870170222Sdougb{ 871170222Sdougb return (isc_mem_createx2(init_max_size, target_size, 872170222Sdougb default_memalloc, default_memfree, NULL, 873170222Sdougb ctxp, flags)); 874170222Sdougb} 875170222Sdougb 876135446Strhodesstatic void 877135446Strhodesdestroy(isc_mem_t *ctx) { 878135446Strhodes unsigned int i; 879135446Strhodes isc_ondestroy_t ondest; 880135446Strhodes 881170222Sdougb LOCK(&lock); 882170222Sdougb ISC_LIST_UNLINK(contexts, ctx, link); 883193149Sdougb totallost += ctx->inuse; 884170222Sdougb UNLOCK(&lock); 885170222Sdougb 886218384Sdougb ctx->magic = 0; 887218384Sdougb 888135446Strhodes INSIST(ISC_LIST_EMPTY(ctx->pools)); 889135446Strhodes 890135446Strhodes#if ISC_MEM_TRACKLINES 891135446Strhodes if (ctx->debuglist != NULL) { 892135446Strhodes if (ctx->checkfree) { 893135446Strhodes for (i = 0; i <= ctx->max_size; i++) { 894135446Strhodes if (!ISC_LIST_EMPTY(ctx->debuglist[i])) 895135446Strhodes print_active(ctx, stderr); 896135446Strhodes INSIST(ISC_LIST_EMPTY(ctx->debuglist[i])); 897135446Strhodes } 898135446Strhodes } else { 899135446Strhodes debuglink_t *dl; 900135446Strhodes 901135446Strhodes for (i = 0; i <= ctx->max_size; i++) 902135446Strhodes for (dl = ISC_LIST_HEAD(ctx->debuglist[i]); 903135446Strhodes dl != NULL; 904135446Strhodes dl = ISC_LIST_HEAD(ctx->debuglist[i])) { 905135446Strhodes ISC_LIST_UNLINK(ctx->debuglist[i], 906186462Sdougb dl, link); 907135446Strhodes free(dl); 908135446Strhodes } 909135446Strhodes } 910135446Strhodes (ctx->memfree)(ctx->arg, ctx->debuglist); 911135446Strhodes } 912135446Strhodes#endif 913135446Strhodes INSIST(ctx->references == 0); 914135446Strhodes 915135446Strhodes if (ctx->checkfree) { 916135446Strhodes for (i = 0; i <= ctx->max_size; i++) { 917135446Strhodes#if ISC_MEM_TRACKLINES 918135446Strhodes if (ctx->stats[i].gets != 0U) 919135446Strhodes print_active(ctx, stderr); 920135446Strhodes#endif 921135446Strhodes INSIST(ctx->stats[i].gets == 0U); 922135446Strhodes } 923135446Strhodes } 924135446Strhodes 925135446Strhodes (ctx->memfree)(ctx->arg, ctx->stats); 926135446Strhodes 927170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 928170222Sdougb for (i = 0; i < ctx->basic_table_count; i++) 929170222Sdougb (ctx->memfree)(ctx->arg, ctx->basic_table[i]); 930170222Sdougb (ctx->memfree)(ctx->arg, ctx->freelists); 931186462Sdougb if (ctx->basic_table != NULL) 932186462Sdougb (ctx->memfree)(ctx->arg, ctx->basic_table); 933170222Sdougb } 934135446Strhodes 935135446Strhodes ondest = ctx->ondestroy; 936135446Strhodes 937170222Sdougb if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 938170222Sdougb DESTROYLOCK(&ctx->lock); 939135446Strhodes (ctx->memfree)(ctx->arg, ctx); 940135446Strhodes 941135446Strhodes isc_ondestroy_notify(&ondest, ctx); 942135446Strhodes} 943135446Strhodes 944135446Strhodesvoid 945135446Strhodesisc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) { 946135446Strhodes REQUIRE(VALID_CONTEXT(source)); 947135446Strhodes REQUIRE(targetp != NULL && *targetp == NULL); 948135446Strhodes 949170222Sdougb MCTXLOCK(source, &source->lock); 950135446Strhodes source->references++; 951170222Sdougb MCTXUNLOCK(source, &source->lock); 952135446Strhodes 953135446Strhodes *targetp = source; 954135446Strhodes} 955135446Strhodes 956135446Strhodesvoid 957135446Strhodesisc_mem_detach(isc_mem_t **ctxp) { 958135446Strhodes isc_mem_t *ctx; 959135446Strhodes isc_boolean_t want_destroy = ISC_FALSE; 960135446Strhodes 961135446Strhodes REQUIRE(ctxp != NULL); 962135446Strhodes ctx = *ctxp; 963135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 964135446Strhodes 965170222Sdougb MCTXLOCK(ctx, &ctx->lock); 966135446Strhodes INSIST(ctx->references > 0); 967135446Strhodes ctx->references--; 968135446Strhodes if (ctx->references == 0) 969135446Strhodes want_destroy = ISC_TRUE; 970170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 971135446Strhodes 972135446Strhodes if (want_destroy) 973135446Strhodes destroy(ctx); 974135446Strhodes 975135446Strhodes *ctxp = NULL; 976135446Strhodes} 977135446Strhodes 978135446Strhodes/* 979135446Strhodes * isc_mem_putanddetach() is the equivalent of: 980135446Strhodes * 981135446Strhodes * mctx = NULL; 982135446Strhodes * isc_mem_attach(ptr->mctx, &mctx); 983135446Strhodes * isc_mem_detach(&ptr->mctx); 984135446Strhodes * isc_mem_put(mctx, ptr, sizeof(*ptr); 985135446Strhodes * isc_mem_detach(&mctx); 986135446Strhodes */ 987135446Strhodes 988135446Strhodesvoid 989135446Strhodesisc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { 990135446Strhodes isc_mem_t *ctx; 991135446Strhodes isc_boolean_t want_destroy = ISC_FALSE; 992170222Sdougb size_info *si; 993170222Sdougb size_t oldsize; 994135446Strhodes 995135446Strhodes REQUIRE(ctxp != NULL); 996135446Strhodes ctx = *ctxp; 997135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 998135446Strhodes REQUIRE(ptr != NULL); 999135446Strhodes 1000135446Strhodes /* 1001135446Strhodes * Must be before mem_putunlocked() as ctxp is usually within 1002135446Strhodes * [ptr..ptr+size). 1003135446Strhodes */ 1004135446Strhodes *ctxp = NULL; 1005135446Strhodes 1006170222Sdougb if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { 1007170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { 1008170222Sdougb si = &(((size_info *)ptr)[-1]); 1009170222Sdougb oldsize = si->u.size - ALIGNMENT_SIZE; 1010170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1011170222Sdougb oldsize -= ALIGNMENT_SIZE; 1012170222Sdougb INSIST(oldsize == size); 1013170222Sdougb } 1014170222Sdougb isc__mem_free(ctx, ptr FLARG_PASS); 1015135446Strhodes 1016170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1017170222Sdougb ctx->references--; 1018170222Sdougb if (ctx->references == 0) 1019170222Sdougb want_destroy = ISC_TRUE; 1020170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1021170222Sdougb if (want_destroy) 1022170222Sdougb destroy(ctx); 1023170222Sdougb 1024170222Sdougb return; 1025170222Sdougb } 1026170222Sdougb 1027170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1028170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1029170222Sdougb mem_putunlocked(ctx, ptr, size); 1030170222Sdougb } else { 1031170222Sdougb mem_put(ctx, ptr, size); 1032170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1033170222Sdougb mem_putstats(ctx, ptr, size); 1034170222Sdougb } 1035170222Sdougb 1036135446Strhodes DELETE_TRACE(ctx, ptr, size, file, line); 1037135446Strhodes INSIST(ctx->references > 0); 1038135446Strhodes ctx->references--; 1039135446Strhodes if (ctx->references == 0) 1040135446Strhodes want_destroy = ISC_TRUE; 1041135446Strhodes 1042170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1043135446Strhodes 1044135446Strhodes if (want_destroy) 1045135446Strhodes destroy(ctx); 1046135446Strhodes} 1047135446Strhodes 1048135446Strhodesvoid 1049135446Strhodesisc_mem_destroy(isc_mem_t **ctxp) { 1050135446Strhodes isc_mem_t *ctx; 1051135446Strhodes 1052135446Strhodes /* 1053135446Strhodes * This routine provides legacy support for callers who use mctxs 1054135446Strhodes * without attaching/detaching. 1055135446Strhodes */ 1056135446Strhodes 1057135446Strhodes REQUIRE(ctxp != NULL); 1058135446Strhodes ctx = *ctxp; 1059135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1060135446Strhodes 1061170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1062135446Strhodes#if ISC_MEM_TRACKLINES 1063135446Strhodes if (ctx->references != 1) 1064135446Strhodes print_active(ctx, stderr); 1065135446Strhodes#endif 1066135446Strhodes REQUIRE(ctx->references == 1); 1067135446Strhodes ctx->references--; 1068170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1069135446Strhodes 1070135446Strhodes destroy(ctx); 1071135446Strhodes 1072135446Strhodes *ctxp = NULL; 1073135446Strhodes} 1074135446Strhodes 1075135446Strhodesisc_result_t 1076135446Strhodesisc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) { 1077135446Strhodes isc_result_t res; 1078135446Strhodes 1079170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1080135446Strhodes res = isc_ondestroy_register(&ctx->ondestroy, task, event); 1081170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1082135446Strhodes 1083135446Strhodes return (res); 1084135446Strhodes} 1085135446Strhodes 1086135446Strhodes 1087135446Strhodesvoid * 1088135446Strhodesisc__mem_get(isc_mem_t *ctx, size_t size FLARG) { 1089135446Strhodes void *ptr; 1090135446Strhodes isc_boolean_t call_water = ISC_FALSE; 1091135446Strhodes 1092135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1093135446Strhodes 1094170222Sdougb if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) 1095170222Sdougb return (isc__mem_allocate(ctx, size FLARG_PASS)); 1096135446Strhodes 1097170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1098170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1099170222Sdougb ptr = mem_getunlocked(ctx, size); 1100170222Sdougb } else { 1101170222Sdougb ptr = mem_get(ctx, size); 1102170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1103170222Sdougb if (ptr != NULL) 1104170222Sdougb mem_getstats(ctx, size); 1105170222Sdougb } 1106170222Sdougb 1107135446Strhodes ADD_TRACE(ctx, ptr, size, file, line); 1108214586Sdougb if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1109214586Sdougb !ctx->is_overmem) { 1110214586Sdougb ctx->is_overmem = ISC_TRUE; 1111214586Sdougb } 1112135446Strhodes if (ctx->hi_water != 0U && !ctx->hi_called && 1113135446Strhodes ctx->inuse > ctx->hi_water) { 1114135446Strhodes call_water = ISC_TRUE; 1115135446Strhodes } 1116135446Strhodes if (ctx->inuse > ctx->maxinuse) { 1117135446Strhodes ctx->maxinuse = ctx->inuse; 1118135446Strhodes if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1119135446Strhodes (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) 1120135446Strhodes fprintf(stderr, "maxinuse = %lu\n", 1121135446Strhodes (unsigned long)ctx->inuse); 1122135446Strhodes } 1123170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1124135446Strhodes 1125135446Strhodes if (call_water) 1126135446Strhodes (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); 1127135446Strhodes 1128135446Strhodes return (ptr); 1129135446Strhodes} 1130135446Strhodes 1131135446Strhodesvoid 1132135446Strhodesisc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG) 1133135446Strhodes{ 1134135446Strhodes isc_boolean_t call_water = ISC_FALSE; 1135170222Sdougb size_info *si; 1136170222Sdougb size_t oldsize; 1137135446Strhodes 1138135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1139135446Strhodes REQUIRE(ptr != NULL); 1140135446Strhodes 1141170222Sdougb if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { 1142170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { 1143170222Sdougb si = &(((size_info *)ptr)[-1]); 1144170222Sdougb oldsize = si->u.size - ALIGNMENT_SIZE; 1145170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1146170222Sdougb oldsize -= ALIGNMENT_SIZE; 1147170222Sdougb INSIST(oldsize == size); 1148170222Sdougb } 1149170222Sdougb isc__mem_free(ctx, ptr FLARG_PASS); 1150170222Sdougb return; 1151170222Sdougb } 1152135446Strhodes 1153170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1154170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1155170222Sdougb mem_putunlocked(ctx, ptr, size); 1156170222Sdougb } else { 1157170222Sdougb mem_put(ctx, ptr, size); 1158170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1159170222Sdougb mem_putstats(ctx, ptr, size); 1160170222Sdougb } 1161170222Sdougb 1162135446Strhodes DELETE_TRACE(ctx, ptr, size, file, line); 1163135446Strhodes 1164135446Strhodes /* 1165135446Strhodes * The check against ctx->lo_water == 0 is for the condition 1166135446Strhodes * when the context was pushed over hi_water but then had 1167135446Strhodes * isc_mem_setwater() called with 0 for hi_water and lo_water. 1168135446Strhodes */ 1169214586Sdougb if (ctx->is_overmem && 1170214586Sdougb (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1171214586Sdougb ctx->is_overmem = ISC_FALSE; 1172214586Sdougb } 1173186462Sdougb if (ctx->hi_called && 1174135446Strhodes (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1175135446Strhodes if (ctx->water != NULL) 1176135446Strhodes call_water = ISC_TRUE; 1177135446Strhodes } 1178170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1179135446Strhodes 1180135446Strhodes if (call_water) 1181135446Strhodes (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1182135446Strhodes} 1183135446Strhodes 1184186462Sdougbvoid 1185186462Sdougbisc_mem_waterack(isc_mem_t *ctx, int flag) { 1186186462Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1187186462Sdougb 1188186462Sdougb MCTXLOCK(ctx, &ctx->lock); 1189186462Sdougb if (flag == ISC_MEM_LOWATER) 1190186462Sdougb ctx->hi_called = ISC_FALSE; 1191186462Sdougb else if (flag == ISC_MEM_HIWATER) 1192186462Sdougb ctx->hi_called = ISC_TRUE; 1193186462Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1194186462Sdougb} 1195186462Sdougb 1196135446Strhodes#if ISC_MEM_TRACKLINES 1197135446Strhodesstatic void 1198135446Strhodesprint_active(isc_mem_t *mctx, FILE *out) { 1199135446Strhodes if (mctx->debuglist != NULL) { 1200135446Strhodes debuglink_t *dl; 1201135446Strhodes unsigned int i, j; 1202135446Strhodes const char *format; 1203135446Strhodes isc_boolean_t found; 1204135446Strhodes 1205193149Sdougb fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1206135446Strhodes ISC_MSG_DUMPALLOC, 1207135446Strhodes "Dump of all outstanding " 1208135446Strhodes "memory allocations:\n")); 1209135446Strhodes found = ISC_FALSE; 1210135446Strhodes format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1211186462Sdougb ISC_MSG_PTRFILELINE, 1212135446Strhodes "\tptr %p size %u file %s line %u\n"); 1213135446Strhodes for (i = 0; i <= mctx->max_size; i++) { 1214135446Strhodes dl = ISC_LIST_HEAD(mctx->debuglist[i]); 1215186462Sdougb 1216135446Strhodes if (dl != NULL) 1217135446Strhodes found = ISC_TRUE; 1218135446Strhodes 1219135446Strhodes while (dl != NULL) { 1220135446Strhodes for (j = 0; j < DEBUGLIST_COUNT; j++) 1221135446Strhodes if (dl->ptr[j] != NULL) 1222135446Strhodes fprintf(out, format, 1223135446Strhodes dl->ptr[j], 1224135446Strhodes dl->size[j], 1225135446Strhodes dl->file[j], 1226135446Strhodes dl->line[j]); 1227135446Strhodes dl = ISC_LIST_NEXT(dl, link); 1228135446Strhodes } 1229135446Strhodes } 1230135446Strhodes if (!found) 1231193149Sdougb fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1232135446Strhodes ISC_MSG_NONE, "\tNone.\n")); 1233135446Strhodes } 1234135446Strhodes} 1235135446Strhodes#endif 1236135446Strhodes 1237135446Strhodes/* 1238135446Strhodes * Print the stats[] on the stream "out" with suitable formatting. 1239135446Strhodes */ 1240135446Strhodesvoid 1241135446Strhodesisc_mem_stats(isc_mem_t *ctx, FILE *out) { 1242135446Strhodes size_t i; 1243135446Strhodes const struct stats *s; 1244135446Strhodes const isc_mempool_t *pool; 1245135446Strhodes 1246135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1247170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1248135446Strhodes 1249135446Strhodes for (i = 0; i <= ctx->max_size; i++) { 1250135446Strhodes s = &ctx->stats[i]; 1251135446Strhodes 1252135446Strhodes if (s->totalgets == 0U && s->gets == 0U) 1253135446Strhodes continue; 1254135446Strhodes fprintf(out, "%s%5lu: %11lu gets, %11lu rem", 1255135446Strhodes (i == ctx->max_size) ? ">=" : " ", 1256135446Strhodes (unsigned long) i, s->totalgets, s->gets); 1257170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 && 1258170222Sdougb (s->blocks != 0U || s->freefrags != 0U)) 1259135446Strhodes fprintf(out, " (%lu bl, %lu ff)", 1260135446Strhodes s->blocks, s->freefrags); 1261135446Strhodes fputc('\n', out); 1262135446Strhodes } 1263135446Strhodes 1264135446Strhodes /* 1265135446Strhodes * Note that since a pool can be locked now, these stats might be 1266135446Strhodes * somewhat off if the pool is in active use at the time the stats 1267135446Strhodes * are dumped. The link fields are protected by the isc_mem_t's 1268135446Strhodes * lock, however, so walking this list and extracting integers from 1269135446Strhodes * stats fields is always safe. 1270135446Strhodes */ 1271135446Strhodes pool = ISC_LIST_HEAD(ctx->pools); 1272135446Strhodes if (pool != NULL) { 1273193149Sdougb fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1274135446Strhodes ISC_MSG_POOLSTATS, 1275135446Strhodes "[Pool statistics]\n")); 1276135446Strhodes fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n", 1277135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1278135446Strhodes ISC_MSG_POOLNAME, "name"), 1279135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1280135446Strhodes ISC_MSG_POOLSIZE, "size"), 1281135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1282135446Strhodes ISC_MSG_POOLMAXALLOC, "maxalloc"), 1283135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1284135446Strhodes ISC_MSG_POOLALLOCATED, "allocated"), 1285135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1286135446Strhodes ISC_MSG_POOLFREECOUNT, "freecount"), 1287135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1288135446Strhodes ISC_MSG_POOLFREEMAX, "freemax"), 1289135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1290135446Strhodes ISC_MSG_POOLFILLCOUNT, "fillcount"), 1291135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1292135446Strhodes ISC_MSG_POOLGETS, "gets"), 1293135446Strhodes "L"); 1294135446Strhodes } 1295135446Strhodes while (pool != NULL) { 1296135446Strhodes fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n", 1297135446Strhodes pool->name, (unsigned long) pool->size, pool->maxalloc, 1298135446Strhodes pool->allocated, pool->freecount, pool->freemax, 1299135446Strhodes pool->fillcount, pool->gets, 1300135446Strhodes (pool->lock == NULL ? "N" : "Y")); 1301135446Strhodes pool = ISC_LIST_NEXT(pool, link); 1302135446Strhodes } 1303135446Strhodes 1304135446Strhodes#if ISC_MEM_TRACKLINES 1305135446Strhodes print_active(ctx, out); 1306135446Strhodes#endif 1307135446Strhodes 1308170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1309135446Strhodes} 1310135446Strhodes 1311135446Strhodes/* 1312135446Strhodes * Replacements for malloc() and free() -- they implicitly remember the 1313135446Strhodes * size of the object allocated (with some additional overhead). 1314135446Strhodes */ 1315135446Strhodes 1316135446Strhodesstatic void * 1317135446Strhodesisc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) { 1318135446Strhodes size_info *si; 1319135446Strhodes 1320135446Strhodes size += ALIGNMENT_SIZE; 1321170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1322170222Sdougb size += ALIGNMENT_SIZE; 1323170222Sdougb 1324170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) 1325170222Sdougb si = mem_getunlocked(ctx, size); 1326170222Sdougb else 1327170222Sdougb si = mem_get(ctx, size); 1328170222Sdougb 1329135446Strhodes if (si == NULL) 1330135446Strhodes return (NULL); 1331170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1332170222Sdougb si->u.ctx = ctx; 1333170222Sdougb si++; 1334170222Sdougb } 1335135446Strhodes si->u.size = size; 1336135446Strhodes return (&si[1]); 1337135446Strhodes} 1338135446Strhodes 1339135446Strhodesvoid * 1340135446Strhodesisc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) { 1341135446Strhodes size_info *si; 1342170222Sdougb isc_boolean_t call_water = ISC_FALSE; 1343135446Strhodes 1344135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1345135446Strhodes 1346170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1347170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1348170222Sdougb si = isc__mem_allocateunlocked(ctx, size); 1349170222Sdougb } else { 1350170222Sdougb si = isc__mem_allocateunlocked(ctx, size); 1351170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1352170222Sdougb if (si != NULL) 1353170222Sdougb mem_getstats(ctx, si[-1].u.size); 1354170222Sdougb } 1355135446Strhodes 1356135446Strhodes#if ISC_MEM_TRACKLINES 1357135446Strhodes ADD_TRACE(ctx, si, si[-1].u.size, file, line); 1358135446Strhodes#endif 1359214586Sdougb if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1360214586Sdougb !ctx->is_overmem) { 1361214586Sdougb ctx->is_overmem = ISC_TRUE; 1362214586Sdougb } 1363214586Sdougb 1364170222Sdougb if (ctx->hi_water != 0U && !ctx->hi_called && 1365170222Sdougb ctx->inuse > ctx->hi_water) { 1366170222Sdougb ctx->hi_called = ISC_TRUE; 1367170222Sdougb call_water = ISC_TRUE; 1368170222Sdougb } 1369170222Sdougb if (ctx->inuse > ctx->maxinuse) { 1370170222Sdougb ctx->maxinuse = ctx->inuse; 1371170222Sdougb if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1372170222Sdougb (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) 1373170222Sdougb fprintf(stderr, "maxinuse = %lu\n", 1374170222Sdougb (unsigned long)ctx->inuse); 1375170222Sdougb } 1376170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1377135446Strhodes 1378170222Sdougb if (call_water) 1379170222Sdougb (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); 1380135446Strhodes 1381135446Strhodes return (si); 1382135446Strhodes} 1383135446Strhodes 1384193149Sdougbvoid * 1385193149Sdougbisc__mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG) { 1386193149Sdougb void *new_ptr = NULL; 1387193149Sdougb size_t oldsize, copysize; 1388193149Sdougb 1389193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1390193149Sdougb 1391193149Sdougb /* 1392193149Sdougb * This function emulates the realloc(3) standard library function: 1393193149Sdougb * - if size > 0, allocate new memory; and if ptr is non NULL, copy 1394193149Sdougb * as much of the old contents to the new buffer and free the old one. 1395193149Sdougb * Note that when allocation fails the original pointer is intact; 1396193149Sdougb * the caller must free it. 1397193149Sdougb * - if size is 0 and ptr is non NULL, simply free the given ptr. 1398193149Sdougb * - this function returns: 1399193149Sdougb * pointer to the newly allocated memory, or 1400193149Sdougb * NULL if allocation fails or doesn't happen. 1401193149Sdougb */ 1402193149Sdougb if (size > 0U) { 1403193149Sdougb new_ptr = isc__mem_allocate(ctx, size FLARG_PASS); 1404193149Sdougb if (new_ptr != NULL && ptr != NULL) { 1405193149Sdougb oldsize = (((size_info *)ptr)[-1]).u.size; 1406193149Sdougb INSIST(oldsize >= ALIGNMENT_SIZE); 1407193149Sdougb oldsize -= ALIGNMENT_SIZE; 1408193149Sdougb copysize = oldsize > size ? size : oldsize; 1409193149Sdougb memcpy(new_ptr, ptr, copysize); 1410193149Sdougb isc__mem_free(ctx, ptr FLARG_PASS); 1411193149Sdougb } 1412193149Sdougb } else if (ptr != NULL) 1413193149Sdougb isc__mem_free(ctx, ptr FLARG_PASS); 1414193149Sdougb 1415193149Sdougb return (new_ptr); 1416193149Sdougb} 1417193149Sdougb 1418135446Strhodesvoid 1419135446Strhodesisc__mem_free(isc_mem_t *ctx, void *ptr FLARG) { 1420135446Strhodes size_info *si; 1421135446Strhodes size_t size; 1422170222Sdougb isc_boolean_t call_water= ISC_FALSE; 1423135446Strhodes 1424135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1425135446Strhodes REQUIRE(ptr != NULL); 1426135446Strhodes 1427170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1428170222Sdougb si = &(((size_info *)ptr)[-2]); 1429170222Sdougb REQUIRE(si->u.ctx == ctx); 1430170222Sdougb size = si[1].u.size; 1431170222Sdougb } else { 1432170222Sdougb si = &(((size_info *)ptr)[-1]); 1433170222Sdougb size = si->u.size; 1434170222Sdougb } 1435135446Strhodes 1436170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1437170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1438170222Sdougb mem_putunlocked(ctx, si, size); 1439170222Sdougb } else { 1440170222Sdougb mem_put(ctx, si, size); 1441170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1442170222Sdougb mem_putstats(ctx, si, size); 1443170222Sdougb } 1444135446Strhodes 1445135446Strhodes DELETE_TRACE(ctx, ptr, size, file, line); 1446135446Strhodes 1447170222Sdougb /* 1448170222Sdougb * The check against ctx->lo_water == 0 is for the condition 1449170222Sdougb * when the context was pushed over hi_water but then had 1450170222Sdougb * isc_mem_setwater() called with 0 for hi_water and lo_water. 1451170222Sdougb */ 1452214586Sdougb if (ctx->is_overmem && 1453214586Sdougb (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1454214586Sdougb ctx->is_overmem = ISC_FALSE; 1455214586Sdougb } 1456214586Sdougb 1457186462Sdougb if (ctx->hi_called && 1458170222Sdougb (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1459170222Sdougb ctx->hi_called = ISC_FALSE; 1460170222Sdougb 1461170222Sdougb if (ctx->water != NULL) 1462170222Sdougb call_water = ISC_TRUE; 1463170222Sdougb } 1464170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1465170222Sdougb 1466170222Sdougb if (call_water) 1467170222Sdougb (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1468135446Strhodes} 1469135446Strhodes 1470135446Strhodes 1471135446Strhodes/* 1472135446Strhodes * Other useful things. 1473135446Strhodes */ 1474135446Strhodes 1475135446Strhodeschar * 1476135446Strhodesisc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) { 1477135446Strhodes size_t len; 1478135446Strhodes char *ns; 1479135446Strhodes 1480135446Strhodes REQUIRE(VALID_CONTEXT(mctx)); 1481135446Strhodes REQUIRE(s != NULL); 1482135446Strhodes 1483135446Strhodes len = strlen(s); 1484135446Strhodes 1485135446Strhodes ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS); 1486135446Strhodes 1487135446Strhodes if (ns != NULL) 1488135446Strhodes strncpy(ns, s, len + 1); 1489135446Strhodes 1490135446Strhodes return (ns); 1491135446Strhodes} 1492135446Strhodes 1493135446Strhodesvoid 1494135446Strhodesisc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) { 1495135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1496170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1497135446Strhodes 1498135446Strhodes ctx->checkfree = flag; 1499135446Strhodes 1500170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1501135446Strhodes} 1502135446Strhodes 1503135446Strhodes/* 1504135446Strhodes * Quotas 1505135446Strhodes */ 1506135446Strhodes 1507135446Strhodesvoid 1508135446Strhodesisc_mem_setquota(isc_mem_t *ctx, size_t quota) { 1509135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1510170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1511135446Strhodes 1512135446Strhodes ctx->quota = quota; 1513135446Strhodes 1514170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1515135446Strhodes} 1516135446Strhodes 1517135446Strhodessize_t 1518135446Strhodesisc_mem_getquota(isc_mem_t *ctx) { 1519135446Strhodes size_t quota; 1520135446Strhodes 1521135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1522170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1523135446Strhodes 1524135446Strhodes quota = ctx->quota; 1525135446Strhodes 1526170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1527135446Strhodes 1528135446Strhodes return (quota); 1529135446Strhodes} 1530135446Strhodes 1531135446Strhodessize_t 1532135446Strhodesisc_mem_inuse(isc_mem_t *ctx) { 1533135446Strhodes size_t inuse; 1534135446Strhodes 1535135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1536170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1537135446Strhodes 1538135446Strhodes inuse = ctx->inuse; 1539135446Strhodes 1540170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1541135446Strhodes 1542135446Strhodes return (inuse); 1543135446Strhodes} 1544135446Strhodes 1545135446Strhodesvoid 1546135446Strhodesisc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, 1547186462Sdougb size_t hiwater, size_t lowater) 1548135446Strhodes{ 1549170222Sdougb isc_boolean_t callwater = ISC_FALSE; 1550170222Sdougb isc_mem_water_t oldwater; 1551170222Sdougb void *oldwater_arg; 1552170222Sdougb 1553135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1554135446Strhodes REQUIRE(hiwater >= lowater); 1555135446Strhodes 1556170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1557170222Sdougb oldwater = ctx->water; 1558170222Sdougb oldwater_arg = ctx->water_arg; 1559135446Strhodes if (water == NULL) { 1560170222Sdougb callwater = ctx->hi_called; 1561135446Strhodes ctx->water = NULL; 1562135446Strhodes ctx->water_arg = NULL; 1563135446Strhodes ctx->hi_water = 0; 1564135446Strhodes ctx->lo_water = 0; 1565135446Strhodes ctx->hi_called = ISC_FALSE; 1566135446Strhodes } else { 1567170222Sdougb if (ctx->hi_called && 1568170222Sdougb (ctx->water != water || ctx->water_arg != water_arg || 1569170222Sdougb ctx->inuse < lowater || lowater == 0U)) 1570170222Sdougb callwater = ISC_TRUE; 1571135446Strhodes ctx->water = water; 1572135446Strhodes ctx->water_arg = water_arg; 1573135446Strhodes ctx->hi_water = hiwater; 1574135446Strhodes ctx->lo_water = lowater; 1575135446Strhodes ctx->hi_called = ISC_FALSE; 1576135446Strhodes } 1577170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1578186462Sdougb 1579170222Sdougb if (callwater && oldwater != NULL) 1580170222Sdougb (oldwater)(oldwater_arg, ISC_MEM_LOWATER); 1581135446Strhodes} 1582135446Strhodes 1583214586Sdougbisc_boolean_t 1584214586Sdougbisc_mem_isovermem(isc_mem_t *ctx) { 1585214586Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1586214586Sdougb 1587214586Sdougb /* 1588214586Sdougb * We don't bother to lock the context because 100% accuracy isn't 1589214586Sdougb * necessary (and even if we locked the context the returned value 1590214586Sdougb * could be different from the actual state when it's used anyway) 1591214586Sdougb */ 1592214586Sdougb return (ctx->is_overmem); 1593214586Sdougb} 1594214586Sdougb 1595193149Sdougbvoid 1596193149Sdougbisc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) { 1597193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1598193149Sdougb 1599193149Sdougb LOCK(&ctx->lock); 1600193149Sdougb memset(ctx->name, 0, sizeof(ctx->name)); 1601193149Sdougb strncpy(ctx->name, name, sizeof(ctx->name) - 1); 1602193149Sdougb ctx->tag = tag; 1603193149Sdougb UNLOCK(&ctx->lock); 1604193149Sdougb} 1605193149Sdougb 1606193149Sdougbconst char * 1607193149Sdougbisc_mem_getname(isc_mem_t *ctx) { 1608193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1609193149Sdougb 1610193149Sdougb return (ctx->name); 1611193149Sdougb} 1612193149Sdougb 1613193149Sdougbvoid * 1614193149Sdougbisc_mem_gettag(isc_mem_t *ctx) { 1615193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1616193149Sdougb 1617193149Sdougb return (ctx->tag); 1618193149Sdougb} 1619193149Sdougb 1620135446Strhodes/* 1621135446Strhodes * Memory pool stuff 1622135446Strhodes */ 1623135446Strhodes 1624135446Strhodesisc_result_t 1625135446Strhodesisc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) { 1626135446Strhodes isc_mempool_t *mpctx; 1627135446Strhodes 1628135446Strhodes REQUIRE(VALID_CONTEXT(mctx)); 1629135446Strhodes REQUIRE(size > 0U); 1630135446Strhodes REQUIRE(mpctxp != NULL && *mpctxp == NULL); 1631135446Strhodes 1632135446Strhodes /* 1633135446Strhodes * Allocate space for this pool, initialize values, and if all works 1634135446Strhodes * well, attach to the memory context. 1635135446Strhodes */ 1636135446Strhodes mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t)); 1637135446Strhodes if (mpctx == NULL) 1638135446Strhodes return (ISC_R_NOMEMORY); 1639135446Strhodes 1640135446Strhodes mpctx->magic = MEMPOOL_MAGIC; 1641135446Strhodes mpctx->lock = NULL; 1642135446Strhodes mpctx->mctx = mctx; 1643135446Strhodes mpctx->size = size; 1644135446Strhodes mpctx->maxalloc = UINT_MAX; 1645135446Strhodes mpctx->allocated = 0; 1646135446Strhodes mpctx->freecount = 0; 1647135446Strhodes mpctx->freemax = 1; 1648135446Strhodes mpctx->fillcount = 1; 1649135446Strhodes mpctx->gets = 0; 1650135446Strhodes#if ISC_MEMPOOL_NAMES 1651135446Strhodes mpctx->name[0] = 0; 1652135446Strhodes#endif 1653135446Strhodes mpctx->items = NULL; 1654135446Strhodes 1655135446Strhodes *mpctxp = mpctx; 1656135446Strhodes 1657170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1658135446Strhodes ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link); 1659193149Sdougb mctx->poolcnt++; 1660170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1661135446Strhodes 1662135446Strhodes return (ISC_R_SUCCESS); 1663135446Strhodes} 1664135446Strhodes 1665135446Strhodesvoid 1666135446Strhodesisc_mempool_setname(isc_mempool_t *mpctx, const char *name) { 1667135446Strhodes REQUIRE(name != NULL); 1668135446Strhodes 1669135446Strhodes#if ISC_MEMPOOL_NAMES 1670135446Strhodes if (mpctx->lock != NULL) 1671135446Strhodes LOCK(mpctx->lock); 1672135446Strhodes 1673135446Strhodes strncpy(mpctx->name, name, sizeof(mpctx->name) - 1); 1674135446Strhodes mpctx->name[sizeof(mpctx->name) - 1] = '\0'; 1675135446Strhodes 1676135446Strhodes if (mpctx->lock != NULL) 1677135446Strhodes UNLOCK(mpctx->lock); 1678135446Strhodes#else 1679135446Strhodes UNUSED(mpctx); 1680135446Strhodes UNUSED(name); 1681135446Strhodes#endif 1682135446Strhodes} 1683135446Strhodes 1684135446Strhodesvoid 1685135446Strhodesisc_mempool_destroy(isc_mempool_t **mpctxp) { 1686135446Strhodes isc_mempool_t *mpctx; 1687135446Strhodes isc_mem_t *mctx; 1688135446Strhodes isc_mutex_t *lock; 1689135446Strhodes element *item; 1690135446Strhodes 1691135446Strhodes REQUIRE(mpctxp != NULL); 1692135446Strhodes mpctx = *mpctxp; 1693135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1694135446Strhodes#if ISC_MEMPOOL_NAMES 1695135446Strhodes if (mpctx->allocated > 0) 1696135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 1697135446Strhodes "isc_mempool_destroy(): mempool %s " 1698135446Strhodes "leaked memory", 1699135446Strhodes mpctx->name); 1700135446Strhodes#endif 1701135446Strhodes REQUIRE(mpctx->allocated == 0); 1702135446Strhodes 1703135446Strhodes mctx = mpctx->mctx; 1704135446Strhodes 1705135446Strhodes lock = mpctx->lock; 1706135446Strhodes 1707135446Strhodes if (lock != NULL) 1708135446Strhodes LOCK(lock); 1709135446Strhodes 1710135446Strhodes /* 1711135446Strhodes * Return any items on the free list 1712135446Strhodes */ 1713170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1714135446Strhodes while (mpctx->items != NULL) { 1715135446Strhodes INSIST(mpctx->freecount > 0); 1716135446Strhodes mpctx->freecount--; 1717135446Strhodes item = mpctx->items; 1718135446Strhodes mpctx->items = item->next; 1719135446Strhodes 1720170222Sdougb if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1721170222Sdougb mem_putunlocked(mctx, item, mpctx->size); 1722170222Sdougb } else { 1723170222Sdougb mem_put(mctx, item, mpctx->size); 1724170222Sdougb mem_putstats(mctx, item, mpctx->size); 1725170222Sdougb } 1726135446Strhodes } 1727170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1728135446Strhodes 1729135446Strhodes /* 1730135446Strhodes * Remove our linked list entry from the memory context. 1731135446Strhodes */ 1732170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1733135446Strhodes ISC_LIST_UNLINK(mctx->pools, mpctx, link); 1734193149Sdougb mctx->poolcnt--; 1735170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1736135446Strhodes 1737135446Strhodes mpctx->magic = 0; 1738135446Strhodes 1739135446Strhodes isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t)); 1740135446Strhodes 1741135446Strhodes if (lock != NULL) 1742135446Strhodes UNLOCK(lock); 1743135446Strhodes 1744135446Strhodes *mpctxp = NULL; 1745135446Strhodes} 1746135446Strhodes 1747135446Strhodesvoid 1748135446Strhodesisc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) { 1749135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1750135446Strhodes REQUIRE(mpctx->lock == NULL); 1751135446Strhodes REQUIRE(lock != NULL); 1752135446Strhodes 1753135446Strhodes mpctx->lock = lock; 1754135446Strhodes} 1755135446Strhodes 1756135446Strhodesvoid * 1757135446Strhodesisc__mempool_get(isc_mempool_t *mpctx FLARG) { 1758135446Strhodes element *item; 1759135446Strhodes isc_mem_t *mctx; 1760135446Strhodes unsigned int i; 1761135446Strhodes 1762135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1763135446Strhodes 1764135446Strhodes mctx = mpctx->mctx; 1765135446Strhodes 1766135446Strhodes if (mpctx->lock != NULL) 1767135446Strhodes LOCK(mpctx->lock); 1768135446Strhodes 1769135446Strhodes /* 1770135446Strhodes * Don't let the caller go over quota 1771135446Strhodes */ 1772135446Strhodes if (mpctx->allocated >= mpctx->maxalloc) { 1773135446Strhodes item = NULL; 1774135446Strhodes goto out; 1775135446Strhodes } 1776135446Strhodes 1777135446Strhodes /* 1778135446Strhodes * if we have a free list item, return the first here 1779135446Strhodes */ 1780135446Strhodes item = mpctx->items; 1781135446Strhodes if (item != NULL) { 1782135446Strhodes mpctx->items = item->next; 1783135446Strhodes INSIST(mpctx->freecount > 0); 1784135446Strhodes mpctx->freecount--; 1785135446Strhodes mpctx->gets++; 1786135446Strhodes mpctx->allocated++; 1787135446Strhodes goto out; 1788135446Strhodes } 1789135446Strhodes 1790135446Strhodes /* 1791135446Strhodes * We need to dip into the well. Lock the memory context here and 1792135446Strhodes * fill up our free list. 1793135446Strhodes */ 1794170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1795135446Strhodes for (i = 0; i < mpctx->fillcount; i++) { 1796170222Sdougb if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1797170222Sdougb item = mem_getunlocked(mctx, mpctx->size); 1798170222Sdougb } else { 1799170222Sdougb item = mem_get(mctx, mpctx->size); 1800170222Sdougb if (item != NULL) 1801170222Sdougb mem_getstats(mctx, mpctx->size); 1802170222Sdougb } 1803135446Strhodes if (item == NULL) 1804135446Strhodes break; 1805135446Strhodes item->next = mpctx->items; 1806135446Strhodes mpctx->items = item; 1807135446Strhodes mpctx->freecount++; 1808135446Strhodes } 1809170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1810135446Strhodes 1811135446Strhodes /* 1812135446Strhodes * If we didn't get any items, return NULL. 1813135446Strhodes */ 1814135446Strhodes item = mpctx->items; 1815135446Strhodes if (item == NULL) 1816135446Strhodes goto out; 1817135446Strhodes 1818135446Strhodes mpctx->items = item->next; 1819135446Strhodes mpctx->freecount--; 1820135446Strhodes mpctx->gets++; 1821135446Strhodes mpctx->allocated++; 1822135446Strhodes 1823135446Strhodes out: 1824135446Strhodes if (mpctx->lock != NULL) 1825135446Strhodes UNLOCK(mpctx->lock); 1826135446Strhodes 1827135446Strhodes#if ISC_MEM_TRACKLINES 1828135446Strhodes if (item != NULL) { 1829170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1830135446Strhodes ADD_TRACE(mctx, item, mpctx->size, file, line); 1831170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1832135446Strhodes } 1833135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 1834135446Strhodes 1835135446Strhodes return (item); 1836135446Strhodes} 1837135446Strhodes 1838135446Strhodesvoid 1839135446Strhodesisc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) { 1840135446Strhodes isc_mem_t *mctx; 1841135446Strhodes element *item; 1842135446Strhodes 1843135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1844135446Strhodes REQUIRE(mem != NULL); 1845135446Strhodes 1846135446Strhodes mctx = mpctx->mctx; 1847135446Strhodes 1848135446Strhodes if (mpctx->lock != NULL) 1849135446Strhodes LOCK(mpctx->lock); 1850135446Strhodes 1851135446Strhodes INSIST(mpctx->allocated > 0); 1852135446Strhodes mpctx->allocated--; 1853135446Strhodes 1854135446Strhodes#if ISC_MEM_TRACKLINES 1855170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1856135446Strhodes DELETE_TRACE(mctx, mem, mpctx->size, file, line); 1857170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1858135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 1859135446Strhodes 1860135446Strhodes /* 1861135446Strhodes * If our free list is full, return this to the mctx directly. 1862135446Strhodes */ 1863135446Strhodes if (mpctx->freecount >= mpctx->freemax) { 1864170222Sdougb if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1865170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1866170222Sdougb mem_putunlocked(mctx, mem, mpctx->size); 1867170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1868170222Sdougb } else { 1869170222Sdougb mem_put(mctx, mem, mpctx->size); 1870170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1871170222Sdougb mem_putstats(mctx, mem, mpctx->size); 1872170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1873170222Sdougb } 1874135446Strhodes if (mpctx->lock != NULL) 1875135446Strhodes UNLOCK(mpctx->lock); 1876135446Strhodes return; 1877135446Strhodes } 1878135446Strhodes 1879135446Strhodes /* 1880135446Strhodes * Otherwise, attach it to our free list and bump the counter. 1881135446Strhodes */ 1882135446Strhodes mpctx->freecount++; 1883135446Strhodes item = (element *)mem; 1884135446Strhodes item->next = mpctx->items; 1885135446Strhodes mpctx->items = item; 1886135446Strhodes 1887135446Strhodes if (mpctx->lock != NULL) 1888135446Strhodes UNLOCK(mpctx->lock); 1889135446Strhodes} 1890135446Strhodes 1891135446Strhodes/* 1892135446Strhodes * Quotas 1893135446Strhodes */ 1894135446Strhodes 1895135446Strhodesvoid 1896135446Strhodesisc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) { 1897135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1898135446Strhodes 1899135446Strhodes if (mpctx->lock != NULL) 1900135446Strhodes LOCK(mpctx->lock); 1901135446Strhodes 1902135446Strhodes mpctx->freemax = limit; 1903135446Strhodes 1904135446Strhodes if (mpctx->lock != NULL) 1905135446Strhodes UNLOCK(mpctx->lock); 1906135446Strhodes} 1907135446Strhodes 1908135446Strhodesunsigned int 1909135446Strhodesisc_mempool_getfreemax(isc_mempool_t *mpctx) { 1910135446Strhodes unsigned int freemax; 1911135446Strhodes 1912135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1913135446Strhodes 1914135446Strhodes if (mpctx->lock != NULL) 1915135446Strhodes LOCK(mpctx->lock); 1916135446Strhodes 1917135446Strhodes freemax = mpctx->freemax; 1918135446Strhodes 1919135446Strhodes if (mpctx->lock != NULL) 1920135446Strhodes UNLOCK(mpctx->lock); 1921135446Strhodes 1922135446Strhodes return (freemax); 1923135446Strhodes} 1924135446Strhodes 1925135446Strhodesunsigned int 1926135446Strhodesisc_mempool_getfreecount(isc_mempool_t *mpctx) { 1927135446Strhodes unsigned int freecount; 1928135446Strhodes 1929135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1930135446Strhodes 1931135446Strhodes if (mpctx->lock != NULL) 1932135446Strhodes LOCK(mpctx->lock); 1933135446Strhodes 1934135446Strhodes freecount = mpctx->freecount; 1935135446Strhodes 1936135446Strhodes if (mpctx->lock != NULL) 1937135446Strhodes UNLOCK(mpctx->lock); 1938135446Strhodes 1939135446Strhodes return (freecount); 1940135446Strhodes} 1941135446Strhodes 1942135446Strhodesvoid 1943135446Strhodesisc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) { 1944135446Strhodes REQUIRE(limit > 0); 1945135446Strhodes 1946135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1947135446Strhodes 1948135446Strhodes if (mpctx->lock != NULL) 1949135446Strhodes LOCK(mpctx->lock); 1950135446Strhodes 1951135446Strhodes mpctx->maxalloc = limit; 1952135446Strhodes 1953135446Strhodes if (mpctx->lock != NULL) 1954135446Strhodes UNLOCK(mpctx->lock); 1955135446Strhodes} 1956135446Strhodes 1957135446Strhodesunsigned int 1958135446Strhodesisc_mempool_getmaxalloc(isc_mempool_t *mpctx) { 1959135446Strhodes unsigned int maxalloc; 1960135446Strhodes 1961135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1962135446Strhodes 1963135446Strhodes if (mpctx->lock != NULL) 1964135446Strhodes LOCK(mpctx->lock); 1965135446Strhodes 1966135446Strhodes maxalloc = mpctx->maxalloc; 1967135446Strhodes 1968135446Strhodes if (mpctx->lock != NULL) 1969135446Strhodes UNLOCK(mpctx->lock); 1970135446Strhodes 1971135446Strhodes return (maxalloc); 1972135446Strhodes} 1973135446Strhodes 1974135446Strhodesunsigned int 1975135446Strhodesisc_mempool_getallocated(isc_mempool_t *mpctx) { 1976135446Strhodes unsigned int allocated; 1977135446Strhodes 1978135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1979135446Strhodes 1980135446Strhodes if (mpctx->lock != NULL) 1981135446Strhodes LOCK(mpctx->lock); 1982135446Strhodes 1983135446Strhodes allocated = mpctx->allocated; 1984135446Strhodes 1985135446Strhodes if (mpctx->lock != NULL) 1986135446Strhodes UNLOCK(mpctx->lock); 1987135446Strhodes 1988135446Strhodes return (allocated); 1989135446Strhodes} 1990135446Strhodes 1991135446Strhodesvoid 1992135446Strhodesisc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) { 1993135446Strhodes REQUIRE(limit > 0); 1994135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1995135446Strhodes 1996135446Strhodes if (mpctx->lock != NULL) 1997135446Strhodes LOCK(mpctx->lock); 1998135446Strhodes 1999135446Strhodes mpctx->fillcount = limit; 2000135446Strhodes 2001135446Strhodes if (mpctx->lock != NULL) 2002135446Strhodes UNLOCK(mpctx->lock); 2003135446Strhodes} 2004135446Strhodes 2005135446Strhodesunsigned int 2006135446Strhodesisc_mempool_getfillcount(isc_mempool_t *mpctx) { 2007135446Strhodes unsigned int fillcount; 2008135446Strhodes 2009135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 2010135446Strhodes 2011135446Strhodes if (mpctx->lock != NULL) 2012135446Strhodes LOCK(mpctx->lock); 2013135446Strhodes 2014135446Strhodes fillcount = mpctx->fillcount; 2015135446Strhodes 2016135446Strhodes if (mpctx->lock != NULL) 2017135446Strhodes UNLOCK(mpctx->lock); 2018135446Strhodes 2019135446Strhodes return (fillcount); 2020135446Strhodes} 2021170222Sdougb 2022170222Sdougbvoid 2023170222Sdougbisc_mem_printactive(isc_mem_t *ctx, FILE *file) { 2024170222Sdougb 2025170222Sdougb REQUIRE(VALID_CONTEXT(ctx)); 2026170222Sdougb REQUIRE(file != NULL); 2027170222Sdougb 2028170222Sdougb#if !ISC_MEM_TRACKLINES 2029170222Sdougb UNUSED(ctx); 2030170222Sdougb UNUSED(file); 2031170222Sdougb#else 2032170222Sdougb print_active(ctx, file); 2033170222Sdougb#endif 2034170222Sdougb} 2035170222Sdougb 2036170222Sdougbvoid 2037170222Sdougbisc_mem_printallactive(FILE *file) { 2038170222Sdougb#if !ISC_MEM_TRACKLINES 2039170222Sdougb UNUSED(file); 2040170222Sdougb#else 2041170222Sdougb isc_mem_t *ctx; 2042170222Sdougb 2043170222Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2044170222Sdougb 2045170222Sdougb LOCK(&lock); 2046170222Sdougb for (ctx = ISC_LIST_HEAD(contexts); 2047170222Sdougb ctx != NULL; 2048170222Sdougb ctx = ISC_LIST_NEXT(ctx, link)) { 2049170222Sdougb fprintf(file, "context: %p\n", ctx); 2050170222Sdougb print_active(ctx, file); 2051170222Sdougb } 2052170222Sdougb UNLOCK(&lock); 2053170222Sdougb#endif 2054170222Sdougb} 2055170222Sdougb 2056186462Sdougbvoid 2057170222Sdougbisc_mem_checkdestroyed(FILE *file) { 2058170222Sdougb 2059170222Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2060170222Sdougb 2061170222Sdougb LOCK(&lock); 2062170222Sdougb if (!ISC_LIST_EMPTY(contexts)) { 2063170222Sdougb#if ISC_MEM_TRACKLINES 2064170222Sdougb isc_mem_t *ctx; 2065170222Sdougb 2066170222Sdougb for (ctx = ISC_LIST_HEAD(contexts); 2067170222Sdougb ctx != NULL; 2068170222Sdougb ctx = ISC_LIST_NEXT(ctx, link)) { 2069170222Sdougb fprintf(file, "context: %p\n", ctx); 2070170222Sdougb print_active(ctx, file); 2071170222Sdougb } 2072170222Sdougb fflush(file); 2073170222Sdougb#endif 2074174187Sdougb INSIST(0); 2075170222Sdougb } 2076170222Sdougb UNLOCK(&lock); 2077170222Sdougb} 2078193149Sdougb 2079193149Sdougbunsigned int 2080193149Sdougbisc_mem_references(isc_mem_t *ctx) { 2081193149Sdougb unsigned int references; 2082193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 2083193149Sdougb 2084193149Sdougb MCTXLOCK(ctx, &ctx->lock); 2085193149Sdougb references = ctx->references; 2086193149Sdougb MCTXUNLOCK(ctx, &ctx->lock); 2087193149Sdougb 2088193149Sdougb return (references); 2089193149Sdougb} 2090193149Sdougb 2091193149Sdougb#ifdef HAVE_LIBXML2 2092193149Sdougb 2093193149Sdougbtypedef struct summarystat { 2094193149Sdougb isc_uint64_t total; 2095193149Sdougb isc_uint64_t inuse; 2096193149Sdougb isc_uint64_t blocksize; 2097193149Sdougb isc_uint64_t contextsize; 2098193149Sdougb} summarystat_t; 2099193149Sdougb 2100193149Sdougbstatic void 2101193149Sdougbrenderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) { 2102193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 2103193149Sdougb 2104193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"); 2105193149Sdougb 2106193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"); 2107193149Sdougb xmlTextWriterWriteFormatString(writer, "%p", ctx); 2108193149Sdougb xmlTextWriterEndElement(writer); /* id */ 2109193149Sdougb 2110193149Sdougb if (ctx->name[0] != 0) { 2111193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); 2112193149Sdougb xmlTextWriterWriteFormatString(writer, "%s", ctx->name); 2113193149Sdougb xmlTextWriterEndElement(writer); /* name */ 2114193149Sdougb } 2115193149Sdougb 2116193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 2117193149Sdougb MCTXLOCK(ctx, &ctx->lock); 2118193149Sdougb 2119193149Sdougb summary->contextsize += sizeof(*ctx) + 2120193149Sdougb (ctx->max_size + 1) * sizeof(struct stats) + 2121193149Sdougb ctx->max_size * sizeof(element *) + 2122193149Sdougb ctx->basic_table_count * sizeof(char *); 2123193149Sdougb#if ISC_MEM_TRACKLINES 2124193149Sdougb if (ctx->debuglist != NULL) { 2125193149Sdougb summary->contextsize += 2126193149Sdougb (ctx->max_size + 1) * sizeof(debuglist_t) + 2127193149Sdougb ctx->debuglistcnt * sizeof(debuglink_t); 2128193149Sdougb } 2129193149Sdougb#endif 2130193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); 2131193149Sdougb xmlTextWriterWriteFormatString(writer, "%d", ctx->references); 2132193149Sdougb xmlTextWriterEndElement(writer); /* references */ 2133193149Sdougb 2134193149Sdougb summary->total += ctx->total; 2135193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"); 2136193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2137193149Sdougb (isc_uint64_t)ctx->total); 2138193149Sdougb xmlTextWriterEndElement(writer); /* total */ 2139193149Sdougb 2140193149Sdougb summary->inuse += ctx->inuse; 2141193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"); 2142193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2143193149Sdougb (isc_uint64_t)ctx->inuse); 2144193149Sdougb xmlTextWriterEndElement(writer); /* inuse */ 2145193149Sdougb 2146193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"); 2147193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2148193149Sdougb (isc_uint64_t)ctx->maxinuse); 2149193149Sdougb xmlTextWriterEndElement(writer); /* maxinuse */ 2150193149Sdougb 2151193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"); 2152193149Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2153193149Sdougb summary->blocksize += ctx->basic_table_count * 2154193149Sdougb NUM_BASIC_BLOCKS * ctx->mem_target; 2155193149Sdougb xmlTextWriterWriteFormatString(writer, 2156193149Sdougb "%" ISC_PRINT_QUADFORMAT "u", 2157193149Sdougb (isc_uint64_t) 2158193149Sdougb ctx->basic_table_count * 2159193149Sdougb NUM_BASIC_BLOCKS * 2160193149Sdougb ctx->mem_target); 2161193149Sdougb } else 2162193149Sdougb xmlTextWriterWriteFormatString(writer, "%s", "-"); 2163193149Sdougb xmlTextWriterEndElement(writer); /* blocksize */ 2164193149Sdougb 2165193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"); 2166193149Sdougb xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt); 2167193149Sdougb xmlTextWriterEndElement(writer); /* pools */ 2168193149Sdougb summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t); 2169193149Sdougb 2170193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"); 2171193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2172193149Sdougb (isc_uint64_t)ctx->hi_water); 2173193149Sdougb xmlTextWriterEndElement(writer); /* hiwater */ 2174193149Sdougb 2175193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"); 2176193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2177193149Sdougb (isc_uint64_t)ctx->lo_water); 2178193149Sdougb xmlTextWriterEndElement(writer); /* lowater */ 2179193149Sdougb 2180193149Sdougb MCTXUNLOCK(ctx, &ctx->lock); 2181193149Sdougb 2182193149Sdougb xmlTextWriterEndElement(writer); /* context */ 2183193149Sdougb} 2184193149Sdougb 2185193149Sdougbvoid 2186193149Sdougbisc_mem_renderxml(xmlTextWriterPtr writer) { 2187193149Sdougb isc_mem_t *ctx; 2188193149Sdougb summarystat_t summary; 2189193149Sdougb isc_uint64_t lost; 2190193149Sdougb 2191193149Sdougb memset(&summary, 0, sizeof(summary)); 2192193149Sdougb 2193193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"); 2194193149Sdougb 2195193149Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2196193149Sdougb 2197193149Sdougb LOCK(&lock); 2198193149Sdougb lost = totallost; 2199193149Sdougb for (ctx = ISC_LIST_HEAD(contexts); 2200193149Sdougb ctx != NULL; 2201193149Sdougb ctx = ISC_LIST_NEXT(ctx, link)) { 2202193149Sdougb renderctx(ctx, &summary, writer); 2203193149Sdougb } 2204193149Sdougb UNLOCK(&lock); 2205193149Sdougb 2206193149Sdougb xmlTextWriterEndElement(writer); /* contexts */ 2207193149Sdougb 2208193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"); 2209193149Sdougb 2210193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"); 2211193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2212193149Sdougb summary.total); 2213193149Sdougb xmlTextWriterEndElement(writer); /* TotalUse */ 2214193149Sdougb 2215193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"); 2216193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2217193149Sdougb summary.inuse); 2218193149Sdougb xmlTextWriterEndElement(writer); /* InUse */ 2219193149Sdougb 2220193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"); 2221193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2222193149Sdougb summary.blocksize); 2223193149Sdougb xmlTextWriterEndElement(writer); /* BlockSize */ 2224193149Sdougb 2225193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"); 2226193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2227193149Sdougb summary.contextsize); 2228193149Sdougb xmlTextWriterEndElement(writer); /* ContextSize */ 2229193149Sdougb 2230193149Sdougb xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"); 2231193149Sdougb xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2232193149Sdougb lost); 2233193149Sdougb xmlTextWriterEndElement(writer); /* Lost */ 2234193149Sdougb 2235193149Sdougb xmlTextWriterEndElement(writer); /* summary */ 2236193149Sdougb} 2237193149Sdougb 2238193149Sdougb#endif /* HAVE_LIBXML2 */ 2239