mem.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2010, 2012-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1997-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 #include <config.h>
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <stddef.h>
00025 
00026 #include <limits.h>
00027 
00028 #include <isc/bind9.h>
00029 #include <isc/json.h>
00030 #include <isc/magic.h>
00031 #include <isc/mem.h>
00032 #include <isc/msgs.h>
00033 #include <isc/once.h>
00034 #include <isc/ondestroy.h>
00035 #include <isc/string.h>
00036 #include <isc/mutex.h>
00037 #include <isc/print.h>
00038 #include <isc/util.h>
00039 #include <isc/xml.h>
00040 
00041 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
00042 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
00043 
00044 #ifndef ISC_MEM_DEBUGGING
00045 #define ISC_MEM_DEBUGGING 0
00046 #endif
00047 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
00048 LIBISC_EXTERNAL_DATA unsigned int isc_mem_defaultflags = ISC_MEMFLAG_DEFAULT;
00049 
00050 /*
00051  * Constants.
00052  */
00053 
00054 #define DEF_MAX_SIZE            1100
00055 #define DEF_MEM_TARGET          4096
00056 #define ALIGNMENT_SIZE          8U              /*%< must be a power of 2 */
00057 #define NUM_BASIC_BLOCKS        64              /*%< must be > 1 */
00058 #define TABLE_INCREMENT         1024
00059 #define DEBUGLIST_COUNT         1024
00060 
00061 /*
00062  * Types.
00063  */
00064 typedef struct isc__mem isc__mem_t;
00065 typedef struct isc__mempool isc__mempool_t;
00066 
00067 #if ISC_MEM_TRACKLINES
00068 typedef struct debuglink debuglink_t;
00069 struct debuglink {
00070         ISC_LINK(debuglink_t)   link;
00071         const void             *ptr[DEBUGLIST_COUNT];
00072         size_t                  size[DEBUGLIST_COUNT];
00073         const char             *file[DEBUGLIST_COUNT];
00074         unsigned int            line[DEBUGLIST_COUNT];
00075         unsigned int            count;
00076 };
00077 
00078 #define FLARG_PASS      , file, line
00079 #define FLARG           , const char *file, unsigned int line
00080 #else
00081 #define FLARG_PASS
00082 #define FLARG
00083 #endif
00084 
00085 typedef struct element element;
00086 struct element {
00087         element *               next;
00088 };
00089 
00090 typedef struct {
00091         /*!
00092          * This structure must be ALIGNMENT_SIZE bytes.
00093          */
00094         union {
00095                 size_t          size;
00096                 isc__mem_t      *ctx;
00097                 char            bytes[ALIGNMENT_SIZE];
00098         } u;
00099 } size_info;
00100 
00101 struct stats {
00102         unsigned long           gets;
00103         unsigned long           totalgets;
00104         unsigned long           blocks;
00105         unsigned long           freefrags;
00106 };
00107 
00108 #define MEM_MAGIC               ISC_MAGIC('M', 'e', 'm', 'C')
00109 #define VALID_CONTEXT(c)        ISC_MAGIC_VALID(c, MEM_MAGIC)
00110 
00111 #if ISC_MEM_TRACKLINES
00112 typedef ISC_LIST(debuglink_t)   debuglist_t;
00113 #endif
00114 
00115 /* List of all active memory contexts. */
00116 
00117 static ISC_LIST(isc__mem_t)     contexts;
00118 
00119 static isc_once_t               once = ISC_ONCE_INIT;
00120 static isc_mutex_t              contextslock;
00121 static isc_mutex_t              createlock;
00122 
00123 /*%
00124  * Total size of lost memory due to a bug of external library.
00125  * Locked by the global lock.
00126  */
00127 static isc_uint64_t             totallost;
00128 
00129 struct isc__mem {
00130         isc_mem_t               common;
00131         isc_ondestroy_t         ondestroy;
00132         unsigned int            flags;
00133         isc_mutex_t             lock;
00134         isc_memalloc_t          memalloc;
00135         isc_memfree_t           memfree;
00136         void *                  arg;
00137         size_t                  max_size;
00138         isc_boolean_t           checkfree;
00139         struct stats *          stats;
00140         unsigned int            references;
00141         char                    name[16];
00142         void *                  tag;
00143         size_t                  quota;
00144         size_t                  total;
00145         size_t                  inuse;
00146         size_t                  maxinuse;
00147         size_t                  hi_water;
00148         size_t                  lo_water;
00149         isc_boolean_t           hi_called;
00150         isc_boolean_t           is_overmem;
00151         isc_mem_water_t         water;
00152         void *                  water_arg;
00153         ISC_LIST(isc__mempool_t) pools;
00154         unsigned int            poolcnt;
00155 
00156         /*  ISC_MEMFLAG_INTERNAL */
00157         size_t                  mem_target;
00158         element **              freelists;
00159         element *               basic_blocks;
00160         unsigned char **        basic_table;
00161         unsigned int            basic_table_count;
00162         unsigned int            basic_table_size;
00163         unsigned char *         lowest;
00164         unsigned char *         highest;
00165 
00166 #if ISC_MEM_TRACKLINES
00167         debuglist_t *           debuglist;
00168         unsigned int            debuglistcnt;
00169 #endif
00170 
00171         unsigned int            memalloc_failures;
00172         ISC_LINK(isc__mem_t)    link;
00173 };
00174 
00175 #define MEMPOOL_MAGIC           ISC_MAGIC('M', 'E', 'M', 'p')
00176 #define VALID_MEMPOOL(c)        ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
00177 
00178 struct isc__mempool {
00179         /* always unlocked */
00180         isc_mempool_t   common;         /*%< common header of mempool's */
00181         isc_mutex_t    *lock;           /*%< optional lock */
00182         isc__mem_t      *mctx;          /*%< our memory context */
00183         /*%< locked via the memory context's lock */
00184         ISC_LINK(isc__mempool_t)        link;   /*%< next pool in this mem context */
00185         /*%< optionally locked from here down */
00186         element        *items;          /*%< low water item list */
00187         size_t          size;           /*%< size of each item on this pool */
00188         unsigned int    maxalloc;       /*%< max number of items allowed */
00189         unsigned int    allocated;      /*%< # of items currently given out */
00190         unsigned int    freecount;      /*%< # of items on reserved list */
00191         unsigned int    freemax;        /*%< # of items allowed on free list */
00192         unsigned int    fillcount;      /*%< # of items to fetch on each fill */
00193         /*%< Stats only. */
00194         unsigned int    gets;           /*%< # of requests to this pool */
00195         /*%< Debugging only. */
00196 #if ISC_MEMPOOL_NAMES
00197         char            name[16];       /*%< printed name in stats reports */
00198 #endif
00199 };
00200 
00201 /*
00202  * Private Inline-able.
00203  */
00204 
00205 #if ! ISC_MEM_TRACKLINES
00206 #define ADD_TRACE(a, b, c, d, e)
00207 #define DELETE_TRACE(a, b, c, d, e)
00208 #define ISC_MEMFUNC_SCOPE
00209 #else
00210 #define ADD_TRACE(a, b, c, d, e) \
00211         do { \
00212                 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
00213                                           ISC_MEM_DEBUGRECORD)) != 0 && \
00214                      b != NULL) \
00215                          add_trace_entry(a, b, c, d, e); \
00216         } while (0)
00217 #define DELETE_TRACE(a, b, c, d, e)     delete_trace_entry(a, b, c, d, e)
00218 
00219 static void
00220 print_active(isc__mem_t *ctx, FILE *out);
00221 
00222 /*%
00223  * The following are intended for internal use (indicated by "isc__"
00224  * prefix) but are not declared as static, allowing direct access
00225  * from unit tests, etc.
00226  */
00227 
00228 isc_result_t
00229 isc__mem_create2(size_t init_max_size, size_t target_size,
00230                  isc_mem_t **ctxp, unsigned int flags);
00231 void
00232 isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp);
00233 void
00234 isc__mem_detach(isc_mem_t **ctxp);
00235 void
00236 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
00237 void
00238 isc__mem_destroy(isc_mem_t **ctxp);
00239 isc_result_t
00240 isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event);
00241 void *
00242 isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
00243 void
00244 isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
00245 void
00246 isc__mem_stats(isc_mem_t *ctx, FILE *out);
00247 void *
00248 isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
00249 void *
00250 isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
00251 void
00252 isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
00253 char *
00254 isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
00255 void
00256 isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag);
00257 void
00258 isc__mem_setquota(isc_mem_t *ctx, size_t quota);
00259 size_t
00260 isc__mem_getquota(isc_mem_t *ctx);
00261 size_t
00262 isc__mem_inuse(isc_mem_t *ctx);
00263 size_t
00264 isc__mem_maxinuse(isc_mem_t *ctx);
00265 size_t
00266 isc__mem_total(isc_mem_t *ctx);
00267 isc_boolean_t
00268 isc__mem_isovermem(isc_mem_t *ctx);
00269 void
00270 isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
00271                   size_t hiwater, size_t lowater);
00272 void
00273 isc__mem_waterack(isc_mem_t *ctx0, int flag);
00274 void
00275 isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag);
00276 const char *
00277 isc__mem_getname(isc_mem_t *ctx);
00278 void *
00279 isc__mem_gettag(isc_mem_t *ctx);
00280 isc_result_t
00281 isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
00282 void
00283 isc__mempool_setname(isc_mempool_t *mpctx, const char *name);
00284 void
00285 isc__mempool_destroy(isc_mempool_t **mpctxp);
00286 void
00287 isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
00288 void *
00289 isc___mempool_get(isc_mempool_t *mpctx FLARG);
00290 void
00291 isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG);
00292 void
00293 isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
00294 unsigned int
00295 isc__mempool_getfreemax(isc_mempool_t *mpctx);
00296 unsigned int
00297 isc__mempool_getfreecount(isc_mempool_t *mpctx);
00298 void
00299 isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
00300 unsigned int
00301 isc__mempool_getmaxalloc(isc_mempool_t *mpctx);
00302 unsigned int
00303 isc__mempool_getallocated(isc_mempool_t *mpctx);
00304 void
00305 isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
00306 unsigned int
00307 isc__mempool_getfillcount(isc_mempool_t *mpctx);
00308 void
00309 isc__mem_printactive(isc_mem_t *ctx0, FILE *file);
00310 void
00311 isc__mem_printallactive(FILE *file);
00312 unsigned int
00313 isc__mem_references(isc_mem_t *ctx0);
00314 #endif /* ISC_MEM_TRACKLINES */
00315 
00316 static struct isc__memmethods {
00317         isc_memmethods_t methods;
00318 
00319         /*%
00320          * The following are defined just for avoiding unused static functions.
00321          */
00322         void *createx, *create, *create2, *ondestroy, *stats,
00323              *setquota, *getquota, *setname, *getname, *gettag;
00324 } memmethods = {
00325         {
00326                 isc__mem_attach,
00327                 isc__mem_detach,
00328                 isc__mem_destroy,
00329                 isc___mem_get,
00330                 isc___mem_put,
00331                 isc___mem_putanddetach,
00332                 isc___mem_allocate,
00333                 isc___mem_reallocate,
00334                 isc___mem_strdup,
00335                 isc___mem_free,
00336                 isc__mem_setdestroycheck,
00337                 isc__mem_setwater,
00338                 isc__mem_waterack,
00339                 isc__mem_inuse,
00340                 isc__mem_maxinuse,
00341                 isc__mem_total,
00342                 isc__mem_isovermem,
00343                 isc__mempool_create
00344         },
00345         (void *)isc_mem_createx,
00346         (void *)isc_mem_create,
00347         (void *)isc_mem_create2,
00348         (void *)isc_mem_ondestroy,
00349         (void *)isc_mem_stats,
00350         (void *)isc_mem_setquota,
00351         (void *)isc_mem_getquota,
00352         (void *)isc_mem_setname,
00353         (void *)isc_mem_getname,
00354         (void *)isc_mem_gettag
00355 };
00356 
00357 static struct isc__mempoolmethods {
00358         isc_mempoolmethods_t methods;
00359 
00360         /*%
00361          * The following are defined just for avoiding unused static functions.
00362          */
00363         void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount;
00364 } mempoolmethods = {
00365         {
00366                 isc__mempool_destroy,
00367                 isc___mempool_get,
00368                 isc___mempool_put,
00369                 isc__mempool_getallocated,
00370                 isc__mempool_setmaxalloc,
00371                 isc__mempool_setfreemax,
00372                 isc__mempool_setname,
00373                 isc__mempool_associatelock,
00374                 isc__mempool_setfillcount
00375         },
00376         (void *)isc_mempool_getfreemax,
00377         (void *)isc_mempool_getfreecount,
00378         (void *)isc_mempool_getmaxalloc,
00379         (void *)isc_mempool_getfillcount
00380 };
00381 
00382 #if ISC_MEM_TRACKLINES
00383 /*!
00384  * mctx must be locked.
00385  */
00386 static inline void
00387 add_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size FLARG) {
00388         debuglink_t *dl;
00389         unsigned int i;
00390         size_t mysize = size;
00391 
00392         if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
00393                 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
00394                                                ISC_MSG_ADDTRACE,
00395                                                "add %p size %u "
00396                                                "file %s line %u mctx %p\n"),
00397                         ptr, size, file, line, mctx);
00398 
00399         if (mctx->debuglist == NULL)
00400                 return;
00401 
00402         if (mysize > mctx->max_size)
00403                 mysize = mctx->max_size;
00404 
00405         dl = ISC_LIST_HEAD(mctx->debuglist[mysize]);
00406         while (dl != NULL) {
00407                 if (dl->count == DEBUGLIST_COUNT)
00408                         goto next;
00409                 for (i = 0; i < DEBUGLIST_COUNT; i++) {
00410                         if (dl->ptr[i] == NULL) {
00411                                 dl->ptr[i] = ptr;
00412                                 dl->size[i] = size;
00413                                 dl->file[i] = file;
00414                                 dl->line[i] = line;
00415                                 dl->count++;
00416                                 return;
00417                         }
00418                 }
00419         next:
00420                 dl = ISC_LIST_NEXT(dl, link);
00421         }
00422 
00423         dl = malloc(sizeof(debuglink_t));
00424         INSIST(dl != NULL);
00425 
00426         ISC_LINK_INIT(dl, link);
00427         for (i = 1; i < DEBUGLIST_COUNT; i++) {
00428                 dl->ptr[i] = NULL;
00429                 dl->size[i] = 0;
00430                 dl->file[i] = NULL;
00431                 dl->line[i] = 0;
00432         }
00433 
00434         dl->ptr[0] = ptr;
00435         dl->size[0] = size;
00436         dl->file[0] = file;
00437         dl->line[0] = line;
00438         dl->count = 1;
00439 
00440         ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link);
00441         mctx->debuglistcnt++;
00442 }
00443 
00444 static inline void
00445 delete_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size,
00446                    const char *file, unsigned int line)
00447 {
00448         debuglink_t *dl;
00449         unsigned int i;
00450 
00451         if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
00452                 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
00453                                                ISC_MSG_DELTRACE,
00454                                                "del %p size %u "
00455                                                "file %s line %u mctx %p\n"),
00456                         ptr, size, file, line, mctx);
00457 
00458         if (mctx->debuglist == NULL)
00459                 return;
00460 
00461         if (size > mctx->max_size)
00462                 size = mctx->max_size;
00463 
00464         dl = ISC_LIST_HEAD(mctx->debuglist[size]);
00465         while (dl != NULL) {
00466                 for (i = 0; i < DEBUGLIST_COUNT; i++) {
00467                         if (dl->ptr[i] == ptr) {
00468                                 dl->ptr[i] = NULL;
00469                                 dl->size[i] = 0;
00470                                 dl->file[i] = NULL;
00471                                 dl->line[i] = 0;
00472 
00473                                 INSIST(dl->count > 0);
00474                                 dl->count--;
00475                                 if (dl->count == 0) {
00476                                         ISC_LIST_UNLINK(mctx->debuglist[size],
00477                                                         dl, link);
00478                                         free(dl);
00479                                 }
00480                                 return;
00481                         }
00482                 }
00483                 dl = ISC_LIST_NEXT(dl, link);
00484         }
00485 
00486         /*
00487          * If we get here, we didn't find the item on the list.  We're
00488          * screwed.
00489          */
00490         INSIST(dl != NULL);
00491 }
00492 #endif /* ISC_MEM_TRACKLINES */
00493 
00494 static inline size_t
00495 rmsize(size_t size) {
00496         /*
00497          * round down to ALIGNMENT_SIZE
00498          */
00499         return (size & (~(ALIGNMENT_SIZE - 1)));
00500 }
00501 
00502 static inline size_t
00503 quantize(size_t size) {
00504         /*!
00505          * Round up the result in order to get a size big
00506          * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
00507          * byte boundaries.
00508          */
00509 
00510         if (size == 0U)
00511                 return (ALIGNMENT_SIZE);
00512         return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
00513 }
00514 
00515 static inline isc_boolean_t
00516 more_basic_blocks(isc__mem_t *ctx) {
00517         void *new;
00518         unsigned char *curr, *next;
00519         unsigned char *first, *last;
00520         unsigned char **table;
00521         unsigned int table_size;
00522         size_t increment;
00523         int i;
00524 
00525         /* Require: we hold the context lock. */
00526 
00527         /*
00528          * Did we hit the quota for this context?
00529          */
00530         increment = NUM_BASIC_BLOCKS * ctx->mem_target;
00531         if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
00532                 return (ISC_FALSE);
00533 
00534         INSIST(ctx->basic_table_count <= ctx->basic_table_size);
00535         if (ctx->basic_table_count == ctx->basic_table_size) {
00536                 table_size = ctx->basic_table_size + TABLE_INCREMENT;
00537                 table = (ctx->memalloc)(ctx->arg,
00538                                         table_size * sizeof(unsigned char *));
00539                 if (table == NULL) {
00540                         ctx->memalloc_failures++;
00541                         return (ISC_FALSE);
00542                 }
00543                 if (ctx->basic_table_size != 0) {
00544                         memmove(table, ctx->basic_table,
00545                                 ctx->basic_table_size *
00546                                   sizeof(unsigned char *));
00547                         (ctx->memfree)(ctx->arg, ctx->basic_table);
00548                 }
00549                 ctx->basic_table = table;
00550                 ctx->basic_table_size = table_size;
00551         }
00552 
00553         new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
00554         if (new == NULL) {
00555                 ctx->memalloc_failures++;
00556                 return (ISC_FALSE);
00557         }
00558         ctx->total += increment;
00559         ctx->basic_table[ctx->basic_table_count] = new;
00560         ctx->basic_table_count++;
00561 
00562         curr = new;
00563         next = curr + ctx->mem_target;
00564         for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
00565                 ((element *)curr)->next = (element *)next;
00566                 curr = next;
00567                 next += ctx->mem_target;
00568         }
00569         /*
00570          * curr is now pointing at the last block in the
00571          * array.
00572          */
00573         ((element *)curr)->next = NULL;
00574         first = new;
00575         last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
00576         if (first < ctx->lowest || ctx->lowest == NULL)
00577                 ctx->lowest = first;
00578         if (last > ctx->highest)
00579                 ctx->highest = last;
00580         ctx->basic_blocks = new;
00581 
00582         return (ISC_TRUE);
00583 }
00584 
00585 static inline isc_boolean_t
00586 more_frags(isc__mem_t *ctx, size_t new_size) {
00587         int i, frags;
00588         size_t total_size;
00589         void *new;
00590         unsigned char *curr, *next;
00591 
00592         /*!
00593          * Try to get more fragments by chopping up a basic block.
00594          */
00595 
00596         if (ctx->basic_blocks == NULL) {
00597                 if (!more_basic_blocks(ctx)) {
00598                         /*
00599                          * We can't get more memory from the OS, or we've
00600                          * hit the quota for this context.
00601                          */
00602                         /*
00603                          * XXXRTH  "At quota" notification here.
00604                          */
00605                         return (ISC_FALSE);
00606                 }
00607         }
00608 
00609         total_size = ctx->mem_target;
00610         new = ctx->basic_blocks;
00611         ctx->basic_blocks = ctx->basic_blocks->next;
00612         frags = (int)(total_size / new_size);
00613         ctx->stats[new_size].blocks++;
00614         ctx->stats[new_size].freefrags += frags;
00615         /*
00616          * Set up a linked-list of blocks of size
00617          * "new_size".
00618          */
00619         curr = new;
00620         next = curr + new_size;
00621         total_size -= new_size;
00622         for (i = 0; i < (frags - 1); i++) {
00623                 ((element *)curr)->next = (element *)next;
00624                 curr = next;
00625                 next += new_size;
00626                 total_size -= new_size;
00627         }
00628         /*
00629          * Add the remaining fragment of the basic block to a free list.
00630          */
00631         total_size = rmsize(total_size);
00632         if (total_size > 0U) {
00633                 ((element *)next)->next = ctx->freelists[total_size];
00634                 ctx->freelists[total_size] = (element *)next;
00635                 ctx->stats[total_size].freefrags++;
00636         }
00637         /*
00638          * curr is now pointing at the last block in the
00639          * array.
00640          */
00641         ((element *)curr)->next = NULL;
00642         ctx->freelists[new_size] = new;
00643 
00644         return (ISC_TRUE);
00645 }
00646 
00647 static inline void *
00648 mem_getunlocked(isc__mem_t *ctx, size_t size) {
00649         size_t new_size = quantize(size);
00650         void *ret;
00651 
00652         if (new_size >= ctx->max_size) {
00653                 /*
00654                  * memget() was called on something beyond our upper limit.
00655                  */
00656                 if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
00657                         ret = NULL;
00658                         goto done;
00659                 }
00660                 ret = (ctx->memalloc)(ctx->arg, size);
00661                 if (ret == NULL) {
00662                         ctx->memalloc_failures++;
00663                         goto done;
00664                 }
00665                 ctx->total += size;
00666                 ctx->inuse += size;
00667                 ctx->stats[ctx->max_size].gets++;
00668                 ctx->stats[ctx->max_size].totalgets++;
00669                 /*
00670                  * If we don't set new_size to size, then the
00671                  * ISC_MEM_FILL code might write over bytes we
00672                  * don't own.
00673                  */
00674                 new_size = size;
00675                 goto done;
00676         }
00677 
00678         /*
00679          * If there are no blocks in the free list for this size, get a chunk
00680          * of memory and then break it up into "new_size"-sized blocks, adding
00681          * them to the free list.
00682          */
00683         if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
00684                 return (NULL);
00685 
00686         /*
00687          * The free list uses the "rounded-up" size "new_size".
00688          */
00689         ret = ctx->freelists[new_size];
00690         ctx->freelists[new_size] = ctx->freelists[new_size]->next;
00691 
00692         /*
00693          * The stats[] uses the _actual_ "size" requested by the
00694          * caller, with the caveat (in the code above) that "size" >= the
00695          * max. size (max_size) ends up getting recorded as a call to
00696          * max_size.
00697          */
00698         ctx->stats[size].gets++;
00699         ctx->stats[size].totalgets++;
00700         ctx->stats[new_size].freefrags--;
00701         ctx->inuse += new_size;
00702 
00703  done:
00704 
00705 #if ISC_MEM_FILL
00706         if (ret != NULL)
00707                 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
00708 #endif
00709 
00710         return (ret);
00711 }
00712 
00713 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
00714 static inline void
00715 check_overrun(void *mem, size_t size, size_t new_size) {
00716         unsigned char *cp;
00717 
00718         cp = (unsigned char *)mem;
00719         cp += size;
00720         while (size < new_size) {
00721                 INSIST(*cp == 0xbe);
00722                 cp++;
00723                 size++;
00724         }
00725 }
00726 #endif
00727 
00728 /* coverity[+free : arg-1] */
00729 static inline void
00730 mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) {
00731         size_t new_size = quantize(size);
00732 
00733         if (new_size >= ctx->max_size) {
00734                 /*
00735                  * memput() called on something beyond our upper limit.
00736                  */
00737 #if ISC_MEM_FILL
00738                 memset(mem, 0xde, size); /* Mnemonic for "dead". */
00739 #endif
00740                 (ctx->memfree)(ctx->arg, mem);
00741                 INSIST(ctx->stats[ctx->max_size].gets != 0U);
00742                 ctx->stats[ctx->max_size].gets--;
00743                 INSIST(size <= ctx->inuse);
00744                 ctx->inuse -= size;
00745                 return;
00746         }
00747 
00748 #if ISC_MEM_FILL
00749 #if ISC_MEM_CHECKOVERRUN
00750         check_overrun(mem, size, new_size);
00751 #endif
00752         memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
00753 #endif
00754 
00755         /*
00756          * The free list uses the "rounded-up" size "new_size".
00757          */
00758         ((element *)mem)->next = ctx->freelists[new_size];
00759         ctx->freelists[new_size] = (element *)mem;
00760 
00761         /*
00762          * The stats[] uses the _actual_ "size" requested by the
00763          * caller, with the caveat (in the code above) that "size" >= the
00764          * max. size (max_size) ends up getting recorded as a call to
00765          * max_size.
00766          */
00767         INSIST(ctx->stats[size].gets != 0U);
00768         ctx->stats[size].gets--;
00769         ctx->stats[new_size].freefrags++;
00770         ctx->inuse -= new_size;
00771 }
00772 
00773 /*!
00774  * Perform a malloc, doing memory filling and overrun detection as necessary.
00775  */
00776 static inline void *
00777 mem_get(isc__mem_t *ctx, size_t size) {
00778         char *ret;
00779 
00780 #if ISC_MEM_CHECKOVERRUN
00781         size += 1;
00782 #endif
00783 
00784         ret = (ctx->memalloc)(ctx->arg, size);
00785         if (ret == NULL)
00786                 ctx->memalloc_failures++;
00787 
00788 #if ISC_MEM_FILL
00789         if (ret != NULL)
00790                 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
00791 #else
00792 #  if ISC_MEM_CHECKOVERRUN
00793         if (ret != NULL)
00794                 ret[size-1] = 0xbe;
00795 #  endif
00796 #endif
00797 
00798         return (ret);
00799 }
00800 
00801 /*!
00802  * Perform a free, doing memory filling and overrun detection as necessary.
00803  */
00804 /* coverity[+free : arg-1] */
00805 static inline void
00806 mem_put(isc__mem_t *ctx, void *mem, size_t size) {
00807 #if ISC_MEM_CHECKOVERRUN
00808         INSIST(((unsigned char *)mem)[size] == 0xbe);
00809 #endif
00810 #if ISC_MEM_FILL
00811         memset(mem, 0xde, size); /* Mnemonic for "dead". */
00812 #else
00813         UNUSED(size);
00814 #endif
00815         (ctx->memfree)(ctx->arg, mem);
00816 }
00817 
00818 /*!
00819  * Update internal counters after a memory get.
00820  */
00821 static inline void
00822 mem_getstats(isc__mem_t *ctx, size_t size) {
00823         ctx->total += size;
00824         ctx->inuse += size;
00825 
00826         if (size > ctx->max_size) {
00827                 ctx->stats[ctx->max_size].gets++;
00828                 ctx->stats[ctx->max_size].totalgets++;
00829         } else {
00830                 ctx->stats[size].gets++;
00831                 ctx->stats[size].totalgets++;
00832         }
00833 }
00834 
00835 /*!
00836  * Update internal counters after a memory put.
00837  */
00838 static inline void
00839 mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) {
00840         UNUSED(ptr);
00841 
00842         INSIST(ctx->inuse >= size);
00843         ctx->inuse -= size;
00844 
00845         if (size > ctx->max_size) {
00846                 INSIST(ctx->stats[ctx->max_size].gets > 0U);
00847                 ctx->stats[ctx->max_size].gets--;
00848         } else {
00849                 INSIST(ctx->stats[size].gets > 0U);
00850                 ctx->stats[size].gets--;
00851         }
00852 }
00853 
00854 /*
00855  * Private.
00856  */
00857 
00858 static void *
00859 default_memalloc(void *arg, size_t size) {
00860         UNUSED(arg);
00861         if (size == 0U)
00862                 size = 1;
00863         return (malloc(size));
00864 }
00865 
00866 static void
00867 default_memfree(void *arg, void *ptr) {
00868         UNUSED(arg);
00869         free(ptr);
00870 }
00871 
00872 static void
00873 initialize_action(void) {
00874         RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
00875         RUNTIME_CHECK(isc_mutex_init(&contextslock) == ISC_R_SUCCESS);
00876         ISC_LIST_INIT(contexts);
00877         totallost = 0;
00878 }
00879 
00880 /*
00881  * Public.
00882  */
00883 
00884 isc_result_t
00885 isc_mem_createx(size_t init_max_size, size_t target_size,
00886                  isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
00887                  isc_mem_t **ctxp)
00888 {
00889         return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
00890                                  arg, ctxp, isc_mem_defaultflags));
00891 
00892 }
00893 
00894 isc_result_t
00895 isc_mem_createx2(size_t init_max_size, size_t target_size,
00896                   isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
00897                   isc_mem_t **ctxp, unsigned int flags)
00898 {
00899         isc__mem_t *ctx;
00900         isc_result_t result;
00901 
00902         REQUIRE(ctxp != NULL && *ctxp == NULL);
00903         REQUIRE(memalloc != NULL);
00904         REQUIRE(memfree != NULL);
00905 
00906         INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
00907 
00908         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
00909 
00910         ctx = (memalloc)(arg, sizeof(*ctx));
00911         if (ctx == NULL)
00912                 return (ISC_R_NOMEMORY);
00913 
00914         if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
00915                 result = isc_mutex_init(&ctx->lock);
00916                 if (result != ISC_R_SUCCESS) {
00917                         (memfree)(arg, ctx);
00918                         return (result);
00919                 }
00920         }
00921 
00922         if (init_max_size == 0U)
00923                 ctx->max_size = DEF_MAX_SIZE;
00924         else
00925                 ctx->max_size = init_max_size;
00926         ctx->flags = flags;
00927         ctx->references = 1;
00928         memset(ctx->name, 0, sizeof(ctx->name));
00929         ctx->tag = NULL;
00930         ctx->quota = 0;
00931         ctx->total = 0;
00932         ctx->inuse = 0;
00933         ctx->maxinuse = 0;
00934         ctx->hi_water = 0;
00935         ctx->lo_water = 0;
00936         ctx->hi_called = ISC_FALSE;
00937         ctx->is_overmem = ISC_FALSE;
00938         ctx->water = NULL;
00939         ctx->water_arg = NULL;
00940         ctx->common.impmagic = MEM_MAGIC;
00941         ctx->common.magic = ISCAPI_MCTX_MAGIC;
00942         ctx->common.methods = (isc_memmethods_t *)&memmethods;
00943         isc_ondestroy_init(&ctx->ondestroy);
00944         ctx->memalloc = memalloc;
00945         ctx->memfree = memfree;
00946         ctx->arg = arg;
00947         ctx->stats = NULL;
00948         ctx->checkfree = ISC_TRUE;
00949 #if ISC_MEM_TRACKLINES
00950         ctx->debuglist = NULL;
00951         ctx->debuglistcnt = 0;
00952 #endif
00953         ISC_LIST_INIT(ctx->pools);
00954         ctx->poolcnt = 0;
00955         ctx->freelists = NULL;
00956         ctx->basic_blocks = NULL;
00957         ctx->basic_table = NULL;
00958         ctx->basic_table_count = 0;
00959         ctx->basic_table_size = 0;
00960         ctx->lowest = NULL;
00961         ctx->highest = NULL;
00962 
00963         ctx->stats = (memalloc)(arg,
00964                                 (ctx->max_size+1) * sizeof(struct stats));
00965         if (ctx->stats == NULL) {
00966                 result = ISC_R_NOMEMORY;
00967                 goto error;
00968         }
00969         memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
00970 
00971         if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
00972                 if (target_size == 0U)
00973                         ctx->mem_target = DEF_MEM_TARGET;
00974                 else
00975                         ctx->mem_target = target_size;
00976                 ctx->freelists = (memalloc)(arg, ctx->max_size *
00977                                                  sizeof(element *));
00978                 if (ctx->freelists == NULL) {
00979                         result = ISC_R_NOMEMORY;
00980                         goto error;
00981                 }
00982                 memset(ctx->freelists, 0,
00983                        ctx->max_size * sizeof(element *));
00984         }
00985 
00986 #if ISC_MEM_TRACKLINES
00987         if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
00988                 unsigned int i;
00989 
00990                 ctx->debuglist = (memalloc)(arg,
00991                                       (ctx->max_size+1) * sizeof(debuglist_t));
00992                 if (ctx->debuglist == NULL) {
00993                         result = ISC_R_NOMEMORY;
00994                         goto error;
00995                 }
00996                 for (i = 0; i <= ctx->max_size; i++)
00997                         ISC_LIST_INIT(ctx->debuglist[i]);
00998         }
00999 #endif
01000 
01001         ctx->memalloc_failures = 0;
01002 
01003         LOCK(&contextslock);
01004         ISC_LIST_INITANDAPPEND(contexts, ctx, link);
01005         UNLOCK(&contextslock);
01006 
01007         *ctxp = (isc_mem_t *)ctx;
01008         return (ISC_R_SUCCESS);
01009 
01010   error:
01011         if (ctx != NULL) {
01012                 if (ctx->stats != NULL)
01013                         (memfree)(arg, ctx->stats);
01014                 if (ctx->freelists != NULL)
01015                         (memfree)(arg, ctx->freelists);
01016 #if ISC_MEM_TRACKLINES
01017                 if (ctx->debuglist != NULL)
01018                         (ctx->memfree)(ctx->arg, ctx->debuglist);
01019 #endif /* ISC_MEM_TRACKLINES */
01020                 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
01021                         DESTROYLOCK(&ctx->lock);
01022                 (memfree)(arg, ctx);
01023         }
01024 
01025         return (result);
01026 }
01027 
01028 static void
01029 destroy(isc__mem_t *ctx) {
01030         unsigned int i;
01031         isc_ondestroy_t ondest;
01032 
01033         LOCK(&contextslock);
01034         ISC_LIST_UNLINK(contexts, ctx, link);
01035         totallost += ctx->inuse;
01036         UNLOCK(&contextslock);
01037 
01038         ctx->common.impmagic = 0;
01039         ctx->common.magic = 0;
01040 
01041         INSIST(ISC_LIST_EMPTY(ctx->pools));
01042 
01043 #if ISC_MEM_TRACKLINES
01044         if (ctx->debuglist != NULL) {
01045                 if (ctx->checkfree) {
01046                         for (i = 0; i <= ctx->max_size; i++) {
01047                                 if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
01048                                         print_active(ctx, stderr);
01049                                 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
01050                         }
01051                 } else {
01052                         debuglink_t *dl;
01053 
01054                         for (i = 0; i <= ctx->max_size; i++)
01055                                 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
01056                                      dl != NULL;
01057                                      dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
01058                                         ISC_LIST_UNLINK(ctx->debuglist[i],
01059                                                         dl, link);
01060                                         free(dl);
01061                                 }
01062                 }
01063                 (ctx->memfree)(ctx->arg, ctx->debuglist);
01064         }
01065 #endif
01066         INSIST(ctx->references == 0);
01067 
01068         if (ctx->checkfree) {
01069                 for (i = 0; i <= ctx->max_size; i++) {
01070                         if (ctx->stats[i].gets != 0U) {
01071                                 fprintf(stderr,
01072                                         "Failing assertion due to probable "
01073                                         "leaked memory in context %p (\"%s\") "
01074                                         "(stats[%u].gets == %lu).\n",
01075                                         ctx, ctx->name, i, ctx->stats[i].gets);
01076 #if ISC_MEM_TRACKLINES
01077                                 print_active(ctx, stderr);
01078 #endif
01079                                 INSIST(ctx->stats[i].gets == 0U);
01080                         }
01081                 }
01082         }
01083 
01084         (ctx->memfree)(ctx->arg, ctx->stats);
01085 
01086         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
01087                 for (i = 0; i < ctx->basic_table_count; i++)
01088                         (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
01089                 (ctx->memfree)(ctx->arg, ctx->freelists);
01090                 if (ctx->basic_table != NULL)
01091                         (ctx->memfree)(ctx->arg, ctx->basic_table);
01092         }
01093 
01094         ondest = ctx->ondestroy;
01095 
01096         if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
01097                 DESTROYLOCK(&ctx->lock);
01098         (ctx->memfree)(ctx->arg, ctx);
01099 
01100         isc_ondestroy_notify(&ondest, ctx);
01101 }
01102 
01103 void
01104 isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) {
01105         isc__mem_t *source = (isc__mem_t *)source0;
01106 
01107         REQUIRE(VALID_CONTEXT(source));
01108         REQUIRE(targetp != NULL && *targetp == NULL);
01109 
01110         MCTXLOCK(source, &source->lock);
01111         source->references++;
01112         MCTXUNLOCK(source, &source->lock);
01113 
01114         *targetp = (isc_mem_t *)source;
01115 }
01116 
01117 void
01118 isc__mem_detach(isc_mem_t **ctxp) {
01119         isc__mem_t *ctx;
01120         isc_boolean_t want_destroy = ISC_FALSE;
01121 
01122         REQUIRE(ctxp != NULL);
01123         ctx = (isc__mem_t *)*ctxp;
01124         REQUIRE(VALID_CONTEXT(ctx));
01125 
01126         MCTXLOCK(ctx, &ctx->lock);
01127         INSIST(ctx->references > 0);
01128         ctx->references--;
01129         if (ctx->references == 0)
01130                 want_destroy = ISC_TRUE;
01131         MCTXUNLOCK(ctx, &ctx->lock);
01132 
01133         if (want_destroy)
01134                 destroy(ctx);
01135 
01136         *ctxp = NULL;
01137 }
01138 
01139 /*
01140  * isc_mem_putanddetach() is the equivalent of:
01141  *
01142  * mctx = NULL;
01143  * isc_mem_attach(ptr->mctx, &mctx);
01144  * isc_mem_detach(&ptr->mctx);
01145  * isc_mem_put(mctx, ptr, sizeof(*ptr);
01146  * isc_mem_detach(&mctx);
01147  */
01148 
01149 void
01150 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
01151         isc__mem_t *ctx;
01152         isc_boolean_t want_destroy = ISC_FALSE;
01153         size_info *si;
01154         size_t oldsize;
01155 
01156         REQUIRE(ctxp != NULL);
01157         ctx = (isc__mem_t *)*ctxp;
01158         REQUIRE(VALID_CONTEXT(ctx));
01159         REQUIRE(ptr != NULL);
01160 
01161         /*
01162          * Must be before mem_putunlocked() as ctxp is usually within
01163          * [ptr..ptr+size).
01164          */
01165         *ctxp = NULL;
01166 
01167         if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
01168                 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
01169                         si = &(((size_info *)ptr)[-1]);
01170                         oldsize = si->u.size - ALIGNMENT_SIZE;
01171                         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
01172                                 oldsize -= ALIGNMENT_SIZE;
01173                         INSIST(oldsize == size);
01174                 }
01175                 isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
01176 
01177                 MCTXLOCK(ctx, &ctx->lock);
01178                 ctx->references--;
01179                 if (ctx->references == 0)
01180                         want_destroy = ISC_TRUE;
01181                 MCTXUNLOCK(ctx, &ctx->lock);
01182                 if (want_destroy)
01183                         destroy(ctx);
01184 
01185                 return;
01186         }
01187 
01188         MCTXLOCK(ctx, &ctx->lock);
01189 
01190         DELETE_TRACE(ctx, ptr, size, file, line);
01191 
01192         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
01193                 mem_putunlocked(ctx, ptr, size);
01194         } else {
01195                 mem_putstats(ctx, ptr, size);
01196                 mem_put(ctx, ptr, size);
01197         }
01198 
01199         INSIST(ctx->references > 0);
01200         ctx->references--;
01201         if (ctx->references == 0)
01202                 want_destroy = ISC_TRUE;
01203 
01204         MCTXUNLOCK(ctx, &ctx->lock);
01205 
01206         if (want_destroy)
01207                 destroy(ctx);
01208 }
01209 
01210 void
01211 isc__mem_destroy(isc_mem_t **ctxp) {
01212         isc__mem_t *ctx;
01213 
01214         /*
01215          * This routine provides legacy support for callers who use mctxs
01216          * without attaching/detaching.
01217          */
01218 
01219         REQUIRE(ctxp != NULL);
01220         ctx = (isc__mem_t *)*ctxp;
01221         REQUIRE(VALID_CONTEXT(ctx));
01222 
01223         MCTXLOCK(ctx, &ctx->lock);
01224 #if ISC_MEM_TRACKLINES
01225         if (ctx->references != 1)
01226                 print_active(ctx, stderr);
01227 #endif
01228         REQUIRE(ctx->references == 1);
01229         ctx->references--;
01230         MCTXUNLOCK(ctx, &ctx->lock);
01231 
01232         destroy(ctx);
01233 
01234         *ctxp = NULL;
01235 }
01236 
01237 isc_result_t
01238 isc_mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) {
01239         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01240         isc_result_t res;
01241 
01242         MCTXLOCK(ctx, &ctx->lock);
01243         res = isc_ondestroy_register(&ctx->ondestroy, task, event);
01244         MCTXUNLOCK(ctx, &ctx->lock);
01245 
01246         return (res);
01247 }
01248 
01249 void *
01250 isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
01251         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01252         void *ptr;
01253         isc_boolean_t call_water = ISC_FALSE;
01254 
01255         REQUIRE(VALID_CONTEXT(ctx));
01256 
01257         if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
01258                 return (isc__mem_allocate(ctx0, size FLARG_PASS));
01259 
01260         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
01261                 MCTXLOCK(ctx, &ctx->lock);
01262                 ptr = mem_getunlocked(ctx, size);
01263         } else {
01264                 ptr = mem_get(ctx, size);
01265                 MCTXLOCK(ctx, &ctx->lock);
01266                 if (ptr != NULL)
01267                         mem_getstats(ctx, size);
01268         }
01269 
01270         ADD_TRACE(ctx, ptr, size, file, line);
01271         if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water) {
01272                 ctx->is_overmem = ISC_TRUE;
01273                 if (!ctx->hi_called)
01274                         call_water = ISC_TRUE;
01275         }
01276         if (ctx->inuse > ctx->maxinuse) {
01277                 ctx->maxinuse = ctx->inuse;
01278                 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
01279                     (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
01280                         fprintf(stderr, "maxinuse = %lu\n",
01281                                 (unsigned long)ctx->inuse);
01282         }
01283         MCTXUNLOCK(ctx, &ctx->lock);
01284 
01285         if (call_water && (ctx->water != NULL))
01286                 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
01287 
01288         return (ptr);
01289 }
01290 
01291 void
01292 isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
01293         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01294         isc_boolean_t call_water = ISC_FALSE;
01295         size_info *si;
01296         size_t oldsize;
01297 
01298         REQUIRE(VALID_CONTEXT(ctx));
01299         REQUIRE(ptr != NULL);
01300 
01301         if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
01302                 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
01303                         si = &(((size_info *)ptr)[-1]);
01304                         oldsize = si->u.size - ALIGNMENT_SIZE;
01305                         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
01306                                 oldsize -= ALIGNMENT_SIZE;
01307                         INSIST(oldsize == size);
01308                 }
01309                 isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
01310                 return;
01311         }
01312 
01313         MCTXLOCK(ctx, &ctx->lock);
01314 
01315         DELETE_TRACE(ctx, ptr, size, file, line);
01316 
01317         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
01318                 mem_putunlocked(ctx, ptr, size);
01319         } else {
01320                 mem_putstats(ctx, ptr, size);
01321                 mem_put(ctx, ptr, size);
01322         }
01323 
01324         /*
01325          * The check against ctx->lo_water == 0 is for the condition
01326          * when the context was pushed over hi_water but then had
01327          * isc_mem_setwater() called with 0 for hi_water and lo_water.
01328          */
01329         if ((ctx->inuse < ctx->lo_water) || (ctx->lo_water == 0U)) {
01330                 ctx->is_overmem = ISC_FALSE;
01331                 if (ctx->hi_called)
01332                         call_water = ISC_TRUE;
01333         }
01334 
01335         MCTXUNLOCK(ctx, &ctx->lock);
01336 
01337         if (call_water && (ctx->water != NULL))
01338                 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
01339 }
01340 
01341 void
01342 isc__mem_waterack(isc_mem_t *ctx0, int flag) {
01343         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01344 
01345         REQUIRE(VALID_CONTEXT(ctx));
01346 
01347         MCTXLOCK(ctx, &ctx->lock);
01348         if (flag == ISC_MEM_LOWATER)
01349                 ctx->hi_called = ISC_FALSE;
01350         else if (flag == ISC_MEM_HIWATER)
01351                 ctx->hi_called = ISC_TRUE;
01352         MCTXUNLOCK(ctx, &ctx->lock);
01353 }
01354 
01355 #if ISC_MEM_TRACKLINES
01356 static void
01357 print_active(isc__mem_t *mctx, FILE *out) {
01358         if (mctx->debuglist != NULL) {
01359                 debuglink_t *dl;
01360                 unsigned int i, j;
01361                 const char *format;
01362                 isc_boolean_t found;
01363 
01364                 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01365                                             ISC_MSG_DUMPALLOC,
01366                                             "Dump of all outstanding "
01367                                             "memory allocations:\n"));
01368                 found = ISC_FALSE;
01369                 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01370                                         ISC_MSG_PTRFILELINE,
01371                                         "\tptr %p size %u file %s line %u\n");
01372                 for (i = 0; i <= mctx->max_size; i++) {
01373                         dl = ISC_LIST_HEAD(mctx->debuglist[i]);
01374 
01375                         if (dl != NULL)
01376                                 found = ISC_TRUE;
01377 
01378                         while (dl != NULL) {
01379                                 for (j = 0; j < DEBUGLIST_COUNT; j++)
01380                                         if (dl->ptr[j] != NULL)
01381                                                 fprintf(out, format,
01382                                                         dl->ptr[j],
01383                                                         dl->size[j],
01384                                                         dl->file[j],
01385                                                         dl->line[j]);
01386                                 dl = ISC_LIST_NEXT(dl, link);
01387                         }
01388                 }
01389                 if (!found)
01390                         fputs(isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01391                                              ISC_MSG_NONE, "\tNone.\n"), out);
01392         }
01393 }
01394 #endif
01395 
01396 /*
01397  * Print the stats[] on the stream "out" with suitable formatting.
01398  */
01399 void
01400 isc_mem_stats(isc_mem_t *ctx0, FILE *out) {
01401         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01402         size_t i;
01403         const struct stats *s;
01404         const isc__mempool_t *pool;
01405 
01406         REQUIRE(VALID_CONTEXT(ctx));
01407         MCTXLOCK(ctx, &ctx->lock);
01408 
01409         for (i = 0; i <= ctx->max_size; i++) {
01410                 s = &ctx->stats[i];
01411 
01412                 if (s->totalgets == 0U && s->gets == 0U)
01413                         continue;
01414                 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
01415                         (i == ctx->max_size) ? ">=" : "  ",
01416                         (unsigned long) i, s->totalgets, s->gets);
01417                 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
01418                     (s->blocks != 0U || s->freefrags != 0U))
01419                         fprintf(out, " (%lu bl, %lu ff)",
01420                                 s->blocks, s->freefrags);
01421                 fputc('\n', out);
01422         }
01423 
01424         /*
01425          * Note that since a pool can be locked now, these stats might be
01426          * somewhat off if the pool is in active use at the time the stats
01427          * are dumped.  The link fields are protected by the isc_mem_t's
01428          * lock, however, so walking this list and extracting integers from
01429          * stats fields is always safe.
01430          */
01431         pool = ISC_LIST_HEAD(ctx->pools);
01432         if (pool != NULL) {
01433                 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01434                                             ISC_MSG_POOLSTATS,
01435                                             "[Pool statistics]\n"));
01436                 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
01437                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01438                                        ISC_MSG_POOLNAME, "name"),
01439                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01440                                        ISC_MSG_POOLSIZE, "size"),
01441                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01442                                        ISC_MSG_POOLMAXALLOC, "maxalloc"),
01443                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01444                                        ISC_MSG_POOLALLOCATED, "allocated"),
01445                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01446                                        ISC_MSG_POOLFREECOUNT, "freecount"),
01447                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01448                                        ISC_MSG_POOLFREEMAX, "freemax"),
01449                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01450                                        ISC_MSG_POOLFILLCOUNT, "fillcount"),
01451                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
01452                                        ISC_MSG_POOLGETS, "gets"),
01453                         "L");
01454         }
01455         while (pool != NULL) {
01456                 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
01457 #if ISC_MEMPOOL_NAMES
01458                         pool->name,
01459 #else
01460                         "(not tracked)",
01461 #endif
01462                         (unsigned long) pool->size, pool->maxalloc,
01463                         pool->allocated, pool->freecount, pool->freemax,
01464                         pool->fillcount, pool->gets,
01465                         (pool->lock == NULL ? "N" : "Y"));
01466                 pool = ISC_LIST_NEXT(pool, link);
01467         }
01468 
01469 #if ISC_MEM_TRACKLINES
01470         print_active(ctx, out);
01471 #endif
01472 
01473         MCTXUNLOCK(ctx, &ctx->lock);
01474 }
01475 
01476 /*
01477  * Replacements for malloc() and free() -- they implicitly remember the
01478  * size of the object allocated (with some additional overhead).
01479  */
01480 
01481 static void *
01482 mem_allocateunlocked(isc_mem_t *ctx0, size_t size) {
01483         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01484         size_info *si;
01485 
01486         size += ALIGNMENT_SIZE;
01487         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
01488                 size += ALIGNMENT_SIZE;
01489 
01490         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
01491                 si = mem_getunlocked(ctx, size);
01492         else
01493                 si = mem_get(ctx, size);
01494 
01495         if (si == NULL)
01496                 return (NULL);
01497         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
01498                 si->u.ctx = ctx;
01499                 si++;
01500         }
01501         si->u.size = size;
01502         return (&si[1]);
01503 }
01504 
01505 void *
01506 isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
01507         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01508         size_info *si;
01509         isc_boolean_t call_water = ISC_FALSE;
01510 
01511         REQUIRE(VALID_CONTEXT(ctx));
01512 
01513         MCTXLOCK(ctx, &ctx->lock);
01514         si = mem_allocateunlocked((isc_mem_t *)ctx, size);
01515         if (((ctx->flags & ISC_MEMFLAG_INTERNAL) == 0) && (si != NULL))
01516                 mem_getstats(ctx, si[-1].u.size);
01517 
01518 #if ISC_MEM_TRACKLINES
01519         ADD_TRACE(ctx, si, si[-1].u.size, file, line);
01520 #endif
01521         if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
01522             !ctx->is_overmem) {
01523                 ctx->is_overmem = ISC_TRUE;
01524         }
01525 
01526         if (ctx->hi_water != 0U && !ctx->hi_called &&
01527             ctx->inuse > ctx->hi_water) {
01528                 ctx->hi_called = ISC_TRUE;
01529                 call_water = ISC_TRUE;
01530         }
01531         if (ctx->inuse > ctx->maxinuse) {
01532                 ctx->maxinuse = ctx->inuse;
01533                 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
01534                     (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
01535                         fprintf(stderr, "maxinuse = %lu\n",
01536                                 (unsigned long)ctx->inuse);
01537         }
01538         MCTXUNLOCK(ctx, &ctx->lock);
01539 
01540         if (call_water)
01541                 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
01542 
01543         return (si);
01544 }
01545 
01546 void *
01547 isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
01548         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01549         void *new_ptr = NULL;
01550         size_t oldsize, copysize;
01551 
01552         REQUIRE(VALID_CONTEXT(ctx));
01553 
01554         /*
01555          * This function emulates the realloc(3) standard library function:
01556          * - if size > 0, allocate new memory; and if ptr is non NULL, copy
01557          *   as much of the old contents to the new buffer and free the old one.
01558          *   Note that when allocation fails the original pointer is intact;
01559          *   the caller must free it.
01560          * - if size is 0 and ptr is non NULL, simply free the given ptr.
01561          * - this function returns:
01562          *     pointer to the newly allocated memory, or
01563          *     NULL if allocation fails or doesn't happen.
01564          */
01565         if (size > 0U) {
01566                 new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS);
01567                 if (new_ptr != NULL && ptr != NULL) {
01568                         oldsize = (((size_info *)ptr)[-1]).u.size;
01569                         INSIST(oldsize >= ALIGNMENT_SIZE);
01570                         oldsize -= ALIGNMENT_SIZE;
01571                         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
01572                                 INSIST(oldsize >= ALIGNMENT_SIZE);
01573                                 oldsize -= ALIGNMENT_SIZE;
01574                         }
01575                         copysize = (oldsize > size) ? size : oldsize;
01576                         memmove(new_ptr, ptr, copysize);
01577                         isc__mem_free(ctx0, ptr FLARG_PASS);
01578                 }
01579         } else if (ptr != NULL)
01580                 isc__mem_free(ctx0, ptr FLARG_PASS);
01581 
01582         return (new_ptr);
01583 }
01584 
01585 void
01586 isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
01587         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01588         size_info *si;
01589         size_t size;
01590         isc_boolean_t call_water= ISC_FALSE;
01591 
01592         REQUIRE(VALID_CONTEXT(ctx));
01593         REQUIRE(ptr != NULL);
01594 
01595         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
01596                 si = &(((size_info *)ptr)[-2]);
01597                 REQUIRE(si->u.ctx == ctx);
01598                 size = si[1].u.size;
01599         } else {
01600                 si = &(((size_info *)ptr)[-1]);
01601                 size = si->u.size;
01602         }
01603 
01604         MCTXLOCK(ctx, &ctx->lock);
01605 
01606         DELETE_TRACE(ctx, ptr, size, file, line);
01607 
01608         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
01609                 mem_putunlocked(ctx, si, size);
01610         } else {
01611                 mem_putstats(ctx, si, size);
01612                 mem_put(ctx, si, size);
01613         }
01614 
01615         /*
01616          * The check against ctx->lo_water == 0 is for the condition
01617          * when the context was pushed over hi_water but then had
01618          * isc_mem_setwater() called with 0 for hi_water and lo_water.
01619          */
01620         if (ctx->is_overmem &&
01621             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
01622                 ctx->is_overmem = ISC_FALSE;
01623         }
01624 
01625         if (ctx->hi_called &&
01626             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
01627                 ctx->hi_called = ISC_FALSE;
01628 
01629                 if (ctx->water != NULL)
01630                         call_water = ISC_TRUE;
01631         }
01632         MCTXUNLOCK(ctx, &ctx->lock);
01633 
01634         if (call_water)
01635                 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
01636 }
01637 
01638 
01639 /*
01640  * Other useful things.
01641  */
01642 
01643 char *
01644 isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
01645         isc__mem_t *mctx = (isc__mem_t *)mctx0;
01646         size_t len;
01647         char *ns;
01648 
01649         REQUIRE(VALID_CONTEXT(mctx));
01650         REQUIRE(s != NULL);
01651 
01652         len = strlen(s);
01653 
01654         ns = isc__mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS);
01655 
01656         if (ns != NULL)
01657                 strncpy(ns, s, len + 1);
01658 
01659         return (ns);
01660 }
01661 
01662 void
01663 isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) {
01664         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01665 
01666         REQUIRE(VALID_CONTEXT(ctx));
01667         MCTXLOCK(ctx, &ctx->lock);
01668 
01669         ctx->checkfree = flag;
01670 
01671         MCTXUNLOCK(ctx, &ctx->lock);
01672 }
01673 
01674 /*
01675  * Quotas
01676  */
01677 
01678 void
01679 isc_mem_setquota(isc_mem_t *ctx0, size_t quota) {
01680         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01681 
01682         REQUIRE(VALID_CONTEXT(ctx));
01683         MCTXLOCK(ctx, &ctx->lock);
01684 
01685         ctx->quota = quota;
01686 
01687         MCTXUNLOCK(ctx, &ctx->lock);
01688 }
01689 
01690 size_t
01691 isc_mem_getquota(isc_mem_t *ctx0) {
01692         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01693         size_t quota;
01694 
01695         REQUIRE(VALID_CONTEXT(ctx));
01696         MCTXLOCK(ctx, &ctx->lock);
01697 
01698         quota = ctx->quota;
01699 
01700         MCTXUNLOCK(ctx, &ctx->lock);
01701 
01702         return (quota);
01703 }
01704 
01705 size_t
01706 isc__mem_inuse(isc_mem_t *ctx0) {
01707         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01708         size_t inuse;
01709 
01710         REQUIRE(VALID_CONTEXT(ctx));
01711         MCTXLOCK(ctx, &ctx->lock);
01712 
01713         inuse = ctx->inuse;
01714 
01715         MCTXUNLOCK(ctx, &ctx->lock);
01716 
01717         return (inuse);
01718 }
01719 
01720 size_t
01721 isc__mem_maxinuse(isc_mem_t *ctx0) {
01722         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01723         size_t maxinuse;
01724 
01725         REQUIRE(VALID_CONTEXT(ctx));
01726         MCTXLOCK(ctx, &ctx->lock);
01727 
01728         maxinuse = ctx->maxinuse;
01729 
01730         MCTXUNLOCK(ctx, &ctx->lock);
01731 
01732         return (maxinuse);
01733 }
01734 
01735 size_t
01736 isc__mem_total(isc_mem_t *ctx0) {
01737         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01738         size_t total;
01739 
01740         REQUIRE(VALID_CONTEXT(ctx));
01741         MCTXLOCK(ctx, &ctx->lock);
01742 
01743         total = ctx->total;
01744 
01745         MCTXUNLOCK(ctx, &ctx->lock);
01746 
01747         return (total);
01748 }
01749 
01750 void
01751 isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg,
01752                   size_t hiwater, size_t lowater)
01753 {
01754         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01755         isc_boolean_t callwater = ISC_FALSE;
01756         isc_mem_water_t oldwater;
01757         void *oldwater_arg;
01758 
01759         REQUIRE(VALID_CONTEXT(ctx));
01760         REQUIRE(hiwater >= lowater);
01761 
01762         MCTXLOCK(ctx, &ctx->lock);
01763         oldwater = ctx->water;
01764         oldwater_arg = ctx->water_arg;
01765         if (water == NULL) {
01766                 callwater = ctx->hi_called;
01767                 ctx->water = NULL;
01768                 ctx->water_arg = NULL;
01769                 ctx->hi_water = 0;
01770                 ctx->lo_water = 0;
01771         } else {
01772                 if (ctx->hi_called &&
01773                     (ctx->water != water || ctx->water_arg != water_arg ||
01774                      ctx->inuse < lowater || lowater == 0U))
01775                         callwater = ISC_TRUE;
01776                 ctx->water = water;
01777                 ctx->water_arg = water_arg;
01778                 ctx->hi_water = hiwater;
01779                 ctx->lo_water = lowater;
01780         }
01781         MCTXUNLOCK(ctx, &ctx->lock);
01782 
01783         if (callwater && oldwater != NULL)
01784                 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
01785 }
01786 
01787 isc_boolean_t
01788 isc__mem_isovermem(isc_mem_t *ctx0) {
01789         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01790 
01791         REQUIRE(VALID_CONTEXT(ctx));
01792 
01793         /*
01794          * We don't bother to lock the context because 100% accuracy isn't
01795          * necessary (and even if we locked the context the returned value
01796          * could be different from the actual state when it's used anyway)
01797          */
01798         return (ctx->is_overmem);
01799 }
01800 
01801 void
01802 isc_mem_setname(isc_mem_t *ctx0, const char *name, void *tag) {
01803         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01804 
01805         REQUIRE(VALID_CONTEXT(ctx));
01806 
01807         LOCK(&ctx->lock);
01808         memset(ctx->name, 0, sizeof(ctx->name));
01809         strncpy(ctx->name, name, sizeof(ctx->name) - 1);
01810         ctx->tag = tag;
01811         UNLOCK(&ctx->lock);
01812 }
01813 
01814 const char *
01815 isc_mem_getname(isc_mem_t *ctx0) {
01816         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01817 
01818         REQUIRE(VALID_CONTEXT(ctx));
01819 
01820         if (ctx->name[0] == 0)
01821                 return ("");
01822 
01823         return (ctx->name);
01824 }
01825 
01826 void *
01827 isc_mem_gettag(isc_mem_t *ctx0) {
01828         isc__mem_t *ctx = (isc__mem_t *)ctx0;
01829 
01830         REQUIRE(VALID_CONTEXT(ctx));
01831 
01832         return (ctx->tag);
01833 }
01834 
01835 /*
01836  * Memory pool stuff
01837  */
01838 
01839 isc_result_t
01840 isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
01841         isc__mem_t *mctx = (isc__mem_t *)mctx0;
01842         isc__mempool_t *mpctx;
01843 
01844         REQUIRE(VALID_CONTEXT(mctx));
01845         REQUIRE(size > 0U);
01846         REQUIRE(mpctxp != NULL && *mpctxp == NULL);
01847 
01848         /*
01849          * Allocate space for this pool, initialize values, and if all works
01850          * well, attach to the memory context.
01851          */
01852         mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t));
01853         if (mpctx == NULL)
01854                 return (ISC_R_NOMEMORY);
01855 
01856         mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods;
01857         mpctx->common.impmagic = MEMPOOL_MAGIC;
01858         mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
01859         mpctx->lock = NULL;
01860         mpctx->mctx = mctx;
01861         mpctx->size = size;
01862         mpctx->maxalloc = UINT_MAX;
01863         mpctx->allocated = 0;
01864         mpctx->freecount = 0;
01865         mpctx->freemax = 1;
01866         mpctx->fillcount = 1;
01867         mpctx->gets = 0;
01868 #if ISC_MEMPOOL_NAMES
01869         mpctx->name[0] = 0;
01870 #endif
01871         mpctx->items = NULL;
01872 
01873         *mpctxp = (isc_mempool_t *)mpctx;
01874 
01875         MCTXLOCK(mctx, &mctx->lock);
01876         ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
01877         mctx->poolcnt++;
01878         MCTXUNLOCK(mctx, &mctx->lock);
01879 
01880         return (ISC_R_SUCCESS);
01881 }
01882 
01883 void
01884 isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) {
01885         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
01886 
01887         REQUIRE(name != NULL);
01888         REQUIRE(VALID_MEMPOOL(mpctx));
01889 
01890 #if ISC_MEMPOOL_NAMES
01891         if (mpctx->lock != NULL)
01892                 LOCK(mpctx->lock);
01893 
01894         strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
01895         mpctx->name[sizeof(mpctx->name) - 1] = '\0';
01896 
01897         if (mpctx->lock != NULL)
01898                 UNLOCK(mpctx->lock);
01899 #else
01900         UNUSED(mpctx);
01901         UNUSED(name);
01902 #endif
01903 }
01904 
01905 void
01906 isc__mempool_destroy(isc_mempool_t **mpctxp) {
01907         isc__mempool_t *mpctx;
01908         isc__mem_t *mctx;
01909         isc_mutex_t *lock;
01910         element *item;
01911 
01912         REQUIRE(mpctxp != NULL);
01913         mpctx = (isc__mempool_t *)*mpctxp;
01914         REQUIRE(VALID_MEMPOOL(mpctx));
01915 #if ISC_MEMPOOL_NAMES
01916         if (mpctx->allocated > 0)
01917                 UNEXPECTED_ERROR(__FILE__, __LINE__,
01918                                  "isc__mempool_destroy(): mempool %s "
01919                                  "leaked memory",
01920                                  mpctx->name);
01921 #endif
01922         REQUIRE(mpctx->allocated == 0);
01923 
01924         mctx = mpctx->mctx;
01925 
01926         lock = mpctx->lock;
01927 
01928         if (lock != NULL)
01929                 LOCK(lock);
01930 
01931         /*
01932          * Return any items on the free list
01933          */
01934         MCTXLOCK(mctx, &mctx->lock);
01935         while (mpctx->items != NULL) {
01936                 INSIST(mpctx->freecount > 0);
01937                 mpctx->freecount--;
01938                 item = mpctx->items;
01939                 mpctx->items = item->next;
01940 
01941                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
01942                         mem_putunlocked(mctx, item, mpctx->size);
01943                 } else {
01944                         mem_putstats(mctx, item, mpctx->size);
01945                         mem_put(mctx, item, mpctx->size);
01946                 }
01947         }
01948         MCTXUNLOCK(mctx, &mctx->lock);
01949 
01950         /*
01951          * Remove our linked list entry from the memory context.
01952          */
01953         MCTXLOCK(mctx, &mctx->lock);
01954         ISC_LIST_UNLINK(mctx->pools, mpctx, link);
01955         mctx->poolcnt--;
01956         MCTXUNLOCK(mctx, &mctx->lock);
01957 
01958         mpctx->common.impmagic = 0;
01959         mpctx->common.magic = 0;
01960 
01961         isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t));
01962 
01963         if (lock != NULL)
01964                 UNLOCK(lock);
01965 
01966         *mpctxp = NULL;
01967 }
01968 
01969 void
01970 isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) {
01971         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
01972 
01973         REQUIRE(VALID_MEMPOOL(mpctx));
01974         REQUIRE(mpctx->lock == NULL);
01975         REQUIRE(lock != NULL);
01976 
01977         mpctx->lock = lock;
01978 }
01979 
01980 void *
01981 isc___mempool_get(isc_mempool_t *mpctx0 FLARG) {
01982         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
01983         element *item;
01984         isc__mem_t *mctx;
01985         unsigned int i;
01986 
01987         REQUIRE(VALID_MEMPOOL(mpctx));
01988 
01989         mctx = mpctx->mctx;
01990 
01991         if (mpctx->lock != NULL)
01992                 LOCK(mpctx->lock);
01993 
01994         /*
01995          * Don't let the caller go over quota
01996          */
01997         if (mpctx->allocated >= mpctx->maxalloc) {
01998                 item = NULL;
01999                 goto out;
02000         }
02001 
02002         /*
02003          * if we have a free list item, return the first here
02004          */
02005         item = mpctx->items;
02006         if (item != NULL) {
02007                 mpctx->items = item->next;
02008                 INSIST(mpctx->freecount > 0);
02009                 mpctx->freecount--;
02010                 mpctx->gets++;
02011                 mpctx->allocated++;
02012                 goto out;
02013         }
02014 
02015         /*
02016          * We need to dip into the well.  Lock the memory context here and
02017          * fill up our free list.
02018          */
02019         MCTXLOCK(mctx, &mctx->lock);
02020         for (i = 0; i < mpctx->fillcount; i++) {
02021                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
02022                         item = mem_getunlocked(mctx, mpctx->size);
02023                 } else {
02024                         item = mem_get(mctx, mpctx->size);
02025                         if (item != NULL)
02026                                 mem_getstats(mctx, mpctx->size);
02027                 }
02028                 if (item == NULL)
02029                         break;
02030                 item->next = mpctx->items;
02031                 mpctx->items = item;
02032                 mpctx->freecount++;
02033         }
02034         MCTXUNLOCK(mctx, &mctx->lock);
02035 
02036         /*
02037          * If we didn't get any items, return NULL.
02038          */
02039         item = mpctx->items;
02040         if (item == NULL)
02041                 goto out;
02042 
02043         mpctx->items = item->next;
02044         mpctx->freecount--;
02045         mpctx->gets++;
02046         mpctx->allocated++;
02047 
02048  out:
02049         if (mpctx->lock != NULL)
02050                 UNLOCK(mpctx->lock);
02051 
02052 #if ISC_MEM_TRACKLINES
02053         if (item != NULL) {
02054                 MCTXLOCK(mctx, &mctx->lock);
02055                 ADD_TRACE(mctx, item, mpctx->size, file, line);
02056                 MCTXUNLOCK(mctx, &mctx->lock);
02057         }
02058 #endif /* ISC_MEM_TRACKLINES */
02059 
02060         return (item);
02061 }
02062 
02063 /* coverity[+free : arg-1] */
02064 void
02065 isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
02066         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
02067         isc__mem_t *mctx;
02068         element *item;
02069 
02070         REQUIRE(VALID_MEMPOOL(mpctx));
02071         REQUIRE(mem != NULL);
02072 
02073         mctx = mpctx->mctx;
02074 
02075         if (mpctx->lock != NULL)
02076                 LOCK(mpctx->lock);
02077 
02078         INSIST(mpctx->allocated > 0);
02079         mpctx->allocated--;
02080 
02081 #if ISC_MEM_TRACKLINES
02082         MCTXLOCK(mctx, &mctx->lock);
02083         DELETE_TRACE(mctx, mem, mpctx->size, file, line);
02084         MCTXUNLOCK(mctx, &mctx->lock);
02085 #endif /* ISC_MEM_TRACKLINES */
02086 
02087         /*
02088          * If our free list is full, return this to the mctx directly.
02089          */
02090         if (mpctx->freecount >= mpctx->freemax) {
02091                 MCTXLOCK(mctx, &mctx->lock);
02092                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
02093                         mem_putunlocked(mctx, mem, mpctx->size);
02094                 } else {
02095                         mem_putstats(mctx, mem, mpctx->size);
02096                         mem_put(mctx, mem, mpctx->size);
02097                 }
02098                 MCTXUNLOCK(mctx, &mctx->lock);
02099                 if (mpctx->lock != NULL)
02100                         UNLOCK(mpctx->lock);
02101                 return;
02102         }
02103 
02104         /*
02105          * Otherwise, attach it to our free list and bump the counter.
02106          */
02107         mpctx->freecount++;
02108         item = (element *)mem;
02109         item->next = mpctx->items;
02110         mpctx->items = item;
02111 
02112         if (mpctx->lock != NULL)
02113                 UNLOCK(mpctx->lock);
02114 }
02115 
02116 /*
02117  * Quotas
02118  */
02119 
02120 void
02121 isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) {
02122         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
02123 
02124         REQUIRE(VALID_MEMPOOL(mpctx));
02125 
02126         if (mpctx->lock != NULL)
02127                 LOCK(mpctx->lock);
02128 
02129         mpctx->freemax = limit;
02130 
02131         if (mpctx->lock != NULL)
02132                 UNLOCK(mpctx->lock);
02133 }
02134 
02135 unsigned int
02136 isc_mempool_getfreemax(isc_mempool_t *mpctx0) {
02137         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
02138         unsigned int freemax;
02139 
02140         REQUIRE(VALID_MEMPOOL(mpctx));
02141 
02142         if (mpctx->lock != NULL)
02143                 LOCK(mpctx->lock);
02144 
02145         freemax = mpctx->freemax;
02146 
02147         if (mpctx->lock != NULL)
02148                 UNLOCK(mpctx->lock);
02149 
02150         return (freemax);
02151 }
02152 
02153 unsigned int
02154 isc_mempool_getfreecount(isc_mempool_t *mpctx0) {
02155         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
02156         unsigned int freecount;
02157 
02158         REQUIRE(VALID_MEMPOOL(mpctx));
02159 
02160         if (mpctx->lock != NULL)
02161                 LOCK(mpctx->lock);
02162 
02163         freecount = mpctx->freecount;
02164 
02165         if (mpctx->lock != NULL)
02166                 UNLOCK(mpctx->lock);
02167 
02168         return (freecount);
02169 }
02170 
02171 void
02172 isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
02173         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
02174 
02175         REQUIRE(limit > 0);
02176 
02177         REQUIRE(VALID_MEMPOOL(mpctx));
02178 
02179         if (mpctx->lock != NULL)
02180                 LOCK(mpctx->lock);
02181 
02182         mpctx->maxalloc = limit;
02183 
02184         if (mpctx->lock != NULL)
02185                 UNLOCK(mpctx->lock);
02186 }
02187 
02188 unsigned int
02189 isc_mempool_getmaxalloc(isc_mempool_t *mpctx0) {
02190         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
02191         unsigned int maxalloc;
02192 
02193         REQUIRE(VALID_MEMPOOL(mpctx));
02194 
02195         if (mpctx->lock != NULL)
02196                 LOCK(mpctx->lock);
02197 
02198         maxalloc = mpctx->maxalloc;
02199 
02200         if (mpctx->lock != NULL)
02201                 UNLOCK(mpctx->lock);
02202 
02203         return (maxalloc);
02204 }
02205 
02206 unsigned int
02207 isc__mempool_getallocated(isc_mempool_t *mpctx0) {
02208         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
02209         unsigned int allocated;
02210 
02211         REQUIRE(VALID_MEMPOOL(mpctx));
02212 
02213         if (mpctx->lock != NULL)
02214                 LOCK(mpctx->lock);
02215 
02216         allocated = mpctx->allocated;
02217 
02218         if (mpctx->lock != NULL)
02219                 UNLOCK(mpctx->lock);
02220 
02221         return (allocated);
02222 }
02223 
02224 void
02225 isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
02226         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
02227 
02228         REQUIRE(limit > 0);
02229         REQUIRE(VALID_MEMPOOL(mpctx));
02230 
02231         if (mpctx->lock != NULL)
02232                 LOCK(mpctx->lock);
02233 
02234         mpctx->fillcount = limit;
02235 
02236         if (mpctx->lock != NULL)
02237                 UNLOCK(mpctx->lock);
02238 }
02239 
02240 unsigned int
02241 isc_mempool_getfillcount(isc_mempool_t *mpctx0) {
02242         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
02243 
02244         unsigned int fillcount;
02245 
02246         REQUIRE(VALID_MEMPOOL(mpctx));
02247 
02248         if (mpctx->lock != NULL)
02249                 LOCK(mpctx->lock);
02250 
02251         fillcount = mpctx->fillcount;
02252 
02253         if (mpctx->lock != NULL)
02254                 UNLOCK(mpctx->lock);
02255 
02256         return (fillcount);
02257 }
02258 
02259 isc_result_t
02260 isc__mem_register(void) {
02261         return (isc_mem_register(isc_mem_create2));
02262 }
02263 
02264 void
02265 isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
02266 #if ISC_MEM_TRACKLINES
02267         isc__mem_t *ctx = (isc__mem_t *)ctx0;
02268 
02269         REQUIRE(VALID_CONTEXT(ctx));
02270         REQUIRE(file != NULL);
02271 
02272         print_active(ctx, file);
02273 #else
02274         UNUSED(ctx0);
02275         UNUSED(file);
02276 #endif
02277 }
02278 
02279 void
02280 isc_mem_printallactive(FILE *file) {
02281 #if !ISC_MEM_TRACKLINES
02282         UNUSED(file);
02283 #else
02284         isc__mem_t *ctx;
02285 
02286         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
02287 
02288         LOCK(&contextslock);
02289         for (ctx = ISC_LIST_HEAD(contexts);
02290              ctx != NULL;
02291              ctx = ISC_LIST_NEXT(ctx, link)) {
02292                 fprintf(file, "context: %p\n", ctx);
02293                 print_active(ctx, file);
02294         }
02295         UNLOCK(&contextslock);
02296 #endif
02297 }
02298 
02299 void
02300 isc_mem_checkdestroyed(FILE *file) {
02301 #if !ISC_MEM_TRACKLINES
02302         UNUSED(file);
02303 #endif
02304 
02305         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
02306 
02307         LOCK(&contextslock);
02308         if (!ISC_LIST_EMPTY(contexts))  {
02309 #if ISC_MEM_TRACKLINES
02310                 isc__mem_t *ctx;
02311 
02312                 for (ctx = ISC_LIST_HEAD(contexts);
02313                      ctx != NULL;
02314                      ctx = ISC_LIST_NEXT(ctx, link)) {
02315                         fprintf(file, "context: %p\n", ctx);
02316                         print_active(ctx, file);
02317                 }
02318                 fflush(file);
02319 #endif
02320                 INSIST(0);
02321         }
02322         UNLOCK(&contextslock);
02323 }
02324 
02325 unsigned int
02326 isc_mem_references(isc_mem_t *ctx0) {
02327         isc__mem_t *ctx = (isc__mem_t *)ctx0;
02328         unsigned int references;
02329 
02330         REQUIRE(VALID_CONTEXT(ctx));
02331 
02332         MCTXLOCK(ctx, &ctx->lock);
02333         references = ctx->references;
02334         MCTXUNLOCK(ctx, &ctx->lock);
02335 
02336         return (references);
02337 }
02338 
02339 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON)
02340 typedef struct summarystat {
02341         isc_uint64_t    total;
02342         isc_uint64_t    inuse;
02343         isc_uint64_t    blocksize;
02344         isc_uint64_t    contextsize;
02345 } summarystat_t;
02346 #endif
02347 
02348 #ifdef HAVE_LIBXML2
02349 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
02350 static int
02351 xml_renderctx(isc__mem_t *ctx, summarystat_t *summary,
02352               xmlTextWriterPtr writer)
02353 {
02354         int xmlrc;
02355 
02356         REQUIRE(VALID_CONTEXT(ctx));
02357 
02358         MCTXLOCK(ctx, &ctx->lock);
02359 
02360         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"));
02361 
02362         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
02363         TRY0(xmlTextWriterWriteFormatString(writer, "%p", ctx));
02364         TRY0(xmlTextWriterEndElement(writer)); /* id */
02365 
02366         if (ctx->name[0] != 0) {
02367                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
02368                 TRY0(xmlTextWriterWriteFormatString(writer, "%s", ctx->name));
02369                 TRY0(xmlTextWriterEndElement(writer)); /* name */
02370         }
02371 
02372         summary->contextsize += sizeof(*ctx) +
02373                 (ctx->max_size + 1) * sizeof(struct stats) +
02374                 ctx->max_size * sizeof(element *) +
02375                 ctx->basic_table_count * sizeof(char *);
02376 #if ISC_MEM_TRACKLINES
02377         if (ctx->debuglist != NULL) {
02378                 summary->contextsize +=
02379                         (ctx->max_size + 1) * sizeof(debuglist_t) +
02380                         ctx->debuglistcnt * sizeof(debuglink_t);
02381         }
02382 #endif
02383         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
02384         TRY0(xmlTextWriterWriteFormatString(writer, "%d", ctx->references));
02385         TRY0(xmlTextWriterEndElement(writer)); /* references */
02386 
02387         summary->total += ctx->total;
02388         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"));
02389         TRY0(xmlTextWriterWriteFormatString(writer,
02390                                             "%" ISC_PRINT_QUADFORMAT "u",
02391                                             (isc_uint64_t)ctx->total));
02392         TRY0(xmlTextWriterEndElement(writer)); /* total */
02393 
02394         summary->inuse += ctx->inuse;
02395         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"));
02396         TRY0(xmlTextWriterWriteFormatString(writer,
02397                                             "%" ISC_PRINT_QUADFORMAT "u",
02398                                             (isc_uint64_t)ctx->inuse));
02399         TRY0(xmlTextWriterEndElement(writer)); /* inuse */
02400 
02401         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"));
02402         TRY0(xmlTextWriterWriteFormatString(writer,
02403                                             "%" ISC_PRINT_QUADFORMAT "u",
02404                                             (isc_uint64_t)ctx->maxinuse));
02405         TRY0(xmlTextWriterEndElement(writer)); /* maxinuse */
02406 
02407         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"));
02408         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
02409                 summary->blocksize += ctx->basic_table_count *
02410                         NUM_BASIC_BLOCKS * ctx->mem_target;
02411                 TRY0(xmlTextWriterWriteFormatString(writer,
02412                                                "%" ISC_PRINT_QUADFORMAT "u",
02413                                                (isc_uint64_t)
02414                                                ctx->basic_table_count *
02415                                                NUM_BASIC_BLOCKS *
02416                                                ctx->mem_target));
02417         } else
02418                 TRY0(xmlTextWriterWriteFormatString(writer, "%s", "-"));
02419         TRY0(xmlTextWriterEndElement(writer)); /* blocksize */
02420 
02421         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"));
02422         TRY0(xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt));
02423         TRY0(xmlTextWriterEndElement(writer)); /* pools */
02424         summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
02425 
02426         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"));
02427         TRY0(xmlTextWriterWriteFormatString(writer,
02428                                             "%" ISC_PRINT_QUADFORMAT "u",
02429                                             (isc_uint64_t)ctx->hi_water));
02430         TRY0(xmlTextWriterEndElement(writer)); /* hiwater */
02431 
02432         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"));
02433         TRY0(xmlTextWriterWriteFormatString(writer,
02434                                             "%" ISC_PRINT_QUADFORMAT "u",
02435                                             (isc_uint64_t)ctx->lo_water));
02436         TRY0(xmlTextWriterEndElement(writer)); /* lowater */
02437 
02438         TRY0(xmlTextWriterEndElement(writer)); /* context */
02439 
02440  error:
02441         MCTXUNLOCK(ctx, &ctx->lock);
02442 
02443         return (xmlrc);
02444 }
02445 
02446 int
02447 isc_mem_renderxml(xmlTextWriterPtr writer) {
02448         isc__mem_t *ctx;
02449         summarystat_t summary;
02450         isc_uint64_t lost;
02451         int xmlrc;
02452 
02453         memset(&summary, 0, sizeof(summary));
02454 
02455         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"));
02456 
02457         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
02458 
02459         LOCK(&contextslock);
02460         lost = totallost;
02461         for (ctx = ISC_LIST_HEAD(contexts);
02462              ctx != NULL;
02463              ctx = ISC_LIST_NEXT(ctx, link)) {
02464                 xmlrc = xml_renderctx(ctx, &summary, writer);
02465                 if (xmlrc < 0) {
02466                         UNLOCK(&contextslock);
02467                         goto error;
02468                 }
02469         }
02470         UNLOCK(&contextslock);
02471 
02472         TRY0(xmlTextWriterEndElement(writer)); /* contexts */
02473 
02474         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"));
02475 
02476         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"));
02477         TRY0(xmlTextWriterWriteFormatString(writer,
02478                                             "%" ISC_PRINT_QUADFORMAT "u",
02479                                             summary.total));
02480         TRY0(xmlTextWriterEndElement(writer)); /* TotalUse */
02481 
02482         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"));
02483         TRY0(xmlTextWriterWriteFormatString(writer,
02484                                             "%" ISC_PRINT_QUADFORMAT "u",
02485                                             summary.inuse));
02486         TRY0(xmlTextWriterEndElement(writer)); /* InUse */
02487 
02488         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"));
02489         TRY0(xmlTextWriterWriteFormatString(writer,
02490                                             "%" ISC_PRINT_QUADFORMAT "u",
02491                                             summary.blocksize));
02492         TRY0(xmlTextWriterEndElement(writer)); /* BlockSize */
02493 
02494         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"));
02495         TRY0(xmlTextWriterWriteFormatString(writer,
02496                                             "%" ISC_PRINT_QUADFORMAT "u",
02497                                             summary.contextsize));
02498         TRY0(xmlTextWriterEndElement(writer)); /* ContextSize */
02499 
02500         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"));
02501         TRY0(xmlTextWriterWriteFormatString(writer,
02502                                             "%" ISC_PRINT_QUADFORMAT "u",
02503                                             lost));
02504         TRY0(xmlTextWriterEndElement(writer)); /* Lost */
02505 
02506         TRY0(xmlTextWriterEndElement(writer)); /* summary */
02507  error:
02508         return (xmlrc);
02509 }
02510 
02511 #endif /* HAVE_LIBXML2 */
02512 
02513 #ifdef HAVE_JSON
02514 #define CHECKMEM(m) do { \
02515         if (m == NULL) { \
02516                 result = ISC_R_NOMEMORY;\
02517                 goto error;\
02518         } \
02519 } while(0)
02520 
02521 static isc_result_t
02522 json_renderctx(isc__mem_t *ctx, summarystat_t *summary, json_object *array) {
02523         isc_result_t result = ISC_R_FAILURE;
02524         json_object *ctxobj, *obj;
02525         char buf[1024];
02526 
02527         REQUIRE(VALID_CONTEXT(ctx));
02528         REQUIRE(summary != NULL);
02529         REQUIRE(array != NULL);
02530 
02531         MCTXLOCK(ctx, &ctx->lock);
02532 
02533         summary->contextsize += sizeof(*ctx) +
02534                 (ctx->max_size + 1) * sizeof(struct stats) +
02535                 ctx->max_size * sizeof(element *) +
02536                 ctx->basic_table_count * sizeof(char *);
02537         summary->total += ctx->total;
02538         summary->inuse += ctx->inuse;
02539         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
02540                 summary->blocksize += ctx->basic_table_count *
02541                         NUM_BASIC_BLOCKS * ctx->mem_target;
02542 #if ISC_MEM_TRACKLINES
02543         if (ctx->debuglist != NULL) {
02544                 summary->contextsize +=
02545                         (ctx->max_size + 1) * sizeof(debuglist_t) +
02546                         ctx->debuglistcnt * sizeof(debuglink_t);
02547         }
02548 #endif
02549 
02550         ctxobj = json_object_new_object();
02551         CHECKMEM(ctxobj);
02552 
02553         sprintf(buf, "%p", ctx);
02554         obj = json_object_new_string(buf);
02555         CHECKMEM(obj);
02556         json_object_object_add(ctxobj, "id", obj);
02557 
02558         if (ctx->name[0] != 0) {
02559                 obj = json_object_new_string(ctx->name);
02560                 CHECKMEM(obj);
02561                 json_object_object_add(ctxobj, "name", obj);
02562         }
02563 
02564         obj = json_object_new_int64(ctx->references);
02565         CHECKMEM(obj);
02566         json_object_object_add(ctxobj, "references", obj);
02567 
02568         obj = json_object_new_int64(ctx->total);
02569         CHECKMEM(obj);
02570         json_object_object_add(ctxobj, "total", obj);
02571 
02572         obj = json_object_new_int64(ctx->inuse);
02573         CHECKMEM(obj);
02574         json_object_object_add(ctxobj, "inuse", obj);
02575 
02576         obj = json_object_new_int64(ctx->maxinuse);
02577         CHECKMEM(obj);
02578         json_object_object_add(ctxobj, "maxinuse", obj);
02579 
02580         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
02581                 isc_uint64_t blocksize;
02582                 blocksize = ctx->basic_table_count * NUM_BASIC_BLOCKS *
02583                         ctx->mem_target;
02584                 obj = json_object_new_int64(blocksize);
02585                 CHECKMEM(obj);
02586                 json_object_object_add(ctxobj, "blocksize", obj);
02587         }
02588 
02589         obj = json_object_new_int64(ctx->poolcnt);
02590         CHECKMEM(obj);
02591         json_object_object_add(ctxobj, "pools", obj);
02592 
02593         summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
02594 
02595         obj = json_object_new_int64(ctx->hi_water);
02596         CHECKMEM(obj);
02597         json_object_object_add(ctxobj, "hiwater", obj);
02598 
02599         obj = json_object_new_int64(ctx->lo_water);
02600         CHECKMEM(obj);
02601         json_object_object_add(ctxobj, "lowater", obj);
02602 
02603         MCTXUNLOCK(ctx, &ctx->lock);
02604         json_object_array_add(array, ctxobj);
02605         return (ISC_R_SUCCESS);
02606 
02607  error:
02608         MCTXUNLOCK(ctx, &ctx->lock);
02609         if (ctxobj != NULL)
02610                 json_object_put(ctxobj);
02611         return (result);
02612 }
02613 
02614 isc_result_t
02615 isc_mem_renderjson(json_object *memobj) {
02616         isc_result_t result = ISC_R_SUCCESS;
02617         isc__mem_t *ctx;
02618         summarystat_t summary;
02619         isc_uint64_t lost;
02620         json_object *ctxarray, *obj;
02621 
02622         memset(&summary, 0, sizeof(summary));
02623         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
02624 
02625         ctxarray = json_object_new_array();
02626         CHECKMEM(ctxarray);
02627 
02628         LOCK(&contextslock);
02629         lost = totallost;
02630         for (ctx = ISC_LIST_HEAD(contexts);
02631              ctx != NULL;
02632              ctx = ISC_LIST_NEXT(ctx, link)) {
02633                 result = json_renderctx(ctx, &summary, ctxarray);
02634                 if (result != ISC_R_SUCCESS) {
02635                         UNLOCK(&contextslock);
02636                         goto error;
02637                 }
02638         }
02639         UNLOCK(&contextslock);
02640 
02641         obj = json_object_new_int64(summary.total);
02642         CHECKMEM(obj);
02643         json_object_object_add(memobj, "TotalUse", obj);
02644 
02645         obj = json_object_new_int64(summary.inuse);
02646         CHECKMEM(obj);
02647         json_object_object_add(memobj, "InUse", obj);
02648 
02649         obj = json_object_new_int64(summary.blocksize);
02650         CHECKMEM(obj);
02651         json_object_object_add(memobj, "BlockSize", obj);
02652 
02653         obj = json_object_new_int64(summary.contextsize);
02654         CHECKMEM(obj);
02655         json_object_object_add(memobj, "ContextSize", obj);
02656 
02657         obj = json_object_new_int64(lost);
02658         CHECKMEM(obj);
02659         json_object_object_add(memobj, "Lost", obj);
02660 
02661         json_object_object_add(memobj, "contexts", ctxarray);
02662         return (ISC_R_SUCCESS);
02663 
02664  error:
02665         if (ctxarray != NULL)
02666                 json_object_put(ctxarray);
02667         return (result);
02668 }
02669 #endif /* HAVE_JSON */
02670 
02671 static isc_memcreatefunc_t mem_createfunc = NULL;
02672 
02673 isc_result_t
02674 isc_mem_register(isc_memcreatefunc_t createfunc) {
02675         isc_result_t result = ISC_R_SUCCESS;
02676 
02677         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
02678 
02679         LOCK(&createlock);
02680         if (mem_createfunc == NULL)
02681                 mem_createfunc = createfunc;
02682         else
02683                 result = ISC_R_EXISTS;
02684         UNLOCK(&createlock);
02685 
02686         return (result);
02687 }
02688 
02689 
02690 isc_result_t
02691 isc__mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **mctxp,
02692                  unsigned int flags)
02693 {
02694         isc_result_t result;
02695 
02696         LOCK(&createlock);
02697 
02698         REQUIRE(mem_createfunc != NULL);
02699         result = (*mem_createfunc)(init_max_size, target_size, mctxp, flags);
02700 
02701         UNLOCK(&createlock);
02702 
02703         return (result);
02704 }
02705 
02706 isc_result_t
02707 isc_mem_create(size_t init_max_size, size_t target_size, isc_mem_t **mctxp) {
02708         isc_result_t result;
02709 
02710         if (isc_bind9)
02711                 return (isc_mem_createx2(init_max_size, target_size,
02712                                          default_memalloc, default_memfree,
02713                                          NULL, mctxp, isc_mem_defaultflags));
02714         LOCK(&createlock);
02715 
02716         REQUIRE(mem_createfunc != NULL);
02717         result = (*mem_createfunc)(init_max_size, target_size, mctxp,
02718                                    isc_mem_defaultflags);
02719 
02720         UNLOCK(&createlock);
02721 
02722         return (result);
02723 }
02724 
02725 isc_result_t
02726 isc_mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **mctxp,
02727                  unsigned int flags)
02728 {
02729         if (isc_bind9)
02730                 return (isc_mem_createx2(init_max_size, target_size,
02731                                          default_memalloc, default_memfree,
02732                                          NULL, mctxp, flags));
02733 
02734         return (isc_mem_createx2(init_max_size, target_size,
02735                                  default_memalloc, default_memfree,
02736                                  NULL, mctxp, flags));
02737 }
02738 
02739 void
02740 isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
02741         REQUIRE(ISCAPI_MCTX_VALID(source));
02742         REQUIRE(targetp != NULL && *targetp == NULL);
02743 
02744         if (isc_bind9)
02745                 isc__mem_attach(source, targetp);
02746         else
02747                 source->methods->attach(source, targetp);
02748 
02749         ENSURE(*targetp == source);
02750 }
02751 
02752 void
02753 isc_mem_detach(isc_mem_t **mctxp) {
02754         REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
02755 
02756         if (isc_bind9)
02757                 isc__mem_detach(mctxp);
02758         else
02759                 (*mctxp)->methods->detach(mctxp);
02760 
02761         ENSURE(*mctxp == NULL);
02762 }
02763 
02764 void
02765 isc_mem_destroy(isc_mem_t **mctxp) {
02766         REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
02767 
02768         if (isc_bind9)
02769                 isc__mem_destroy(mctxp);
02770         else
02771                 (*mctxp)->methods->destroy(mctxp);
02772 
02773         ENSURE(*mctxp == NULL);
02774 }
02775 
02776 void
02777 isc_mem_setdestroycheck(isc_mem_t *mctx, isc_boolean_t flag) {
02778         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02779 
02780         mctx->methods->setdestroycheck(mctx, flag);
02781 }
02782 
02783 void
02784 isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
02785                  size_t hiwater, size_t lowater)
02786 {
02787         REQUIRE(ISCAPI_MCTX_VALID(ctx));
02788 
02789         if (isc_bind9)
02790                 isc__mem_setwater(ctx, water, water_arg, hiwater, lowater);
02791         else
02792                 ctx->methods->setwater(ctx, water, water_arg, hiwater, lowater);
02793 }
02794 
02795 void
02796 isc_mem_waterack(isc_mem_t *ctx, int flag) {
02797         REQUIRE(ISCAPI_MCTX_VALID(ctx));
02798 
02799         if (isc_bind9)
02800                 isc__mem_waterack(ctx, flag);
02801         else
02802                 ctx->methods->waterack(ctx, flag);
02803 }
02804 
02805 size_t
02806 isc_mem_inuse(isc_mem_t *mctx) {
02807         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02808 
02809         if (isc_bind9)
02810                 return (isc__mem_inuse(mctx));
02811 
02812         return (mctx->methods->inuse(mctx));
02813 }
02814 
02815 size_t
02816 isc_mem_maxinuse(isc_mem_t *mctx) {
02817         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02818 
02819         if (isc_bind9)
02820                 return (isc__mem_maxinuse(mctx));
02821 
02822         return (mctx->methods->maxinuse(mctx));
02823 }
02824 
02825 size_t
02826 isc_mem_total(isc_mem_t *mctx) {
02827         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02828 
02829         if (isc_bind9)
02830                 return (isc__mem_total(mctx));
02831 
02832         return (mctx->methods->total(mctx));
02833 }
02834 
02835 isc_boolean_t
02836 isc_mem_isovermem(isc_mem_t *mctx) {
02837         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02838 
02839         if (isc_bind9)
02840                 return (isc__mem_isovermem(mctx));
02841 
02842         return (mctx->methods->isovermem(mctx));
02843 }
02844 
02845 
02846 isc_result_t
02847 isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
02848         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02849 
02850         return (mctx->methods->mpcreate(mctx, size, mpctxp));
02851 }
02852 
02853 void
02854 isc_mempool_destroy(isc_mempool_t **mpctxp) {
02855         REQUIRE(mpctxp != NULL && ISCAPI_MPOOL_VALID(*mpctxp));
02856 
02857         if (isc_bind9)
02858                 isc__mempool_destroy(mpctxp);
02859         else
02860                 (*mpctxp)->methods->destroy(mpctxp);
02861 
02862         ENSURE(*mpctxp == NULL);
02863 }
02864 
02865 unsigned int
02866 isc_mempool_getallocated(isc_mempool_t *mpctx) {
02867         REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
02868 
02869         if (isc_bind9)
02870                 return (isc__mempool_getallocated(mpctx));
02871 
02872         return (mpctx->methods->getallocated(mpctx));
02873 }
02874 
02875 void
02876 isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
02877         REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
02878 
02879         if (isc_bind9)
02880                 isc__mempool_setmaxalloc(mpctx, limit);
02881         else
02882                 mpctx->methods->setmaxalloc(mpctx, limit);
02883 }
02884 
02885 void
02886 isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
02887         REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
02888 
02889         if (isc_bind9)
02890                 isc__mempool_setfreemax(mpctx, limit);
02891         else
02892                 mpctx->methods->setfreemax(mpctx, limit);
02893 }
02894 
02895 void
02896 isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
02897         REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
02898 
02899         if (isc_bind9)
02900                 isc__mempool_setname(mpctx, name);
02901         else
02902                 mpctx->methods->setname(mpctx, name);
02903 }
02904 
02905 void
02906 isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
02907         REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
02908 
02909         if (isc_bind9)
02910                 isc__mempool_associatelock(mpctx, lock);
02911         else
02912                 mpctx->methods->associatelock(mpctx, lock);
02913 }
02914 
02915 void
02916 isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
02917         REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
02918 
02919         if (isc_bind9)
02920                 isc__mempool_setfillcount(mpctx, limit);
02921         else
02922                 mpctx->methods->setfillcount(mpctx, limit);
02923 }
02924 
02925 void *
02926 isc__mem_get(isc_mem_t *mctx, size_t size FLARG) {
02927         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02928 
02929         if (isc_bind9)
02930                 return (isc___mem_get(mctx, size FLARG_PASS));
02931 
02932         return (mctx->methods->memget(mctx, size FLARG_PASS));
02933 
02934 }
02935 
02936 void
02937 isc__mem_put(isc_mem_t *mctx, void *ptr, size_t size FLARG) {
02938         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02939 
02940         if (isc_bind9)
02941                 isc___mem_put(mctx, ptr, size FLARG_PASS);
02942         else
02943                 mctx->methods->memput(mctx, ptr, size FLARG_PASS);
02944 }
02945 
02946 void
02947 isc__mem_putanddetach(isc_mem_t **mctxp, void *ptr, size_t size FLARG) {
02948         REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
02949 
02950         if (isc_bind9)
02951                 isc___mem_putanddetach(mctxp, ptr, size FLARG_PASS);
02952         else
02953                 (*mctxp)->methods->memputanddetach(mctxp, ptr, size FLARG_PASS);
02954 
02955         /*
02956          * XXX: We cannot always ensure *mctxp == NULL here
02957          * (see lib/isc/mem.c).
02958          */
02959 }
02960 
02961 void *
02962 isc__mem_allocate(isc_mem_t *mctx, size_t size FLARG) {
02963         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02964 
02965         if (isc_bind9)
02966                 return (isc___mem_allocate(mctx, size FLARG_PASS));
02967 
02968         return (mctx->methods->memallocate(mctx, size FLARG_PASS));
02969 }
02970 
02971 void *
02972 isc__mem_reallocate(isc_mem_t *mctx, void *ptr, size_t size FLARG) {
02973         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02974 
02975         if (isc_bind9)
02976                 return (isc___mem_reallocate(mctx, ptr, size FLARG_PASS));
02977 
02978         return (mctx->methods->memreallocate(mctx, ptr, size FLARG_PASS));
02979 }
02980 
02981 char *
02982 isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
02983         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02984 
02985         if (isc_bind9)
02986                 return (isc___mem_strdup(mctx, s FLARG_PASS));
02987 
02988         return (mctx->methods->memstrdup(mctx, s FLARG_PASS));
02989 }
02990 
02991 void
02992 isc__mem_free(isc_mem_t *mctx, void *ptr FLARG) {
02993         REQUIRE(ISCAPI_MCTX_VALID(mctx));
02994 
02995         if (isc_bind9)
02996                 isc___mem_free(mctx, ptr FLARG_PASS);
02997         else
02998                 mctx->methods->memfree(mctx, ptr FLARG_PASS);
02999 }
03000 
03001 void *
03002 isc__mempool_get(isc_mempool_t *mpctx FLARG) {
03003         REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
03004 
03005         if (isc_bind9)
03006                 return (isc___mempool_get(mpctx FLARG_PASS));
03007 
03008         return (mpctx->methods->get(mpctx FLARG_PASS));
03009 }
03010 
03011 void
03012 isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
03013         REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
03014 
03015         if (isc_bind9)
03016                 isc___mempool_put(mpctx, mem FLARG_PASS);
03017         else
03018                 mpctx->methods->put(mpctx, mem FLARG_PASS);
03019 }

Generated on Tue Apr 28 17:41:04 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha