1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2010, 2012-2014 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 18234010Sdougb/* $Id$ */ 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 */ 63224092Sdougbtypedef struct isc__mem isc__mem_t; 64224092Sdougbtypedef struct isc__mempool isc__mempool_t; 65224092Sdougb 66135446Strhodes#if ISC_MEM_TRACKLINES 67135446Strhodestypedef struct debuglink debuglink_t; 68135446Strhodesstruct debuglink { 69135446Strhodes ISC_LINK(debuglink_t) link; 70135446Strhodes const void *ptr[DEBUGLIST_COUNT]; 71262706Serwin size_t size[DEBUGLIST_COUNT]; 72135446Strhodes const char *file[DEBUGLIST_COUNT]; 73135446Strhodes unsigned int line[DEBUGLIST_COUNT]; 74135446Strhodes unsigned int count; 75135446Strhodes}; 76135446Strhodes 77135446Strhodes#define FLARG_PASS , file, line 78218384Sdougb#define FLARG , const char *file, unsigned int line 79135446Strhodes#else 80135446Strhodes#define FLARG_PASS 81135446Strhodes#define FLARG 82135446Strhodes#endif 83135446Strhodes 84135446Strhodestypedef struct element element; 85135446Strhodesstruct element { 86135446Strhodes element * next; 87135446Strhodes}; 88135446Strhodes 89135446Strhodestypedef struct { 90170222Sdougb /*! 91135446Strhodes * This structure must be ALIGNMENT_SIZE bytes. 92135446Strhodes */ 93135446Strhodes union { 94135446Strhodes size_t size; 95224092Sdougb isc__mem_t *ctx; 96135446Strhodes char bytes[ALIGNMENT_SIZE]; 97135446Strhodes } u; 98135446Strhodes} size_info; 99135446Strhodes 100135446Strhodesstruct stats { 101135446Strhodes unsigned long gets; 102135446Strhodes unsigned long totalgets; 103135446Strhodes unsigned long blocks; 104135446Strhodes unsigned long freefrags; 105135446Strhodes}; 106135446Strhodes 107135446Strhodes#define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C') 108135446Strhodes#define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC) 109135446Strhodes 110135446Strhodes#if ISC_MEM_TRACKLINES 111135446Strhodestypedef ISC_LIST(debuglink_t) debuglist_t; 112135446Strhodes#endif 113135446Strhodes 114170222Sdougb/* List of all active memory contexts. */ 115170222Sdougb 116224092Sdougbstatic ISC_LIST(isc__mem_t) contexts; 117170222Sdougbstatic isc_once_t once = ISC_ONCE_INIT; 118170222Sdougbstatic isc_mutex_t lock; 119170222Sdougb 120193149Sdougb/*% 121193149Sdougb * Total size of lost memory due to a bug of external library. 122193149Sdougb * Locked by the global lock. 123193149Sdougb */ 124193149Sdougbstatic isc_uint64_t totallost; 125193149Sdougb 126224092Sdougbstruct isc__mem { 127224092Sdougb isc_mem_t common; 128135446Strhodes isc_ondestroy_t ondestroy; 129170222Sdougb unsigned int flags; 130135446Strhodes isc_mutex_t lock; 131135446Strhodes isc_memalloc_t memalloc; 132135446Strhodes isc_memfree_t memfree; 133135446Strhodes void * arg; 134135446Strhodes size_t max_size; 135135446Strhodes isc_boolean_t checkfree; 136135446Strhodes struct stats * stats; 137135446Strhodes unsigned int references; 138193149Sdougb char name[16]; 139193149Sdougb void * tag; 140135446Strhodes size_t quota; 141135446Strhodes size_t total; 142135446Strhodes size_t inuse; 143135446Strhodes size_t maxinuse; 144135446Strhodes size_t hi_water; 145135446Strhodes size_t lo_water; 146135446Strhodes isc_boolean_t hi_called; 147214586Sdougb isc_boolean_t is_overmem; 148135446Strhodes isc_mem_water_t water; 149135446Strhodes void * water_arg; 150224092Sdougb ISC_LIST(isc__mempool_t) pools; 151193149Sdougb unsigned int poolcnt; 152135446Strhodes 153170222Sdougb /* ISC_MEMFLAG_INTERNAL */ 154135446Strhodes size_t mem_target; 155135446Strhodes element ** freelists; 156135446Strhodes element * basic_blocks; 157135446Strhodes unsigned char ** basic_table; 158135446Strhodes unsigned int basic_table_count; 159135446Strhodes unsigned int basic_table_size; 160135446Strhodes unsigned char * lowest; 161135446Strhodes unsigned char * highest; 162135446Strhodes 163135446Strhodes#if ISC_MEM_TRACKLINES 164135446Strhodes debuglist_t * debuglist; 165193149Sdougb unsigned int debuglistcnt; 166135446Strhodes#endif 167135446Strhodes 168135446Strhodes unsigned int memalloc_failures; 169224092Sdougb ISC_LINK(isc__mem_t) link; 170135446Strhodes}; 171135446Strhodes 172135446Strhodes#define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p') 173135446Strhodes#define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC) 174135446Strhodes 175224092Sdougbstruct isc__mempool { 176135446Strhodes /* always unlocked */ 177224092Sdougb isc_mempool_t common; /*%< common header of mempool's */ 178170222Sdougb isc_mutex_t *lock; /*%< optional lock */ 179224092Sdougb isc__mem_t *mctx; /*%< our memory context */ 180170222Sdougb /*%< locked via the memory context's lock */ 181224092Sdougb ISC_LINK(isc__mempool_t) link; /*%< next pool in this mem context */ 182170222Sdougb /*%< optionally locked from here down */ 183170222Sdougb element *items; /*%< low water item list */ 184170222Sdougb size_t size; /*%< size of each item on this pool */ 185170222Sdougb unsigned int maxalloc; /*%< max number of items allowed */ 186170222Sdougb unsigned int allocated; /*%< # of items currently given out */ 187170222Sdougb unsigned int freecount; /*%< # of items on reserved list */ 188170222Sdougb unsigned int freemax; /*%< # of items allowed on free list */ 189170222Sdougb unsigned int fillcount; /*%< # of items to fetch on each fill */ 190170222Sdougb /*%< Stats only. */ 191170222Sdougb unsigned int gets; /*%< # of requests to this pool */ 192170222Sdougb /*%< Debugging only. */ 193135446Strhodes#if ISC_MEMPOOL_NAMES 194170222Sdougb char name[16]; /*%< printed name in stats reports */ 195135446Strhodes#endif 196135446Strhodes}; 197135446Strhodes 198135446Strhodes/* 199135446Strhodes * Private Inline-able. 200135446Strhodes */ 201135446Strhodes 202135446Strhodes#if ! ISC_MEM_TRACKLINES 203135446Strhodes#define ADD_TRACE(a, b, c, d, e) 204135446Strhodes#define DELETE_TRACE(a, b, c, d, e) 205254402Serwin#define ISC_MEMFUNC_SCOPE 206135446Strhodes#else 207135446Strhodes#define ADD_TRACE(a, b, c, d, e) \ 208135446Strhodes do { \ 209135446Strhodes if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \ 210135446Strhodes ISC_MEM_DEBUGRECORD)) != 0 && \ 211135446Strhodes b != NULL) \ 212186462Sdougb add_trace_entry(a, b, c, d, e); \ 213135446Strhodes } while (0) 214135446Strhodes#define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e) 215135446Strhodes 216135446Strhodesstatic void 217224092Sdougbprint_active(isc__mem_t *ctx, FILE *out); 218135446Strhodes 219224092Sdougb/*% 220224092Sdougb * The following can be either static or public, depending on build environment. 221224092Sdougb */ 222224092Sdougb 223224092Sdougb#ifdef BIND9 224224092Sdougb#define ISC_MEMFUNC_SCOPE 225224092Sdougb#else 226224092Sdougb#define ISC_MEMFUNC_SCOPE static 227224092Sdougb#endif 228224092Sdougb 229224092SdougbISC_MEMFUNC_SCOPE isc_result_t 230224092Sdougbisc__mem_createx(size_t init_max_size, size_t target_size, 231224092Sdougb isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 232224092Sdougb isc_mem_t **ctxp); 233224092SdougbISC_MEMFUNC_SCOPE isc_result_t 234224092Sdougbisc__mem_createx2(size_t init_max_size, size_t target_size, 235224092Sdougb isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 236224092Sdougb isc_mem_t **ctxp, unsigned int flags); 237224092SdougbISC_MEMFUNC_SCOPE isc_result_t 238224092Sdougbisc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp); 239224092SdougbISC_MEMFUNC_SCOPE isc_result_t 240224092Sdougbisc__mem_create2(size_t init_max_size, size_t target_size, 241224092Sdougb isc_mem_t **ctxp, unsigned int flags); 242224092SdougbISC_MEMFUNC_SCOPE void 243224092Sdougbisc__mem_attach(isc_mem_t *source, isc_mem_t **targetp); 244224092SdougbISC_MEMFUNC_SCOPE void 245224092Sdougbisc__mem_detach(isc_mem_t **ctxp); 246224092SdougbISC_MEMFUNC_SCOPE void 247224092Sdougbisc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG); 248224092SdougbISC_MEMFUNC_SCOPE void 249224092Sdougbisc__mem_destroy(isc_mem_t **ctxp); 250224092SdougbISC_MEMFUNC_SCOPE isc_result_t 251224092Sdougbisc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event); 252224092SdougbISC_MEMFUNC_SCOPE void * 253224092Sdougbisc___mem_get(isc_mem_t *ctx, size_t size FLARG); 254224092SdougbISC_MEMFUNC_SCOPE void 255224092Sdougbisc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG); 256224092SdougbISC_MEMFUNC_SCOPE void 257224092Sdougbisc__mem_stats(isc_mem_t *ctx, FILE *out); 258224092SdougbISC_MEMFUNC_SCOPE void * 259224092Sdougbisc___mem_allocate(isc_mem_t *ctx, size_t size FLARG); 260224092SdougbISC_MEMFUNC_SCOPE void * 261224092Sdougbisc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG); 262224092SdougbISC_MEMFUNC_SCOPE void 263224092Sdougbisc___mem_free(isc_mem_t *ctx, void *ptr FLARG); 264224092SdougbISC_MEMFUNC_SCOPE char * 265224092Sdougbisc___mem_strdup(isc_mem_t *mctx, const char *s FLARG); 266224092SdougbISC_MEMFUNC_SCOPE void 267224092Sdougbisc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag); 268224092SdougbISC_MEMFUNC_SCOPE void 269224092Sdougbisc__mem_setquota(isc_mem_t *ctx, size_t quota); 270224092SdougbISC_MEMFUNC_SCOPE size_t 271224092Sdougbisc__mem_getquota(isc_mem_t *ctx); 272224092SdougbISC_MEMFUNC_SCOPE size_t 273224092Sdougbisc__mem_inuse(isc_mem_t *ctx); 274224092SdougbISC_MEMFUNC_SCOPE isc_boolean_t 275224092Sdougbisc__mem_isovermem(isc_mem_t *ctx); 276224092SdougbISC_MEMFUNC_SCOPE void 277224092Sdougbisc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, 278224092Sdougb size_t hiwater, size_t lowater); 279224092SdougbISC_MEMFUNC_SCOPE void 280224092Sdougbisc__mem_waterack(isc_mem_t *ctx0, int flag); 281224092SdougbISC_MEMFUNC_SCOPE void 282224092Sdougbisc__mem_setname(isc_mem_t *ctx, const char *name, void *tag); 283224092SdougbISC_MEMFUNC_SCOPE const char * 284224092Sdougbisc__mem_getname(isc_mem_t *ctx); 285224092SdougbISC_MEMFUNC_SCOPE void * 286224092Sdougbisc__mem_gettag(isc_mem_t *ctx); 287224092SdougbISC_MEMFUNC_SCOPE isc_result_t 288224092Sdougbisc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp); 289224092SdougbISC_MEMFUNC_SCOPE void 290224092Sdougbisc__mempool_setname(isc_mempool_t *mpctx, const char *name); 291224092SdougbISC_MEMFUNC_SCOPE void 292224092Sdougbisc__mempool_destroy(isc_mempool_t **mpctxp); 293224092SdougbISC_MEMFUNC_SCOPE void 294224092Sdougbisc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock); 295224092SdougbISC_MEMFUNC_SCOPE void * 296224092Sdougbisc___mempool_get(isc_mempool_t *mpctx FLARG); 297224092SdougbISC_MEMFUNC_SCOPE void 298224092Sdougbisc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG); 299224092SdougbISC_MEMFUNC_SCOPE void 300224092Sdougbisc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit); 301224092SdougbISC_MEMFUNC_SCOPE unsigned int 302224092Sdougbisc__mempool_getfreemax(isc_mempool_t *mpctx); 303224092SdougbISC_MEMFUNC_SCOPE unsigned int 304224092Sdougbisc__mempool_getfreecount(isc_mempool_t *mpctx); 305224092SdougbISC_MEMFUNC_SCOPE void 306224092Sdougbisc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit); 307224092SdougbISC_MEMFUNC_SCOPE unsigned int 308224092Sdougbisc__mempool_getmaxalloc(isc_mempool_t *mpctx); 309224092SdougbISC_MEMFUNC_SCOPE unsigned int 310224092Sdougbisc__mempool_getallocated(isc_mempool_t *mpctx); 311224092SdougbISC_MEMFUNC_SCOPE void 312224092Sdougbisc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit); 313224092SdougbISC_MEMFUNC_SCOPE unsigned int 314224092Sdougbisc__mempool_getfillcount(isc_mempool_t *mpctx); 315224092Sdougb#ifdef BIND9 316224092SdougbISC_MEMFUNC_SCOPE void 317224092Sdougbisc__mem_printactive(isc_mem_t *ctx0, FILE *file); 318224092SdougbISC_MEMFUNC_SCOPE void 319224092Sdougbisc__mem_printallactive(FILE *file); 320224092SdougbISC_MEMFUNC_SCOPE void 321224092Sdougbisc__mem_checkdestroyed(FILE *file); 322224092SdougbISC_MEMFUNC_SCOPE unsigned int 323224092Sdougbisc__mem_references(isc_mem_t *ctx0); 324224092Sdougb#endif 325254402Serwin#endif /* ISC_MEM_TRACKLINES */ 326224092Sdougb 327224092Sdougbstatic struct isc__memmethods { 328224092Sdougb isc_memmethods_t methods; 329224092Sdougb 330224092Sdougb /*% 331224092Sdougb * The following are defined just for avoiding unused static functions. 332224092Sdougb */ 333224092Sdougb#ifndef BIND9 334224092Sdougb void *createx, *create, *create2, *ondestroy, *stats, 335224092Sdougb *setquota, *getquota, *setname, *getname, *gettag; 336224092Sdougb#endif 337224092Sdougb} memmethods = { 338224092Sdougb { 339224092Sdougb isc__mem_attach, 340224092Sdougb isc__mem_detach, 341224092Sdougb isc__mem_destroy, 342224092Sdougb isc___mem_get, 343224092Sdougb isc___mem_put, 344224092Sdougb isc___mem_putanddetach, 345224092Sdougb isc___mem_allocate, 346224092Sdougb isc___mem_reallocate, 347224092Sdougb isc___mem_strdup, 348224092Sdougb isc___mem_free, 349224092Sdougb isc__mem_setdestroycheck, 350224092Sdougb isc__mem_setwater, 351224092Sdougb isc__mem_waterack, 352224092Sdougb isc__mem_inuse, 353224092Sdougb isc__mem_isovermem, 354224092Sdougb isc__mempool_create 355224092Sdougb } 356224092Sdougb#ifndef BIND9 357224092Sdougb , 358224092Sdougb (void *)isc__mem_createx, (void *)isc__mem_create, 359224092Sdougb (void *)isc__mem_create2, (void *)isc__mem_ondestroy, 360224092Sdougb (void *)isc__mem_stats, (void *)isc__mem_setquota, 361224092Sdougb (void *)isc__mem_getquota, (void *)isc__mem_setname, 362224092Sdougb (void *)isc__mem_getname, (void *)isc__mem_gettag 363224092Sdougb#endif 364224092Sdougb}; 365224092Sdougb 366224092Sdougbstatic struct isc__mempoolmethods { 367224092Sdougb isc_mempoolmethods_t methods; 368224092Sdougb 369224092Sdougb /*% 370224092Sdougb * The following are defined just for avoiding unused static functions. 371224092Sdougb */ 372224092Sdougb#ifndef BIND9 373224092Sdougb void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount; 374224092Sdougb#endif 375224092Sdougb} mempoolmethods = { 376224092Sdougb { 377224092Sdougb isc__mempool_destroy, 378224092Sdougb isc___mempool_get, 379224092Sdougb isc___mempool_put, 380224092Sdougb isc__mempool_getallocated, 381224092Sdougb isc__mempool_setmaxalloc, 382224092Sdougb isc__mempool_setfreemax, 383224092Sdougb isc__mempool_setname, 384224092Sdougb isc__mempool_associatelock, 385224092Sdougb isc__mempool_setfillcount 386224092Sdougb } 387224092Sdougb#ifndef BIND9 388224092Sdougb , 389224092Sdougb (void *)isc__mempool_getfreemax, (void *)isc__mempool_getfreecount, 390224092Sdougb (void *)isc__mempool_getmaxalloc, (void *)isc__mempool_getfillcount 391224092Sdougb#endif 392224092Sdougb}; 393224092Sdougb 394254402Serwin#if ISC_MEM_TRACKLINES 395170222Sdougb/*! 396135446Strhodes * mctx must be locked. 397135446Strhodes */ 398135446Strhodesstatic inline void 399262706Serwinadd_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size FLARG) { 400135446Strhodes debuglink_t *dl; 401135446Strhodes unsigned int i; 402262706Serwin size_t mysize = size; 403135446Strhodes 404135446Strhodes if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) 405135446Strhodes fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 406135446Strhodes ISC_MSG_ADDTRACE, 407135446Strhodes "add %p size %u " 408135446Strhodes "file %s line %u mctx %p\n"), 409135446Strhodes ptr, size, file, line, mctx); 410135446Strhodes 411135446Strhodes if (mctx->debuglist == NULL) 412135446Strhodes return; 413135446Strhodes 414218384Sdougb if (mysize > mctx->max_size) 415218384Sdougb mysize = mctx->max_size; 416135446Strhodes 417218384Sdougb dl = ISC_LIST_HEAD(mctx->debuglist[mysize]); 418135446Strhodes while (dl != NULL) { 419135446Strhodes if (dl->count == DEBUGLIST_COUNT) 420135446Strhodes goto next; 421135446Strhodes for (i = 0; i < DEBUGLIST_COUNT; i++) { 422135446Strhodes if (dl->ptr[i] == NULL) { 423135446Strhodes dl->ptr[i] = ptr; 424135446Strhodes dl->size[i] = size; 425135446Strhodes dl->file[i] = file; 426135446Strhodes dl->line[i] = line; 427135446Strhodes dl->count++; 428135446Strhodes return; 429135446Strhodes } 430135446Strhodes } 431135446Strhodes next: 432135446Strhodes dl = ISC_LIST_NEXT(dl, link); 433135446Strhodes } 434135446Strhodes 435135446Strhodes dl = malloc(sizeof(debuglink_t)); 436135446Strhodes INSIST(dl != NULL); 437135446Strhodes 438135446Strhodes ISC_LINK_INIT(dl, link); 439135446Strhodes for (i = 1; i < DEBUGLIST_COUNT; i++) { 440135446Strhodes dl->ptr[i] = NULL; 441135446Strhodes dl->size[i] = 0; 442135446Strhodes dl->file[i] = NULL; 443135446Strhodes dl->line[i] = 0; 444135446Strhodes } 445135446Strhodes 446135446Strhodes dl->ptr[0] = ptr; 447135446Strhodes dl->size[0] = size; 448135446Strhodes dl->file[0] = file; 449135446Strhodes dl->line[0] = line; 450135446Strhodes dl->count = 1; 451135446Strhodes 452218384Sdougb ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link); 453193149Sdougb mctx->debuglistcnt++; 454135446Strhodes} 455135446Strhodes 456135446Strhodesstatic inline void 457262706Serwindelete_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size, 458135446Strhodes const char *file, unsigned int line) 459135446Strhodes{ 460135446Strhodes debuglink_t *dl; 461135446Strhodes unsigned int i; 462135446Strhodes 463135446Strhodes if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) 464135446Strhodes fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 465135446Strhodes ISC_MSG_DELTRACE, 466135446Strhodes "del %p size %u " 467135446Strhodes "file %s line %u mctx %p\n"), 468135446Strhodes ptr, size, file, line, mctx); 469135446Strhodes 470135446Strhodes if (mctx->debuglist == NULL) 471135446Strhodes return; 472135446Strhodes 473135446Strhodes if (size > mctx->max_size) 474135446Strhodes size = mctx->max_size; 475135446Strhodes 476135446Strhodes dl = ISC_LIST_HEAD(mctx->debuglist[size]); 477135446Strhodes while (dl != NULL) { 478135446Strhodes for (i = 0; i < DEBUGLIST_COUNT; i++) { 479135446Strhodes if (dl->ptr[i] == ptr) { 480135446Strhodes dl->ptr[i] = NULL; 481135446Strhodes dl->size[i] = 0; 482135446Strhodes dl->file[i] = NULL; 483135446Strhodes dl->line[i] = 0; 484135446Strhodes 485135446Strhodes INSIST(dl->count > 0); 486135446Strhodes dl->count--; 487135446Strhodes if (dl->count == 0) { 488135446Strhodes ISC_LIST_UNLINK(mctx->debuglist[size], 489135446Strhodes dl, link); 490135446Strhodes free(dl); 491135446Strhodes } 492135446Strhodes return; 493135446Strhodes } 494135446Strhodes } 495135446Strhodes dl = ISC_LIST_NEXT(dl, link); 496135446Strhodes } 497135446Strhodes 498135446Strhodes /* 499135446Strhodes * If we get here, we didn't find the item on the list. We're 500135446Strhodes * screwed. 501135446Strhodes */ 502135446Strhodes INSIST(dl != NULL); 503135446Strhodes} 504135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 505135446Strhodes 506135446Strhodesstatic inline size_t 507135446Strhodesrmsize(size_t size) { 508135446Strhodes /* 509186462Sdougb * round down to ALIGNMENT_SIZE 510135446Strhodes */ 511135446Strhodes return (size & (~(ALIGNMENT_SIZE - 1))); 512135446Strhodes} 513135446Strhodes 514135446Strhodesstatic inline size_t 515135446Strhodesquantize(size_t size) { 516170222Sdougb /*! 517135446Strhodes * Round up the result in order to get a size big 518135446Strhodes * enough to satisfy the request and be aligned on ALIGNMENT_SIZE 519135446Strhodes * byte boundaries. 520135446Strhodes */ 521135446Strhodes 522170222Sdougb if (size == 0U) 523135446Strhodes return (ALIGNMENT_SIZE); 524135446Strhodes return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1))); 525135446Strhodes} 526135446Strhodes 527135446Strhodesstatic inline isc_boolean_t 528224092Sdougbmore_basic_blocks(isc__mem_t *ctx) { 529135446Strhodes void *new; 530135446Strhodes unsigned char *curr, *next; 531135446Strhodes unsigned char *first, *last; 532135446Strhodes unsigned char **table; 533135446Strhodes unsigned int table_size; 534135446Strhodes size_t increment; 535135446Strhodes int i; 536135446Strhodes 537135446Strhodes /* Require: we hold the context lock. */ 538135446Strhodes 539135446Strhodes /* 540135446Strhodes * Did we hit the quota for this context? 541135446Strhodes */ 542135446Strhodes increment = NUM_BASIC_BLOCKS * ctx->mem_target; 543170222Sdougb if (ctx->quota != 0U && ctx->total + increment > ctx->quota) 544135446Strhodes return (ISC_FALSE); 545135446Strhodes 546135446Strhodes INSIST(ctx->basic_table_count <= ctx->basic_table_size); 547135446Strhodes if (ctx->basic_table_count == ctx->basic_table_size) { 548135446Strhodes table_size = ctx->basic_table_size + TABLE_INCREMENT; 549135446Strhodes table = (ctx->memalloc)(ctx->arg, 550135446Strhodes table_size * sizeof(unsigned char *)); 551135446Strhodes if (table == NULL) { 552135446Strhodes ctx->memalloc_failures++; 553135446Strhodes return (ISC_FALSE); 554135446Strhodes } 555135446Strhodes if (ctx->basic_table_size != 0) { 556262706Serwin memmove(table, ctx->basic_table, 557262706Serwin ctx->basic_table_size * 558262706Serwin sizeof(unsigned char *)); 559135446Strhodes (ctx->memfree)(ctx->arg, ctx->basic_table); 560135446Strhodes } 561135446Strhodes ctx->basic_table = table; 562135446Strhodes ctx->basic_table_size = table_size; 563135446Strhodes } 564135446Strhodes 565135446Strhodes new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target); 566135446Strhodes if (new == NULL) { 567135446Strhodes ctx->memalloc_failures++; 568135446Strhodes return (ISC_FALSE); 569135446Strhodes } 570135446Strhodes ctx->total += increment; 571135446Strhodes ctx->basic_table[ctx->basic_table_count] = new; 572135446Strhodes ctx->basic_table_count++; 573135446Strhodes 574135446Strhodes curr = new; 575135446Strhodes next = curr + ctx->mem_target; 576135446Strhodes for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { 577135446Strhodes ((element *)curr)->next = (element *)next; 578135446Strhodes curr = next; 579135446Strhodes next += ctx->mem_target; 580135446Strhodes } 581135446Strhodes /* 582135446Strhodes * curr is now pointing at the last block in the 583135446Strhodes * array. 584135446Strhodes */ 585135446Strhodes ((element *)curr)->next = NULL; 586135446Strhodes first = new; 587135446Strhodes last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1; 588135446Strhodes if (first < ctx->lowest || ctx->lowest == NULL) 589135446Strhodes ctx->lowest = first; 590135446Strhodes if (last > ctx->highest) 591135446Strhodes ctx->highest = last; 592135446Strhodes ctx->basic_blocks = new; 593135446Strhodes 594135446Strhodes return (ISC_TRUE); 595135446Strhodes} 596135446Strhodes 597135446Strhodesstatic inline isc_boolean_t 598224092Sdougbmore_frags(isc__mem_t *ctx, size_t new_size) { 599135446Strhodes int i, frags; 600135446Strhodes size_t total_size; 601135446Strhodes void *new; 602135446Strhodes unsigned char *curr, *next; 603135446Strhodes 604170222Sdougb /*! 605135446Strhodes * Try to get more fragments by chopping up a basic block. 606135446Strhodes */ 607135446Strhodes 608135446Strhodes if (ctx->basic_blocks == NULL) { 609135446Strhodes if (!more_basic_blocks(ctx)) { 610135446Strhodes /* 611135446Strhodes * We can't get more memory from the OS, or we've 612135446Strhodes * hit the quota for this context. 613135446Strhodes */ 614135446Strhodes /* 615135446Strhodes * XXXRTH "At quota" notification here. 616135446Strhodes */ 617135446Strhodes return (ISC_FALSE); 618135446Strhodes } 619135446Strhodes } 620135446Strhodes 621135446Strhodes total_size = ctx->mem_target; 622135446Strhodes new = ctx->basic_blocks; 623135446Strhodes ctx->basic_blocks = ctx->basic_blocks->next; 624262706Serwin frags = (int)(total_size / new_size); 625135446Strhodes ctx->stats[new_size].blocks++; 626135446Strhodes ctx->stats[new_size].freefrags += frags; 627135446Strhodes /* 628135446Strhodes * Set up a linked-list of blocks of size 629135446Strhodes * "new_size". 630135446Strhodes */ 631135446Strhodes curr = new; 632135446Strhodes next = curr + new_size; 633135446Strhodes total_size -= new_size; 634135446Strhodes for (i = 0; i < (frags - 1); i++) { 635135446Strhodes ((element *)curr)->next = (element *)next; 636135446Strhodes curr = next; 637135446Strhodes next += new_size; 638135446Strhodes total_size -= new_size; 639135446Strhodes } 640135446Strhodes /* 641135446Strhodes * Add the remaining fragment of the basic block to a free list. 642135446Strhodes */ 643135446Strhodes total_size = rmsize(total_size); 644170222Sdougb if (total_size > 0U) { 645135446Strhodes ((element *)next)->next = ctx->freelists[total_size]; 646135446Strhodes ctx->freelists[total_size] = (element *)next; 647135446Strhodes ctx->stats[total_size].freefrags++; 648135446Strhodes } 649135446Strhodes /* 650135446Strhodes * curr is now pointing at the last block in the 651135446Strhodes * array. 652135446Strhodes */ 653135446Strhodes ((element *)curr)->next = NULL; 654135446Strhodes ctx->freelists[new_size] = new; 655135446Strhodes 656135446Strhodes return (ISC_TRUE); 657135446Strhodes} 658135446Strhodes 659135446Strhodesstatic inline void * 660224092Sdougbmem_getunlocked(isc__mem_t *ctx, size_t size) { 661135446Strhodes size_t new_size = quantize(size); 662135446Strhodes void *ret; 663135446Strhodes 664135446Strhodes if (size >= ctx->max_size || new_size >= ctx->max_size) { 665135446Strhodes /* 666135446Strhodes * memget() was called on something beyond our upper limit. 667135446Strhodes */ 668170222Sdougb if (ctx->quota != 0U && ctx->total + size > ctx->quota) { 669135446Strhodes ret = NULL; 670135446Strhodes goto done; 671135446Strhodes } 672135446Strhodes ret = (ctx->memalloc)(ctx->arg, size); 673135446Strhodes if (ret == NULL) { 674135446Strhodes ctx->memalloc_failures++; 675135446Strhodes goto done; 676135446Strhodes } 677135446Strhodes ctx->total += size; 678135446Strhodes ctx->inuse += size; 679135446Strhodes ctx->stats[ctx->max_size].gets++; 680135446Strhodes ctx->stats[ctx->max_size].totalgets++; 681135446Strhodes /* 682135446Strhodes * If we don't set new_size to size, then the 683135446Strhodes * ISC_MEM_FILL code might write over bytes we 684135446Strhodes * don't own. 685135446Strhodes */ 686135446Strhodes new_size = size; 687135446Strhodes goto done; 688135446Strhodes } 689135446Strhodes 690135446Strhodes /* 691135446Strhodes * If there are no blocks in the free list for this size, get a chunk 692135446Strhodes * of memory and then break it up into "new_size"-sized blocks, adding 693135446Strhodes * them to the free list. 694135446Strhodes */ 695135446Strhodes if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size)) 696135446Strhodes return (NULL); 697135446Strhodes 698135446Strhodes /* 699135446Strhodes * The free list uses the "rounded-up" size "new_size". 700135446Strhodes */ 701135446Strhodes ret = ctx->freelists[new_size]; 702135446Strhodes ctx->freelists[new_size] = ctx->freelists[new_size]->next; 703135446Strhodes 704135446Strhodes /* 705135446Strhodes * The stats[] uses the _actual_ "size" requested by the 706135446Strhodes * caller, with the caveat (in the code above) that "size" >= the 707135446Strhodes * max. size (max_size) ends up getting recorded as a call to 708135446Strhodes * max_size. 709135446Strhodes */ 710135446Strhodes ctx->stats[size].gets++; 711135446Strhodes ctx->stats[size].totalgets++; 712135446Strhodes ctx->stats[new_size].freefrags--; 713135446Strhodes ctx->inuse += new_size; 714135446Strhodes 715135446Strhodes done: 716135446Strhodes 717135446Strhodes#if ISC_MEM_FILL 718135446Strhodes if (ret != NULL) 719135446Strhodes memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */ 720135446Strhodes#endif 721135446Strhodes 722135446Strhodes return (ret); 723135446Strhodes} 724135446Strhodes 725135446Strhodes#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN 726135446Strhodesstatic inline void 727135446Strhodescheck_overrun(void *mem, size_t size, size_t new_size) { 728135446Strhodes unsigned char *cp; 729135446Strhodes 730135446Strhodes cp = (unsigned char *)mem; 731135446Strhodes cp += size; 732135446Strhodes while (size < new_size) { 733135446Strhodes INSIST(*cp == 0xbe); 734135446Strhodes cp++; 735135446Strhodes size++; 736135446Strhodes } 737135446Strhodes} 738135446Strhodes#endif 739135446Strhodes 740135446Strhodesstatic inline void 741224092Sdougbmem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) { 742135446Strhodes size_t new_size = quantize(size); 743135446Strhodes 744135446Strhodes if (size == ctx->max_size || new_size >= ctx->max_size) { 745135446Strhodes /* 746135446Strhodes * memput() called on something beyond our upper limit. 747135446Strhodes */ 748135446Strhodes#if ISC_MEM_FILL 749135446Strhodes memset(mem, 0xde, size); /* Mnemonic for "dead". */ 750135446Strhodes#endif 751135446Strhodes (ctx->memfree)(ctx->arg, mem); 752170222Sdougb INSIST(ctx->stats[ctx->max_size].gets != 0U); 753135446Strhodes ctx->stats[ctx->max_size].gets--; 754135446Strhodes INSIST(size <= ctx->total); 755135446Strhodes ctx->inuse -= size; 756135446Strhodes ctx->total -= size; 757135446Strhodes return; 758135446Strhodes } 759135446Strhodes 760135446Strhodes#if ISC_MEM_FILL 761135446Strhodes#if ISC_MEM_CHECKOVERRUN 762135446Strhodes check_overrun(mem, size, new_size); 763135446Strhodes#endif 764135446Strhodes memset(mem, 0xde, new_size); /* Mnemonic for "dead". */ 765135446Strhodes#endif 766135446Strhodes 767135446Strhodes /* 768135446Strhodes * The free list uses the "rounded-up" size "new_size". 769135446Strhodes */ 770135446Strhodes ((element *)mem)->next = ctx->freelists[new_size]; 771135446Strhodes ctx->freelists[new_size] = (element *)mem; 772135446Strhodes 773135446Strhodes /* 774135446Strhodes * The stats[] uses the _actual_ "size" requested by the 775135446Strhodes * caller, with the caveat (in the code above) that "size" >= the 776135446Strhodes * max. size (max_size) ends up getting recorded as a call to 777135446Strhodes * max_size. 778135446Strhodes */ 779170222Sdougb INSIST(ctx->stats[size].gets != 0U); 780135446Strhodes ctx->stats[size].gets--; 781135446Strhodes ctx->stats[new_size].freefrags++; 782135446Strhodes ctx->inuse -= new_size; 783135446Strhodes} 784135446Strhodes 785170222Sdougb/*! 786135446Strhodes * Perform a malloc, doing memory filling and overrun detection as necessary. 787135446Strhodes */ 788135446Strhodesstatic inline void * 789224092Sdougbmem_get(isc__mem_t *ctx, size_t size) { 790135446Strhodes char *ret; 791135446Strhodes 792135446Strhodes#if ISC_MEM_CHECKOVERRUN 793135446Strhodes size += 1; 794135446Strhodes#endif 795135446Strhodes 796135446Strhodes ret = (ctx->memalloc)(ctx->arg, size); 797135446Strhodes if (ret == NULL) 798186462Sdougb ctx->memalloc_failures++; 799135446Strhodes 800135446Strhodes#if ISC_MEM_FILL 801135446Strhodes if (ret != NULL) 802135446Strhodes memset(ret, 0xbe, size); /* Mnemonic for "beef". */ 803135446Strhodes#else 804135446Strhodes# if ISC_MEM_CHECKOVERRUN 805135446Strhodes if (ret != NULL) 806135446Strhodes ret[size-1] = 0xbe; 807135446Strhodes# endif 808135446Strhodes#endif 809135446Strhodes 810135446Strhodes return (ret); 811135446Strhodes} 812135446Strhodes 813170222Sdougb/*! 814135446Strhodes * Perform a free, doing memory filling and overrun detection as necessary. 815135446Strhodes */ 816135446Strhodesstatic inline void 817224092Sdougbmem_put(isc__mem_t *ctx, void *mem, size_t size) { 818135446Strhodes#if ISC_MEM_CHECKOVERRUN 819135446Strhodes INSIST(((unsigned char *)mem)[size] == 0xbe); 820135446Strhodes#endif 821135446Strhodes#if ISC_MEM_FILL 822135446Strhodes memset(mem, 0xde, size); /* Mnemonic for "dead". */ 823135446Strhodes#else 824135446Strhodes UNUSED(size); 825135446Strhodes#endif 826135446Strhodes (ctx->memfree)(ctx->arg, mem); 827135446Strhodes} 828135446Strhodes 829170222Sdougb/*! 830135446Strhodes * Update internal counters after a memory get. 831135446Strhodes */ 832135446Strhodesstatic inline void 833224092Sdougbmem_getstats(isc__mem_t *ctx, size_t size) { 834135446Strhodes ctx->total += size; 835135446Strhodes ctx->inuse += size; 836135446Strhodes 837135446Strhodes if (size > ctx->max_size) { 838135446Strhodes ctx->stats[ctx->max_size].gets++; 839135446Strhodes ctx->stats[ctx->max_size].totalgets++; 840135446Strhodes } else { 841135446Strhodes ctx->stats[size].gets++; 842135446Strhodes ctx->stats[size].totalgets++; 843135446Strhodes } 844135446Strhodes} 845135446Strhodes 846170222Sdougb/*! 847135446Strhodes * Update internal counters after a memory put. 848135446Strhodes */ 849135446Strhodesstatic inline void 850224092Sdougbmem_putstats(isc__mem_t *ctx, void *ptr, size_t size) { 851135446Strhodes UNUSED(ptr); 852135446Strhodes 853135446Strhodes INSIST(ctx->inuse >= size); 854135446Strhodes ctx->inuse -= size; 855135446Strhodes 856135446Strhodes if (size > ctx->max_size) { 857135446Strhodes INSIST(ctx->stats[ctx->max_size].gets > 0U); 858135446Strhodes ctx->stats[ctx->max_size].gets--; 859135446Strhodes } else { 860135446Strhodes INSIST(ctx->stats[size].gets > 0U); 861135446Strhodes ctx->stats[size].gets--; 862135446Strhodes } 863135446Strhodes} 864135446Strhodes 865135446Strhodes/* 866135446Strhodes * Private. 867135446Strhodes */ 868135446Strhodes 869135446Strhodesstatic void * 870135446Strhodesdefault_memalloc(void *arg, size_t size) { 871135446Strhodes UNUSED(arg); 872135446Strhodes if (size == 0U) 873135446Strhodes size = 1; 874135446Strhodes return (malloc(size)); 875135446Strhodes} 876135446Strhodes 877135446Strhodesstatic void 878135446Strhodesdefault_memfree(void *arg, void *ptr) { 879135446Strhodes UNUSED(arg); 880135446Strhodes free(ptr); 881135446Strhodes} 882135446Strhodes 883170222Sdougbstatic void 884170222Sdougbinitialize_action(void) { 885174187Sdougb RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS); 886174187Sdougb ISC_LIST_INIT(contexts); 887193149Sdougb totallost = 0; 888170222Sdougb} 889170222Sdougb 890135446Strhodes/* 891135446Strhodes * Public. 892135446Strhodes */ 893135446Strhodes 894224092SdougbISC_MEMFUNC_SCOPE isc_result_t 895224092Sdougbisc__mem_createx(size_t init_max_size, size_t target_size, 896224092Sdougb isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 897224092Sdougb isc_mem_t **ctxp) 898135446Strhodes{ 899224092Sdougb return (isc__mem_createx2(init_max_size, target_size, memalloc, memfree, 900224092Sdougb arg, ctxp, ISC_MEMFLAG_DEFAULT)); 901186462Sdougb 902170222Sdougb} 903170222Sdougb 904224092SdougbISC_MEMFUNC_SCOPE isc_result_t 905224092Sdougbisc__mem_createx2(size_t init_max_size, size_t target_size, 906224092Sdougb isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 907224092Sdougb isc_mem_t **ctxp, unsigned int flags) 908170222Sdougb{ 909224092Sdougb isc__mem_t *ctx; 910135446Strhodes isc_result_t result; 911135446Strhodes 912135446Strhodes REQUIRE(ctxp != NULL && *ctxp == NULL); 913135446Strhodes REQUIRE(memalloc != NULL); 914135446Strhodes REQUIRE(memfree != NULL); 915135446Strhodes 916135446Strhodes INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0); 917135446Strhodes 918170222Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 919135446Strhodes 920135446Strhodes ctx = (memalloc)(arg, sizeof(*ctx)); 921135446Strhodes if (ctx == NULL) 922135446Strhodes return (ISC_R_NOMEMORY); 923135446Strhodes 924170222Sdougb if ((flags & ISC_MEMFLAG_NOLOCK) == 0) { 925170222Sdougb result = isc_mutex_init(&ctx->lock); 926170222Sdougb if (result != ISC_R_SUCCESS) { 927170222Sdougb (memfree)(arg, ctx); 928170222Sdougb return (result); 929170222Sdougb } 930153816Sdougb } 931153816Sdougb 932135446Strhodes if (init_max_size == 0U) 933135446Strhodes ctx->max_size = DEF_MAX_SIZE; 934135446Strhodes else 935135446Strhodes ctx->max_size = init_max_size; 936170222Sdougb ctx->flags = flags; 937135446Strhodes ctx->references = 1; 938193149Sdougb memset(ctx->name, 0, sizeof(ctx->name)); 939193149Sdougb ctx->tag = NULL; 940135446Strhodes ctx->quota = 0; 941135446Strhodes ctx->total = 0; 942135446Strhodes ctx->inuse = 0; 943135446Strhodes ctx->maxinuse = 0; 944135446Strhodes ctx->hi_water = 0; 945135446Strhodes ctx->lo_water = 0; 946135446Strhodes ctx->hi_called = ISC_FALSE; 947214586Sdougb ctx->is_overmem = ISC_FALSE; 948135446Strhodes ctx->water = NULL; 949135446Strhodes ctx->water_arg = NULL; 950224092Sdougb ctx->common.impmagic = MEM_MAGIC; 951224092Sdougb ctx->common.magic = ISCAPI_MCTX_MAGIC; 952224092Sdougb ctx->common.methods = (isc_memmethods_t *)&memmethods; 953135446Strhodes isc_ondestroy_init(&ctx->ondestroy); 954135446Strhodes ctx->memalloc = memalloc; 955135446Strhodes ctx->memfree = memfree; 956135446Strhodes ctx->arg = arg; 957135446Strhodes ctx->stats = NULL; 958135446Strhodes ctx->checkfree = ISC_TRUE; 959135446Strhodes#if ISC_MEM_TRACKLINES 960135446Strhodes ctx->debuglist = NULL; 961193149Sdougb ctx->debuglistcnt = 0; 962135446Strhodes#endif 963135446Strhodes ISC_LIST_INIT(ctx->pools); 964193149Sdougb ctx->poolcnt = 0; 965135446Strhodes ctx->freelists = NULL; 966170222Sdougb ctx->basic_blocks = NULL; 967170222Sdougb ctx->basic_table = NULL; 968170222Sdougb ctx->basic_table_count = 0; 969170222Sdougb ctx->basic_table_size = 0; 970170222Sdougb ctx->lowest = NULL; 971170222Sdougb ctx->highest = NULL; 972135446Strhodes 973135446Strhodes ctx->stats = (memalloc)(arg, 974135446Strhodes (ctx->max_size+1) * sizeof(struct stats)); 975135446Strhodes if (ctx->stats == NULL) { 976135446Strhodes result = ISC_R_NOMEMORY; 977135446Strhodes goto error; 978135446Strhodes } 979135446Strhodes memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats)); 980135446Strhodes 981170222Sdougb if ((flags & ISC_MEMFLAG_INTERNAL) != 0) { 982170222Sdougb if (target_size == 0U) 983170222Sdougb ctx->mem_target = DEF_MEM_TARGET; 984170222Sdougb else 985170222Sdougb ctx->mem_target = target_size; 986170222Sdougb ctx->freelists = (memalloc)(arg, ctx->max_size * 987170222Sdougb sizeof(element *)); 988170222Sdougb if (ctx->freelists == NULL) { 989170222Sdougb result = ISC_R_NOMEMORY; 990170222Sdougb goto error; 991170222Sdougb } 992170222Sdougb memset(ctx->freelists, 0, 993170222Sdougb ctx->max_size * sizeof(element *)); 994135446Strhodes } 995135446Strhodes 996135446Strhodes#if ISC_MEM_TRACKLINES 997135446Strhodes if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) { 998135446Strhodes unsigned int i; 999135446Strhodes 1000135446Strhodes ctx->debuglist = (memalloc)(arg, 1001135446Strhodes (ctx->max_size+1) * sizeof(debuglist_t)); 1002135446Strhodes if (ctx->debuglist == NULL) { 1003135446Strhodes result = ISC_R_NOMEMORY; 1004135446Strhodes goto error; 1005135446Strhodes } 1006135446Strhodes for (i = 0; i <= ctx->max_size; i++) 1007135446Strhodes ISC_LIST_INIT(ctx->debuglist[i]); 1008135446Strhodes } 1009135446Strhodes#endif 1010135446Strhodes 1011135446Strhodes ctx->memalloc_failures = 0; 1012135446Strhodes 1013170222Sdougb LOCK(&lock); 1014170222Sdougb ISC_LIST_INITANDAPPEND(contexts, ctx, link); 1015170222Sdougb UNLOCK(&lock); 1016170222Sdougb 1017224092Sdougb *ctxp = (isc_mem_t *)ctx; 1018135446Strhodes return (ISC_R_SUCCESS); 1019135446Strhodes 1020135446Strhodes error: 1021153816Sdougb if (ctx != NULL) { 1022153816Sdougb if (ctx->stats != NULL) 1023135446Strhodes (memfree)(arg, ctx->stats); 1024153816Sdougb if (ctx->freelists != NULL) 1025135446Strhodes (memfree)(arg, ctx->freelists); 1026135446Strhodes#if ISC_MEM_TRACKLINES 1027153816Sdougb if (ctx->debuglist != NULL) 1028135446Strhodes (ctx->memfree)(ctx->arg, ctx->debuglist); 1029135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 1030170222Sdougb if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 1031170222Sdougb DESTROYLOCK(&ctx->lock); 1032135446Strhodes (memfree)(arg, ctx); 1033135446Strhodes } 1034135446Strhodes 1035135446Strhodes return (result); 1036135446Strhodes} 1037135446Strhodes 1038224092SdougbISC_MEMFUNC_SCOPE isc_result_t 1039224092Sdougbisc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) { 1040224092Sdougb return (isc__mem_createx2(init_max_size, target_size, 1041224092Sdougb default_memalloc, default_memfree, NULL, 1042224092Sdougb ctxp, ISC_MEMFLAG_DEFAULT)); 1043135446Strhodes} 1044135446Strhodes 1045224092SdougbISC_MEMFUNC_SCOPE isc_result_t 1046224092Sdougbisc__mem_create2(size_t init_max_size, size_t target_size, 1047224092Sdougb isc_mem_t **ctxp, unsigned int flags) 1048170222Sdougb{ 1049224092Sdougb return (isc__mem_createx2(init_max_size, target_size, 1050224092Sdougb default_memalloc, default_memfree, NULL, 1051224092Sdougb ctxp, flags)); 1052170222Sdougb} 1053170222Sdougb 1054135446Strhodesstatic void 1055224092Sdougbdestroy(isc__mem_t *ctx) { 1056135446Strhodes unsigned int i; 1057135446Strhodes isc_ondestroy_t ondest; 1058135446Strhodes 1059170222Sdougb LOCK(&lock); 1060170222Sdougb ISC_LIST_UNLINK(contexts, ctx, link); 1061193149Sdougb totallost += ctx->inuse; 1062170222Sdougb UNLOCK(&lock); 1063170222Sdougb 1064224092Sdougb ctx->common.impmagic = 0; 1065224092Sdougb ctx->common.magic = 0; 1066218384Sdougb 1067135446Strhodes INSIST(ISC_LIST_EMPTY(ctx->pools)); 1068135446Strhodes 1069135446Strhodes#if ISC_MEM_TRACKLINES 1070135446Strhodes if (ctx->debuglist != NULL) { 1071135446Strhodes if (ctx->checkfree) { 1072135446Strhodes for (i = 0; i <= ctx->max_size; i++) { 1073135446Strhodes if (!ISC_LIST_EMPTY(ctx->debuglist[i])) 1074135446Strhodes print_active(ctx, stderr); 1075135446Strhodes INSIST(ISC_LIST_EMPTY(ctx->debuglist[i])); 1076135446Strhodes } 1077135446Strhodes } else { 1078135446Strhodes debuglink_t *dl; 1079135446Strhodes 1080135446Strhodes for (i = 0; i <= ctx->max_size; i++) 1081135446Strhodes for (dl = ISC_LIST_HEAD(ctx->debuglist[i]); 1082135446Strhodes dl != NULL; 1083135446Strhodes dl = ISC_LIST_HEAD(ctx->debuglist[i])) { 1084135446Strhodes ISC_LIST_UNLINK(ctx->debuglist[i], 1085186462Sdougb dl, link); 1086135446Strhodes free(dl); 1087135446Strhodes } 1088135446Strhodes } 1089135446Strhodes (ctx->memfree)(ctx->arg, ctx->debuglist); 1090135446Strhodes } 1091135446Strhodes#endif 1092135446Strhodes INSIST(ctx->references == 0); 1093135446Strhodes 1094135446Strhodes if (ctx->checkfree) { 1095135446Strhodes for (i = 0; i <= ctx->max_size; i++) { 1096135446Strhodes#if ISC_MEM_TRACKLINES 1097135446Strhodes if (ctx->stats[i].gets != 0U) 1098135446Strhodes print_active(ctx, stderr); 1099135446Strhodes#endif 1100135446Strhodes INSIST(ctx->stats[i].gets == 0U); 1101135446Strhodes } 1102135446Strhodes } 1103135446Strhodes 1104135446Strhodes (ctx->memfree)(ctx->arg, ctx->stats); 1105135446Strhodes 1106170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1107170222Sdougb for (i = 0; i < ctx->basic_table_count; i++) 1108170222Sdougb (ctx->memfree)(ctx->arg, ctx->basic_table[i]); 1109170222Sdougb (ctx->memfree)(ctx->arg, ctx->freelists); 1110186462Sdougb if (ctx->basic_table != NULL) 1111186462Sdougb (ctx->memfree)(ctx->arg, ctx->basic_table); 1112170222Sdougb } 1113135446Strhodes 1114135446Strhodes ondest = ctx->ondestroy; 1115135446Strhodes 1116170222Sdougb if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 1117170222Sdougb DESTROYLOCK(&ctx->lock); 1118135446Strhodes (ctx->memfree)(ctx->arg, ctx); 1119135446Strhodes 1120135446Strhodes isc_ondestroy_notify(&ondest, ctx); 1121135446Strhodes} 1122135446Strhodes 1123224092SdougbISC_MEMFUNC_SCOPE void 1124224092Sdougbisc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) { 1125224092Sdougb isc__mem_t *source = (isc__mem_t *)source0; 1126224092Sdougb 1127135446Strhodes REQUIRE(VALID_CONTEXT(source)); 1128135446Strhodes REQUIRE(targetp != NULL && *targetp == NULL); 1129135446Strhodes 1130170222Sdougb MCTXLOCK(source, &source->lock); 1131135446Strhodes source->references++; 1132170222Sdougb MCTXUNLOCK(source, &source->lock); 1133135446Strhodes 1134224092Sdougb *targetp = (isc_mem_t *)source; 1135135446Strhodes} 1136135446Strhodes 1137224092SdougbISC_MEMFUNC_SCOPE void 1138224092Sdougbisc__mem_detach(isc_mem_t **ctxp) { 1139224092Sdougb isc__mem_t *ctx; 1140135446Strhodes isc_boolean_t want_destroy = ISC_FALSE; 1141135446Strhodes 1142135446Strhodes REQUIRE(ctxp != NULL); 1143224092Sdougb ctx = (isc__mem_t *)*ctxp; 1144135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1145135446Strhodes 1146170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1147135446Strhodes INSIST(ctx->references > 0); 1148135446Strhodes ctx->references--; 1149135446Strhodes if (ctx->references == 0) 1150135446Strhodes want_destroy = ISC_TRUE; 1151170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1152135446Strhodes 1153135446Strhodes if (want_destroy) 1154135446Strhodes destroy(ctx); 1155135446Strhodes 1156135446Strhodes *ctxp = NULL; 1157135446Strhodes} 1158135446Strhodes 1159135446Strhodes/* 1160135446Strhodes * isc_mem_putanddetach() is the equivalent of: 1161135446Strhodes * 1162135446Strhodes * mctx = NULL; 1163135446Strhodes * isc_mem_attach(ptr->mctx, &mctx); 1164135446Strhodes * isc_mem_detach(&ptr->mctx); 1165135446Strhodes * isc_mem_put(mctx, ptr, sizeof(*ptr); 1166135446Strhodes * isc_mem_detach(&mctx); 1167135446Strhodes */ 1168135446Strhodes 1169224092SdougbISC_MEMFUNC_SCOPE void 1170224092Sdougbisc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { 1171224092Sdougb isc__mem_t *ctx; 1172135446Strhodes isc_boolean_t want_destroy = ISC_FALSE; 1173170222Sdougb size_info *si; 1174170222Sdougb size_t oldsize; 1175135446Strhodes 1176135446Strhodes REQUIRE(ctxp != NULL); 1177224092Sdougb ctx = (isc__mem_t *)*ctxp; 1178135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1179135446Strhodes REQUIRE(ptr != NULL); 1180135446Strhodes 1181135446Strhodes /* 1182135446Strhodes * Must be before mem_putunlocked() as ctxp is usually within 1183135446Strhodes * [ptr..ptr+size). 1184135446Strhodes */ 1185135446Strhodes *ctxp = NULL; 1186135446Strhodes 1187170222Sdougb if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { 1188170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { 1189170222Sdougb si = &(((size_info *)ptr)[-1]); 1190170222Sdougb oldsize = si->u.size - ALIGNMENT_SIZE; 1191170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1192170222Sdougb oldsize -= ALIGNMENT_SIZE; 1193170222Sdougb INSIST(oldsize == size); 1194170222Sdougb } 1195245163Serwin isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS); 1196135446Strhodes 1197170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1198170222Sdougb ctx->references--; 1199170222Sdougb if (ctx->references == 0) 1200170222Sdougb want_destroy = ISC_TRUE; 1201170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1202170222Sdougb if (want_destroy) 1203170222Sdougb destroy(ctx); 1204170222Sdougb 1205170222Sdougb return; 1206170222Sdougb } 1207170222Sdougb 1208170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1209170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1210170222Sdougb mem_putunlocked(ctx, ptr, size); 1211170222Sdougb } else { 1212170222Sdougb mem_put(ctx, ptr, size); 1213170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1214170222Sdougb mem_putstats(ctx, ptr, size); 1215170222Sdougb } 1216170222Sdougb 1217135446Strhodes DELETE_TRACE(ctx, ptr, size, file, line); 1218135446Strhodes INSIST(ctx->references > 0); 1219135446Strhodes ctx->references--; 1220135446Strhodes if (ctx->references == 0) 1221135446Strhodes want_destroy = ISC_TRUE; 1222135446Strhodes 1223170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1224135446Strhodes 1225135446Strhodes if (want_destroy) 1226135446Strhodes destroy(ctx); 1227135446Strhodes} 1228135446Strhodes 1229224092SdougbISC_MEMFUNC_SCOPE void 1230224092Sdougbisc__mem_destroy(isc_mem_t **ctxp) { 1231224092Sdougb isc__mem_t *ctx; 1232135446Strhodes 1233135446Strhodes /* 1234135446Strhodes * This routine provides legacy support for callers who use mctxs 1235135446Strhodes * without attaching/detaching. 1236135446Strhodes */ 1237135446Strhodes 1238135446Strhodes REQUIRE(ctxp != NULL); 1239224092Sdougb ctx = (isc__mem_t *)*ctxp; 1240135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1241135446Strhodes 1242170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1243135446Strhodes#if ISC_MEM_TRACKLINES 1244135446Strhodes if (ctx->references != 1) 1245135446Strhodes print_active(ctx, stderr); 1246135446Strhodes#endif 1247135446Strhodes REQUIRE(ctx->references == 1); 1248135446Strhodes ctx->references--; 1249170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1250135446Strhodes 1251135446Strhodes destroy(ctx); 1252135446Strhodes 1253135446Strhodes *ctxp = NULL; 1254135446Strhodes} 1255135446Strhodes 1256224092SdougbISC_MEMFUNC_SCOPE isc_result_t 1257224092Sdougbisc__mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) { 1258224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1259135446Strhodes isc_result_t res; 1260135446Strhodes 1261170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1262135446Strhodes res = isc_ondestroy_register(&ctx->ondestroy, task, event); 1263170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1264135446Strhodes 1265135446Strhodes return (res); 1266135446Strhodes} 1267135446Strhodes 1268224092SdougbISC_MEMFUNC_SCOPE void * 1269224092Sdougbisc___mem_get(isc_mem_t *ctx0, size_t size FLARG) { 1270224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1271135446Strhodes void *ptr; 1272135446Strhodes isc_boolean_t call_water = ISC_FALSE; 1273135446Strhodes 1274135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1275135446Strhodes 1276170222Sdougb if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) 1277224092Sdougb return (isc__mem_allocate(ctx0, size FLARG_PASS)); 1278135446Strhodes 1279170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1280170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1281170222Sdougb ptr = mem_getunlocked(ctx, size); 1282170222Sdougb } else { 1283170222Sdougb ptr = mem_get(ctx, size); 1284170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1285170222Sdougb if (ptr != NULL) 1286170222Sdougb mem_getstats(ctx, size); 1287170222Sdougb } 1288170222Sdougb 1289135446Strhodes ADD_TRACE(ctx, ptr, size, file, line); 1290214586Sdougb if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1291214586Sdougb !ctx->is_overmem) { 1292214586Sdougb ctx->is_overmem = ISC_TRUE; 1293214586Sdougb } 1294135446Strhodes if (ctx->hi_water != 0U && !ctx->hi_called && 1295135446Strhodes ctx->inuse > ctx->hi_water) { 1296135446Strhodes call_water = ISC_TRUE; 1297135446Strhodes } 1298135446Strhodes if (ctx->inuse > ctx->maxinuse) { 1299135446Strhodes ctx->maxinuse = ctx->inuse; 1300135446Strhodes if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1301135446Strhodes (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) 1302135446Strhodes fprintf(stderr, "maxinuse = %lu\n", 1303135446Strhodes (unsigned long)ctx->inuse); 1304135446Strhodes } 1305170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1306135446Strhodes 1307135446Strhodes if (call_water) 1308135446Strhodes (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); 1309135446Strhodes 1310135446Strhodes return (ptr); 1311135446Strhodes} 1312135446Strhodes 1313224092SdougbISC_MEMFUNC_SCOPE void 1314224092Sdougbisc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) { 1315224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1316135446Strhodes isc_boolean_t call_water = ISC_FALSE; 1317170222Sdougb size_info *si; 1318170222Sdougb size_t oldsize; 1319135446Strhodes 1320135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1321135446Strhodes REQUIRE(ptr != NULL); 1322135446Strhodes 1323170222Sdougb if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { 1324170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { 1325170222Sdougb si = &(((size_info *)ptr)[-1]); 1326170222Sdougb oldsize = si->u.size - ALIGNMENT_SIZE; 1327170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1328170222Sdougb oldsize -= ALIGNMENT_SIZE; 1329170222Sdougb INSIST(oldsize == size); 1330170222Sdougb } 1331245163Serwin isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS); 1332170222Sdougb return; 1333170222Sdougb } 1334135446Strhodes 1335170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1336170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1337170222Sdougb mem_putunlocked(ctx, ptr, size); 1338170222Sdougb } else { 1339170222Sdougb mem_put(ctx, ptr, size); 1340170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1341170222Sdougb mem_putstats(ctx, ptr, size); 1342170222Sdougb } 1343170222Sdougb 1344135446Strhodes DELETE_TRACE(ctx, ptr, size, file, line); 1345135446Strhodes 1346135446Strhodes /* 1347135446Strhodes * The check against ctx->lo_water == 0 is for the condition 1348135446Strhodes * when the context was pushed over hi_water but then had 1349135446Strhodes * isc_mem_setwater() called with 0 for hi_water and lo_water. 1350135446Strhodes */ 1351214586Sdougb if (ctx->is_overmem && 1352214586Sdougb (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1353214586Sdougb ctx->is_overmem = ISC_FALSE; 1354214586Sdougb } 1355186462Sdougb if (ctx->hi_called && 1356135446Strhodes (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1357135446Strhodes if (ctx->water != NULL) 1358135446Strhodes call_water = ISC_TRUE; 1359135446Strhodes } 1360170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1361135446Strhodes 1362135446Strhodes if (call_water) 1363135446Strhodes (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1364135446Strhodes} 1365135446Strhodes 1366224092SdougbISC_MEMFUNC_SCOPE void 1367224092Sdougbisc__mem_waterack(isc_mem_t *ctx0, int flag) { 1368224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1369224092Sdougb 1370186462Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1371186462Sdougb 1372186462Sdougb MCTXLOCK(ctx, &ctx->lock); 1373186462Sdougb if (flag == ISC_MEM_LOWATER) 1374186462Sdougb ctx->hi_called = ISC_FALSE; 1375186462Sdougb else if (flag == ISC_MEM_HIWATER) 1376186462Sdougb ctx->hi_called = ISC_TRUE; 1377186462Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1378186462Sdougb} 1379186462Sdougb 1380135446Strhodes#if ISC_MEM_TRACKLINES 1381135446Strhodesstatic void 1382224092Sdougbprint_active(isc__mem_t *mctx, FILE *out) { 1383135446Strhodes if (mctx->debuglist != NULL) { 1384135446Strhodes debuglink_t *dl; 1385135446Strhodes unsigned int i, j; 1386135446Strhodes const char *format; 1387135446Strhodes isc_boolean_t found; 1388135446Strhodes 1389193149Sdougb fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1390135446Strhodes ISC_MSG_DUMPALLOC, 1391135446Strhodes "Dump of all outstanding " 1392135446Strhodes "memory allocations:\n")); 1393135446Strhodes found = ISC_FALSE; 1394135446Strhodes format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1395186462Sdougb ISC_MSG_PTRFILELINE, 1396135446Strhodes "\tptr %p size %u file %s line %u\n"); 1397135446Strhodes for (i = 0; i <= mctx->max_size; i++) { 1398135446Strhodes dl = ISC_LIST_HEAD(mctx->debuglist[i]); 1399186462Sdougb 1400135446Strhodes if (dl != NULL) 1401135446Strhodes found = ISC_TRUE; 1402135446Strhodes 1403135446Strhodes while (dl != NULL) { 1404135446Strhodes for (j = 0; j < DEBUGLIST_COUNT; j++) 1405135446Strhodes if (dl->ptr[j] != NULL) 1406135446Strhodes fprintf(out, format, 1407135446Strhodes dl->ptr[j], 1408135446Strhodes dl->size[j], 1409135446Strhodes dl->file[j], 1410135446Strhodes dl->line[j]); 1411135446Strhodes dl = ISC_LIST_NEXT(dl, link); 1412135446Strhodes } 1413135446Strhodes } 1414135446Strhodes if (!found) 1415193149Sdougb fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1416135446Strhodes ISC_MSG_NONE, "\tNone.\n")); 1417135446Strhodes } 1418135446Strhodes} 1419135446Strhodes#endif 1420135446Strhodes 1421135446Strhodes/* 1422135446Strhodes * Print the stats[] on the stream "out" with suitable formatting. 1423135446Strhodes */ 1424224092SdougbISC_MEMFUNC_SCOPE void 1425224092Sdougbisc__mem_stats(isc_mem_t *ctx0, FILE *out) { 1426224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1427135446Strhodes size_t i; 1428135446Strhodes const struct stats *s; 1429224092Sdougb const isc__mempool_t *pool; 1430135446Strhodes 1431135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1432170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1433135446Strhodes 1434135446Strhodes for (i = 0; i <= ctx->max_size; i++) { 1435135446Strhodes s = &ctx->stats[i]; 1436135446Strhodes 1437135446Strhodes if (s->totalgets == 0U && s->gets == 0U) 1438135446Strhodes continue; 1439135446Strhodes fprintf(out, "%s%5lu: %11lu gets, %11lu rem", 1440135446Strhodes (i == ctx->max_size) ? ">=" : " ", 1441135446Strhodes (unsigned long) i, s->totalgets, s->gets); 1442170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 && 1443170222Sdougb (s->blocks != 0U || s->freefrags != 0U)) 1444135446Strhodes fprintf(out, " (%lu bl, %lu ff)", 1445135446Strhodes s->blocks, s->freefrags); 1446135446Strhodes fputc('\n', out); 1447135446Strhodes } 1448135446Strhodes 1449135446Strhodes /* 1450135446Strhodes * Note that since a pool can be locked now, these stats might be 1451135446Strhodes * somewhat off if the pool is in active use at the time the stats 1452135446Strhodes * are dumped. The link fields are protected by the isc_mem_t's 1453135446Strhodes * lock, however, so walking this list and extracting integers from 1454135446Strhodes * stats fields is always safe. 1455135446Strhodes */ 1456135446Strhodes pool = ISC_LIST_HEAD(ctx->pools); 1457135446Strhodes if (pool != NULL) { 1458193149Sdougb fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1459135446Strhodes ISC_MSG_POOLSTATS, 1460135446Strhodes "[Pool statistics]\n")); 1461135446Strhodes fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n", 1462135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1463135446Strhodes ISC_MSG_POOLNAME, "name"), 1464135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1465135446Strhodes ISC_MSG_POOLSIZE, "size"), 1466135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1467135446Strhodes ISC_MSG_POOLMAXALLOC, "maxalloc"), 1468135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1469135446Strhodes ISC_MSG_POOLALLOCATED, "allocated"), 1470135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1471135446Strhodes ISC_MSG_POOLFREECOUNT, "freecount"), 1472135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1473135446Strhodes ISC_MSG_POOLFREEMAX, "freemax"), 1474135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1475135446Strhodes ISC_MSG_POOLFILLCOUNT, "fillcount"), 1476135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1477135446Strhodes ISC_MSG_POOLGETS, "gets"), 1478135446Strhodes "L"); 1479135446Strhodes } 1480135446Strhodes while (pool != NULL) { 1481135446Strhodes fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n", 1482254402Serwin#if ISC_MEMPOOL_NAMES 1483254402Serwin pool->name, 1484254402Serwin#else 1485254402Serwin "(not tracked)", 1486254402Serwin#endif 1487254402Serwin (unsigned long) pool->size, pool->maxalloc, 1488135446Strhodes pool->allocated, pool->freecount, pool->freemax, 1489135446Strhodes pool->fillcount, pool->gets, 1490135446Strhodes (pool->lock == NULL ? "N" : "Y")); 1491135446Strhodes pool = ISC_LIST_NEXT(pool, link); 1492135446Strhodes } 1493135446Strhodes 1494135446Strhodes#if ISC_MEM_TRACKLINES 1495135446Strhodes print_active(ctx, out); 1496135446Strhodes#endif 1497135446Strhodes 1498170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1499135446Strhodes} 1500135446Strhodes 1501135446Strhodes/* 1502135446Strhodes * Replacements for malloc() and free() -- they implicitly remember the 1503135446Strhodes * size of the object allocated (with some additional overhead). 1504135446Strhodes */ 1505135446Strhodes 1506135446Strhodesstatic void * 1507224092Sdougbisc__mem_allocateunlocked(isc_mem_t *ctx0, size_t size) { 1508224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1509135446Strhodes size_info *si; 1510135446Strhodes 1511135446Strhodes size += ALIGNMENT_SIZE; 1512170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1513170222Sdougb size += ALIGNMENT_SIZE; 1514170222Sdougb 1515170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) 1516170222Sdougb si = mem_getunlocked(ctx, size); 1517170222Sdougb else 1518170222Sdougb si = mem_get(ctx, size); 1519170222Sdougb 1520135446Strhodes if (si == NULL) 1521135446Strhodes return (NULL); 1522170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1523170222Sdougb si->u.ctx = ctx; 1524170222Sdougb si++; 1525170222Sdougb } 1526135446Strhodes si->u.size = size; 1527135446Strhodes return (&si[1]); 1528135446Strhodes} 1529135446Strhodes 1530224092SdougbISC_MEMFUNC_SCOPE void * 1531224092Sdougbisc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) { 1532224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1533135446Strhodes size_info *si; 1534170222Sdougb isc_boolean_t call_water = ISC_FALSE; 1535135446Strhodes 1536135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1537135446Strhodes 1538170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1539170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1540224092Sdougb si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size); 1541170222Sdougb } else { 1542224092Sdougb si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size); 1543170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1544170222Sdougb if (si != NULL) 1545170222Sdougb mem_getstats(ctx, si[-1].u.size); 1546170222Sdougb } 1547135446Strhodes 1548135446Strhodes#if ISC_MEM_TRACKLINES 1549135446Strhodes ADD_TRACE(ctx, si, si[-1].u.size, file, line); 1550135446Strhodes#endif 1551214586Sdougb if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1552214586Sdougb !ctx->is_overmem) { 1553214586Sdougb ctx->is_overmem = ISC_TRUE; 1554214586Sdougb } 1555214586Sdougb 1556170222Sdougb if (ctx->hi_water != 0U && !ctx->hi_called && 1557170222Sdougb ctx->inuse > ctx->hi_water) { 1558170222Sdougb ctx->hi_called = ISC_TRUE; 1559170222Sdougb call_water = ISC_TRUE; 1560170222Sdougb } 1561170222Sdougb if (ctx->inuse > ctx->maxinuse) { 1562170222Sdougb ctx->maxinuse = ctx->inuse; 1563170222Sdougb if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1564170222Sdougb (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) 1565170222Sdougb fprintf(stderr, "maxinuse = %lu\n", 1566170222Sdougb (unsigned long)ctx->inuse); 1567170222Sdougb } 1568170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1569135446Strhodes 1570170222Sdougb if (call_water) 1571170222Sdougb (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); 1572135446Strhodes 1573135446Strhodes return (si); 1574135446Strhodes} 1575135446Strhodes 1576224092SdougbISC_MEMFUNC_SCOPE void * 1577224092Sdougbisc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) { 1578224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1579193149Sdougb void *new_ptr = NULL; 1580193149Sdougb size_t oldsize, copysize; 1581193149Sdougb 1582193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1583193149Sdougb 1584193149Sdougb /* 1585193149Sdougb * This function emulates the realloc(3) standard library function: 1586193149Sdougb * - if size > 0, allocate new memory; and if ptr is non NULL, copy 1587193149Sdougb * as much of the old contents to the new buffer and free the old one. 1588193149Sdougb * Note that when allocation fails the original pointer is intact; 1589193149Sdougb * the caller must free it. 1590193149Sdougb * - if size is 0 and ptr is non NULL, simply free the given ptr. 1591193149Sdougb * - this function returns: 1592193149Sdougb * pointer to the newly allocated memory, or 1593193149Sdougb * NULL if allocation fails or doesn't happen. 1594193149Sdougb */ 1595193149Sdougb if (size > 0U) { 1596224092Sdougb new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS); 1597193149Sdougb if (new_ptr != NULL && ptr != NULL) { 1598193149Sdougb oldsize = (((size_info *)ptr)[-1]).u.size; 1599193149Sdougb INSIST(oldsize >= ALIGNMENT_SIZE); 1600193149Sdougb oldsize -= ALIGNMENT_SIZE; 1601245163Serwin if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1602245163Serwin INSIST(oldsize >= ALIGNMENT_SIZE); 1603245163Serwin oldsize -= ALIGNMENT_SIZE; 1604245163Serwin } 1605245163Serwin copysize = (oldsize > size) ? size : oldsize; 1606262706Serwin memmove(new_ptr, ptr, copysize); 1607224092Sdougb isc__mem_free(ctx0, ptr FLARG_PASS); 1608193149Sdougb } 1609193149Sdougb } else if (ptr != NULL) 1610224092Sdougb isc__mem_free(ctx0, ptr FLARG_PASS); 1611193149Sdougb 1612193149Sdougb return (new_ptr); 1613193149Sdougb} 1614193149Sdougb 1615224092SdougbISC_MEMFUNC_SCOPE void 1616224092Sdougbisc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) { 1617224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1618135446Strhodes size_info *si; 1619135446Strhodes size_t size; 1620170222Sdougb isc_boolean_t call_water= ISC_FALSE; 1621135446Strhodes 1622135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1623135446Strhodes REQUIRE(ptr != NULL); 1624135446Strhodes 1625170222Sdougb if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1626170222Sdougb si = &(((size_info *)ptr)[-2]); 1627170222Sdougb REQUIRE(si->u.ctx == ctx); 1628170222Sdougb size = si[1].u.size; 1629170222Sdougb } else { 1630170222Sdougb si = &(((size_info *)ptr)[-1]); 1631170222Sdougb size = si->u.size; 1632170222Sdougb } 1633135446Strhodes 1634170222Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1635170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1636170222Sdougb mem_putunlocked(ctx, si, size); 1637170222Sdougb } else { 1638170222Sdougb mem_put(ctx, si, size); 1639170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1640170222Sdougb mem_putstats(ctx, si, size); 1641170222Sdougb } 1642135446Strhodes 1643135446Strhodes DELETE_TRACE(ctx, ptr, size, file, line); 1644135446Strhodes 1645170222Sdougb /* 1646170222Sdougb * The check against ctx->lo_water == 0 is for the condition 1647170222Sdougb * when the context was pushed over hi_water but then had 1648170222Sdougb * isc_mem_setwater() called with 0 for hi_water and lo_water. 1649170222Sdougb */ 1650214586Sdougb if (ctx->is_overmem && 1651214586Sdougb (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1652214586Sdougb ctx->is_overmem = ISC_FALSE; 1653214586Sdougb } 1654214586Sdougb 1655186462Sdougb if (ctx->hi_called && 1656170222Sdougb (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1657170222Sdougb ctx->hi_called = ISC_FALSE; 1658170222Sdougb 1659170222Sdougb if (ctx->water != NULL) 1660170222Sdougb call_water = ISC_TRUE; 1661170222Sdougb } 1662170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1663170222Sdougb 1664170222Sdougb if (call_water) 1665170222Sdougb (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1666135446Strhodes} 1667135446Strhodes 1668135446Strhodes 1669135446Strhodes/* 1670135446Strhodes * Other useful things. 1671135446Strhodes */ 1672135446Strhodes 1673224092SdougbISC_MEMFUNC_SCOPE char * 1674224092Sdougbisc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) { 1675224092Sdougb isc__mem_t *mctx = (isc__mem_t *)mctx0; 1676135446Strhodes size_t len; 1677135446Strhodes char *ns; 1678135446Strhodes 1679135446Strhodes REQUIRE(VALID_CONTEXT(mctx)); 1680135446Strhodes REQUIRE(s != NULL); 1681135446Strhodes 1682135446Strhodes len = strlen(s); 1683135446Strhodes 1684224092Sdougb ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS); 1685135446Strhodes 1686135446Strhodes if (ns != NULL) 1687135446Strhodes strncpy(ns, s, len + 1); 1688135446Strhodes 1689135446Strhodes return (ns); 1690135446Strhodes} 1691135446Strhodes 1692224092SdougbISC_MEMFUNC_SCOPE void 1693224092Sdougbisc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) { 1694224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1695224092Sdougb 1696135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1697170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1698135446Strhodes 1699135446Strhodes ctx->checkfree = flag; 1700135446Strhodes 1701170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1702135446Strhodes} 1703135446Strhodes 1704135446Strhodes/* 1705135446Strhodes * Quotas 1706135446Strhodes */ 1707135446Strhodes 1708224092SdougbISC_MEMFUNC_SCOPE void 1709224092Sdougbisc__mem_setquota(isc_mem_t *ctx0, size_t quota) { 1710224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1711224092Sdougb 1712135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1713170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1714135446Strhodes 1715135446Strhodes ctx->quota = quota; 1716135446Strhodes 1717170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1718135446Strhodes} 1719135446Strhodes 1720224092SdougbISC_MEMFUNC_SCOPE size_t 1721224092Sdougbisc__mem_getquota(isc_mem_t *ctx0) { 1722224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1723135446Strhodes size_t quota; 1724135446Strhodes 1725135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1726170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1727135446Strhodes 1728135446Strhodes quota = ctx->quota; 1729135446Strhodes 1730170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1731135446Strhodes 1732135446Strhodes return (quota); 1733135446Strhodes} 1734135446Strhodes 1735224092SdougbISC_MEMFUNC_SCOPE size_t 1736224092Sdougbisc__mem_inuse(isc_mem_t *ctx0) { 1737224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1738135446Strhodes size_t inuse; 1739135446Strhodes 1740135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1741170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1742135446Strhodes 1743135446Strhodes inuse = ctx->inuse; 1744135446Strhodes 1745170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1746135446Strhodes 1747135446Strhodes return (inuse); 1748135446Strhodes} 1749135446Strhodes 1750224092SdougbISC_MEMFUNC_SCOPE void 1751224092Sdougbisc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg, 1752186462Sdougb size_t hiwater, size_t lowater) 1753135446Strhodes{ 1754224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1755170222Sdougb isc_boolean_t callwater = ISC_FALSE; 1756170222Sdougb isc_mem_water_t oldwater; 1757170222Sdougb void *oldwater_arg; 1758170222Sdougb 1759135446Strhodes REQUIRE(VALID_CONTEXT(ctx)); 1760135446Strhodes REQUIRE(hiwater >= lowater); 1761135446Strhodes 1762170222Sdougb MCTXLOCK(ctx, &ctx->lock); 1763170222Sdougb oldwater = ctx->water; 1764170222Sdougb oldwater_arg = ctx->water_arg; 1765135446Strhodes if (water == NULL) { 1766170222Sdougb callwater = ctx->hi_called; 1767135446Strhodes ctx->water = NULL; 1768135446Strhodes ctx->water_arg = NULL; 1769135446Strhodes ctx->hi_water = 0; 1770135446Strhodes ctx->lo_water = 0; 1771135446Strhodes ctx->hi_called = ISC_FALSE; 1772135446Strhodes } else { 1773170222Sdougb if (ctx->hi_called && 1774170222Sdougb (ctx->water != water || ctx->water_arg != water_arg || 1775170222Sdougb ctx->inuse < lowater || lowater == 0U)) 1776170222Sdougb callwater = ISC_TRUE; 1777135446Strhodes ctx->water = water; 1778135446Strhodes ctx->water_arg = water_arg; 1779135446Strhodes ctx->hi_water = hiwater; 1780135446Strhodes ctx->lo_water = lowater; 1781135446Strhodes ctx->hi_called = ISC_FALSE; 1782135446Strhodes } 1783170222Sdougb MCTXUNLOCK(ctx, &ctx->lock); 1784186462Sdougb 1785170222Sdougb if (callwater && oldwater != NULL) 1786170222Sdougb (oldwater)(oldwater_arg, ISC_MEM_LOWATER); 1787135446Strhodes} 1788135446Strhodes 1789224092SdougbISC_MEMFUNC_SCOPE isc_boolean_t 1790224092Sdougbisc__mem_isovermem(isc_mem_t *ctx0) { 1791224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1792224092Sdougb 1793214586Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1794214586Sdougb 1795214586Sdougb /* 1796214586Sdougb * We don't bother to lock the context because 100% accuracy isn't 1797214586Sdougb * necessary (and even if we locked the context the returned value 1798214586Sdougb * could be different from the actual state when it's used anyway) 1799214586Sdougb */ 1800214586Sdougb return (ctx->is_overmem); 1801214586Sdougb} 1802214586Sdougb 1803224092SdougbISC_MEMFUNC_SCOPE void 1804224092Sdougbisc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) { 1805224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1806224092Sdougb 1807193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1808193149Sdougb 1809193149Sdougb LOCK(&ctx->lock); 1810193149Sdougb memset(ctx->name, 0, sizeof(ctx->name)); 1811193149Sdougb strncpy(ctx->name, name, sizeof(ctx->name) - 1); 1812193149Sdougb ctx->tag = tag; 1813193149Sdougb UNLOCK(&ctx->lock); 1814193149Sdougb} 1815193149Sdougb 1816224092SdougbISC_MEMFUNC_SCOPE const char * 1817224092Sdougbisc__mem_getname(isc_mem_t *ctx0) { 1818224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1819224092Sdougb 1820193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1821193149Sdougb 1822193149Sdougb return (ctx->name); 1823193149Sdougb} 1824193149Sdougb 1825224092SdougbISC_MEMFUNC_SCOPE void * 1826224092Sdougbisc__mem_gettag(isc_mem_t *ctx0) { 1827224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 1828224092Sdougb 1829193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 1830193149Sdougb 1831193149Sdougb return (ctx->tag); 1832193149Sdougb} 1833193149Sdougb 1834135446Strhodes/* 1835135446Strhodes * Memory pool stuff 1836135446Strhodes */ 1837135446Strhodes 1838224092SdougbISC_MEMFUNC_SCOPE isc_result_t 1839224092Sdougbisc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) { 1840224092Sdougb isc__mem_t *mctx = (isc__mem_t *)mctx0; 1841224092Sdougb isc__mempool_t *mpctx; 1842135446Strhodes 1843135446Strhodes REQUIRE(VALID_CONTEXT(mctx)); 1844135446Strhodes REQUIRE(size > 0U); 1845135446Strhodes REQUIRE(mpctxp != NULL && *mpctxp == NULL); 1846135446Strhodes 1847135446Strhodes /* 1848135446Strhodes * Allocate space for this pool, initialize values, and if all works 1849135446Strhodes * well, attach to the memory context. 1850135446Strhodes */ 1851224092Sdougb mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t)); 1852135446Strhodes if (mpctx == NULL) 1853135446Strhodes return (ISC_R_NOMEMORY); 1854135446Strhodes 1855224092Sdougb mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods; 1856224092Sdougb mpctx->common.impmagic = MEMPOOL_MAGIC; 1857224092Sdougb mpctx->common.magic = ISCAPI_MPOOL_MAGIC; 1858135446Strhodes mpctx->lock = NULL; 1859135446Strhodes mpctx->mctx = mctx; 1860135446Strhodes mpctx->size = size; 1861135446Strhodes mpctx->maxalloc = UINT_MAX; 1862135446Strhodes mpctx->allocated = 0; 1863135446Strhodes mpctx->freecount = 0; 1864135446Strhodes mpctx->freemax = 1; 1865135446Strhodes mpctx->fillcount = 1; 1866135446Strhodes mpctx->gets = 0; 1867135446Strhodes#if ISC_MEMPOOL_NAMES 1868135446Strhodes mpctx->name[0] = 0; 1869135446Strhodes#endif 1870135446Strhodes mpctx->items = NULL; 1871135446Strhodes 1872224092Sdougb *mpctxp = (isc_mempool_t *)mpctx; 1873135446Strhodes 1874170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1875135446Strhodes ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link); 1876193149Sdougb mctx->poolcnt++; 1877170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1878135446Strhodes 1879135446Strhodes return (ISC_R_SUCCESS); 1880135446Strhodes} 1881135446Strhodes 1882224092SdougbISC_MEMFUNC_SCOPE void 1883224092Sdougbisc__mempool_setname(isc_mempool_t *mpctx0, const char *name) { 1884224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1885224092Sdougb 1886135446Strhodes REQUIRE(name != NULL); 1887224092Sdougb REQUIRE(VALID_MEMPOOL(mpctx)); 1888135446Strhodes 1889135446Strhodes#if ISC_MEMPOOL_NAMES 1890135446Strhodes if (mpctx->lock != NULL) 1891135446Strhodes LOCK(mpctx->lock); 1892135446Strhodes 1893135446Strhodes strncpy(mpctx->name, name, sizeof(mpctx->name) - 1); 1894135446Strhodes mpctx->name[sizeof(mpctx->name) - 1] = '\0'; 1895135446Strhodes 1896135446Strhodes if (mpctx->lock != NULL) 1897135446Strhodes UNLOCK(mpctx->lock); 1898135446Strhodes#else 1899135446Strhodes UNUSED(mpctx); 1900135446Strhodes UNUSED(name); 1901135446Strhodes#endif 1902135446Strhodes} 1903135446Strhodes 1904224092SdougbISC_MEMFUNC_SCOPE void 1905224092Sdougbisc__mempool_destroy(isc_mempool_t **mpctxp) { 1906224092Sdougb isc__mempool_t *mpctx; 1907224092Sdougb isc__mem_t *mctx; 1908135446Strhodes isc_mutex_t *lock; 1909135446Strhodes element *item; 1910135446Strhodes 1911135446Strhodes REQUIRE(mpctxp != NULL); 1912224092Sdougb mpctx = (isc__mempool_t *)*mpctxp; 1913135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1914135446Strhodes#if ISC_MEMPOOL_NAMES 1915135446Strhodes if (mpctx->allocated > 0) 1916135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 1917224092Sdougb "isc__mempool_destroy(): mempool %s " 1918135446Strhodes "leaked memory", 1919135446Strhodes mpctx->name); 1920135446Strhodes#endif 1921135446Strhodes REQUIRE(mpctx->allocated == 0); 1922135446Strhodes 1923135446Strhodes mctx = mpctx->mctx; 1924135446Strhodes 1925135446Strhodes lock = mpctx->lock; 1926135446Strhodes 1927135446Strhodes if (lock != NULL) 1928135446Strhodes LOCK(lock); 1929135446Strhodes 1930135446Strhodes /* 1931135446Strhodes * Return any items on the free list 1932135446Strhodes */ 1933170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1934135446Strhodes while (mpctx->items != NULL) { 1935135446Strhodes INSIST(mpctx->freecount > 0); 1936135446Strhodes mpctx->freecount--; 1937135446Strhodes item = mpctx->items; 1938135446Strhodes mpctx->items = item->next; 1939135446Strhodes 1940170222Sdougb if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1941170222Sdougb mem_putunlocked(mctx, item, mpctx->size); 1942170222Sdougb } else { 1943170222Sdougb mem_put(mctx, item, mpctx->size); 1944170222Sdougb mem_putstats(mctx, item, mpctx->size); 1945170222Sdougb } 1946135446Strhodes } 1947170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1948135446Strhodes 1949135446Strhodes /* 1950135446Strhodes * Remove our linked list entry from the memory context. 1951135446Strhodes */ 1952170222Sdougb MCTXLOCK(mctx, &mctx->lock); 1953135446Strhodes ISC_LIST_UNLINK(mctx->pools, mpctx, link); 1954193149Sdougb mctx->poolcnt--; 1955170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 1956135446Strhodes 1957224092Sdougb mpctx->common.impmagic = 0; 1958224092Sdougb mpctx->common.magic = 0; 1959135446Strhodes 1960224092Sdougb isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t)); 1961135446Strhodes 1962135446Strhodes if (lock != NULL) 1963135446Strhodes UNLOCK(lock); 1964135446Strhodes 1965135446Strhodes *mpctxp = NULL; 1966135446Strhodes} 1967135446Strhodes 1968224092SdougbISC_MEMFUNC_SCOPE void 1969224092Sdougbisc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) { 1970224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1971224092Sdougb 1972135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1973135446Strhodes REQUIRE(mpctx->lock == NULL); 1974135446Strhodes REQUIRE(lock != NULL); 1975135446Strhodes 1976135446Strhodes mpctx->lock = lock; 1977135446Strhodes} 1978135446Strhodes 1979224092SdougbISC_MEMFUNC_SCOPE void * 1980224092Sdougbisc___mempool_get(isc_mempool_t *mpctx0 FLARG) { 1981224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1982135446Strhodes element *item; 1983224092Sdougb isc__mem_t *mctx; 1984135446Strhodes unsigned int i; 1985135446Strhodes 1986135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 1987135446Strhodes 1988135446Strhodes mctx = mpctx->mctx; 1989135446Strhodes 1990135446Strhodes if (mpctx->lock != NULL) 1991135446Strhodes LOCK(mpctx->lock); 1992135446Strhodes 1993135446Strhodes /* 1994135446Strhodes * Don't let the caller go over quota 1995135446Strhodes */ 1996135446Strhodes if (mpctx->allocated >= mpctx->maxalloc) { 1997135446Strhodes item = NULL; 1998135446Strhodes goto out; 1999135446Strhodes } 2000135446Strhodes 2001135446Strhodes /* 2002135446Strhodes * if we have a free list item, return the first here 2003135446Strhodes */ 2004135446Strhodes item = mpctx->items; 2005135446Strhodes if (item != NULL) { 2006135446Strhodes mpctx->items = item->next; 2007135446Strhodes INSIST(mpctx->freecount > 0); 2008135446Strhodes mpctx->freecount--; 2009135446Strhodes mpctx->gets++; 2010135446Strhodes mpctx->allocated++; 2011135446Strhodes goto out; 2012135446Strhodes } 2013135446Strhodes 2014135446Strhodes /* 2015135446Strhodes * We need to dip into the well. Lock the memory context here and 2016135446Strhodes * fill up our free list. 2017135446Strhodes */ 2018170222Sdougb MCTXLOCK(mctx, &mctx->lock); 2019135446Strhodes for (i = 0; i < mpctx->fillcount; i++) { 2020170222Sdougb if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2021170222Sdougb item = mem_getunlocked(mctx, mpctx->size); 2022170222Sdougb } else { 2023170222Sdougb item = mem_get(mctx, mpctx->size); 2024170222Sdougb if (item != NULL) 2025170222Sdougb mem_getstats(mctx, mpctx->size); 2026170222Sdougb } 2027135446Strhodes if (item == NULL) 2028135446Strhodes break; 2029135446Strhodes item->next = mpctx->items; 2030135446Strhodes mpctx->items = item; 2031135446Strhodes mpctx->freecount++; 2032135446Strhodes } 2033170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 2034135446Strhodes 2035135446Strhodes /* 2036135446Strhodes * If we didn't get any items, return NULL. 2037135446Strhodes */ 2038135446Strhodes item = mpctx->items; 2039135446Strhodes if (item == NULL) 2040135446Strhodes goto out; 2041135446Strhodes 2042135446Strhodes mpctx->items = item->next; 2043135446Strhodes mpctx->freecount--; 2044135446Strhodes mpctx->gets++; 2045135446Strhodes mpctx->allocated++; 2046135446Strhodes 2047135446Strhodes out: 2048135446Strhodes if (mpctx->lock != NULL) 2049135446Strhodes UNLOCK(mpctx->lock); 2050135446Strhodes 2051135446Strhodes#if ISC_MEM_TRACKLINES 2052135446Strhodes if (item != NULL) { 2053170222Sdougb MCTXLOCK(mctx, &mctx->lock); 2054135446Strhodes ADD_TRACE(mctx, item, mpctx->size, file, line); 2055170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 2056135446Strhodes } 2057135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 2058135446Strhodes 2059135446Strhodes return (item); 2060135446Strhodes} 2061135446Strhodes 2062224092SdougbISC_MEMFUNC_SCOPE void 2063224092Sdougbisc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) { 2064224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2065224092Sdougb isc__mem_t *mctx; 2066135446Strhodes element *item; 2067135446Strhodes 2068135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 2069135446Strhodes REQUIRE(mem != NULL); 2070135446Strhodes 2071135446Strhodes mctx = mpctx->mctx; 2072135446Strhodes 2073135446Strhodes if (mpctx->lock != NULL) 2074135446Strhodes LOCK(mpctx->lock); 2075135446Strhodes 2076135446Strhodes INSIST(mpctx->allocated > 0); 2077135446Strhodes mpctx->allocated--; 2078135446Strhodes 2079135446Strhodes#if ISC_MEM_TRACKLINES 2080170222Sdougb MCTXLOCK(mctx, &mctx->lock); 2081135446Strhodes DELETE_TRACE(mctx, mem, mpctx->size, file, line); 2082170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 2083135446Strhodes#endif /* ISC_MEM_TRACKLINES */ 2084135446Strhodes 2085135446Strhodes /* 2086135446Strhodes * If our free list is full, return this to the mctx directly. 2087135446Strhodes */ 2088135446Strhodes if (mpctx->freecount >= mpctx->freemax) { 2089170222Sdougb if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2090170222Sdougb MCTXLOCK(mctx, &mctx->lock); 2091170222Sdougb mem_putunlocked(mctx, mem, mpctx->size); 2092170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 2093170222Sdougb } else { 2094170222Sdougb mem_put(mctx, mem, mpctx->size); 2095170222Sdougb MCTXLOCK(mctx, &mctx->lock); 2096170222Sdougb mem_putstats(mctx, mem, mpctx->size); 2097170222Sdougb MCTXUNLOCK(mctx, &mctx->lock); 2098170222Sdougb } 2099135446Strhodes if (mpctx->lock != NULL) 2100135446Strhodes UNLOCK(mpctx->lock); 2101135446Strhodes return; 2102135446Strhodes } 2103135446Strhodes 2104135446Strhodes /* 2105135446Strhodes * Otherwise, attach it to our free list and bump the counter. 2106135446Strhodes */ 2107135446Strhodes mpctx->freecount++; 2108135446Strhodes item = (element *)mem; 2109135446Strhodes item->next = mpctx->items; 2110135446Strhodes mpctx->items = item; 2111135446Strhodes 2112135446Strhodes if (mpctx->lock != NULL) 2113135446Strhodes UNLOCK(mpctx->lock); 2114135446Strhodes} 2115135446Strhodes 2116135446Strhodes/* 2117135446Strhodes * Quotas 2118135446Strhodes */ 2119135446Strhodes 2120224092SdougbISC_MEMFUNC_SCOPE void 2121224092Sdougbisc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) { 2122224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2123224092Sdougb 2124135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 2125135446Strhodes 2126135446Strhodes if (mpctx->lock != NULL) 2127135446Strhodes LOCK(mpctx->lock); 2128135446Strhodes 2129135446Strhodes mpctx->freemax = limit; 2130135446Strhodes 2131135446Strhodes if (mpctx->lock != NULL) 2132135446Strhodes UNLOCK(mpctx->lock); 2133135446Strhodes} 2134135446Strhodes 2135224092SdougbISC_MEMFUNC_SCOPE unsigned int 2136224092Sdougbisc__mempool_getfreemax(isc_mempool_t *mpctx0) { 2137224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2138135446Strhodes unsigned int freemax; 2139135446Strhodes 2140135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 2141135446Strhodes 2142135446Strhodes if (mpctx->lock != NULL) 2143135446Strhodes LOCK(mpctx->lock); 2144135446Strhodes 2145135446Strhodes freemax = mpctx->freemax; 2146135446Strhodes 2147135446Strhodes if (mpctx->lock != NULL) 2148135446Strhodes UNLOCK(mpctx->lock); 2149135446Strhodes 2150135446Strhodes return (freemax); 2151135446Strhodes} 2152135446Strhodes 2153224092SdougbISC_MEMFUNC_SCOPE unsigned int 2154224092Sdougbisc__mempool_getfreecount(isc_mempool_t *mpctx0) { 2155224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2156135446Strhodes unsigned int freecount; 2157135446Strhodes 2158135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 2159135446Strhodes 2160135446Strhodes if (mpctx->lock != NULL) 2161135446Strhodes LOCK(mpctx->lock); 2162135446Strhodes 2163135446Strhodes freecount = mpctx->freecount; 2164135446Strhodes 2165135446Strhodes if (mpctx->lock != NULL) 2166135446Strhodes UNLOCK(mpctx->lock); 2167135446Strhodes 2168135446Strhodes return (freecount); 2169135446Strhodes} 2170135446Strhodes 2171224092SdougbISC_MEMFUNC_SCOPE void 2172224092Sdougbisc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) { 2173224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2174224092Sdougb 2175135446Strhodes REQUIRE(limit > 0); 2176135446Strhodes 2177135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 2178135446Strhodes 2179135446Strhodes if (mpctx->lock != NULL) 2180135446Strhodes LOCK(mpctx->lock); 2181135446Strhodes 2182135446Strhodes mpctx->maxalloc = limit; 2183135446Strhodes 2184135446Strhodes if (mpctx->lock != NULL) 2185135446Strhodes UNLOCK(mpctx->lock); 2186135446Strhodes} 2187135446Strhodes 2188224092SdougbISC_MEMFUNC_SCOPE unsigned int 2189224092Sdougbisc__mempool_getmaxalloc(isc_mempool_t *mpctx0) { 2190224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2191135446Strhodes unsigned int maxalloc; 2192135446Strhodes 2193135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 2194135446Strhodes 2195135446Strhodes if (mpctx->lock != NULL) 2196135446Strhodes LOCK(mpctx->lock); 2197135446Strhodes 2198135446Strhodes maxalloc = mpctx->maxalloc; 2199135446Strhodes 2200135446Strhodes if (mpctx->lock != NULL) 2201135446Strhodes UNLOCK(mpctx->lock); 2202135446Strhodes 2203135446Strhodes return (maxalloc); 2204135446Strhodes} 2205135446Strhodes 2206224092SdougbISC_MEMFUNC_SCOPE unsigned int 2207224092Sdougbisc__mempool_getallocated(isc_mempool_t *mpctx0) { 2208224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2209135446Strhodes unsigned int allocated; 2210135446Strhodes 2211135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 2212135446Strhodes 2213135446Strhodes if (mpctx->lock != NULL) 2214135446Strhodes LOCK(mpctx->lock); 2215135446Strhodes 2216135446Strhodes allocated = mpctx->allocated; 2217135446Strhodes 2218135446Strhodes if (mpctx->lock != NULL) 2219135446Strhodes UNLOCK(mpctx->lock); 2220135446Strhodes 2221135446Strhodes return (allocated); 2222135446Strhodes} 2223135446Strhodes 2224224092SdougbISC_MEMFUNC_SCOPE void 2225224092Sdougbisc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) { 2226224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2227224092Sdougb 2228135446Strhodes REQUIRE(limit > 0); 2229135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 2230135446Strhodes 2231135446Strhodes if (mpctx->lock != NULL) 2232135446Strhodes LOCK(mpctx->lock); 2233135446Strhodes 2234135446Strhodes mpctx->fillcount = limit; 2235135446Strhodes 2236135446Strhodes if (mpctx->lock != NULL) 2237135446Strhodes UNLOCK(mpctx->lock); 2238135446Strhodes} 2239135446Strhodes 2240224092SdougbISC_MEMFUNC_SCOPE unsigned int 2241224092Sdougbisc__mempool_getfillcount(isc_mempool_t *mpctx0) { 2242224092Sdougb isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2243224092Sdougb 2244135446Strhodes unsigned int fillcount; 2245135446Strhodes 2246135446Strhodes REQUIRE(VALID_MEMPOOL(mpctx)); 2247135446Strhodes 2248135446Strhodes if (mpctx->lock != NULL) 2249135446Strhodes LOCK(mpctx->lock); 2250135446Strhodes 2251135446Strhodes fillcount = mpctx->fillcount; 2252135446Strhodes 2253135446Strhodes if (mpctx->lock != NULL) 2254135446Strhodes UNLOCK(mpctx->lock); 2255135446Strhodes 2256135446Strhodes return (fillcount); 2257135446Strhodes} 2258170222Sdougb 2259224092Sdougb#ifdef USE_MEMIMPREGISTER 2260224092Sdougbisc_result_t 2261224092Sdougbisc__mem_register() { 2262224092Sdougb return (isc_mem_register(isc__mem_create2)); 2263224092Sdougb} 2264224092Sdougb#endif 2265170222Sdougb 2266224092Sdougb#ifdef BIND9 2267224092SdougbISC_MEMFUNC_SCOPE void 2268224092Sdougbisc__mem_printactive(isc_mem_t *ctx0, FILE *file) { 2269254402Serwin#if ISC_MEM_TRACKLINES 2270224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 2271224092Sdougb 2272170222Sdougb REQUIRE(VALID_CONTEXT(ctx)); 2273170222Sdougb REQUIRE(file != NULL); 2274170222Sdougb 2275254402Serwin print_active(ctx, file); 2276254402Serwin#else 2277254402Serwin UNUSED(ctx0); 2278170222Sdougb UNUSED(file); 2279170222Sdougb#endif 2280170222Sdougb} 2281170222Sdougb 2282224092SdougbISC_MEMFUNC_SCOPE void 2283224092Sdougbisc__mem_printallactive(FILE *file) { 2284170222Sdougb#if !ISC_MEM_TRACKLINES 2285170222Sdougb UNUSED(file); 2286170222Sdougb#else 2287224092Sdougb isc__mem_t *ctx; 2288170222Sdougb 2289170222Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2290170222Sdougb 2291170222Sdougb LOCK(&lock); 2292170222Sdougb for (ctx = ISC_LIST_HEAD(contexts); 2293170222Sdougb ctx != NULL; 2294170222Sdougb ctx = ISC_LIST_NEXT(ctx, link)) { 2295170222Sdougb fprintf(file, "context: %p\n", ctx); 2296170222Sdougb print_active(ctx, file); 2297170222Sdougb } 2298170222Sdougb UNLOCK(&lock); 2299170222Sdougb#endif 2300170222Sdougb} 2301170222Sdougb 2302224092SdougbISC_MEMFUNC_SCOPE void 2303224092Sdougbisc__mem_checkdestroyed(FILE *file) { 2304254402Serwin#if !ISC_MEM_TRACKLINES 2305254402Serwin UNUSED(file); 2306254402Serwin#endif 2307170222Sdougb 2308170222Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2309170222Sdougb 2310170222Sdougb LOCK(&lock); 2311170222Sdougb if (!ISC_LIST_EMPTY(contexts)) { 2312170222Sdougb#if ISC_MEM_TRACKLINES 2313224092Sdougb isc__mem_t *ctx; 2314170222Sdougb 2315170222Sdougb for (ctx = ISC_LIST_HEAD(contexts); 2316170222Sdougb ctx != NULL; 2317170222Sdougb ctx = ISC_LIST_NEXT(ctx, link)) { 2318170222Sdougb fprintf(file, "context: %p\n", ctx); 2319170222Sdougb print_active(ctx, file); 2320170222Sdougb } 2321170222Sdougb fflush(file); 2322170222Sdougb#endif 2323174187Sdougb INSIST(0); 2324170222Sdougb } 2325170222Sdougb UNLOCK(&lock); 2326170222Sdougb} 2327193149Sdougb 2328224092SdougbISC_MEMFUNC_SCOPE unsigned int 2329224092Sdougbisc_mem_references(isc_mem_t *ctx0) { 2330224092Sdougb isc__mem_t *ctx = (isc__mem_t *)ctx0; 2331193149Sdougb unsigned int references; 2332224092Sdougb 2333193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 2334193149Sdougb 2335193149Sdougb MCTXLOCK(ctx, &ctx->lock); 2336193149Sdougb references = ctx->references; 2337193149Sdougb MCTXUNLOCK(ctx, &ctx->lock); 2338193149Sdougb 2339193149Sdougb return (references); 2340193149Sdougb} 2341193149Sdougb 2342193149Sdougb#ifdef HAVE_LIBXML2 2343193149Sdougb 2344193149Sdougbtypedef struct summarystat { 2345193149Sdougb isc_uint64_t total; 2346193149Sdougb isc_uint64_t inuse; 2347193149Sdougb isc_uint64_t blocksize; 2348193149Sdougb isc_uint64_t contextsize; 2349193149Sdougb} summarystat_t; 2350193149Sdougb 2351254402Serwin#define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0) 2352254402Serwinstatic int 2353224092Sdougbrenderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) { 2354254402Serwin int xmlrc; 2355254402Serwin 2356193149Sdougb REQUIRE(VALID_CONTEXT(ctx)); 2357193149Sdougb 2358254402Serwin MCTXLOCK(ctx, &ctx->lock); 2359193149Sdougb 2360254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "context")); 2361193149Sdougb 2362254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id")); 2363254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, "%p", ctx)); 2364254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* id */ 2365254402Serwin 2366193149Sdougb if (ctx->name[0] != 0) { 2367254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name")); 2368254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, "%s", ctx->name)); 2369254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* name */ 2370193149Sdougb } 2371193149Sdougb 2372193149Sdougb summary->contextsize += sizeof(*ctx) + 2373193149Sdougb (ctx->max_size + 1) * sizeof(struct stats) + 2374193149Sdougb ctx->max_size * sizeof(element *) + 2375193149Sdougb ctx->basic_table_count * sizeof(char *); 2376193149Sdougb#if ISC_MEM_TRACKLINES 2377193149Sdougb if (ctx->debuglist != NULL) { 2378193149Sdougb summary->contextsize += 2379193149Sdougb (ctx->max_size + 1) * sizeof(debuglist_t) + 2380193149Sdougb ctx->debuglistcnt * sizeof(debuglink_t); 2381193149Sdougb } 2382193149Sdougb#endif 2383254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references")); 2384254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, "%d", ctx->references)); 2385254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* references */ 2386193149Sdougb 2387193149Sdougb summary->total += ctx->total; 2388254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "total")); 2389254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2390254402Serwin "%" ISC_PRINT_QUADFORMAT "u", 2391254402Serwin (isc_uint64_t)ctx->total)); 2392254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* total */ 2393193149Sdougb 2394193149Sdougb summary->inuse += ctx->inuse; 2395254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse")); 2396254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2397254402Serwin "%" ISC_PRINT_QUADFORMAT "u", 2398254402Serwin (isc_uint64_t)ctx->inuse)); 2399254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* inuse */ 2400193149Sdougb 2401254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse")); 2402254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2403254402Serwin "%" ISC_PRINT_QUADFORMAT "u", 2404254402Serwin (isc_uint64_t)ctx->maxinuse)); 2405254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* maxinuse */ 2406193149Sdougb 2407254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize")); 2408193149Sdougb if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2409193149Sdougb summary->blocksize += ctx->basic_table_count * 2410193149Sdougb NUM_BASIC_BLOCKS * ctx->mem_target; 2411254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2412193149Sdougb "%" ISC_PRINT_QUADFORMAT "u", 2413193149Sdougb (isc_uint64_t) 2414193149Sdougb ctx->basic_table_count * 2415193149Sdougb NUM_BASIC_BLOCKS * 2416254402Serwin ctx->mem_target)); 2417193149Sdougb } else 2418254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, "%s", "-")); 2419254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* blocksize */ 2420193149Sdougb 2421254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools")); 2422254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt)); 2423254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* pools */ 2424193149Sdougb summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t); 2425193149Sdougb 2426254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater")); 2427254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2428254402Serwin "%" ISC_PRINT_QUADFORMAT "u", 2429254402Serwin (isc_uint64_t)ctx->hi_water)); 2430254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* hiwater */ 2431193149Sdougb 2432254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater")); 2433254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2434254402Serwin "%" ISC_PRINT_QUADFORMAT "u", 2435254402Serwin (isc_uint64_t)ctx->lo_water)); 2436254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* lowater */ 2437193149Sdougb 2438254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* context */ 2439254402Serwin 2440254402Serwin error: 2441193149Sdougb MCTXUNLOCK(ctx, &ctx->lock); 2442193149Sdougb 2443254402Serwin return (xmlrc); 2444193149Sdougb} 2445193149Sdougb 2446254402Serwinint 2447193149Sdougbisc_mem_renderxml(xmlTextWriterPtr writer) { 2448224092Sdougb isc__mem_t *ctx; 2449193149Sdougb summarystat_t summary; 2450193149Sdougb isc_uint64_t lost; 2451254402Serwin int xmlrc; 2452193149Sdougb 2453193149Sdougb memset(&summary, 0, sizeof(summary)); 2454193149Sdougb 2455254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts")); 2456193149Sdougb 2457193149Sdougb RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2458193149Sdougb 2459193149Sdougb LOCK(&lock); 2460193149Sdougb lost = totallost; 2461193149Sdougb for (ctx = ISC_LIST_HEAD(contexts); 2462193149Sdougb ctx != NULL; 2463193149Sdougb ctx = ISC_LIST_NEXT(ctx, link)) { 2464254402Serwin xmlrc = renderctx(ctx, &summary, writer); 2465254402Serwin if (xmlrc < 0) { 2466254402Serwin UNLOCK(&lock); 2467254402Serwin goto error; 2468254402Serwin } 2469193149Sdougb } 2470193149Sdougb UNLOCK(&lock); 2471193149Sdougb 2472254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* contexts */ 2473193149Sdougb 2474254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary")); 2475193149Sdougb 2476254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse")); 2477254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2478254402Serwin "%" ISC_PRINT_QUADFORMAT "u", 2479254402Serwin summary.total)); 2480254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* TotalUse */ 2481193149Sdougb 2482254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse")); 2483254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2484254402Serwin "%" ISC_PRINT_QUADFORMAT "u", 2485254402Serwin summary.inuse)); 2486254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* InUse */ 2487193149Sdougb 2488254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize")); 2489254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2490254402Serwin "%" ISC_PRINT_QUADFORMAT "u", 2491254402Serwin summary.blocksize)); 2492254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* BlockSize */ 2493193149Sdougb 2494254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize")); 2495254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2496254402Serwin "%" ISC_PRINT_QUADFORMAT "u", 2497254402Serwin summary.contextsize)); 2498254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* ContextSize */ 2499193149Sdougb 2500254402Serwin TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost")); 2501254402Serwin TRY0(xmlTextWriterWriteFormatString(writer, 2502254402Serwin "%" ISC_PRINT_QUADFORMAT "u", 2503254402Serwin lost)); 2504254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* Lost */ 2505193149Sdougb 2506254402Serwin TRY0(xmlTextWriterEndElement(writer)); /* summary */ 2507254402Serwin error: 2508254402Serwin return (xmlrc); 2509193149Sdougb} 2510193149Sdougb 2511193149Sdougb#endif /* HAVE_LIBXML2 */ 2512224092Sdougb#endif /* BIND9 */ 2513