1258945Sroberto/* 2280849Scy * Copyright (C) 2004-2010, 2012 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * Copyright (C) 1997-2003 Internet Software Consortium. 4258945Sroberto * 5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any 6258945Sroberto * purpose with or without fee is hereby granted, provided that the above 7258945Sroberto * copyright notice and this permission notice appear in all copies. 8258945Sroberto * 9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11258945Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15258945Sroberto * PERFORMANCE OF THIS SOFTWARE. 16258945Sroberto */ 17258945Sroberto 18280849Scy/* $Id$ */ 19258945Sroberto 20258945Sroberto/*! \file */ 21258945Sroberto 22258945Sroberto#include <config.h> 23258945Sroberto 24258945Sroberto#include <stdio.h> 25258945Sroberto#include <stdlib.h> 26258945Sroberto#include <stddef.h> 27258945Sroberto 28258945Sroberto#include <limits.h> 29258945Sroberto 30258945Sroberto#include <isc/magic.h> 31258945Sroberto#include <isc/mem.h> 32258945Sroberto#include <isc/msgs.h> 33258945Sroberto#include <isc/once.h> 34258945Sroberto#include <isc/ondestroy.h> 35258945Sroberto#include <isc/string.h> 36258945Sroberto#include <isc/mutex.h> 37258945Sroberto#include <isc/print.h> 38258945Sroberto#include <isc/util.h> 39258945Sroberto#include <isc/xml.h> 40258945Sroberto 41258945Sroberto#define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l) 42258945Sroberto#define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l) 43258945Sroberto 44258945Sroberto#ifndef ISC_MEM_DEBUGGING 45258945Sroberto#define ISC_MEM_DEBUGGING 0 46258945Sroberto#endif 47258945SrobertoLIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING; 48258945Sroberto 49258945Sroberto/* 50258945Sroberto * Constants. 51258945Sroberto */ 52258945Sroberto 53258945Sroberto#define DEF_MAX_SIZE 1100 54258945Sroberto#define DEF_MEM_TARGET 4096 55258945Sroberto#define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */ 56258945Sroberto#define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */ 57258945Sroberto#define TABLE_INCREMENT 1024 58258945Sroberto#define DEBUGLIST_COUNT 1024 59258945Sroberto 60258945Sroberto/* 61258945Sroberto * Types. 62258945Sroberto */ 63280849Scytypedef struct isc__mem isc__mem_t; 64280849Scytypedef struct isc__mempool isc__mempool_t; 65280849Scy 66258945Sroberto#if ISC_MEM_TRACKLINES 67258945Srobertotypedef struct debuglink debuglink_t; 68258945Srobertostruct debuglink { 69258945Sroberto ISC_LINK(debuglink_t) link; 70258945Sroberto const void *ptr[DEBUGLIST_COUNT]; 71258945Sroberto unsigned int size[DEBUGLIST_COUNT]; 72258945Sroberto const char *file[DEBUGLIST_COUNT]; 73258945Sroberto unsigned int line[DEBUGLIST_COUNT]; 74258945Sroberto unsigned int count; 75258945Sroberto}; 76258945Sroberto 77258945Sroberto#define FLARG_PASS , file, line 78280849Scy#define FLARG , const char *file, unsigned int line 79258945Sroberto#else 80258945Sroberto#define FLARG_PASS 81258945Sroberto#define FLARG 82258945Sroberto#endif 83258945Sroberto 84258945Srobertotypedef struct element element; 85258945Srobertostruct element { 86258945Sroberto element * next; 87258945Sroberto}; 88258945Sroberto 89258945Srobertotypedef struct { 90258945Sroberto /*! 91258945Sroberto * This structure must be ALIGNMENT_SIZE bytes. 92258945Sroberto */ 93258945Sroberto union { 94258945Sroberto size_t size; 95280849Scy isc__mem_t *ctx; 96258945Sroberto char bytes[ALIGNMENT_SIZE]; 97258945Sroberto } u; 98258945Sroberto} size_info; 99258945Sroberto 100258945Srobertostruct stats { 101258945Sroberto unsigned long gets; 102258945Sroberto unsigned long totalgets; 103258945Sroberto unsigned long blocks; 104258945Sroberto unsigned long freefrags; 105258945Sroberto}; 106258945Sroberto 107258945Sroberto#define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C') 108258945Sroberto#define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC) 109258945Sroberto 110258945Sroberto#if ISC_MEM_TRACKLINES 111258945Srobertotypedef ISC_LIST(debuglink_t) debuglist_t; 112258945Sroberto#endif 113258945Sroberto 114258945Sroberto/* List of all active memory contexts. */ 115258945Sroberto 116280849Scystatic ISC_LIST(isc__mem_t) contexts; 117258945Srobertostatic isc_once_t once = ISC_ONCE_INIT; 118258945Srobertostatic isc_mutex_t lock; 119258945Sroberto 120258945Sroberto/*% 121258945Sroberto * Total size of lost memory due to a bug of external library. 122258945Sroberto * Locked by the global lock. 123258945Sroberto */ 124258945Srobertostatic isc_uint64_t totallost; 125258945Sroberto 126280849Scystruct isc__mem { 127280849Scy isc_mem_t common; 128258945Sroberto isc_ondestroy_t ondestroy; 129258945Sroberto unsigned int flags; 130258945Sroberto isc_mutex_t lock; 131258945Sroberto isc_memalloc_t memalloc; 132258945Sroberto isc_memfree_t memfree; 133258945Sroberto void * arg; 134258945Sroberto size_t max_size; 135258945Sroberto isc_boolean_t checkfree; 136258945Sroberto struct stats * stats; 137258945Sroberto unsigned int references; 138258945Sroberto char name[16]; 139258945Sroberto void * tag; 140258945Sroberto size_t quota; 141258945Sroberto size_t total; 142258945Sroberto size_t inuse; 143258945Sroberto size_t maxinuse; 144258945Sroberto size_t hi_water; 145258945Sroberto size_t lo_water; 146258945Sroberto isc_boolean_t hi_called; 147280849Scy isc_boolean_t is_overmem; 148258945Sroberto isc_mem_water_t water; 149258945Sroberto void * water_arg; 150280849Scy ISC_LIST(isc__mempool_t) pools; 151258945Sroberto unsigned int poolcnt; 152258945Sroberto 153258945Sroberto /* ISC_MEMFLAG_INTERNAL */ 154258945Sroberto size_t mem_target; 155258945Sroberto element ** freelists; 156258945Sroberto element * basic_blocks; 157258945Sroberto unsigned char ** basic_table; 158258945Sroberto unsigned int basic_table_count; 159258945Sroberto unsigned int basic_table_size; 160258945Sroberto unsigned char * lowest; 161258945Sroberto unsigned char * highest; 162258945Sroberto 163258945Sroberto#if ISC_MEM_TRACKLINES 164258945Sroberto debuglist_t * debuglist; 165258945Sroberto unsigned int debuglistcnt; 166258945Sroberto#endif 167258945Sroberto 168258945Sroberto unsigned int memalloc_failures; 169280849Scy ISC_LINK(isc__mem_t) link; 170258945Sroberto}; 171258945Sroberto 172258945Sroberto#define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p') 173258945Sroberto#define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC) 174258945Sroberto 175280849Scystruct isc__mempool { 176258945Sroberto /* always unlocked */ 177280849Scy isc_mempool_t common; /*%< common header of mempool's */ 178258945Sroberto isc_mutex_t *lock; /*%< optional lock */ 179280849Scy isc__mem_t *mctx; /*%< our memory context */ 180258945Sroberto /*%< locked via the memory context's lock */ 181280849Scy ISC_LINK(isc__mempool_t) link; /*%< next pool in this mem context */ 182258945Sroberto /*%< optionally locked from here down */ 183258945Sroberto element *items; /*%< low water item list */ 184258945Sroberto size_t size; /*%< size of each item on this pool */ 185258945Sroberto unsigned int maxalloc; /*%< max number of items allowed */ 186258945Sroberto unsigned int allocated; /*%< # of items currently given out */ 187258945Sroberto unsigned int freecount; /*%< # of items on reserved list */ 188258945Sroberto unsigned int freemax; /*%< # of items allowed on free list */ 189258945Sroberto unsigned int fillcount; /*%< # of items to fetch on each fill */ 190258945Sroberto /*%< Stats only. */ 191258945Sroberto unsigned int gets; /*%< # of requests to this pool */ 192258945Sroberto /*%< Debugging only. */ 193258945Sroberto#if ISC_MEMPOOL_NAMES 194258945Sroberto char name[16]; /*%< printed name in stats reports */ 195258945Sroberto#endif 196258945Sroberto}; 197258945Sroberto 198258945Sroberto/* 199258945Sroberto * Private Inline-able. 200258945Sroberto */ 201258945Sroberto 202258945Sroberto#if ! ISC_MEM_TRACKLINES 203258945Sroberto#define ADD_TRACE(a, b, c, d, e) 204258945Sroberto#define DELETE_TRACE(a, b, c, d, e) 205258945Sroberto#else 206258945Sroberto#define ADD_TRACE(a, b, c, d, e) \ 207258945Sroberto do { \ 208258945Sroberto if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \ 209258945Sroberto ISC_MEM_DEBUGRECORD)) != 0 && \ 210258945Sroberto b != NULL) \ 211258945Sroberto add_trace_entry(a, b, c, d, e); \ 212258945Sroberto } while (0) 213258945Sroberto#define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e) 214258945Sroberto 215258945Srobertostatic void 216280849Scyprint_active(isc__mem_t *ctx, FILE *out); 217258945Sroberto 218280849Scy/*% 219280849Scy * The following can be either static or public, depending on build environment. 220280849Scy */ 221280849Scy 222280849Scy#ifdef BIND9 223280849Scy#define ISC_MEMFUNC_SCOPE 224280849Scy#else 225280849Scy#define ISC_MEMFUNC_SCOPE static 226280849Scy#endif 227280849Scy 228280849ScyISC_MEMFUNC_SCOPE isc_result_t 229280849Scyisc__mem_createx(size_t init_max_size, size_t target_size, 230280849Scy isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 231280849Scy isc_mem_t **ctxp); 232280849ScyISC_MEMFUNC_SCOPE isc_result_t 233280849Scyisc__mem_createx2(size_t init_max_size, size_t target_size, 234280849Scy isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 235280849Scy isc_mem_t **ctxp, unsigned int flags); 236280849ScyISC_MEMFUNC_SCOPE isc_result_t 237280849Scyisc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp); 238280849ScyISC_MEMFUNC_SCOPE isc_result_t 239280849Scyisc__mem_create2(size_t init_max_size, size_t target_size, 240280849Scy isc_mem_t **ctxp, unsigned int flags); 241280849ScyISC_MEMFUNC_SCOPE void 242280849Scyisc__mem_attach(isc_mem_t *source, isc_mem_t **targetp); 243280849ScyISC_MEMFUNC_SCOPE void 244280849Scyisc__mem_detach(isc_mem_t **ctxp); 245280849ScyISC_MEMFUNC_SCOPE void 246280849Scyisc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG); 247280849ScyISC_MEMFUNC_SCOPE void 248280849Scyisc__mem_destroy(isc_mem_t **ctxp); 249280849ScyISC_MEMFUNC_SCOPE isc_result_t 250280849Scyisc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event); 251280849ScyISC_MEMFUNC_SCOPE void * 252280849Scyisc___mem_get(isc_mem_t *ctx, size_t size FLARG); 253280849ScyISC_MEMFUNC_SCOPE void 254280849Scyisc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG); 255280849ScyISC_MEMFUNC_SCOPE void 256280849Scyisc__mem_stats(isc_mem_t *ctx, FILE *out); 257280849ScyISC_MEMFUNC_SCOPE void * 258280849Scyisc___mem_allocate(isc_mem_t *ctx, size_t size FLARG); 259280849ScyISC_MEMFUNC_SCOPE void * 260280849Scyisc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG); 261280849ScyISC_MEMFUNC_SCOPE void 262280849Scyisc___mem_free(isc_mem_t *ctx, void *ptr FLARG); 263280849ScyISC_MEMFUNC_SCOPE char * 264280849Scyisc___mem_strdup(isc_mem_t *mctx, const char *s FLARG); 265280849ScyISC_MEMFUNC_SCOPE void 266280849Scyisc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag); 267280849ScyISC_MEMFUNC_SCOPE void 268280849Scyisc__mem_setquota(isc_mem_t *ctx, size_t quota); 269280849ScyISC_MEMFUNC_SCOPE size_t 270280849Scyisc__mem_getquota(isc_mem_t *ctx); 271280849ScyISC_MEMFUNC_SCOPE size_t 272280849Scyisc__mem_inuse(isc_mem_t *ctx); 273280849ScyISC_MEMFUNC_SCOPE isc_boolean_t 274280849Scyisc__mem_isovermem(isc_mem_t *ctx); 275280849ScyISC_MEMFUNC_SCOPE void 276280849Scyisc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, 277280849Scy size_t hiwater, size_t lowater); 278280849ScyISC_MEMFUNC_SCOPE void 279280849Scyisc__mem_waterack(isc_mem_t *ctx0, int flag); 280280849ScyISC_MEMFUNC_SCOPE void 281280849Scyisc__mem_setname(isc_mem_t *ctx, const char *name, void *tag); 282280849ScyISC_MEMFUNC_SCOPE const char * 283280849Scyisc__mem_getname(isc_mem_t *ctx); 284280849ScyISC_MEMFUNC_SCOPE void * 285280849Scyisc__mem_gettag(isc_mem_t *ctx); 286280849ScyISC_MEMFUNC_SCOPE isc_result_t 287280849Scyisc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp); 288280849ScyISC_MEMFUNC_SCOPE void 289280849Scyisc__mempool_setname(isc_mempool_t *mpctx, const char *name); 290280849ScyISC_MEMFUNC_SCOPE void 291280849Scyisc__mempool_destroy(isc_mempool_t **mpctxp); 292280849ScyISC_MEMFUNC_SCOPE void 293280849Scyisc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock); 294280849ScyISC_MEMFUNC_SCOPE void * 295280849Scyisc___mempool_get(isc_mempool_t *mpctx FLARG); 296280849ScyISC_MEMFUNC_SCOPE void 297280849Scyisc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG); 298280849ScyISC_MEMFUNC_SCOPE void 299280849Scyisc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit); 300280849ScyISC_MEMFUNC_SCOPE unsigned int 301280849Scyisc__mempool_getfreemax(isc_mempool_t *mpctx); 302280849ScyISC_MEMFUNC_SCOPE unsigned int 303280849Scyisc__mempool_getfreecount(isc_mempool_t *mpctx); 304280849ScyISC_MEMFUNC_SCOPE void 305280849Scyisc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit); 306280849ScyISC_MEMFUNC_SCOPE unsigned int 307280849Scyisc__mempool_getmaxalloc(isc_mempool_t *mpctx); 308280849ScyISC_MEMFUNC_SCOPE unsigned int 309280849Scyisc__mempool_getallocated(isc_mempool_t *mpctx); 310280849ScyISC_MEMFUNC_SCOPE void 311280849Scyisc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit); 312280849ScyISC_MEMFUNC_SCOPE unsigned int 313280849Scyisc__mempool_getfillcount(isc_mempool_t *mpctx); 314280849Scy#ifdef BIND9 315280849ScyISC_MEMFUNC_SCOPE void 316280849Scyisc__mem_printactive(isc_mem_t *ctx0, FILE *file); 317280849ScyISC_MEMFUNC_SCOPE void 318280849Scyisc__mem_printallactive(FILE *file); 319280849ScyISC_MEMFUNC_SCOPE void 320280849Scyisc__mem_checkdestroyed(FILE *file); 321280849ScyISC_MEMFUNC_SCOPE unsigned int 322280849Scyisc__mem_references(isc_mem_t *ctx0); 323280849Scy#endif 324280849Scy 325280849Scystatic struct isc__memmethods { 326280849Scy isc_memmethods_t methods; 327280849Scy 328280849Scy /*% 329280849Scy * The following are defined just for avoiding unused static functions. 330280849Scy */ 331280849Scy#ifndef BIND9 332280849Scy void *createx, *create, *create2, *ondestroy, *stats, 333280849Scy *setquota, *getquota, *setname, *getname, *gettag; 334280849Scy#endif 335280849Scy} memmethods = { 336280849Scy { 337280849Scy isc__mem_attach, 338280849Scy isc__mem_detach, 339280849Scy isc__mem_destroy, 340280849Scy isc___mem_get, 341280849Scy isc___mem_put, 342280849Scy isc___mem_putanddetach, 343280849Scy isc___mem_allocate, 344280849Scy isc___mem_reallocate, 345280849Scy isc___mem_strdup, 346280849Scy isc___mem_free, 347280849Scy isc__mem_setdestroycheck, 348280849Scy isc__mem_setwater, 349280849Scy isc__mem_waterack, 350280849Scy isc__mem_inuse, 351280849Scy isc__mem_isovermem, 352280849Scy isc__mempool_create 353280849Scy } 354280849Scy#ifndef BIND9 355280849Scy , 356280849Scy (void *)isc__mem_createx, (void *)isc__mem_create, 357280849Scy (void *)isc__mem_create2, (void *)isc__mem_ondestroy, 358280849Scy (void *)isc__mem_stats, (void *)isc__mem_setquota, 359280849Scy (void *)isc__mem_getquota, (void *)isc__mem_setname, 360280849Scy (void *)isc__mem_getname, (void *)isc__mem_gettag 361280849Scy#endif 362280849Scy}; 363280849Scy 364280849Scystatic struct isc__mempoolmethods { 365280849Scy isc_mempoolmethods_t methods; 366280849Scy 367280849Scy /*% 368280849Scy * The following are defined just for avoiding unused static functions. 369280849Scy */ 370280849Scy#ifndef BIND9 371280849Scy void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount; 372280849Scy#endif 373280849Scy} mempoolmethods = { 374280849Scy { 375280849Scy isc__mempool_destroy, 376280849Scy isc___mempool_get, 377280849Scy isc___mempool_put, 378280849Scy isc__mempool_getallocated, 379280849Scy isc__mempool_setmaxalloc, 380280849Scy isc__mempool_setfreemax, 381280849Scy isc__mempool_setname, 382280849Scy isc__mempool_associatelock, 383280849Scy isc__mempool_setfillcount 384280849Scy } 385280849Scy#ifndef BIND9 386280849Scy , 387280849Scy (void *)isc__mempool_getfreemax, (void *)isc__mempool_getfreecount, 388280849Scy (void *)isc__mempool_getmaxalloc, (void *)isc__mempool_getfillcount 389280849Scy#endif 390280849Scy}; 391280849Scy 392258945Sroberto/*! 393258945Sroberto * mctx must be locked. 394258945Sroberto */ 395258945Srobertostatic inline void 396280849Scyadd_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size 397258945Sroberto FLARG) 398258945Sroberto{ 399258945Sroberto debuglink_t *dl; 400258945Sroberto unsigned int i; 401280849Scy unsigned int mysize = size; 402258945Sroberto 403258945Sroberto if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) 404258945Sroberto fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 405258945Sroberto ISC_MSG_ADDTRACE, 406258945Sroberto "add %p size %u " 407258945Sroberto "file %s line %u mctx %p\n"), 408258945Sroberto ptr, size, file, line, mctx); 409258945Sroberto 410258945Sroberto if (mctx->debuglist == NULL) 411258945Sroberto return; 412258945Sroberto 413280849Scy if (mysize > mctx->max_size) 414280849Scy mysize = mctx->max_size; 415258945Sroberto 416280849Scy dl = ISC_LIST_HEAD(mctx->debuglist[mysize]); 417258945Sroberto while (dl != NULL) { 418258945Sroberto if (dl->count == DEBUGLIST_COUNT) 419258945Sroberto goto next; 420258945Sroberto for (i = 0; i < DEBUGLIST_COUNT; i++) { 421258945Sroberto if (dl->ptr[i] == NULL) { 422258945Sroberto dl->ptr[i] = ptr; 423258945Sroberto dl->size[i] = size; 424258945Sroberto dl->file[i] = file; 425258945Sroberto dl->line[i] = line; 426258945Sroberto dl->count++; 427258945Sroberto return; 428258945Sroberto } 429258945Sroberto } 430258945Sroberto next: 431258945Sroberto dl = ISC_LIST_NEXT(dl, link); 432258945Sroberto } 433258945Sroberto 434258945Sroberto dl = malloc(sizeof(debuglink_t)); 435258945Sroberto INSIST(dl != NULL); 436258945Sroberto 437258945Sroberto ISC_LINK_INIT(dl, link); 438258945Sroberto for (i = 1; i < DEBUGLIST_COUNT; i++) { 439258945Sroberto dl->ptr[i] = NULL; 440258945Sroberto dl->size[i] = 0; 441258945Sroberto dl->file[i] = NULL; 442258945Sroberto dl->line[i] = 0; 443258945Sroberto } 444258945Sroberto 445258945Sroberto dl->ptr[0] = ptr; 446258945Sroberto dl->size[0] = size; 447258945Sroberto dl->file[0] = file; 448258945Sroberto dl->line[0] = line; 449258945Sroberto dl->count = 1; 450258945Sroberto 451280849Scy ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link); 452258945Sroberto mctx->debuglistcnt++; 453258945Sroberto} 454258945Sroberto 455258945Srobertostatic inline void 456280849Scydelete_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size, 457258945Sroberto const char *file, unsigned int line) 458258945Sroberto{ 459258945Sroberto debuglink_t *dl; 460258945Sroberto unsigned int i; 461258945Sroberto 462258945Sroberto if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) 463258945Sroberto fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 464258945Sroberto ISC_MSG_DELTRACE, 465258945Sroberto "del %p size %u " 466258945Sroberto "file %s line %u mctx %p\n"), 467258945Sroberto ptr, size, file, line, mctx); 468258945Sroberto 469258945Sroberto if (mctx->debuglist == NULL) 470258945Sroberto return; 471258945Sroberto 472258945Sroberto if (size > mctx->max_size) 473258945Sroberto size = mctx->max_size; 474258945Sroberto 475258945Sroberto dl = ISC_LIST_HEAD(mctx->debuglist[size]); 476258945Sroberto while (dl != NULL) { 477258945Sroberto for (i = 0; i < DEBUGLIST_COUNT; i++) { 478258945Sroberto if (dl->ptr[i] == ptr) { 479258945Sroberto dl->ptr[i] = NULL; 480258945Sroberto dl->size[i] = 0; 481258945Sroberto dl->file[i] = NULL; 482258945Sroberto dl->line[i] = 0; 483258945Sroberto 484258945Sroberto INSIST(dl->count > 0); 485258945Sroberto dl->count--; 486258945Sroberto if (dl->count == 0) { 487258945Sroberto ISC_LIST_UNLINK(mctx->debuglist[size], 488258945Sroberto dl, link); 489258945Sroberto free(dl); 490258945Sroberto } 491258945Sroberto return; 492258945Sroberto } 493258945Sroberto } 494258945Sroberto dl = ISC_LIST_NEXT(dl, link); 495258945Sroberto } 496258945Sroberto 497258945Sroberto /* 498258945Sroberto * If we get here, we didn't find the item on the list. We're 499258945Sroberto * screwed. 500258945Sroberto */ 501258945Sroberto INSIST(dl != NULL); 502258945Sroberto} 503258945Sroberto#endif /* ISC_MEM_TRACKLINES */ 504258945Sroberto 505258945Srobertostatic inline size_t 506258945Srobertormsize(size_t size) { 507258945Sroberto /* 508258945Sroberto * round down to ALIGNMENT_SIZE 509258945Sroberto */ 510258945Sroberto return (size & (~(ALIGNMENT_SIZE - 1))); 511258945Sroberto} 512258945Sroberto 513258945Srobertostatic inline size_t 514258945Srobertoquantize(size_t size) { 515258945Sroberto /*! 516258945Sroberto * Round up the result in order to get a size big 517258945Sroberto * enough to satisfy the request and be aligned on ALIGNMENT_SIZE 518258945Sroberto * byte boundaries. 519258945Sroberto */ 520258945Sroberto 521258945Sroberto if (size == 0U) 522258945Sroberto return (ALIGNMENT_SIZE); 523258945Sroberto return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1))); 524258945Sroberto} 525258945Sroberto 526258945Srobertostatic inline isc_boolean_t 527280849Scymore_basic_blocks(isc__mem_t *ctx) { 528258945Sroberto void *new; 529258945Sroberto unsigned char *curr, *next; 530258945Sroberto unsigned char *first, *last; 531258945Sroberto unsigned char **table; 532258945Sroberto unsigned int table_size; 533258945Sroberto size_t increment; 534258945Sroberto int i; 535258945Sroberto 536258945Sroberto /* Require: we hold the context lock. */ 537258945Sroberto 538258945Sroberto /* 539258945Sroberto * Did we hit the quota for this context? 540258945Sroberto */ 541258945Sroberto increment = NUM_BASIC_BLOCKS * ctx->mem_target; 542258945Sroberto if (ctx->quota != 0U && ctx->total + increment > ctx->quota) 543258945Sroberto return (ISC_FALSE); 544258945Sroberto 545258945Sroberto INSIST(ctx->basic_table_count <= ctx->basic_table_size); 546258945Sroberto if (ctx->basic_table_count == ctx->basic_table_size) { 547258945Sroberto table_size = ctx->basic_table_size + TABLE_INCREMENT; 548258945Sroberto table = (ctx->memalloc)(ctx->arg, 549258945Sroberto table_size * sizeof(unsigned char *)); 550258945Sroberto if (table == NULL) { 551258945Sroberto ctx->memalloc_failures++; 552258945Sroberto return (ISC_FALSE); 553258945Sroberto } 554258945Sroberto if (ctx->basic_table_size != 0) { 555258945Sroberto memcpy(table, ctx->basic_table, 556258945Sroberto ctx->basic_table_size * 557258945Sroberto sizeof(unsigned char *)); 558258945Sroberto (ctx->memfree)(ctx->arg, ctx->basic_table); 559258945Sroberto } 560258945Sroberto ctx->basic_table = table; 561258945Sroberto ctx->basic_table_size = table_size; 562258945Sroberto } 563258945Sroberto 564258945Sroberto new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target); 565258945Sroberto if (new == NULL) { 566258945Sroberto ctx->memalloc_failures++; 567258945Sroberto return (ISC_FALSE); 568258945Sroberto } 569258945Sroberto ctx->total += increment; 570258945Sroberto ctx->basic_table[ctx->basic_table_count] = new; 571258945Sroberto ctx->basic_table_count++; 572258945Sroberto 573258945Sroberto curr = new; 574258945Sroberto next = curr + ctx->mem_target; 575258945Sroberto for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { 576258945Sroberto ((element *)curr)->next = (element *)next; 577258945Sroberto curr = next; 578258945Sroberto next += ctx->mem_target; 579258945Sroberto } 580258945Sroberto /* 581258945Sroberto * curr is now pointing at the last block in the 582258945Sroberto * array. 583258945Sroberto */ 584258945Sroberto ((element *)curr)->next = NULL; 585258945Sroberto first = new; 586258945Sroberto last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1; 587258945Sroberto if (first < ctx->lowest || ctx->lowest == NULL) 588258945Sroberto ctx->lowest = first; 589258945Sroberto if (last > ctx->highest) 590258945Sroberto ctx->highest = last; 591258945Sroberto ctx->basic_blocks = new; 592258945Sroberto 593258945Sroberto return (ISC_TRUE); 594258945Sroberto} 595258945Sroberto 596258945Srobertostatic inline isc_boolean_t 597280849Scymore_frags(isc__mem_t *ctx, size_t new_size) { 598258945Sroberto int i, frags; 599258945Sroberto size_t total_size; 600258945Sroberto void *new; 601258945Sroberto unsigned char *curr, *next; 602258945Sroberto 603258945Sroberto /*! 604258945Sroberto * Try to get more fragments by chopping up a basic block. 605258945Sroberto */ 606258945Sroberto 607258945Sroberto if (ctx->basic_blocks == NULL) { 608258945Sroberto if (!more_basic_blocks(ctx)) { 609258945Sroberto /* 610258945Sroberto * We can't get more memory from the OS, or we've 611258945Sroberto * hit the quota for this context. 612258945Sroberto */ 613258945Sroberto /* 614258945Sroberto * XXXRTH "At quota" notification here. 615258945Sroberto */ 616258945Sroberto return (ISC_FALSE); 617258945Sroberto } 618258945Sroberto } 619258945Sroberto 620258945Sroberto total_size = ctx->mem_target; 621258945Sroberto new = ctx->basic_blocks; 622258945Sroberto ctx->basic_blocks = ctx->basic_blocks->next; 623258945Sroberto frags = total_size / new_size; 624258945Sroberto ctx->stats[new_size].blocks++; 625258945Sroberto ctx->stats[new_size].freefrags += frags; 626258945Sroberto /* 627258945Sroberto * Set up a linked-list of blocks of size 628258945Sroberto * "new_size". 629258945Sroberto */ 630258945Sroberto curr = new; 631258945Sroberto next = curr + new_size; 632258945Sroberto total_size -= new_size; 633258945Sroberto for (i = 0; i < (frags - 1); i++) { 634258945Sroberto ((element *)curr)->next = (element *)next; 635258945Sroberto curr = next; 636258945Sroberto next += new_size; 637258945Sroberto total_size -= new_size; 638258945Sroberto } 639258945Sroberto /* 640258945Sroberto * Add the remaining fragment of the basic block to a free list. 641258945Sroberto */ 642258945Sroberto total_size = rmsize(total_size); 643258945Sroberto if (total_size > 0U) { 644258945Sroberto ((element *)next)->next = ctx->freelists[total_size]; 645258945Sroberto ctx->freelists[total_size] = (element *)next; 646258945Sroberto ctx->stats[total_size].freefrags++; 647258945Sroberto } 648258945Sroberto /* 649258945Sroberto * curr is now pointing at the last block in the 650258945Sroberto * array. 651258945Sroberto */ 652258945Sroberto ((element *)curr)->next = NULL; 653258945Sroberto ctx->freelists[new_size] = new; 654258945Sroberto 655258945Sroberto return (ISC_TRUE); 656258945Sroberto} 657258945Sroberto 658258945Srobertostatic inline void * 659280849Scymem_getunlocked(isc__mem_t *ctx, size_t size) { 660258945Sroberto size_t new_size = quantize(size); 661258945Sroberto void *ret; 662258945Sroberto 663258945Sroberto if (size >= ctx->max_size || new_size >= ctx->max_size) { 664258945Sroberto /* 665258945Sroberto * memget() was called on something beyond our upper limit. 666258945Sroberto */ 667258945Sroberto if (ctx->quota != 0U && ctx->total + size > ctx->quota) { 668258945Sroberto ret = NULL; 669258945Sroberto goto done; 670258945Sroberto } 671258945Sroberto ret = (ctx->memalloc)(ctx->arg, size); 672258945Sroberto if (ret == NULL) { 673258945Sroberto ctx->memalloc_failures++; 674258945Sroberto goto done; 675258945Sroberto } 676258945Sroberto ctx->total += size; 677258945Sroberto ctx->inuse += size; 678258945Sroberto ctx->stats[ctx->max_size].gets++; 679258945Sroberto ctx->stats[ctx->max_size].totalgets++; 680258945Sroberto /* 681258945Sroberto * If we don't set new_size to size, then the 682258945Sroberto * ISC_MEM_FILL code might write over bytes we 683258945Sroberto * don't own. 684258945Sroberto */ 685258945Sroberto new_size = size; 686258945Sroberto goto done; 687258945Sroberto } 688258945Sroberto 689258945Sroberto /* 690258945Sroberto * If there are no blocks in the free list for this size, get a chunk 691258945Sroberto * of memory and then break it up into "new_size"-sized blocks, adding 692258945Sroberto * them to the free list. 693258945Sroberto */ 694258945Sroberto if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size)) 695258945Sroberto return (NULL); 696258945Sroberto 697258945Sroberto /* 698258945Sroberto * The free list uses the "rounded-up" size "new_size". 699258945Sroberto */ 700258945Sroberto ret = ctx->freelists[new_size]; 701258945Sroberto ctx->freelists[new_size] = ctx->freelists[new_size]->next; 702258945Sroberto 703258945Sroberto /* 704258945Sroberto * The stats[] uses the _actual_ "size" requested by the 705258945Sroberto * caller, with the caveat (in the code above) that "size" >= the 706258945Sroberto * max. size (max_size) ends up getting recorded as a call to 707258945Sroberto * max_size. 708258945Sroberto */ 709258945Sroberto ctx->stats[size].gets++; 710258945Sroberto ctx->stats[size].totalgets++; 711258945Sroberto ctx->stats[new_size].freefrags--; 712258945Sroberto ctx->inuse += new_size; 713258945Sroberto 714258945Sroberto done: 715258945Sroberto 716258945Sroberto#if ISC_MEM_FILL 717258945Sroberto if (ret != NULL) 718258945Sroberto memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */ 719258945Sroberto#endif 720258945Sroberto 721258945Sroberto return (ret); 722258945Sroberto} 723258945Sroberto 724258945Sroberto#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN 725258945Srobertostatic inline void 726258945Srobertocheck_overrun(void *mem, size_t size, size_t new_size) { 727258945Sroberto unsigned char *cp; 728258945Sroberto 729258945Sroberto cp = (unsigned char *)mem; 730258945Sroberto cp += size; 731258945Sroberto while (size < new_size) { 732258945Sroberto INSIST(*cp == 0xbe); 733258945Sroberto cp++; 734258945Sroberto size++; 735258945Sroberto } 736258945Sroberto} 737258945Sroberto#endif 738258945Sroberto 739258945Srobertostatic inline void 740280849Scymem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) { 741258945Sroberto size_t new_size = quantize(size); 742258945Sroberto 743258945Sroberto if (size == ctx->max_size || new_size >= ctx->max_size) { 744258945Sroberto /* 745258945Sroberto * memput() called on something beyond our upper limit. 746258945Sroberto */ 747258945Sroberto#if ISC_MEM_FILL 748258945Sroberto memset(mem, 0xde, size); /* Mnemonic for "dead". */ 749258945Sroberto#endif 750258945Sroberto (ctx->memfree)(ctx->arg, mem); 751258945Sroberto INSIST(ctx->stats[ctx->max_size].gets != 0U); 752258945Sroberto ctx->stats[ctx->max_size].gets--; 753258945Sroberto INSIST(size <= ctx->total); 754258945Sroberto ctx->inuse -= size; 755258945Sroberto ctx->total -= size; 756258945Sroberto return; 757258945Sroberto } 758258945Sroberto 759258945Sroberto#if ISC_MEM_FILL 760258945Sroberto#if ISC_MEM_CHECKOVERRUN 761258945Sroberto check_overrun(mem, size, new_size); 762258945Sroberto#endif 763258945Sroberto memset(mem, 0xde, new_size); /* Mnemonic for "dead". */ 764258945Sroberto#endif 765258945Sroberto 766258945Sroberto /* 767258945Sroberto * The free list uses the "rounded-up" size "new_size". 768258945Sroberto */ 769258945Sroberto ((element *)mem)->next = ctx->freelists[new_size]; 770258945Sroberto ctx->freelists[new_size] = (element *)mem; 771258945Sroberto 772258945Sroberto /* 773258945Sroberto * The stats[] uses the _actual_ "size" requested by the 774258945Sroberto * caller, with the caveat (in the code above) that "size" >= the 775258945Sroberto * max. size (max_size) ends up getting recorded as a call to 776258945Sroberto * max_size. 777258945Sroberto */ 778258945Sroberto INSIST(ctx->stats[size].gets != 0U); 779258945Sroberto ctx->stats[size].gets--; 780258945Sroberto ctx->stats[new_size].freefrags++; 781258945Sroberto ctx->inuse -= new_size; 782258945Sroberto} 783258945Sroberto 784258945Sroberto/*! 785258945Sroberto * Perform a malloc, doing memory filling and overrun detection as necessary. 786258945Sroberto */ 787258945Srobertostatic inline void * 788280849Scymem_get(isc__mem_t *ctx, size_t size) { 789258945Sroberto char *ret; 790258945Sroberto 791258945Sroberto#if ISC_MEM_CHECKOVERRUN 792258945Sroberto size += 1; 793258945Sroberto#endif 794258945Sroberto 795258945Sroberto ret = (ctx->memalloc)(ctx->arg, size); 796258945Sroberto if (ret == NULL) 797258945Sroberto ctx->memalloc_failures++; 798258945Sroberto 799258945Sroberto#if ISC_MEM_FILL 800258945Sroberto if (ret != NULL) 801258945Sroberto memset(ret, 0xbe, size); /* Mnemonic for "beef". */ 802258945Sroberto#else 803258945Sroberto# if ISC_MEM_CHECKOVERRUN 804258945Sroberto if (ret != NULL) 805258945Sroberto ret[size-1] = 0xbe; 806258945Sroberto# endif 807258945Sroberto#endif 808258945Sroberto 809258945Sroberto return (ret); 810258945Sroberto} 811258945Sroberto 812258945Sroberto/*! 813258945Sroberto * Perform a free, doing memory filling and overrun detection as necessary. 814258945Sroberto */ 815258945Srobertostatic inline void 816280849Scymem_put(isc__mem_t *ctx, void *mem, size_t size) { 817258945Sroberto#if ISC_MEM_CHECKOVERRUN 818258945Sroberto INSIST(((unsigned char *)mem)[size] == 0xbe); 819258945Sroberto#endif 820258945Sroberto#if ISC_MEM_FILL 821258945Sroberto memset(mem, 0xde, size); /* Mnemonic for "dead". */ 822258945Sroberto#else 823258945Sroberto UNUSED(size); 824258945Sroberto#endif 825258945Sroberto (ctx->memfree)(ctx->arg, mem); 826258945Sroberto} 827258945Sroberto 828258945Sroberto/*! 829258945Sroberto * Update internal counters after a memory get. 830258945Sroberto */ 831258945Srobertostatic inline void 832280849Scymem_getstats(isc__mem_t *ctx, size_t size) { 833258945Sroberto ctx->total += size; 834258945Sroberto ctx->inuse += size; 835258945Sroberto 836258945Sroberto if (size > ctx->max_size) { 837258945Sroberto ctx->stats[ctx->max_size].gets++; 838258945Sroberto ctx->stats[ctx->max_size].totalgets++; 839258945Sroberto } else { 840258945Sroberto ctx->stats[size].gets++; 841258945Sroberto ctx->stats[size].totalgets++; 842258945Sroberto } 843258945Sroberto} 844258945Sroberto 845258945Sroberto/*! 846258945Sroberto * Update internal counters after a memory put. 847258945Sroberto */ 848258945Srobertostatic inline void 849280849Scymem_putstats(isc__mem_t *ctx, void *ptr, size_t size) { 850258945Sroberto UNUSED(ptr); 851258945Sroberto 852258945Sroberto INSIST(ctx->inuse >= size); 853258945Sroberto ctx->inuse -= size; 854258945Sroberto 855258945Sroberto if (size > ctx->max_size) { 856258945Sroberto INSIST(ctx->stats[ctx->max_size].gets > 0U); 857258945Sroberto ctx->stats[ctx->max_size].gets--; 858258945Sroberto } else { 859258945Sroberto INSIST(ctx->stats[size].gets > 0U); 860258945Sroberto ctx->stats[size].gets--; 861258945Sroberto } 862258945Sroberto} 863258945Sroberto 864258945Sroberto/* 865258945Sroberto * Private. 866258945Sroberto */ 867258945Sroberto 868258945Srobertostatic void * 869258945Srobertodefault_memalloc(void *arg, size_t size) { 870258945Sroberto UNUSED(arg); 871258945Sroberto if (size == 0U) 872258945Sroberto size = 1; 873258945Sroberto return (malloc(size)); 874258945Sroberto} 875258945Sroberto 876258945Srobertostatic void 877258945Srobertodefault_memfree(void *arg, void *ptr) { 878258945Sroberto UNUSED(arg); 879258945Sroberto free(ptr); 880258945Sroberto} 881258945Sroberto 882258945Srobertostatic void 883258945Srobertoinitialize_action(void) { 884258945Sroberto RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS); 885258945Sroberto ISC_LIST_INIT(contexts); 886258945Sroberto totallost = 0; 887258945Sroberto} 888258945Sroberto 889258945Sroberto/* 890258945Sroberto * Public. 891258945Sroberto */ 892258945Sroberto 893280849ScyISC_MEMFUNC_SCOPE isc_result_t 894280849Scyisc__mem_createx(size_t init_max_size, size_t target_size, 895280849Scy isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 896280849Scy isc_mem_t **ctxp) 897258945Sroberto{ 898280849Scy return (isc__mem_createx2(init_max_size, target_size, memalloc, memfree, 899280849Scy arg, ctxp, ISC_MEMFLAG_DEFAULT)); 900258945Sroberto 901258945Sroberto} 902258945Sroberto 903280849ScyISC_MEMFUNC_SCOPE isc_result_t 904280849Scyisc__mem_createx2(size_t init_max_size, size_t target_size, 905280849Scy isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, 906280849Scy isc_mem_t **ctxp, unsigned int flags) 907258945Sroberto{ 908280849Scy isc__mem_t *ctx; 909258945Sroberto isc_result_t result; 910258945Sroberto 911258945Sroberto REQUIRE(ctxp != NULL && *ctxp == NULL); 912258945Sroberto REQUIRE(memalloc != NULL); 913258945Sroberto REQUIRE(memfree != NULL); 914258945Sroberto 915258945Sroberto INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0); 916258945Sroberto 917258945Sroberto RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 918258945Sroberto 919258945Sroberto ctx = (memalloc)(arg, sizeof(*ctx)); 920258945Sroberto if (ctx == NULL) 921258945Sroberto return (ISC_R_NOMEMORY); 922258945Sroberto 923258945Sroberto if ((flags & ISC_MEMFLAG_NOLOCK) == 0) { 924258945Sroberto result = isc_mutex_init(&ctx->lock); 925258945Sroberto if (result != ISC_R_SUCCESS) { 926258945Sroberto (memfree)(arg, ctx); 927258945Sroberto return (result); 928258945Sroberto } 929258945Sroberto } 930258945Sroberto 931258945Sroberto if (init_max_size == 0U) 932258945Sroberto ctx->max_size = DEF_MAX_SIZE; 933258945Sroberto else 934258945Sroberto ctx->max_size = init_max_size; 935258945Sroberto ctx->flags = flags; 936258945Sroberto ctx->references = 1; 937258945Sroberto memset(ctx->name, 0, sizeof(ctx->name)); 938258945Sroberto ctx->tag = NULL; 939258945Sroberto ctx->quota = 0; 940258945Sroberto ctx->total = 0; 941258945Sroberto ctx->inuse = 0; 942258945Sroberto ctx->maxinuse = 0; 943258945Sroberto ctx->hi_water = 0; 944258945Sroberto ctx->lo_water = 0; 945258945Sroberto ctx->hi_called = ISC_FALSE; 946280849Scy ctx->is_overmem = ISC_FALSE; 947258945Sroberto ctx->water = NULL; 948258945Sroberto ctx->water_arg = NULL; 949280849Scy ctx->common.impmagic = MEM_MAGIC; 950280849Scy ctx->common.magic = ISCAPI_MCTX_MAGIC; 951280849Scy ctx->common.methods = (isc_memmethods_t *)&memmethods; 952258945Sroberto isc_ondestroy_init(&ctx->ondestroy); 953258945Sroberto ctx->memalloc = memalloc; 954258945Sroberto ctx->memfree = memfree; 955258945Sroberto ctx->arg = arg; 956258945Sroberto ctx->stats = NULL; 957258945Sroberto ctx->checkfree = ISC_TRUE; 958258945Sroberto#if ISC_MEM_TRACKLINES 959258945Sroberto ctx->debuglist = NULL; 960258945Sroberto ctx->debuglistcnt = 0; 961258945Sroberto#endif 962258945Sroberto ISC_LIST_INIT(ctx->pools); 963258945Sroberto ctx->poolcnt = 0; 964258945Sroberto ctx->freelists = NULL; 965258945Sroberto ctx->basic_blocks = NULL; 966258945Sroberto ctx->basic_table = NULL; 967258945Sroberto ctx->basic_table_count = 0; 968258945Sroberto ctx->basic_table_size = 0; 969258945Sroberto ctx->lowest = NULL; 970258945Sroberto ctx->highest = NULL; 971258945Sroberto 972258945Sroberto ctx->stats = (memalloc)(arg, 973258945Sroberto (ctx->max_size+1) * sizeof(struct stats)); 974258945Sroberto if (ctx->stats == NULL) { 975258945Sroberto result = ISC_R_NOMEMORY; 976258945Sroberto goto error; 977258945Sroberto } 978258945Sroberto memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats)); 979258945Sroberto 980258945Sroberto if ((flags & ISC_MEMFLAG_INTERNAL) != 0) { 981258945Sroberto if (target_size == 0U) 982258945Sroberto ctx->mem_target = DEF_MEM_TARGET; 983258945Sroberto else 984258945Sroberto ctx->mem_target = target_size; 985258945Sroberto ctx->freelists = (memalloc)(arg, ctx->max_size * 986258945Sroberto sizeof(element *)); 987258945Sroberto if (ctx->freelists == NULL) { 988258945Sroberto result = ISC_R_NOMEMORY; 989258945Sroberto goto error; 990258945Sroberto } 991258945Sroberto memset(ctx->freelists, 0, 992258945Sroberto ctx->max_size * sizeof(element *)); 993258945Sroberto } 994258945Sroberto 995258945Sroberto#if ISC_MEM_TRACKLINES 996258945Sroberto if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) { 997258945Sroberto unsigned int i; 998258945Sroberto 999258945Sroberto ctx->debuglist = (memalloc)(arg, 1000258945Sroberto (ctx->max_size+1) * sizeof(debuglist_t)); 1001258945Sroberto if (ctx->debuglist == NULL) { 1002258945Sroberto result = ISC_R_NOMEMORY; 1003258945Sroberto goto error; 1004258945Sroberto } 1005258945Sroberto for (i = 0; i <= ctx->max_size; i++) 1006258945Sroberto ISC_LIST_INIT(ctx->debuglist[i]); 1007258945Sroberto } 1008258945Sroberto#endif 1009258945Sroberto 1010258945Sroberto ctx->memalloc_failures = 0; 1011258945Sroberto 1012258945Sroberto LOCK(&lock); 1013258945Sroberto ISC_LIST_INITANDAPPEND(contexts, ctx, link); 1014258945Sroberto UNLOCK(&lock); 1015258945Sroberto 1016280849Scy *ctxp = (isc_mem_t *)ctx; 1017258945Sroberto return (ISC_R_SUCCESS); 1018258945Sroberto 1019258945Sroberto error: 1020258945Sroberto if (ctx != NULL) { 1021258945Sroberto if (ctx->stats != NULL) 1022258945Sroberto (memfree)(arg, ctx->stats); 1023258945Sroberto if (ctx->freelists != NULL) 1024258945Sroberto (memfree)(arg, ctx->freelists); 1025258945Sroberto#if ISC_MEM_TRACKLINES 1026258945Sroberto if (ctx->debuglist != NULL) 1027258945Sroberto (ctx->memfree)(ctx->arg, ctx->debuglist); 1028258945Sroberto#endif /* ISC_MEM_TRACKLINES */ 1029258945Sroberto if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 1030258945Sroberto DESTROYLOCK(&ctx->lock); 1031258945Sroberto (memfree)(arg, ctx); 1032258945Sroberto } 1033258945Sroberto 1034258945Sroberto return (result); 1035258945Sroberto} 1036258945Sroberto 1037280849ScyISC_MEMFUNC_SCOPE isc_result_t 1038280849Scyisc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) { 1039280849Scy return (isc__mem_createx2(init_max_size, target_size, 1040280849Scy default_memalloc, default_memfree, NULL, 1041280849Scy ctxp, ISC_MEMFLAG_DEFAULT)); 1042258945Sroberto} 1043258945Sroberto 1044280849ScyISC_MEMFUNC_SCOPE isc_result_t 1045280849Scyisc__mem_create2(size_t init_max_size, size_t target_size, 1046280849Scy isc_mem_t **ctxp, unsigned int flags) 1047258945Sroberto{ 1048280849Scy return (isc__mem_createx2(init_max_size, target_size, 1049280849Scy default_memalloc, default_memfree, NULL, 1050280849Scy ctxp, flags)); 1051258945Sroberto} 1052258945Sroberto 1053258945Srobertostatic void 1054280849Scydestroy(isc__mem_t *ctx) { 1055258945Sroberto unsigned int i; 1056258945Sroberto isc_ondestroy_t ondest; 1057258945Sroberto 1058258945Sroberto LOCK(&lock); 1059258945Sroberto ISC_LIST_UNLINK(contexts, ctx, link); 1060258945Sroberto totallost += ctx->inuse; 1061258945Sroberto UNLOCK(&lock); 1062258945Sroberto 1063280849Scy ctx->common.impmagic = 0; 1064280849Scy ctx->common.magic = 0; 1065280849Scy 1066258945Sroberto INSIST(ISC_LIST_EMPTY(ctx->pools)); 1067258945Sroberto 1068258945Sroberto#if ISC_MEM_TRACKLINES 1069258945Sroberto if (ctx->debuglist != NULL) { 1070258945Sroberto if (ctx->checkfree) { 1071258945Sroberto for (i = 0; i <= ctx->max_size; i++) { 1072258945Sroberto if (!ISC_LIST_EMPTY(ctx->debuglist[i])) 1073258945Sroberto print_active(ctx, stderr); 1074258945Sroberto INSIST(ISC_LIST_EMPTY(ctx->debuglist[i])); 1075258945Sroberto } 1076258945Sroberto } else { 1077258945Sroberto debuglink_t *dl; 1078258945Sroberto 1079258945Sroberto for (i = 0; i <= ctx->max_size; i++) 1080258945Sroberto for (dl = ISC_LIST_HEAD(ctx->debuglist[i]); 1081258945Sroberto dl != NULL; 1082258945Sroberto dl = ISC_LIST_HEAD(ctx->debuglist[i])) { 1083258945Sroberto ISC_LIST_UNLINK(ctx->debuglist[i], 1084258945Sroberto dl, link); 1085258945Sroberto free(dl); 1086258945Sroberto } 1087258945Sroberto } 1088258945Sroberto (ctx->memfree)(ctx->arg, ctx->debuglist); 1089258945Sroberto } 1090258945Sroberto#endif 1091258945Sroberto INSIST(ctx->references == 0); 1092258945Sroberto 1093258945Sroberto if (ctx->checkfree) { 1094258945Sroberto for (i = 0; i <= ctx->max_size; i++) { 1095258945Sroberto#if ISC_MEM_TRACKLINES 1096258945Sroberto if (ctx->stats[i].gets != 0U) 1097258945Sroberto print_active(ctx, stderr); 1098258945Sroberto#endif 1099258945Sroberto INSIST(ctx->stats[i].gets == 0U); 1100258945Sroberto } 1101258945Sroberto } 1102258945Sroberto 1103258945Sroberto (ctx->memfree)(ctx->arg, ctx->stats); 1104258945Sroberto 1105258945Sroberto if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1106258945Sroberto for (i = 0; i < ctx->basic_table_count; i++) 1107258945Sroberto (ctx->memfree)(ctx->arg, ctx->basic_table[i]); 1108258945Sroberto (ctx->memfree)(ctx->arg, ctx->freelists); 1109258945Sroberto if (ctx->basic_table != NULL) 1110258945Sroberto (ctx->memfree)(ctx->arg, ctx->basic_table); 1111258945Sroberto } 1112258945Sroberto 1113258945Sroberto ondest = ctx->ondestroy; 1114258945Sroberto 1115258945Sroberto if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 1116258945Sroberto DESTROYLOCK(&ctx->lock); 1117258945Sroberto (ctx->memfree)(ctx->arg, ctx); 1118258945Sroberto 1119258945Sroberto isc_ondestroy_notify(&ondest, ctx); 1120258945Sroberto} 1121258945Sroberto 1122280849ScyISC_MEMFUNC_SCOPE void 1123280849Scyisc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) { 1124280849Scy isc__mem_t *source = (isc__mem_t *)source0; 1125280849Scy 1126258945Sroberto REQUIRE(VALID_CONTEXT(source)); 1127258945Sroberto REQUIRE(targetp != NULL && *targetp == NULL); 1128258945Sroberto 1129258945Sroberto MCTXLOCK(source, &source->lock); 1130258945Sroberto source->references++; 1131258945Sroberto MCTXUNLOCK(source, &source->lock); 1132258945Sroberto 1133280849Scy *targetp = (isc_mem_t *)source; 1134258945Sroberto} 1135258945Sroberto 1136280849ScyISC_MEMFUNC_SCOPE void 1137280849Scyisc__mem_detach(isc_mem_t **ctxp) { 1138280849Scy isc__mem_t *ctx; 1139258945Sroberto isc_boolean_t want_destroy = ISC_FALSE; 1140258945Sroberto 1141258945Sroberto REQUIRE(ctxp != NULL); 1142280849Scy ctx = (isc__mem_t *)*ctxp; 1143258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1144258945Sroberto 1145258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1146258945Sroberto INSIST(ctx->references > 0); 1147258945Sroberto ctx->references--; 1148258945Sroberto if (ctx->references == 0) 1149258945Sroberto want_destroy = ISC_TRUE; 1150258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1151258945Sroberto 1152258945Sroberto if (want_destroy) 1153258945Sroberto destroy(ctx); 1154258945Sroberto 1155258945Sroberto *ctxp = NULL; 1156258945Sroberto} 1157258945Sroberto 1158258945Sroberto/* 1159258945Sroberto * isc_mem_putanddetach() is the equivalent of: 1160258945Sroberto * 1161258945Sroberto * mctx = NULL; 1162258945Sroberto * isc_mem_attach(ptr->mctx, &mctx); 1163258945Sroberto * isc_mem_detach(&ptr->mctx); 1164258945Sroberto * isc_mem_put(mctx, ptr, sizeof(*ptr); 1165258945Sroberto * isc_mem_detach(&mctx); 1166258945Sroberto */ 1167258945Sroberto 1168280849ScyISC_MEMFUNC_SCOPE void 1169280849Scyisc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { 1170280849Scy isc__mem_t *ctx; 1171258945Sroberto isc_boolean_t want_destroy = ISC_FALSE; 1172258945Sroberto size_info *si; 1173258945Sroberto size_t oldsize; 1174258945Sroberto 1175258945Sroberto REQUIRE(ctxp != NULL); 1176280849Scy ctx = (isc__mem_t *)*ctxp; 1177258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1178258945Sroberto REQUIRE(ptr != NULL); 1179258945Sroberto 1180258945Sroberto /* 1181258945Sroberto * Must be before mem_putunlocked() as ctxp is usually within 1182258945Sroberto * [ptr..ptr+size). 1183258945Sroberto */ 1184258945Sroberto *ctxp = NULL; 1185258945Sroberto 1186258945Sroberto if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { 1187258945Sroberto if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { 1188258945Sroberto si = &(((size_info *)ptr)[-1]); 1189258945Sroberto oldsize = si->u.size - ALIGNMENT_SIZE; 1190258945Sroberto if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1191258945Sroberto oldsize -= ALIGNMENT_SIZE; 1192258945Sroberto INSIST(oldsize == size); 1193258945Sroberto } 1194280849Scy isc_mem_free((isc_mem_t *)ctx, ptr); 1195258945Sroberto 1196258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1197258945Sroberto ctx->references--; 1198258945Sroberto if (ctx->references == 0) 1199258945Sroberto want_destroy = ISC_TRUE; 1200258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1201258945Sroberto if (want_destroy) 1202258945Sroberto destroy(ctx); 1203258945Sroberto 1204258945Sroberto return; 1205258945Sroberto } 1206258945Sroberto 1207258945Sroberto if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1208258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1209258945Sroberto mem_putunlocked(ctx, ptr, size); 1210258945Sroberto } else { 1211258945Sroberto mem_put(ctx, ptr, size); 1212258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1213258945Sroberto mem_putstats(ctx, ptr, size); 1214258945Sroberto } 1215258945Sroberto 1216258945Sroberto DELETE_TRACE(ctx, ptr, size, file, line); 1217258945Sroberto INSIST(ctx->references > 0); 1218258945Sroberto ctx->references--; 1219258945Sroberto if (ctx->references == 0) 1220258945Sroberto want_destroy = ISC_TRUE; 1221258945Sroberto 1222258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1223258945Sroberto 1224258945Sroberto if (want_destroy) 1225258945Sroberto destroy(ctx); 1226258945Sroberto} 1227258945Sroberto 1228280849ScyISC_MEMFUNC_SCOPE void 1229280849Scyisc__mem_destroy(isc_mem_t **ctxp) { 1230280849Scy isc__mem_t *ctx; 1231258945Sroberto 1232258945Sroberto /* 1233258945Sroberto * This routine provides legacy support for callers who use mctxs 1234258945Sroberto * without attaching/detaching. 1235258945Sroberto */ 1236258945Sroberto 1237258945Sroberto REQUIRE(ctxp != NULL); 1238280849Scy ctx = (isc__mem_t *)*ctxp; 1239258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1240258945Sroberto 1241258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1242258945Sroberto#if ISC_MEM_TRACKLINES 1243258945Sroberto if (ctx->references != 1) 1244258945Sroberto print_active(ctx, stderr); 1245258945Sroberto#endif 1246258945Sroberto REQUIRE(ctx->references == 1); 1247258945Sroberto ctx->references--; 1248258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1249258945Sroberto 1250258945Sroberto destroy(ctx); 1251258945Sroberto 1252258945Sroberto *ctxp = NULL; 1253258945Sroberto} 1254258945Sroberto 1255280849ScyISC_MEMFUNC_SCOPE isc_result_t 1256280849Scyisc__mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) { 1257280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1258258945Sroberto isc_result_t res; 1259258945Sroberto 1260258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1261258945Sroberto res = isc_ondestroy_register(&ctx->ondestroy, task, event); 1262258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1263258945Sroberto 1264258945Sroberto return (res); 1265258945Sroberto} 1266258945Sroberto 1267280849ScyISC_MEMFUNC_SCOPE void * 1268280849Scyisc___mem_get(isc_mem_t *ctx0, size_t size FLARG) { 1269280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1270258945Sroberto void *ptr; 1271258945Sroberto isc_boolean_t call_water = ISC_FALSE; 1272258945Sroberto 1273258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1274258945Sroberto 1275258945Sroberto if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) 1276280849Scy return (isc__mem_allocate(ctx0, size FLARG_PASS)); 1277258945Sroberto 1278258945Sroberto if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1279258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1280258945Sroberto ptr = mem_getunlocked(ctx, size); 1281258945Sroberto } else { 1282258945Sroberto ptr = mem_get(ctx, size); 1283258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1284258945Sroberto if (ptr != NULL) 1285258945Sroberto mem_getstats(ctx, size); 1286258945Sroberto } 1287258945Sroberto 1288258945Sroberto ADD_TRACE(ctx, ptr, size, file, line); 1289280849Scy if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1290280849Scy !ctx->is_overmem) { 1291280849Scy ctx->is_overmem = ISC_TRUE; 1292280849Scy } 1293258945Sroberto if (ctx->hi_water != 0U && !ctx->hi_called && 1294258945Sroberto ctx->inuse > ctx->hi_water) { 1295258945Sroberto call_water = ISC_TRUE; 1296258945Sroberto } 1297258945Sroberto if (ctx->inuse > ctx->maxinuse) { 1298258945Sroberto ctx->maxinuse = ctx->inuse; 1299258945Sroberto if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1300258945Sroberto (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) 1301258945Sroberto fprintf(stderr, "maxinuse = %lu\n", 1302258945Sroberto (unsigned long)ctx->inuse); 1303258945Sroberto } 1304258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1305258945Sroberto 1306258945Sroberto if (call_water) 1307258945Sroberto (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); 1308258945Sroberto 1309258945Sroberto return (ptr); 1310258945Sroberto} 1311258945Sroberto 1312280849ScyISC_MEMFUNC_SCOPE void 1313280849Scyisc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) { 1314280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1315258945Sroberto isc_boolean_t call_water = ISC_FALSE; 1316258945Sroberto size_info *si; 1317258945Sroberto size_t oldsize; 1318258945Sroberto 1319258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1320258945Sroberto REQUIRE(ptr != NULL); 1321258945Sroberto 1322258945Sroberto if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { 1323258945Sroberto if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { 1324258945Sroberto si = &(((size_info *)ptr)[-1]); 1325258945Sroberto oldsize = si->u.size - ALIGNMENT_SIZE; 1326258945Sroberto if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1327258945Sroberto oldsize -= ALIGNMENT_SIZE; 1328258945Sroberto INSIST(oldsize == size); 1329258945Sroberto } 1330280849Scy isc_mem_free((isc_mem_t *)ctx, ptr); 1331258945Sroberto return; 1332258945Sroberto } 1333258945Sroberto 1334258945Sroberto if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1335258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1336258945Sroberto mem_putunlocked(ctx, ptr, size); 1337258945Sroberto } else { 1338258945Sroberto mem_put(ctx, ptr, size); 1339258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1340258945Sroberto mem_putstats(ctx, ptr, size); 1341258945Sroberto } 1342258945Sroberto 1343258945Sroberto DELETE_TRACE(ctx, ptr, size, file, line); 1344258945Sroberto 1345258945Sroberto /* 1346258945Sroberto * The check against ctx->lo_water == 0 is for the condition 1347258945Sroberto * when the context was pushed over hi_water but then had 1348258945Sroberto * isc_mem_setwater() called with 0 for hi_water and lo_water. 1349258945Sroberto */ 1350280849Scy if (ctx->is_overmem && 1351280849Scy (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1352280849Scy ctx->is_overmem = ISC_FALSE; 1353280849Scy } 1354258945Sroberto if (ctx->hi_called && 1355258945Sroberto (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1356258945Sroberto if (ctx->water != NULL) 1357258945Sroberto call_water = ISC_TRUE; 1358258945Sroberto } 1359258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1360258945Sroberto 1361258945Sroberto if (call_water) 1362258945Sroberto (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1363258945Sroberto} 1364258945Sroberto 1365280849ScyISC_MEMFUNC_SCOPE void 1366280849Scyisc__mem_waterack(isc_mem_t *ctx0, int flag) { 1367280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1368280849Scy 1369258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1370258945Sroberto 1371258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1372258945Sroberto if (flag == ISC_MEM_LOWATER) 1373258945Sroberto ctx->hi_called = ISC_FALSE; 1374258945Sroberto else if (flag == ISC_MEM_HIWATER) 1375258945Sroberto ctx->hi_called = ISC_TRUE; 1376258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1377258945Sroberto} 1378258945Sroberto 1379258945Sroberto#if ISC_MEM_TRACKLINES 1380258945Srobertostatic void 1381280849Scyprint_active(isc__mem_t *mctx, FILE *out) { 1382258945Sroberto if (mctx->debuglist != NULL) { 1383258945Sroberto debuglink_t *dl; 1384258945Sroberto unsigned int i, j; 1385258945Sroberto const char *format; 1386258945Sroberto isc_boolean_t found; 1387258945Sroberto 1388258945Sroberto fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1389258945Sroberto ISC_MSG_DUMPALLOC, 1390258945Sroberto "Dump of all outstanding " 1391258945Sroberto "memory allocations:\n")); 1392258945Sroberto found = ISC_FALSE; 1393258945Sroberto format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1394258945Sroberto ISC_MSG_PTRFILELINE, 1395258945Sroberto "\tptr %p size %u file %s line %u\n"); 1396258945Sroberto for (i = 0; i <= mctx->max_size; i++) { 1397258945Sroberto dl = ISC_LIST_HEAD(mctx->debuglist[i]); 1398258945Sroberto 1399258945Sroberto if (dl != NULL) 1400258945Sroberto found = ISC_TRUE; 1401258945Sroberto 1402258945Sroberto while (dl != NULL) { 1403258945Sroberto for (j = 0; j < DEBUGLIST_COUNT; j++) 1404258945Sroberto if (dl->ptr[j] != NULL) 1405258945Sroberto fprintf(out, format, 1406258945Sroberto dl->ptr[j], 1407258945Sroberto dl->size[j], 1408258945Sroberto dl->file[j], 1409258945Sroberto dl->line[j]); 1410258945Sroberto dl = ISC_LIST_NEXT(dl, link); 1411258945Sroberto } 1412258945Sroberto } 1413258945Sroberto if (!found) 1414258945Sroberto fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1415258945Sroberto ISC_MSG_NONE, "\tNone.\n")); 1416258945Sroberto } 1417258945Sroberto} 1418258945Sroberto#endif 1419258945Sroberto 1420258945Sroberto/* 1421258945Sroberto * Print the stats[] on the stream "out" with suitable formatting. 1422258945Sroberto */ 1423280849ScyISC_MEMFUNC_SCOPE void 1424280849Scyisc__mem_stats(isc_mem_t *ctx0, FILE *out) { 1425280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1426258945Sroberto size_t i; 1427258945Sroberto const struct stats *s; 1428280849Scy const isc__mempool_t *pool; 1429258945Sroberto 1430258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1431258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1432258945Sroberto 1433258945Sroberto for (i = 0; i <= ctx->max_size; i++) { 1434258945Sroberto s = &ctx->stats[i]; 1435258945Sroberto 1436258945Sroberto if (s->totalgets == 0U && s->gets == 0U) 1437258945Sroberto continue; 1438258945Sroberto fprintf(out, "%s%5lu: %11lu gets, %11lu rem", 1439258945Sroberto (i == ctx->max_size) ? ">=" : " ", 1440258945Sroberto (unsigned long) i, s->totalgets, s->gets); 1441258945Sroberto if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 && 1442258945Sroberto (s->blocks != 0U || s->freefrags != 0U)) 1443258945Sroberto fprintf(out, " (%lu bl, %lu ff)", 1444258945Sroberto s->blocks, s->freefrags); 1445258945Sroberto fputc('\n', out); 1446258945Sroberto } 1447258945Sroberto 1448258945Sroberto /* 1449258945Sroberto * Note that since a pool can be locked now, these stats might be 1450258945Sroberto * somewhat off if the pool is in active use at the time the stats 1451258945Sroberto * are dumped. The link fields are protected by the isc_mem_t's 1452258945Sroberto * lock, however, so walking this list and extracting integers from 1453258945Sroberto * stats fields is always safe. 1454258945Sroberto */ 1455258945Sroberto pool = ISC_LIST_HEAD(ctx->pools); 1456258945Sroberto if (pool != NULL) { 1457258945Sroberto fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1458258945Sroberto ISC_MSG_POOLSTATS, 1459258945Sroberto "[Pool statistics]\n")); 1460258945Sroberto fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n", 1461258945Sroberto isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1462258945Sroberto ISC_MSG_POOLNAME, "name"), 1463258945Sroberto isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1464258945Sroberto ISC_MSG_POOLSIZE, "size"), 1465258945Sroberto isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1466258945Sroberto ISC_MSG_POOLMAXALLOC, "maxalloc"), 1467258945Sroberto isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1468258945Sroberto ISC_MSG_POOLALLOCATED, "allocated"), 1469258945Sroberto isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1470258945Sroberto ISC_MSG_POOLFREECOUNT, "freecount"), 1471258945Sroberto isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1472258945Sroberto ISC_MSG_POOLFREEMAX, "freemax"), 1473258945Sroberto isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1474258945Sroberto ISC_MSG_POOLFILLCOUNT, "fillcount"), 1475258945Sroberto isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, 1476258945Sroberto ISC_MSG_POOLGETS, "gets"), 1477258945Sroberto "L"); 1478258945Sroberto } 1479258945Sroberto while (pool != NULL) { 1480258945Sroberto fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n", 1481258945Sroberto pool->name, (unsigned long) pool->size, pool->maxalloc, 1482258945Sroberto pool->allocated, pool->freecount, pool->freemax, 1483258945Sroberto pool->fillcount, pool->gets, 1484258945Sroberto (pool->lock == NULL ? "N" : "Y")); 1485258945Sroberto pool = ISC_LIST_NEXT(pool, link); 1486258945Sroberto } 1487258945Sroberto 1488258945Sroberto#if ISC_MEM_TRACKLINES 1489258945Sroberto print_active(ctx, out); 1490258945Sroberto#endif 1491258945Sroberto 1492258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1493258945Sroberto} 1494258945Sroberto 1495258945Sroberto/* 1496258945Sroberto * Replacements for malloc() and free() -- they implicitly remember the 1497258945Sroberto * size of the object allocated (with some additional overhead). 1498258945Sroberto */ 1499258945Sroberto 1500258945Srobertostatic void * 1501280849Scyisc__mem_allocateunlocked(isc_mem_t *ctx0, size_t size) { 1502280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1503258945Sroberto size_info *si; 1504258945Sroberto 1505258945Sroberto size += ALIGNMENT_SIZE; 1506258945Sroberto if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) 1507258945Sroberto size += ALIGNMENT_SIZE; 1508258945Sroberto 1509258945Sroberto if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) 1510258945Sroberto si = mem_getunlocked(ctx, size); 1511258945Sroberto else 1512258945Sroberto si = mem_get(ctx, size); 1513258945Sroberto 1514258945Sroberto if (si == NULL) 1515258945Sroberto return (NULL); 1516258945Sroberto if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1517258945Sroberto si->u.ctx = ctx; 1518258945Sroberto si++; 1519258945Sroberto } 1520258945Sroberto si->u.size = size; 1521258945Sroberto return (&si[1]); 1522258945Sroberto} 1523258945Sroberto 1524280849ScyISC_MEMFUNC_SCOPE void * 1525280849Scyisc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) { 1526280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1527258945Sroberto size_info *si; 1528258945Sroberto isc_boolean_t call_water = ISC_FALSE; 1529258945Sroberto 1530258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1531258945Sroberto 1532258945Sroberto if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1533258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1534280849Scy si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size); 1535258945Sroberto } else { 1536280849Scy si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size); 1537258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1538258945Sroberto if (si != NULL) 1539258945Sroberto mem_getstats(ctx, si[-1].u.size); 1540258945Sroberto } 1541258945Sroberto 1542258945Sroberto#if ISC_MEM_TRACKLINES 1543258945Sroberto ADD_TRACE(ctx, si, si[-1].u.size, file, line); 1544258945Sroberto#endif 1545280849Scy if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1546280849Scy !ctx->is_overmem) { 1547280849Scy ctx->is_overmem = ISC_TRUE; 1548280849Scy } 1549280849Scy 1550258945Sroberto if (ctx->hi_water != 0U && !ctx->hi_called && 1551258945Sroberto ctx->inuse > ctx->hi_water) { 1552258945Sroberto ctx->hi_called = ISC_TRUE; 1553258945Sroberto call_water = ISC_TRUE; 1554258945Sroberto } 1555258945Sroberto if (ctx->inuse > ctx->maxinuse) { 1556258945Sroberto ctx->maxinuse = ctx->inuse; 1557258945Sroberto if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && 1558258945Sroberto (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) 1559258945Sroberto fprintf(stderr, "maxinuse = %lu\n", 1560258945Sroberto (unsigned long)ctx->inuse); 1561258945Sroberto } 1562258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1563258945Sroberto 1564258945Sroberto if (call_water) 1565258945Sroberto (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); 1566258945Sroberto 1567258945Sroberto return (si); 1568258945Sroberto} 1569258945Sroberto 1570280849ScyISC_MEMFUNC_SCOPE void * 1571280849Scyisc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) { 1572280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1573258945Sroberto void *new_ptr = NULL; 1574258945Sroberto size_t oldsize, copysize; 1575258945Sroberto 1576258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1577258945Sroberto 1578258945Sroberto /* 1579258945Sroberto * This function emulates the realloc(3) standard library function: 1580258945Sroberto * - if size > 0, allocate new memory; and if ptr is non NULL, copy 1581258945Sroberto * as much of the old contents to the new buffer and free the old one. 1582258945Sroberto * Note that when allocation fails the original pointer is intact; 1583258945Sroberto * the caller must free it. 1584258945Sroberto * - if size is 0 and ptr is non NULL, simply free the given ptr. 1585258945Sroberto * - this function returns: 1586258945Sroberto * pointer to the newly allocated memory, or 1587258945Sroberto * NULL if allocation fails or doesn't happen. 1588258945Sroberto */ 1589258945Sroberto if (size > 0U) { 1590280849Scy new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS); 1591258945Sroberto if (new_ptr != NULL && ptr != NULL) { 1592258945Sroberto oldsize = (((size_info *)ptr)[-1]).u.size; 1593258945Sroberto INSIST(oldsize >= ALIGNMENT_SIZE); 1594258945Sroberto oldsize -= ALIGNMENT_SIZE; 1595258945Sroberto copysize = oldsize > size ? size : oldsize; 1596258945Sroberto memcpy(new_ptr, ptr, copysize); 1597280849Scy isc__mem_free(ctx0, ptr FLARG_PASS); 1598258945Sroberto } 1599258945Sroberto } else if (ptr != NULL) 1600280849Scy isc__mem_free(ctx0, ptr FLARG_PASS); 1601258945Sroberto 1602258945Sroberto return (new_ptr); 1603258945Sroberto} 1604258945Sroberto 1605280849ScyISC_MEMFUNC_SCOPE void 1606280849Scyisc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) { 1607280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1608258945Sroberto size_info *si; 1609258945Sroberto size_t size; 1610258945Sroberto isc_boolean_t call_water= ISC_FALSE; 1611258945Sroberto 1612258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1613258945Sroberto REQUIRE(ptr != NULL); 1614258945Sroberto 1615258945Sroberto if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { 1616258945Sroberto si = &(((size_info *)ptr)[-2]); 1617258945Sroberto REQUIRE(si->u.ctx == ctx); 1618258945Sroberto size = si[1].u.size; 1619258945Sroberto } else { 1620258945Sroberto si = &(((size_info *)ptr)[-1]); 1621258945Sroberto size = si->u.size; 1622258945Sroberto } 1623258945Sroberto 1624258945Sroberto if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1625258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1626258945Sroberto mem_putunlocked(ctx, si, size); 1627258945Sroberto } else { 1628258945Sroberto mem_put(ctx, si, size); 1629258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1630258945Sroberto mem_putstats(ctx, si, size); 1631258945Sroberto } 1632258945Sroberto 1633258945Sroberto DELETE_TRACE(ctx, ptr, size, file, line); 1634258945Sroberto 1635258945Sroberto /* 1636258945Sroberto * The check against ctx->lo_water == 0 is for the condition 1637258945Sroberto * when the context was pushed over hi_water but then had 1638258945Sroberto * isc_mem_setwater() called with 0 for hi_water and lo_water. 1639258945Sroberto */ 1640280849Scy if (ctx->is_overmem && 1641280849Scy (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1642280849Scy ctx->is_overmem = ISC_FALSE; 1643280849Scy } 1644280849Scy 1645258945Sroberto if (ctx->hi_called && 1646258945Sroberto (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { 1647258945Sroberto ctx->hi_called = ISC_FALSE; 1648258945Sroberto 1649258945Sroberto if (ctx->water != NULL) 1650258945Sroberto call_water = ISC_TRUE; 1651258945Sroberto } 1652258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1653258945Sroberto 1654258945Sroberto if (call_water) 1655258945Sroberto (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); 1656258945Sroberto} 1657258945Sroberto 1658258945Sroberto 1659258945Sroberto/* 1660258945Sroberto * Other useful things. 1661258945Sroberto */ 1662258945Sroberto 1663280849ScyISC_MEMFUNC_SCOPE char * 1664280849Scyisc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) { 1665280849Scy isc__mem_t *mctx = (isc__mem_t *)mctx0; 1666258945Sroberto size_t len; 1667258945Sroberto char *ns; 1668258945Sroberto 1669258945Sroberto REQUIRE(VALID_CONTEXT(mctx)); 1670258945Sroberto REQUIRE(s != NULL); 1671258945Sroberto 1672258945Sroberto len = strlen(s); 1673258945Sroberto 1674280849Scy ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS); 1675258945Sroberto 1676258945Sroberto if (ns != NULL) 1677258945Sroberto strncpy(ns, s, len + 1); 1678258945Sroberto 1679258945Sroberto return (ns); 1680258945Sroberto} 1681258945Sroberto 1682280849ScyISC_MEMFUNC_SCOPE void 1683280849Scyisc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) { 1684280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1685280849Scy 1686258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1687258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1688258945Sroberto 1689258945Sroberto ctx->checkfree = flag; 1690258945Sroberto 1691258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1692258945Sroberto} 1693258945Sroberto 1694258945Sroberto/* 1695258945Sroberto * Quotas 1696258945Sroberto */ 1697258945Sroberto 1698280849ScyISC_MEMFUNC_SCOPE void 1699280849Scyisc__mem_setquota(isc_mem_t *ctx0, size_t quota) { 1700280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1701280849Scy 1702258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1703258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1704258945Sroberto 1705258945Sroberto ctx->quota = quota; 1706258945Sroberto 1707258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1708258945Sroberto} 1709258945Sroberto 1710280849ScyISC_MEMFUNC_SCOPE size_t 1711280849Scyisc__mem_getquota(isc_mem_t *ctx0) { 1712280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1713258945Sroberto size_t quota; 1714258945Sroberto 1715258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1716258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1717258945Sroberto 1718258945Sroberto quota = ctx->quota; 1719258945Sroberto 1720258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1721258945Sroberto 1722258945Sroberto return (quota); 1723258945Sroberto} 1724258945Sroberto 1725280849ScyISC_MEMFUNC_SCOPE size_t 1726280849Scyisc__mem_inuse(isc_mem_t *ctx0) { 1727280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1728258945Sroberto size_t inuse; 1729258945Sroberto 1730258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1731258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1732258945Sroberto 1733258945Sroberto inuse = ctx->inuse; 1734258945Sroberto 1735258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1736258945Sroberto 1737258945Sroberto return (inuse); 1738258945Sroberto} 1739258945Sroberto 1740280849ScyISC_MEMFUNC_SCOPE void 1741280849Scyisc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg, 1742258945Sroberto size_t hiwater, size_t lowater) 1743258945Sroberto{ 1744280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1745258945Sroberto isc_boolean_t callwater = ISC_FALSE; 1746258945Sroberto isc_mem_water_t oldwater; 1747258945Sroberto void *oldwater_arg; 1748258945Sroberto 1749258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1750258945Sroberto REQUIRE(hiwater >= lowater); 1751258945Sroberto 1752258945Sroberto MCTXLOCK(ctx, &ctx->lock); 1753258945Sroberto oldwater = ctx->water; 1754258945Sroberto oldwater_arg = ctx->water_arg; 1755258945Sroberto if (water == NULL) { 1756258945Sroberto callwater = ctx->hi_called; 1757258945Sroberto ctx->water = NULL; 1758258945Sroberto ctx->water_arg = NULL; 1759258945Sroberto ctx->hi_water = 0; 1760258945Sroberto ctx->lo_water = 0; 1761258945Sroberto ctx->hi_called = ISC_FALSE; 1762258945Sroberto } else { 1763258945Sroberto if (ctx->hi_called && 1764258945Sroberto (ctx->water != water || ctx->water_arg != water_arg || 1765258945Sroberto ctx->inuse < lowater || lowater == 0U)) 1766258945Sroberto callwater = ISC_TRUE; 1767258945Sroberto ctx->water = water; 1768258945Sroberto ctx->water_arg = water_arg; 1769258945Sroberto ctx->hi_water = hiwater; 1770258945Sroberto ctx->lo_water = lowater; 1771258945Sroberto ctx->hi_called = ISC_FALSE; 1772258945Sroberto } 1773258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 1774258945Sroberto 1775258945Sroberto if (callwater && oldwater != NULL) 1776258945Sroberto (oldwater)(oldwater_arg, ISC_MEM_LOWATER); 1777258945Sroberto} 1778258945Sroberto 1779280849ScyISC_MEMFUNC_SCOPE isc_boolean_t 1780280849Scyisc__mem_isovermem(isc_mem_t *ctx0) { 1781280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1782280849Scy 1783258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1784258945Sroberto 1785280849Scy /* 1786280849Scy * We don't bother to lock the context because 100% accuracy isn't 1787280849Scy * necessary (and even if we locked the context the returned value 1788280849Scy * could be different from the actual state when it's used anyway) 1789280849Scy */ 1790280849Scy return (ctx->is_overmem); 1791280849Scy} 1792280849Scy 1793280849ScyISC_MEMFUNC_SCOPE void 1794280849Scyisc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) { 1795280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1796280849Scy 1797280849Scy REQUIRE(VALID_CONTEXT(ctx)); 1798280849Scy 1799258945Sroberto LOCK(&ctx->lock); 1800258945Sroberto memset(ctx->name, 0, sizeof(ctx->name)); 1801258945Sroberto strncpy(ctx->name, name, sizeof(ctx->name) - 1); 1802258945Sroberto ctx->tag = tag; 1803258945Sroberto UNLOCK(&ctx->lock); 1804258945Sroberto} 1805258945Sroberto 1806280849ScyISC_MEMFUNC_SCOPE const char * 1807280849Scyisc__mem_getname(isc_mem_t *ctx0) { 1808280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1809280849Scy 1810258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1811258945Sroberto 1812258945Sroberto return (ctx->name); 1813258945Sroberto} 1814258945Sroberto 1815280849ScyISC_MEMFUNC_SCOPE void * 1816280849Scyisc__mem_gettag(isc_mem_t *ctx0) { 1817280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 1818280849Scy 1819258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 1820258945Sroberto 1821258945Sroberto return (ctx->tag); 1822258945Sroberto} 1823258945Sroberto 1824258945Sroberto/* 1825258945Sroberto * Memory pool stuff 1826258945Sroberto */ 1827258945Sroberto 1828280849ScyISC_MEMFUNC_SCOPE isc_result_t 1829280849Scyisc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) { 1830280849Scy isc__mem_t *mctx = (isc__mem_t *)mctx0; 1831280849Scy isc__mempool_t *mpctx; 1832258945Sroberto 1833258945Sroberto REQUIRE(VALID_CONTEXT(mctx)); 1834258945Sroberto REQUIRE(size > 0U); 1835258945Sroberto REQUIRE(mpctxp != NULL && *mpctxp == NULL); 1836258945Sroberto 1837258945Sroberto /* 1838258945Sroberto * Allocate space for this pool, initialize values, and if all works 1839258945Sroberto * well, attach to the memory context. 1840258945Sroberto */ 1841280849Scy mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t)); 1842258945Sroberto if (mpctx == NULL) 1843258945Sroberto return (ISC_R_NOMEMORY); 1844258945Sroberto 1845280849Scy mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods; 1846280849Scy mpctx->common.impmagic = MEMPOOL_MAGIC; 1847280849Scy mpctx->common.magic = ISCAPI_MPOOL_MAGIC; 1848258945Sroberto mpctx->lock = NULL; 1849258945Sroberto mpctx->mctx = mctx; 1850258945Sroberto mpctx->size = size; 1851258945Sroberto mpctx->maxalloc = UINT_MAX; 1852258945Sroberto mpctx->allocated = 0; 1853258945Sroberto mpctx->freecount = 0; 1854258945Sroberto mpctx->freemax = 1; 1855258945Sroberto mpctx->fillcount = 1; 1856258945Sroberto mpctx->gets = 0; 1857258945Sroberto#if ISC_MEMPOOL_NAMES 1858258945Sroberto mpctx->name[0] = 0; 1859258945Sroberto#endif 1860258945Sroberto mpctx->items = NULL; 1861258945Sroberto 1862280849Scy *mpctxp = (isc_mempool_t *)mpctx; 1863258945Sroberto 1864258945Sroberto MCTXLOCK(mctx, &mctx->lock); 1865258945Sroberto ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link); 1866258945Sroberto mctx->poolcnt++; 1867258945Sroberto MCTXUNLOCK(mctx, &mctx->lock); 1868258945Sroberto 1869258945Sroberto return (ISC_R_SUCCESS); 1870258945Sroberto} 1871258945Sroberto 1872280849ScyISC_MEMFUNC_SCOPE void 1873280849Scyisc__mempool_setname(isc_mempool_t *mpctx0, const char *name) { 1874280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1875280849Scy 1876258945Sroberto REQUIRE(name != NULL); 1877280849Scy REQUIRE(VALID_MEMPOOL(mpctx)); 1878258945Sroberto 1879258945Sroberto#if ISC_MEMPOOL_NAMES 1880258945Sroberto if (mpctx->lock != NULL) 1881258945Sroberto LOCK(mpctx->lock); 1882258945Sroberto 1883258945Sroberto strncpy(mpctx->name, name, sizeof(mpctx->name) - 1); 1884258945Sroberto mpctx->name[sizeof(mpctx->name) - 1] = '\0'; 1885258945Sroberto 1886258945Sroberto if (mpctx->lock != NULL) 1887258945Sroberto UNLOCK(mpctx->lock); 1888258945Sroberto#else 1889258945Sroberto UNUSED(mpctx); 1890258945Sroberto UNUSED(name); 1891258945Sroberto#endif 1892258945Sroberto} 1893258945Sroberto 1894280849ScyISC_MEMFUNC_SCOPE void 1895280849Scyisc__mempool_destroy(isc_mempool_t **mpctxp) { 1896280849Scy isc__mempool_t *mpctx; 1897280849Scy isc__mem_t *mctx; 1898258945Sroberto isc_mutex_t *lock; 1899258945Sroberto element *item; 1900258945Sroberto 1901258945Sroberto REQUIRE(mpctxp != NULL); 1902280849Scy mpctx = (isc__mempool_t *)*mpctxp; 1903258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 1904258945Sroberto#if ISC_MEMPOOL_NAMES 1905258945Sroberto if (mpctx->allocated > 0) 1906258945Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 1907280849Scy "isc__mempool_destroy(): mempool %s " 1908258945Sroberto "leaked memory", 1909258945Sroberto mpctx->name); 1910258945Sroberto#endif 1911258945Sroberto REQUIRE(mpctx->allocated == 0); 1912258945Sroberto 1913258945Sroberto mctx = mpctx->mctx; 1914258945Sroberto 1915258945Sroberto lock = mpctx->lock; 1916258945Sroberto 1917258945Sroberto if (lock != NULL) 1918258945Sroberto LOCK(lock); 1919258945Sroberto 1920258945Sroberto /* 1921258945Sroberto * Return any items on the free list 1922258945Sroberto */ 1923258945Sroberto MCTXLOCK(mctx, &mctx->lock); 1924258945Sroberto while (mpctx->items != NULL) { 1925258945Sroberto INSIST(mpctx->freecount > 0); 1926258945Sroberto mpctx->freecount--; 1927258945Sroberto item = mpctx->items; 1928258945Sroberto mpctx->items = item->next; 1929258945Sroberto 1930258945Sroberto if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 1931258945Sroberto mem_putunlocked(mctx, item, mpctx->size); 1932258945Sroberto } else { 1933258945Sroberto mem_put(mctx, item, mpctx->size); 1934258945Sroberto mem_putstats(mctx, item, mpctx->size); 1935258945Sroberto } 1936258945Sroberto } 1937258945Sroberto MCTXUNLOCK(mctx, &mctx->lock); 1938258945Sroberto 1939258945Sroberto /* 1940258945Sroberto * Remove our linked list entry from the memory context. 1941258945Sroberto */ 1942258945Sroberto MCTXLOCK(mctx, &mctx->lock); 1943258945Sroberto ISC_LIST_UNLINK(mctx->pools, mpctx, link); 1944258945Sroberto mctx->poolcnt--; 1945258945Sroberto MCTXUNLOCK(mctx, &mctx->lock); 1946258945Sroberto 1947280849Scy mpctx->common.impmagic = 0; 1948280849Scy mpctx->common.magic = 0; 1949258945Sroberto 1950280849Scy isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t)); 1951258945Sroberto 1952258945Sroberto if (lock != NULL) 1953258945Sroberto UNLOCK(lock); 1954258945Sroberto 1955258945Sroberto *mpctxp = NULL; 1956258945Sroberto} 1957258945Sroberto 1958280849ScyISC_MEMFUNC_SCOPE void 1959280849Scyisc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) { 1960280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1961280849Scy 1962258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 1963258945Sroberto REQUIRE(mpctx->lock == NULL); 1964258945Sroberto REQUIRE(lock != NULL); 1965258945Sroberto 1966258945Sroberto mpctx->lock = lock; 1967258945Sroberto} 1968258945Sroberto 1969280849ScyISC_MEMFUNC_SCOPE void * 1970280849Scyisc___mempool_get(isc_mempool_t *mpctx0 FLARG) { 1971280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 1972258945Sroberto element *item; 1973280849Scy isc__mem_t *mctx; 1974258945Sroberto unsigned int i; 1975258945Sroberto 1976258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 1977258945Sroberto 1978258945Sroberto mctx = mpctx->mctx; 1979258945Sroberto 1980258945Sroberto if (mpctx->lock != NULL) 1981258945Sroberto LOCK(mpctx->lock); 1982258945Sroberto 1983258945Sroberto /* 1984258945Sroberto * Don't let the caller go over quota 1985258945Sroberto */ 1986258945Sroberto if (mpctx->allocated >= mpctx->maxalloc) { 1987258945Sroberto item = NULL; 1988258945Sroberto goto out; 1989258945Sroberto } 1990258945Sroberto 1991258945Sroberto /* 1992258945Sroberto * if we have a free list item, return the first here 1993258945Sroberto */ 1994258945Sroberto item = mpctx->items; 1995258945Sroberto if (item != NULL) { 1996258945Sroberto mpctx->items = item->next; 1997258945Sroberto INSIST(mpctx->freecount > 0); 1998258945Sroberto mpctx->freecount--; 1999258945Sroberto mpctx->gets++; 2000258945Sroberto mpctx->allocated++; 2001258945Sroberto goto out; 2002258945Sroberto } 2003258945Sroberto 2004258945Sroberto /* 2005258945Sroberto * We need to dip into the well. Lock the memory context here and 2006258945Sroberto * fill up our free list. 2007258945Sroberto */ 2008258945Sroberto MCTXLOCK(mctx, &mctx->lock); 2009258945Sroberto for (i = 0; i < mpctx->fillcount; i++) { 2010258945Sroberto if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2011258945Sroberto item = mem_getunlocked(mctx, mpctx->size); 2012258945Sroberto } else { 2013258945Sroberto item = mem_get(mctx, mpctx->size); 2014258945Sroberto if (item != NULL) 2015258945Sroberto mem_getstats(mctx, mpctx->size); 2016258945Sroberto } 2017258945Sroberto if (item == NULL) 2018258945Sroberto break; 2019258945Sroberto item->next = mpctx->items; 2020258945Sroberto mpctx->items = item; 2021258945Sroberto mpctx->freecount++; 2022258945Sroberto } 2023258945Sroberto MCTXUNLOCK(mctx, &mctx->lock); 2024258945Sroberto 2025258945Sroberto /* 2026258945Sroberto * If we didn't get any items, return NULL. 2027258945Sroberto */ 2028258945Sroberto item = mpctx->items; 2029258945Sroberto if (item == NULL) 2030258945Sroberto goto out; 2031258945Sroberto 2032258945Sroberto mpctx->items = item->next; 2033258945Sroberto mpctx->freecount--; 2034258945Sroberto mpctx->gets++; 2035258945Sroberto mpctx->allocated++; 2036258945Sroberto 2037258945Sroberto out: 2038258945Sroberto if (mpctx->lock != NULL) 2039258945Sroberto UNLOCK(mpctx->lock); 2040258945Sroberto 2041258945Sroberto#if ISC_MEM_TRACKLINES 2042258945Sroberto if (item != NULL) { 2043258945Sroberto MCTXLOCK(mctx, &mctx->lock); 2044258945Sroberto ADD_TRACE(mctx, item, mpctx->size, file, line); 2045258945Sroberto MCTXUNLOCK(mctx, &mctx->lock); 2046258945Sroberto } 2047258945Sroberto#endif /* ISC_MEM_TRACKLINES */ 2048258945Sroberto 2049258945Sroberto return (item); 2050258945Sroberto} 2051258945Sroberto 2052280849ScyISC_MEMFUNC_SCOPE void 2053280849Scyisc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) { 2054280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2055280849Scy isc__mem_t *mctx; 2056258945Sroberto element *item; 2057258945Sroberto 2058258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 2059258945Sroberto REQUIRE(mem != NULL); 2060258945Sroberto 2061258945Sroberto mctx = mpctx->mctx; 2062258945Sroberto 2063258945Sroberto if (mpctx->lock != NULL) 2064258945Sroberto LOCK(mpctx->lock); 2065258945Sroberto 2066258945Sroberto INSIST(mpctx->allocated > 0); 2067258945Sroberto mpctx->allocated--; 2068258945Sroberto 2069258945Sroberto#if ISC_MEM_TRACKLINES 2070258945Sroberto MCTXLOCK(mctx, &mctx->lock); 2071258945Sroberto DELETE_TRACE(mctx, mem, mpctx->size, file, line); 2072258945Sroberto MCTXUNLOCK(mctx, &mctx->lock); 2073258945Sroberto#endif /* ISC_MEM_TRACKLINES */ 2074258945Sroberto 2075258945Sroberto /* 2076258945Sroberto * If our free list is full, return this to the mctx directly. 2077258945Sroberto */ 2078258945Sroberto if (mpctx->freecount >= mpctx->freemax) { 2079258945Sroberto if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2080258945Sroberto MCTXLOCK(mctx, &mctx->lock); 2081258945Sroberto mem_putunlocked(mctx, mem, mpctx->size); 2082258945Sroberto MCTXUNLOCK(mctx, &mctx->lock); 2083258945Sroberto } else { 2084258945Sroberto mem_put(mctx, mem, mpctx->size); 2085258945Sroberto MCTXLOCK(mctx, &mctx->lock); 2086258945Sroberto mem_putstats(mctx, mem, mpctx->size); 2087258945Sroberto MCTXUNLOCK(mctx, &mctx->lock); 2088258945Sroberto } 2089258945Sroberto if (mpctx->lock != NULL) 2090258945Sroberto UNLOCK(mpctx->lock); 2091258945Sroberto return; 2092258945Sroberto } 2093258945Sroberto 2094258945Sroberto /* 2095258945Sroberto * Otherwise, attach it to our free list and bump the counter. 2096258945Sroberto */ 2097258945Sroberto mpctx->freecount++; 2098258945Sroberto item = (element *)mem; 2099258945Sroberto item->next = mpctx->items; 2100258945Sroberto mpctx->items = item; 2101258945Sroberto 2102258945Sroberto if (mpctx->lock != NULL) 2103258945Sroberto UNLOCK(mpctx->lock); 2104258945Sroberto} 2105258945Sroberto 2106258945Sroberto/* 2107258945Sroberto * Quotas 2108258945Sroberto */ 2109258945Sroberto 2110280849ScyISC_MEMFUNC_SCOPE void 2111280849Scyisc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) { 2112280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2113280849Scy 2114258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 2115258945Sroberto 2116258945Sroberto if (mpctx->lock != NULL) 2117258945Sroberto LOCK(mpctx->lock); 2118258945Sroberto 2119258945Sroberto mpctx->freemax = limit; 2120258945Sroberto 2121258945Sroberto if (mpctx->lock != NULL) 2122258945Sroberto UNLOCK(mpctx->lock); 2123258945Sroberto} 2124258945Sroberto 2125280849ScyISC_MEMFUNC_SCOPE unsigned int 2126280849Scyisc__mempool_getfreemax(isc_mempool_t *mpctx0) { 2127280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2128258945Sroberto unsigned int freemax; 2129258945Sroberto 2130258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 2131258945Sroberto 2132258945Sroberto if (mpctx->lock != NULL) 2133258945Sroberto LOCK(mpctx->lock); 2134258945Sroberto 2135258945Sroberto freemax = mpctx->freemax; 2136258945Sroberto 2137258945Sroberto if (mpctx->lock != NULL) 2138258945Sroberto UNLOCK(mpctx->lock); 2139258945Sroberto 2140258945Sroberto return (freemax); 2141258945Sroberto} 2142258945Sroberto 2143280849ScyISC_MEMFUNC_SCOPE unsigned int 2144280849Scyisc__mempool_getfreecount(isc_mempool_t *mpctx0) { 2145280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2146258945Sroberto unsigned int freecount; 2147258945Sroberto 2148258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 2149258945Sroberto 2150258945Sroberto if (mpctx->lock != NULL) 2151258945Sroberto LOCK(mpctx->lock); 2152258945Sroberto 2153258945Sroberto freecount = mpctx->freecount; 2154258945Sroberto 2155258945Sroberto if (mpctx->lock != NULL) 2156258945Sroberto UNLOCK(mpctx->lock); 2157258945Sroberto 2158258945Sroberto return (freecount); 2159258945Sroberto} 2160258945Sroberto 2161280849ScyISC_MEMFUNC_SCOPE void 2162280849Scyisc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) { 2163280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2164280849Scy 2165258945Sroberto REQUIRE(limit > 0); 2166258945Sroberto 2167258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 2168258945Sroberto 2169258945Sroberto if (mpctx->lock != NULL) 2170258945Sroberto LOCK(mpctx->lock); 2171258945Sroberto 2172258945Sroberto mpctx->maxalloc = limit; 2173258945Sroberto 2174258945Sroberto if (mpctx->lock != NULL) 2175258945Sroberto UNLOCK(mpctx->lock); 2176258945Sroberto} 2177258945Sroberto 2178280849ScyISC_MEMFUNC_SCOPE unsigned int 2179280849Scyisc__mempool_getmaxalloc(isc_mempool_t *mpctx0) { 2180280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2181258945Sroberto unsigned int maxalloc; 2182258945Sroberto 2183258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 2184258945Sroberto 2185258945Sroberto if (mpctx->lock != NULL) 2186258945Sroberto LOCK(mpctx->lock); 2187258945Sroberto 2188258945Sroberto maxalloc = mpctx->maxalloc; 2189258945Sroberto 2190258945Sroberto if (mpctx->lock != NULL) 2191258945Sroberto UNLOCK(mpctx->lock); 2192258945Sroberto 2193258945Sroberto return (maxalloc); 2194258945Sroberto} 2195258945Sroberto 2196280849ScyISC_MEMFUNC_SCOPE unsigned int 2197280849Scyisc__mempool_getallocated(isc_mempool_t *mpctx0) { 2198280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2199258945Sroberto unsigned int allocated; 2200258945Sroberto 2201258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 2202258945Sroberto 2203258945Sroberto if (mpctx->lock != NULL) 2204258945Sroberto LOCK(mpctx->lock); 2205258945Sroberto 2206258945Sroberto allocated = mpctx->allocated; 2207258945Sroberto 2208258945Sroberto if (mpctx->lock != NULL) 2209258945Sroberto UNLOCK(mpctx->lock); 2210258945Sroberto 2211258945Sroberto return (allocated); 2212258945Sroberto} 2213258945Sroberto 2214280849ScyISC_MEMFUNC_SCOPE void 2215280849Scyisc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) { 2216280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2217280849Scy 2218258945Sroberto REQUIRE(limit > 0); 2219258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 2220258945Sroberto 2221258945Sroberto if (mpctx->lock != NULL) 2222258945Sroberto LOCK(mpctx->lock); 2223258945Sroberto 2224258945Sroberto mpctx->fillcount = limit; 2225258945Sroberto 2226258945Sroberto if (mpctx->lock != NULL) 2227258945Sroberto UNLOCK(mpctx->lock); 2228258945Sroberto} 2229258945Sroberto 2230280849ScyISC_MEMFUNC_SCOPE unsigned int 2231280849Scyisc__mempool_getfillcount(isc_mempool_t *mpctx0) { 2232280849Scy isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; 2233280849Scy 2234258945Sroberto unsigned int fillcount; 2235258945Sroberto 2236258945Sroberto REQUIRE(VALID_MEMPOOL(mpctx)); 2237258945Sroberto 2238258945Sroberto if (mpctx->lock != NULL) 2239258945Sroberto LOCK(mpctx->lock); 2240258945Sroberto 2241258945Sroberto fillcount = mpctx->fillcount; 2242258945Sroberto 2243258945Sroberto if (mpctx->lock != NULL) 2244258945Sroberto UNLOCK(mpctx->lock); 2245258945Sroberto 2246258945Sroberto return (fillcount); 2247258945Sroberto} 2248258945Sroberto 2249280849Scy#ifdef USE_MEMIMPREGISTER 2250280849Scyisc_result_t 2251280849Scyisc__mem_register() { 2252280849Scy return (isc_mem_register(isc__mem_create2)); 2253280849Scy} 2254280849Scy#endif 2255258945Sroberto 2256280849Scy#ifdef BIND9 2257280849ScyISC_MEMFUNC_SCOPE void 2258280849Scyisc__mem_printactive(isc_mem_t *ctx0, FILE *file) { 2259280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 2260280849Scy 2261258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 2262258945Sroberto REQUIRE(file != NULL); 2263258945Sroberto 2264258945Sroberto#if !ISC_MEM_TRACKLINES 2265258945Sroberto UNUSED(ctx); 2266258945Sroberto UNUSED(file); 2267258945Sroberto#else 2268258945Sroberto print_active(ctx, file); 2269258945Sroberto#endif 2270258945Sroberto} 2271258945Sroberto 2272280849ScyISC_MEMFUNC_SCOPE void 2273280849Scyisc__mem_printallactive(FILE *file) { 2274258945Sroberto#if !ISC_MEM_TRACKLINES 2275258945Sroberto UNUSED(file); 2276258945Sroberto#else 2277280849Scy isc__mem_t *ctx; 2278258945Sroberto 2279258945Sroberto RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2280258945Sroberto 2281258945Sroberto LOCK(&lock); 2282258945Sroberto for (ctx = ISC_LIST_HEAD(contexts); 2283258945Sroberto ctx != NULL; 2284258945Sroberto ctx = ISC_LIST_NEXT(ctx, link)) { 2285258945Sroberto fprintf(file, "context: %p\n", ctx); 2286258945Sroberto print_active(ctx, file); 2287258945Sroberto } 2288258945Sroberto UNLOCK(&lock); 2289258945Sroberto#endif 2290258945Sroberto} 2291258945Sroberto 2292280849ScyISC_MEMFUNC_SCOPE void 2293280849Scyisc__mem_checkdestroyed(FILE *file) { 2294258945Sroberto 2295258945Sroberto RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2296258945Sroberto 2297258945Sroberto LOCK(&lock); 2298258945Sroberto if (!ISC_LIST_EMPTY(contexts)) { 2299258945Sroberto#if ISC_MEM_TRACKLINES 2300280849Scy isc__mem_t *ctx; 2301258945Sroberto 2302258945Sroberto for (ctx = ISC_LIST_HEAD(contexts); 2303258945Sroberto ctx != NULL; 2304258945Sroberto ctx = ISC_LIST_NEXT(ctx, link)) { 2305258945Sroberto fprintf(file, "context: %p\n", ctx); 2306258945Sroberto print_active(ctx, file); 2307258945Sroberto } 2308258945Sroberto fflush(file); 2309258945Sroberto#endif 2310258945Sroberto INSIST(0); 2311258945Sroberto } 2312258945Sroberto UNLOCK(&lock); 2313258945Sroberto} 2314258945Sroberto 2315280849ScyISC_MEMFUNC_SCOPE unsigned int 2316280849Scyisc_mem_references(isc_mem_t *ctx0) { 2317280849Scy isc__mem_t *ctx = (isc__mem_t *)ctx0; 2318258945Sroberto unsigned int references; 2319280849Scy 2320258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 2321258945Sroberto 2322258945Sroberto MCTXLOCK(ctx, &ctx->lock); 2323258945Sroberto references = ctx->references; 2324258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 2325258945Sroberto 2326258945Sroberto return (references); 2327258945Sroberto} 2328258945Sroberto 2329258945Sroberto#ifdef HAVE_LIBXML2 2330258945Sroberto 2331258945Srobertotypedef struct summarystat { 2332258945Sroberto isc_uint64_t total; 2333258945Sroberto isc_uint64_t inuse; 2334258945Sroberto isc_uint64_t blocksize; 2335258945Sroberto isc_uint64_t contextsize; 2336258945Sroberto} summarystat_t; 2337258945Sroberto 2338258945Srobertostatic void 2339280849Scyrenderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) { 2340258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 2341258945Sroberto 2342258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"); 2343258945Sroberto 2344258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"); 2345258945Sroberto xmlTextWriterWriteFormatString(writer, "%p", ctx); 2346258945Sroberto xmlTextWriterEndElement(writer); /* id */ 2347258945Sroberto 2348258945Sroberto if (ctx->name[0] != 0) { 2349258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); 2350258945Sroberto xmlTextWriterWriteFormatString(writer, "%s", ctx->name); 2351258945Sroberto xmlTextWriterEndElement(writer); /* name */ 2352258945Sroberto } 2353258945Sroberto 2354258945Sroberto REQUIRE(VALID_CONTEXT(ctx)); 2355258945Sroberto MCTXLOCK(ctx, &ctx->lock); 2356258945Sroberto 2357258945Sroberto summary->contextsize += sizeof(*ctx) + 2358258945Sroberto (ctx->max_size + 1) * sizeof(struct stats) + 2359258945Sroberto ctx->max_size * sizeof(element *) + 2360258945Sroberto ctx->basic_table_count * sizeof(char *); 2361258945Sroberto#if ISC_MEM_TRACKLINES 2362258945Sroberto if (ctx->debuglist != NULL) { 2363258945Sroberto summary->contextsize += 2364258945Sroberto (ctx->max_size + 1) * sizeof(debuglist_t) + 2365258945Sroberto ctx->debuglistcnt * sizeof(debuglink_t); 2366258945Sroberto } 2367258945Sroberto#endif 2368258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); 2369258945Sroberto xmlTextWriterWriteFormatString(writer, "%d", ctx->references); 2370258945Sroberto xmlTextWriterEndElement(writer); /* references */ 2371258945Sroberto 2372258945Sroberto summary->total += ctx->total; 2373258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"); 2374258945Sroberto xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2375258945Sroberto (isc_uint64_t)ctx->total); 2376258945Sroberto xmlTextWriterEndElement(writer); /* total */ 2377258945Sroberto 2378258945Sroberto summary->inuse += ctx->inuse; 2379258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"); 2380258945Sroberto xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2381258945Sroberto (isc_uint64_t)ctx->inuse); 2382258945Sroberto xmlTextWriterEndElement(writer); /* inuse */ 2383258945Sroberto 2384258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"); 2385258945Sroberto xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2386258945Sroberto (isc_uint64_t)ctx->maxinuse); 2387258945Sroberto xmlTextWriterEndElement(writer); /* maxinuse */ 2388258945Sroberto 2389258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"); 2390258945Sroberto if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 2391258945Sroberto summary->blocksize += ctx->basic_table_count * 2392258945Sroberto NUM_BASIC_BLOCKS * ctx->mem_target; 2393258945Sroberto xmlTextWriterWriteFormatString(writer, 2394258945Sroberto "%" ISC_PRINT_QUADFORMAT "u", 2395258945Sroberto (isc_uint64_t) 2396258945Sroberto ctx->basic_table_count * 2397258945Sroberto NUM_BASIC_BLOCKS * 2398258945Sroberto ctx->mem_target); 2399258945Sroberto } else 2400258945Sroberto xmlTextWriterWriteFormatString(writer, "%s", "-"); 2401258945Sroberto xmlTextWriterEndElement(writer); /* blocksize */ 2402258945Sroberto 2403258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"); 2404258945Sroberto xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt); 2405258945Sroberto xmlTextWriterEndElement(writer); /* pools */ 2406258945Sroberto summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t); 2407258945Sroberto 2408258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"); 2409258945Sroberto xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2410258945Sroberto (isc_uint64_t)ctx->hi_water); 2411258945Sroberto xmlTextWriterEndElement(writer); /* hiwater */ 2412258945Sroberto 2413258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"); 2414258945Sroberto xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2415258945Sroberto (isc_uint64_t)ctx->lo_water); 2416258945Sroberto xmlTextWriterEndElement(writer); /* lowater */ 2417258945Sroberto 2418258945Sroberto MCTXUNLOCK(ctx, &ctx->lock); 2419258945Sroberto 2420258945Sroberto xmlTextWriterEndElement(writer); /* context */ 2421258945Sroberto} 2422258945Sroberto 2423258945Srobertovoid 2424258945Srobertoisc_mem_renderxml(xmlTextWriterPtr writer) { 2425280849Scy isc__mem_t *ctx; 2426258945Sroberto summarystat_t summary; 2427258945Sroberto isc_uint64_t lost; 2428258945Sroberto 2429258945Sroberto memset(&summary, 0, sizeof(summary)); 2430258945Sroberto 2431258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"); 2432258945Sroberto 2433258945Sroberto RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 2434258945Sroberto 2435258945Sroberto LOCK(&lock); 2436258945Sroberto lost = totallost; 2437258945Sroberto for (ctx = ISC_LIST_HEAD(contexts); 2438258945Sroberto ctx != NULL; 2439258945Sroberto ctx = ISC_LIST_NEXT(ctx, link)) { 2440258945Sroberto renderctx(ctx, &summary, writer); 2441258945Sroberto } 2442258945Sroberto UNLOCK(&lock); 2443258945Sroberto 2444258945Sroberto xmlTextWriterEndElement(writer); /* contexts */ 2445258945Sroberto 2446258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"); 2447258945Sroberto 2448258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"); 2449258945Sroberto xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2450258945Sroberto summary.total); 2451258945Sroberto xmlTextWriterEndElement(writer); /* TotalUse */ 2452258945Sroberto 2453258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"); 2454258945Sroberto xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2455258945Sroberto summary.inuse); 2456258945Sroberto xmlTextWriterEndElement(writer); /* InUse */ 2457258945Sroberto 2458258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"); 2459258945Sroberto xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2460258945Sroberto summary.blocksize); 2461258945Sroberto xmlTextWriterEndElement(writer); /* BlockSize */ 2462258945Sroberto 2463258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"); 2464258945Sroberto xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2465258945Sroberto summary.contextsize); 2466258945Sroberto xmlTextWriterEndElement(writer); /* ContextSize */ 2467258945Sroberto 2468258945Sroberto xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"); 2469258945Sroberto xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", 2470258945Sroberto lost); 2471258945Sroberto xmlTextWriterEndElement(writer); /* Lost */ 2472258945Sroberto 2473258945Sroberto xmlTextWriterEndElement(writer); /* summary */ 2474258945Sroberto} 2475258945Sroberto 2476258945Sroberto#endif /* HAVE_LIBXML2 */ 2477280849Scy#endif /* BIND9 */ 2478