]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/lib/isc/mem.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / lib / isc / mem.c
1 /*
2  * Copyright (C) 2004-2010, 2012  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1997-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id$ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stddef.h>
27
28 #include <limits.h>
29
30 #include <isc/magic.h>
31 #include <isc/mem.h>
32 #include <isc/msgs.h>
33 #include <isc/once.h>
34 #include <isc/ondestroy.h>
35 #include <isc/string.h>
36 #include <isc/mutex.h>
37 #include <isc/print.h>
38 #include <isc/util.h>
39 #include <isc/xml.h>
40
41 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
42 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
43
44 #ifndef ISC_MEM_DEBUGGING
45 #define ISC_MEM_DEBUGGING 0
46 #endif
47 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
48
49 /*
50  * Constants.
51  */
52
53 #define DEF_MAX_SIZE            1100
54 #define DEF_MEM_TARGET          4096
55 #define ALIGNMENT_SIZE          8U              /*%< must be a power of 2 */
56 #define NUM_BASIC_BLOCKS        64              /*%< must be > 1 */
57 #define TABLE_INCREMENT         1024
58 #define DEBUGLIST_COUNT         1024
59
60 /*
61  * Types.
62  */
63 typedef struct isc__mem isc__mem_t;
64 typedef struct isc__mempool isc__mempool_t;
65
66 #if ISC_MEM_TRACKLINES
67 typedef struct debuglink debuglink_t;
68 struct debuglink {
69         ISC_LINK(debuglink_t)   link;
70         const void             *ptr[DEBUGLIST_COUNT];
71         unsigned int            size[DEBUGLIST_COUNT];
72         const char             *file[DEBUGLIST_COUNT];
73         unsigned int            line[DEBUGLIST_COUNT];
74         unsigned int            count;
75 };
76
77 #define FLARG_PASS      , file, line
78 #define FLARG           , const char *file, unsigned int line
79 #else
80 #define FLARG_PASS
81 #define FLARG
82 #endif
83
84 typedef struct element element;
85 struct element {
86         element *               next;
87 };
88
89 typedef struct {
90         /*!
91          * This structure must be ALIGNMENT_SIZE bytes.
92          */
93         union {
94                 size_t          size;
95                 isc__mem_t      *ctx;
96                 char            bytes[ALIGNMENT_SIZE];
97         } u;
98 } size_info;
99
100 struct stats {
101         unsigned long           gets;
102         unsigned long           totalgets;
103         unsigned long           blocks;
104         unsigned long           freefrags;
105 };
106
107 #define MEM_MAGIC               ISC_MAGIC('M', 'e', 'm', 'C')
108 #define VALID_CONTEXT(c)        ISC_MAGIC_VALID(c, MEM_MAGIC)
109
110 #if ISC_MEM_TRACKLINES
111 typedef ISC_LIST(debuglink_t)   debuglist_t;
112 #endif
113
114 /* List of all active memory contexts. */
115
116 static ISC_LIST(isc__mem_t)     contexts;
117 static isc_once_t               once = ISC_ONCE_INIT;
118 static isc_mutex_t              lock;
119
120 /*%
121  * Total size of lost memory due to a bug of external library.
122  * Locked by the global lock.
123  */
124 static isc_uint64_t             totallost;
125
126 struct isc__mem {
127         isc_mem_t               common;
128         isc_ondestroy_t         ondestroy;
129         unsigned int            flags;
130         isc_mutex_t             lock;
131         isc_memalloc_t          memalloc;
132         isc_memfree_t           memfree;
133         void *                  arg;
134         size_t                  max_size;
135         isc_boolean_t           checkfree;
136         struct stats *          stats;
137         unsigned int            references;
138         char                    name[16];
139         void *                  tag;
140         size_t                  quota;
141         size_t                  total;
142         size_t                  inuse;
143         size_t                  maxinuse;
144         size_t                  hi_water;
145         size_t                  lo_water;
146         isc_boolean_t           hi_called;
147         isc_boolean_t           is_overmem;
148         isc_mem_water_t         water;
149         void *                  water_arg;
150         ISC_LIST(isc__mempool_t) pools;
151         unsigned int            poolcnt;
152
153         /*  ISC_MEMFLAG_INTERNAL */
154         size_t                  mem_target;
155         element **              freelists;
156         element *               basic_blocks;
157         unsigned char **        basic_table;
158         unsigned int            basic_table_count;
159         unsigned int            basic_table_size;
160         unsigned char *         lowest;
161         unsigned char *         highest;
162
163 #if ISC_MEM_TRACKLINES
164         debuglist_t *           debuglist;
165         unsigned int            debuglistcnt;
166 #endif
167
168         unsigned int            memalloc_failures;
169         ISC_LINK(isc__mem_t)    link;
170 };
171
172 #define MEMPOOL_MAGIC           ISC_MAGIC('M', 'E', 'M', 'p')
173 #define VALID_MEMPOOL(c)        ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
174
175 struct isc__mempool {
176         /* always unlocked */
177         isc_mempool_t   common;         /*%< common header of mempool's */
178         isc_mutex_t    *lock;           /*%< optional lock */
179         isc__mem_t      *mctx;          /*%< our memory context */
180         /*%< locked via the memory context's lock */
181         ISC_LINK(isc__mempool_t)        link;   /*%< next pool in this mem context */
182         /*%< optionally locked from here down */
183         element        *items;          /*%< low water item list */
184         size_t          size;           /*%< size of each item on this pool */
185         unsigned int    maxalloc;       /*%< max number of items allowed */
186         unsigned int    allocated;      /*%< # of items currently given out */
187         unsigned int    freecount;      /*%< # of items on reserved list */
188         unsigned int    freemax;        /*%< # of items allowed on free list */
189         unsigned int    fillcount;      /*%< # of items to fetch on each fill */
190         /*%< Stats only. */
191         unsigned int    gets;           /*%< # of requests to this pool */
192         /*%< Debugging only. */
193 #if ISC_MEMPOOL_NAMES
194         char            name[16];       /*%< printed name in stats reports */
195 #endif
196 };
197
198 /*
199  * Private Inline-able.
200  */
201
202 #if ! ISC_MEM_TRACKLINES
203 #define ADD_TRACE(a, b, c, d, e)
204 #define DELETE_TRACE(a, b, c, d, e)
205 #else
206 #define ADD_TRACE(a, b, c, d, e) \
207         do { \
208                 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
209                                           ISC_MEM_DEBUGRECORD)) != 0 && \
210                      b != NULL) \
211                          add_trace_entry(a, b, c, d, e); \
212         } while (0)
213 #define DELETE_TRACE(a, b, c, d, e)     delete_trace_entry(a, b, c, d, e)
214
215 static void
216 print_active(isc__mem_t *ctx, FILE *out);
217
218 /*%
219  * The following can be either static or public, depending on build environment.
220  */
221
222 #ifdef BIND9
223 #define ISC_MEMFUNC_SCOPE
224 #else
225 #define ISC_MEMFUNC_SCOPE static
226 #endif
227
228 ISC_MEMFUNC_SCOPE isc_result_t
229 isc__mem_createx(size_t init_max_size, size_t target_size,
230                  isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
231                  isc_mem_t **ctxp);
232 ISC_MEMFUNC_SCOPE isc_result_t
233 isc__mem_createx2(size_t init_max_size, size_t target_size,
234                   isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
235                   isc_mem_t **ctxp, unsigned int flags);
236 ISC_MEMFUNC_SCOPE isc_result_t
237 isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp);
238 ISC_MEMFUNC_SCOPE isc_result_t
239 isc__mem_create2(size_t init_max_size, size_t target_size,
240                  isc_mem_t **ctxp, unsigned int flags);
241 ISC_MEMFUNC_SCOPE void
242 isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp);
243 ISC_MEMFUNC_SCOPE void
244 isc__mem_detach(isc_mem_t **ctxp);
245 ISC_MEMFUNC_SCOPE void
246 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
247 ISC_MEMFUNC_SCOPE void
248 isc__mem_destroy(isc_mem_t **ctxp);
249 ISC_MEMFUNC_SCOPE isc_result_t
250 isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event);
251 ISC_MEMFUNC_SCOPE void *
252 isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
253 ISC_MEMFUNC_SCOPE void
254 isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
255 ISC_MEMFUNC_SCOPE void
256 isc__mem_stats(isc_mem_t *ctx, FILE *out);
257 ISC_MEMFUNC_SCOPE void *
258 isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
259 ISC_MEMFUNC_SCOPE void *
260 isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
261 ISC_MEMFUNC_SCOPE void
262 isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
263 ISC_MEMFUNC_SCOPE char *
264 isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
265 ISC_MEMFUNC_SCOPE void
266 isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag);
267 ISC_MEMFUNC_SCOPE void
268 isc__mem_setquota(isc_mem_t *ctx, size_t quota);
269 ISC_MEMFUNC_SCOPE size_t
270 isc__mem_getquota(isc_mem_t *ctx);
271 ISC_MEMFUNC_SCOPE size_t
272 isc__mem_inuse(isc_mem_t *ctx);
273 ISC_MEMFUNC_SCOPE isc_boolean_t
274 isc__mem_isovermem(isc_mem_t *ctx);
275 ISC_MEMFUNC_SCOPE void
276 isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
277                   size_t hiwater, size_t lowater);
278 ISC_MEMFUNC_SCOPE void
279 isc__mem_waterack(isc_mem_t *ctx0, int flag);
280 ISC_MEMFUNC_SCOPE void
281 isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag);
282 ISC_MEMFUNC_SCOPE const char *
283 isc__mem_getname(isc_mem_t *ctx);
284 ISC_MEMFUNC_SCOPE void *
285 isc__mem_gettag(isc_mem_t *ctx);
286 ISC_MEMFUNC_SCOPE isc_result_t
287 isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
288 ISC_MEMFUNC_SCOPE void
289 isc__mempool_setname(isc_mempool_t *mpctx, const char *name);
290 ISC_MEMFUNC_SCOPE void
291 isc__mempool_destroy(isc_mempool_t **mpctxp);
292 ISC_MEMFUNC_SCOPE void
293 isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
294 ISC_MEMFUNC_SCOPE void *
295 isc___mempool_get(isc_mempool_t *mpctx FLARG);
296 ISC_MEMFUNC_SCOPE void
297 isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG);
298 ISC_MEMFUNC_SCOPE void
299 isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
300 ISC_MEMFUNC_SCOPE unsigned int
301 isc__mempool_getfreemax(isc_mempool_t *mpctx);
302 ISC_MEMFUNC_SCOPE unsigned int
303 isc__mempool_getfreecount(isc_mempool_t *mpctx);
304 ISC_MEMFUNC_SCOPE void
305 isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
306 ISC_MEMFUNC_SCOPE unsigned int
307 isc__mempool_getmaxalloc(isc_mempool_t *mpctx);
308 ISC_MEMFUNC_SCOPE unsigned int
309 isc__mempool_getallocated(isc_mempool_t *mpctx);
310 ISC_MEMFUNC_SCOPE void
311 isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
312 ISC_MEMFUNC_SCOPE unsigned int
313 isc__mempool_getfillcount(isc_mempool_t *mpctx);
314 #ifdef BIND9
315 ISC_MEMFUNC_SCOPE void
316 isc__mem_printactive(isc_mem_t *ctx0, FILE *file);
317 ISC_MEMFUNC_SCOPE void
318 isc__mem_printallactive(FILE *file);
319 ISC_MEMFUNC_SCOPE void
320 isc__mem_checkdestroyed(FILE *file);
321 ISC_MEMFUNC_SCOPE unsigned int
322 isc__mem_references(isc_mem_t *ctx0);
323 #endif
324
325 static struct isc__memmethods {
326         isc_memmethods_t methods;
327
328         /*%
329          * The following are defined just for avoiding unused static functions.
330          */
331 #ifndef BIND9
332         void *createx, *create, *create2, *ondestroy, *stats,
333                 *setquota, *getquota, *setname, *getname, *gettag;
334 #endif
335 } memmethods = {
336         {
337                 isc__mem_attach,
338                 isc__mem_detach,
339                 isc__mem_destroy,
340                 isc___mem_get,
341                 isc___mem_put,
342                 isc___mem_putanddetach,
343                 isc___mem_allocate,
344                 isc___mem_reallocate,
345                 isc___mem_strdup,
346                 isc___mem_free,
347                 isc__mem_setdestroycheck,
348                 isc__mem_setwater,
349                 isc__mem_waterack,
350                 isc__mem_inuse,
351                 isc__mem_isovermem,
352                 isc__mempool_create
353         }
354 #ifndef BIND9
355         ,
356         (void *)isc__mem_createx, (void *)isc__mem_create,
357         (void *)isc__mem_create2, (void *)isc__mem_ondestroy,
358         (void *)isc__mem_stats, (void *)isc__mem_setquota,
359         (void *)isc__mem_getquota, (void *)isc__mem_setname,
360         (void *)isc__mem_getname, (void *)isc__mem_gettag
361 #endif
362 };
363
364 static struct isc__mempoolmethods {
365         isc_mempoolmethods_t methods;
366
367         /*%
368          * The following are defined just for avoiding unused static functions.
369          */
370 #ifndef BIND9
371         void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount;
372 #endif
373 } mempoolmethods = {
374         {
375                 isc__mempool_destroy,
376                 isc___mempool_get,
377                 isc___mempool_put,
378                 isc__mempool_getallocated,
379                 isc__mempool_setmaxalloc,
380                 isc__mempool_setfreemax,
381                 isc__mempool_setname,
382                 isc__mempool_associatelock,
383                 isc__mempool_setfillcount
384         }
385 #ifndef BIND9
386         ,
387         (void *)isc__mempool_getfreemax, (void *)isc__mempool_getfreecount,
388         (void *)isc__mempool_getmaxalloc, (void *)isc__mempool_getfillcount
389 #endif
390 };
391
392 /*!
393  * mctx must be locked.
394  */
395 static inline void
396 add_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size
397                 FLARG)
398 {
399         debuglink_t *dl;
400         unsigned int i;
401         unsigned int mysize = size;
402
403         if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
404                 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
405                                                ISC_MSG_ADDTRACE,
406                                                "add %p size %u "
407                                                "file %s line %u mctx %p\n"),
408                         ptr, size, file, line, mctx);
409
410         if (mctx->debuglist == NULL)
411                 return;
412
413         if (mysize > mctx->max_size)
414                 mysize = mctx->max_size;
415
416         dl = ISC_LIST_HEAD(mctx->debuglist[mysize]);
417         while (dl != NULL) {
418                 if (dl->count == DEBUGLIST_COUNT)
419                         goto next;
420                 for (i = 0; i < DEBUGLIST_COUNT; i++) {
421                         if (dl->ptr[i] == NULL) {
422                                 dl->ptr[i] = ptr;
423                                 dl->size[i] = size;
424                                 dl->file[i] = file;
425                                 dl->line[i] = line;
426                                 dl->count++;
427                                 return;
428                         }
429                 }
430         next:
431                 dl = ISC_LIST_NEXT(dl, link);
432         }
433
434         dl = malloc(sizeof(debuglink_t));
435         INSIST(dl != NULL);
436
437         ISC_LINK_INIT(dl, link);
438         for (i = 1; i < DEBUGLIST_COUNT; i++) {
439                 dl->ptr[i] = NULL;
440                 dl->size[i] = 0;
441                 dl->file[i] = NULL;
442                 dl->line[i] = 0;
443         }
444
445         dl->ptr[0] = ptr;
446         dl->size[0] = size;
447         dl->file[0] = file;
448         dl->line[0] = line;
449         dl->count = 1;
450
451         ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link);
452         mctx->debuglistcnt++;
453 }
454
455 static inline void
456 delete_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size,
457                    const char *file, unsigned int line)
458 {
459         debuglink_t *dl;
460         unsigned int i;
461
462         if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
463                 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
464                                                ISC_MSG_DELTRACE,
465                                                "del %p size %u "
466                                                "file %s line %u mctx %p\n"),
467                         ptr, size, file, line, mctx);
468
469         if (mctx->debuglist == NULL)
470                 return;
471
472         if (size > mctx->max_size)
473                 size = mctx->max_size;
474
475         dl = ISC_LIST_HEAD(mctx->debuglist[size]);
476         while (dl != NULL) {
477                 for (i = 0; i < DEBUGLIST_COUNT; i++) {
478                         if (dl->ptr[i] == ptr) {
479                                 dl->ptr[i] = NULL;
480                                 dl->size[i] = 0;
481                                 dl->file[i] = NULL;
482                                 dl->line[i] = 0;
483
484                                 INSIST(dl->count > 0);
485                                 dl->count--;
486                                 if (dl->count == 0) {
487                                         ISC_LIST_UNLINK(mctx->debuglist[size],
488                                                         dl, link);
489                                         free(dl);
490                                 }
491                                 return;
492                         }
493                 }
494                 dl = ISC_LIST_NEXT(dl, link);
495         }
496
497         /*
498          * If we get here, we didn't find the item on the list.  We're
499          * screwed.
500          */
501         INSIST(dl != NULL);
502 }
503 #endif /* ISC_MEM_TRACKLINES */
504
505 static inline size_t
506 rmsize(size_t size) {
507         /*
508          * round down to ALIGNMENT_SIZE
509          */
510         return (size & (~(ALIGNMENT_SIZE - 1)));
511 }
512
513 static inline size_t
514 quantize(size_t size) {
515         /*!
516          * Round up the result in order to get a size big
517          * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
518          * byte boundaries.
519          */
520
521         if (size == 0U)
522                 return (ALIGNMENT_SIZE);
523         return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
524 }
525
526 static inline isc_boolean_t
527 more_basic_blocks(isc__mem_t *ctx) {
528         void *new;
529         unsigned char *curr, *next;
530         unsigned char *first, *last;
531         unsigned char **table;
532         unsigned int table_size;
533         size_t increment;
534         int i;
535
536         /* Require: we hold the context lock. */
537
538         /*
539          * Did we hit the quota for this context?
540          */
541         increment = NUM_BASIC_BLOCKS * ctx->mem_target;
542         if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
543                 return (ISC_FALSE);
544
545         INSIST(ctx->basic_table_count <= ctx->basic_table_size);
546         if (ctx->basic_table_count == ctx->basic_table_size) {
547                 table_size = ctx->basic_table_size + TABLE_INCREMENT;
548                 table = (ctx->memalloc)(ctx->arg,
549                                         table_size * sizeof(unsigned char *));
550                 if (table == NULL) {
551                         ctx->memalloc_failures++;
552                         return (ISC_FALSE);
553                 }
554                 if (ctx->basic_table_size != 0) {
555                         memcpy(table, ctx->basic_table,
556                                ctx->basic_table_size *
557                                sizeof(unsigned char *));
558                         (ctx->memfree)(ctx->arg, ctx->basic_table);
559                 }
560                 ctx->basic_table = table;
561                 ctx->basic_table_size = table_size;
562         }
563
564         new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
565         if (new == NULL) {
566                 ctx->memalloc_failures++;
567                 return (ISC_FALSE);
568         }
569         ctx->total += increment;
570         ctx->basic_table[ctx->basic_table_count] = new;
571         ctx->basic_table_count++;
572
573         curr = new;
574         next = curr + ctx->mem_target;
575         for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
576                 ((element *)curr)->next = (element *)next;
577                 curr = next;
578                 next += ctx->mem_target;
579         }
580         /*
581          * curr is now pointing at the last block in the
582          * array.
583          */
584         ((element *)curr)->next = NULL;
585         first = new;
586         last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
587         if (first < ctx->lowest || ctx->lowest == NULL)
588                 ctx->lowest = first;
589         if (last > ctx->highest)
590                 ctx->highest = last;
591         ctx->basic_blocks = new;
592
593         return (ISC_TRUE);
594 }
595
596 static inline isc_boolean_t
597 more_frags(isc__mem_t *ctx, size_t new_size) {
598         int i, frags;
599         size_t total_size;
600         void *new;
601         unsigned char *curr, *next;
602
603         /*!
604          * Try to get more fragments by chopping up a basic block.
605          */
606
607         if (ctx->basic_blocks == NULL) {
608                 if (!more_basic_blocks(ctx)) {
609                         /*
610                          * We can't get more memory from the OS, or we've
611                          * hit the quota for this context.
612                          */
613                         /*
614                          * XXXRTH  "At quota" notification here.
615                          */
616                         return (ISC_FALSE);
617                 }
618         }
619
620         total_size = ctx->mem_target;
621         new = ctx->basic_blocks;
622         ctx->basic_blocks = ctx->basic_blocks->next;
623         frags = total_size / new_size;
624         ctx->stats[new_size].blocks++;
625         ctx->stats[new_size].freefrags += frags;
626         /*
627          * Set up a linked-list of blocks of size
628          * "new_size".
629          */
630         curr = new;
631         next = curr + new_size;
632         total_size -= new_size;
633         for (i = 0; i < (frags - 1); i++) {
634                 ((element *)curr)->next = (element *)next;
635                 curr = next;
636                 next += new_size;
637                 total_size -= new_size;
638         }
639         /*
640          * Add the remaining fragment of the basic block to a free list.
641          */
642         total_size = rmsize(total_size);
643         if (total_size > 0U) {
644                 ((element *)next)->next = ctx->freelists[total_size];
645                 ctx->freelists[total_size] = (element *)next;
646                 ctx->stats[total_size].freefrags++;
647         }
648         /*
649          * curr is now pointing at the last block in the
650          * array.
651          */
652         ((element *)curr)->next = NULL;
653         ctx->freelists[new_size] = new;
654
655         return (ISC_TRUE);
656 }
657
658 static inline void *
659 mem_getunlocked(isc__mem_t *ctx, size_t size) {
660         size_t new_size = quantize(size);
661         void *ret;
662
663         if (size >= ctx->max_size || new_size >= ctx->max_size) {
664                 /*
665                  * memget() was called on something beyond our upper limit.
666                  */
667                 if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
668                         ret = NULL;
669                         goto done;
670                 }
671                 ret = (ctx->memalloc)(ctx->arg, size);
672                 if (ret == NULL) {
673                         ctx->memalloc_failures++;
674                         goto done;
675                 }
676                 ctx->total += size;
677                 ctx->inuse += size;
678                 ctx->stats[ctx->max_size].gets++;
679                 ctx->stats[ctx->max_size].totalgets++;
680                 /*
681                  * If we don't set new_size to size, then the
682                  * ISC_MEM_FILL code might write over bytes we
683                  * don't own.
684                  */
685                 new_size = size;
686                 goto done;
687         }
688
689         /*
690          * If there are no blocks in the free list for this size, get a chunk
691          * of memory and then break it up into "new_size"-sized blocks, adding
692          * them to the free list.
693          */
694         if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
695                 return (NULL);
696
697         /*
698          * The free list uses the "rounded-up" size "new_size".
699          */
700         ret = ctx->freelists[new_size];
701         ctx->freelists[new_size] = ctx->freelists[new_size]->next;
702
703         /*
704          * The stats[] uses the _actual_ "size" requested by the
705          * caller, with the caveat (in the code above) that "size" >= the
706          * max. size (max_size) ends up getting recorded as a call to
707          * max_size.
708          */
709         ctx->stats[size].gets++;
710         ctx->stats[size].totalgets++;
711         ctx->stats[new_size].freefrags--;
712         ctx->inuse += new_size;
713
714  done:
715
716 #if ISC_MEM_FILL
717         if (ret != NULL)
718                 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
719 #endif
720
721         return (ret);
722 }
723
724 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
725 static inline void
726 check_overrun(void *mem, size_t size, size_t new_size) {
727         unsigned char *cp;
728
729         cp = (unsigned char *)mem;
730         cp += size;
731         while (size < new_size) {
732                 INSIST(*cp == 0xbe);
733                 cp++;
734                 size++;
735         }
736 }
737 #endif
738
739 static inline void
740 mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) {
741         size_t new_size = quantize(size);
742
743         if (size == ctx->max_size || new_size >= ctx->max_size) {
744                 /*
745                  * memput() called on something beyond our upper limit.
746                  */
747 #if ISC_MEM_FILL
748                 memset(mem, 0xde, size); /* Mnemonic for "dead". */
749 #endif
750                 (ctx->memfree)(ctx->arg, mem);
751                 INSIST(ctx->stats[ctx->max_size].gets != 0U);
752                 ctx->stats[ctx->max_size].gets--;
753                 INSIST(size <= ctx->total);
754                 ctx->inuse -= size;
755                 ctx->total -= size;
756                 return;
757         }
758
759 #if ISC_MEM_FILL
760 #if ISC_MEM_CHECKOVERRUN
761         check_overrun(mem, size, new_size);
762 #endif
763         memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
764 #endif
765
766         /*
767          * The free list uses the "rounded-up" size "new_size".
768          */
769         ((element *)mem)->next = ctx->freelists[new_size];
770         ctx->freelists[new_size] = (element *)mem;
771
772         /*
773          * The stats[] uses the _actual_ "size" requested by the
774          * caller, with the caveat (in the code above) that "size" >= the
775          * max. size (max_size) ends up getting recorded as a call to
776          * max_size.
777          */
778         INSIST(ctx->stats[size].gets != 0U);
779         ctx->stats[size].gets--;
780         ctx->stats[new_size].freefrags++;
781         ctx->inuse -= new_size;
782 }
783
784 /*!
785  * Perform a malloc, doing memory filling and overrun detection as necessary.
786  */
787 static inline void *
788 mem_get(isc__mem_t *ctx, size_t size) {
789         char *ret;
790
791 #if ISC_MEM_CHECKOVERRUN
792         size += 1;
793 #endif
794
795         ret = (ctx->memalloc)(ctx->arg, size);
796         if (ret == NULL)
797                 ctx->memalloc_failures++;
798
799 #if ISC_MEM_FILL
800         if (ret != NULL)
801                 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
802 #else
803 #  if ISC_MEM_CHECKOVERRUN
804         if (ret != NULL)
805                 ret[size-1] = 0xbe;
806 #  endif
807 #endif
808
809         return (ret);
810 }
811
812 /*!
813  * Perform a free, doing memory filling and overrun detection as necessary.
814  */
815 static inline void
816 mem_put(isc__mem_t *ctx, void *mem, size_t size) {
817 #if ISC_MEM_CHECKOVERRUN
818         INSIST(((unsigned char *)mem)[size] == 0xbe);
819 #endif
820 #if ISC_MEM_FILL
821         memset(mem, 0xde, size); /* Mnemonic for "dead". */
822 #else
823         UNUSED(size);
824 #endif
825         (ctx->memfree)(ctx->arg, mem);
826 }
827
828 /*!
829  * Update internal counters after a memory get.
830  */
831 static inline void
832 mem_getstats(isc__mem_t *ctx, size_t size) {
833         ctx->total += size;
834         ctx->inuse += size;
835
836         if (size > ctx->max_size) {
837                 ctx->stats[ctx->max_size].gets++;
838                 ctx->stats[ctx->max_size].totalgets++;
839         } else {
840                 ctx->stats[size].gets++;
841                 ctx->stats[size].totalgets++;
842         }
843 }
844
845 /*!
846  * Update internal counters after a memory put.
847  */
848 static inline void
849 mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) {
850         UNUSED(ptr);
851
852         INSIST(ctx->inuse >= size);
853         ctx->inuse -= size;
854
855         if (size > ctx->max_size) {
856                 INSIST(ctx->stats[ctx->max_size].gets > 0U);
857                 ctx->stats[ctx->max_size].gets--;
858         } else {
859                 INSIST(ctx->stats[size].gets > 0U);
860                 ctx->stats[size].gets--;
861         }
862 }
863
864 /*
865  * Private.
866  */
867
868 static void *
869 default_memalloc(void *arg, size_t size) {
870         UNUSED(arg);
871         if (size == 0U)
872                 size = 1;
873         return (malloc(size));
874 }
875
876 static void
877 default_memfree(void *arg, void *ptr) {
878         UNUSED(arg);
879         free(ptr);
880 }
881
882 static void
883 initialize_action(void) {
884         RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
885         ISC_LIST_INIT(contexts);
886         totallost = 0;
887 }
888
889 /*
890  * Public.
891  */
892
893 ISC_MEMFUNC_SCOPE isc_result_t
894 isc__mem_createx(size_t init_max_size, size_t target_size,
895                  isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
896                  isc_mem_t **ctxp)
897 {
898         return (isc__mem_createx2(init_max_size, target_size, memalloc, memfree,
899                                   arg, ctxp, ISC_MEMFLAG_DEFAULT));
900
901 }
902
903 ISC_MEMFUNC_SCOPE isc_result_t
904 isc__mem_createx2(size_t init_max_size, size_t target_size,
905                   isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
906                   isc_mem_t **ctxp, unsigned int flags)
907 {
908         isc__mem_t *ctx;
909         isc_result_t result;
910
911         REQUIRE(ctxp != NULL && *ctxp == NULL);
912         REQUIRE(memalloc != NULL);
913         REQUIRE(memfree != NULL);
914
915         INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
916
917         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
918
919         ctx = (memalloc)(arg, sizeof(*ctx));
920         if (ctx == NULL)
921                 return (ISC_R_NOMEMORY);
922
923         if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
924                 result = isc_mutex_init(&ctx->lock);
925                 if (result != ISC_R_SUCCESS) {
926                         (memfree)(arg, ctx);
927                         return (result);
928                 }
929         }
930
931         if (init_max_size == 0U)
932                 ctx->max_size = DEF_MAX_SIZE;
933         else
934                 ctx->max_size = init_max_size;
935         ctx->flags = flags;
936         ctx->references = 1;
937         memset(ctx->name, 0, sizeof(ctx->name));
938         ctx->tag = NULL;
939         ctx->quota = 0;
940         ctx->total = 0;
941         ctx->inuse = 0;
942         ctx->maxinuse = 0;
943         ctx->hi_water = 0;
944         ctx->lo_water = 0;
945         ctx->hi_called = ISC_FALSE;
946         ctx->is_overmem = ISC_FALSE;
947         ctx->water = NULL;
948         ctx->water_arg = NULL;
949         ctx->common.impmagic = MEM_MAGIC;
950         ctx->common.magic = ISCAPI_MCTX_MAGIC;
951         ctx->common.methods = (isc_memmethods_t *)&memmethods;
952         isc_ondestroy_init(&ctx->ondestroy);
953         ctx->memalloc = memalloc;
954         ctx->memfree = memfree;
955         ctx->arg = arg;
956         ctx->stats = NULL;
957         ctx->checkfree = ISC_TRUE;
958 #if ISC_MEM_TRACKLINES
959         ctx->debuglist = NULL;
960         ctx->debuglistcnt = 0;
961 #endif
962         ISC_LIST_INIT(ctx->pools);
963         ctx->poolcnt = 0;
964         ctx->freelists = NULL;
965         ctx->basic_blocks = NULL;
966         ctx->basic_table = NULL;
967         ctx->basic_table_count = 0;
968         ctx->basic_table_size = 0;
969         ctx->lowest = NULL;
970         ctx->highest = NULL;
971
972         ctx->stats = (memalloc)(arg,
973                                 (ctx->max_size+1) * sizeof(struct stats));
974         if (ctx->stats == NULL) {
975                 result = ISC_R_NOMEMORY;
976                 goto error;
977         }
978         memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
979
980         if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
981                 if (target_size == 0U)
982                         ctx->mem_target = DEF_MEM_TARGET;
983                 else
984                         ctx->mem_target = target_size;
985                 ctx->freelists = (memalloc)(arg, ctx->max_size *
986                                                  sizeof(element *));
987                 if (ctx->freelists == NULL) {
988                         result = ISC_R_NOMEMORY;
989                         goto error;
990                 }
991                 memset(ctx->freelists, 0,
992                        ctx->max_size * sizeof(element *));
993         }
994
995 #if ISC_MEM_TRACKLINES
996         if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
997                 unsigned int i;
998
999                 ctx->debuglist = (memalloc)(arg,
1000                                       (ctx->max_size+1) * sizeof(debuglist_t));
1001                 if (ctx->debuglist == NULL) {
1002                         result = ISC_R_NOMEMORY;
1003                         goto error;
1004                 }
1005                 for (i = 0; i <= ctx->max_size; i++)
1006                         ISC_LIST_INIT(ctx->debuglist[i]);
1007         }
1008 #endif
1009
1010         ctx->memalloc_failures = 0;
1011
1012         LOCK(&lock);
1013         ISC_LIST_INITANDAPPEND(contexts, ctx, link);
1014         UNLOCK(&lock);
1015
1016         *ctxp = (isc_mem_t *)ctx;
1017         return (ISC_R_SUCCESS);
1018
1019   error:
1020         if (ctx != NULL) {
1021                 if (ctx->stats != NULL)
1022                         (memfree)(arg, ctx->stats);
1023                 if (ctx->freelists != NULL)
1024                         (memfree)(arg, ctx->freelists);
1025 #if ISC_MEM_TRACKLINES
1026                 if (ctx->debuglist != NULL)
1027                         (ctx->memfree)(ctx->arg, ctx->debuglist);
1028 #endif /* ISC_MEM_TRACKLINES */
1029                 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1030                         DESTROYLOCK(&ctx->lock);
1031                 (memfree)(arg, ctx);
1032         }
1033
1034         return (result);
1035 }
1036
1037 ISC_MEMFUNC_SCOPE isc_result_t
1038 isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) {
1039         return (isc__mem_createx2(init_max_size, target_size,
1040                                   default_memalloc, default_memfree, NULL,
1041                                   ctxp, ISC_MEMFLAG_DEFAULT));
1042 }
1043
1044 ISC_MEMFUNC_SCOPE isc_result_t
1045 isc__mem_create2(size_t init_max_size, size_t target_size,
1046                  isc_mem_t **ctxp, unsigned int flags)
1047 {
1048         return (isc__mem_createx2(init_max_size, target_size,
1049                                   default_memalloc, default_memfree, NULL,
1050                                   ctxp, flags));
1051 }
1052
1053 static void
1054 destroy(isc__mem_t *ctx) {
1055         unsigned int i;
1056         isc_ondestroy_t ondest;
1057
1058         LOCK(&lock);
1059         ISC_LIST_UNLINK(contexts, ctx, link);
1060         totallost += ctx->inuse;
1061         UNLOCK(&lock);
1062
1063         ctx->common.impmagic = 0;
1064         ctx->common.magic = 0;
1065
1066         INSIST(ISC_LIST_EMPTY(ctx->pools));
1067
1068 #if ISC_MEM_TRACKLINES
1069         if (ctx->debuglist != NULL) {
1070                 if (ctx->checkfree) {
1071                         for (i = 0; i <= ctx->max_size; i++) {
1072                                 if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
1073                                         print_active(ctx, stderr);
1074                                 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
1075                         }
1076                 } else {
1077                         debuglink_t *dl;
1078
1079                         for (i = 0; i <= ctx->max_size; i++)
1080                                 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
1081                                      dl != NULL;
1082                                      dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
1083                                         ISC_LIST_UNLINK(ctx->debuglist[i],
1084                                                         dl, link);
1085                                         free(dl);
1086                                 }
1087                 }
1088                 (ctx->memfree)(ctx->arg, ctx->debuglist);
1089         }
1090 #endif
1091         INSIST(ctx->references == 0);
1092
1093         if (ctx->checkfree) {
1094                 for (i = 0; i <= ctx->max_size; i++) {
1095 #if ISC_MEM_TRACKLINES
1096                         if (ctx->stats[i].gets != 0U)
1097                                 print_active(ctx, stderr);
1098 #endif
1099                         INSIST(ctx->stats[i].gets == 0U);
1100                 }
1101         }
1102
1103         (ctx->memfree)(ctx->arg, ctx->stats);
1104
1105         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1106                 for (i = 0; i < ctx->basic_table_count; i++)
1107                         (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
1108                 (ctx->memfree)(ctx->arg, ctx->freelists);
1109                 if (ctx->basic_table != NULL)
1110                         (ctx->memfree)(ctx->arg, ctx->basic_table);
1111         }
1112
1113         ondest = ctx->ondestroy;
1114
1115         if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1116                 DESTROYLOCK(&ctx->lock);
1117         (ctx->memfree)(ctx->arg, ctx);
1118
1119         isc_ondestroy_notify(&ondest, ctx);
1120 }
1121
1122 ISC_MEMFUNC_SCOPE void
1123 isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) {
1124         isc__mem_t *source = (isc__mem_t *)source0;
1125
1126         REQUIRE(VALID_CONTEXT(source));
1127         REQUIRE(targetp != NULL && *targetp == NULL);
1128
1129         MCTXLOCK(source, &source->lock);
1130         source->references++;
1131         MCTXUNLOCK(source, &source->lock);
1132
1133         *targetp = (isc_mem_t *)source;
1134 }
1135
1136 ISC_MEMFUNC_SCOPE void
1137 isc__mem_detach(isc_mem_t **ctxp) {
1138         isc__mem_t *ctx;
1139         isc_boolean_t want_destroy = ISC_FALSE;
1140
1141         REQUIRE(ctxp != NULL);
1142         ctx = (isc__mem_t *)*ctxp;
1143         REQUIRE(VALID_CONTEXT(ctx));
1144
1145         MCTXLOCK(ctx, &ctx->lock);
1146         INSIST(ctx->references > 0);
1147         ctx->references--;
1148         if (ctx->references == 0)
1149                 want_destroy = ISC_TRUE;
1150         MCTXUNLOCK(ctx, &ctx->lock);
1151
1152         if (want_destroy)
1153                 destroy(ctx);
1154
1155         *ctxp = NULL;
1156 }
1157
1158 /*
1159  * isc_mem_putanddetach() is the equivalent of:
1160  *
1161  * mctx = NULL;
1162  * isc_mem_attach(ptr->mctx, &mctx);
1163  * isc_mem_detach(&ptr->mctx);
1164  * isc_mem_put(mctx, ptr, sizeof(*ptr);
1165  * isc_mem_detach(&mctx);
1166  */
1167
1168 ISC_MEMFUNC_SCOPE void
1169 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
1170         isc__mem_t *ctx;
1171         isc_boolean_t want_destroy = ISC_FALSE;
1172         size_info *si;
1173         size_t oldsize;
1174
1175         REQUIRE(ctxp != NULL);
1176         ctx = (isc__mem_t *)*ctxp;
1177         REQUIRE(VALID_CONTEXT(ctx));
1178         REQUIRE(ptr != NULL);
1179
1180         /*
1181          * Must be before mem_putunlocked() as ctxp is usually within
1182          * [ptr..ptr+size).
1183          */
1184         *ctxp = NULL;
1185
1186         if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1187                 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1188                         si = &(((size_info *)ptr)[-1]);
1189                         oldsize = si->u.size - ALIGNMENT_SIZE;
1190                         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1191                                 oldsize -= ALIGNMENT_SIZE;
1192                         INSIST(oldsize == size);
1193                 }
1194                 isc_mem_free((isc_mem_t *)ctx, ptr);
1195
1196                 MCTXLOCK(ctx, &ctx->lock);
1197                 ctx->references--;
1198                 if (ctx->references == 0)
1199                         want_destroy = ISC_TRUE;
1200                 MCTXUNLOCK(ctx, &ctx->lock);
1201                 if (want_destroy)
1202                         destroy(ctx);
1203
1204                 return;
1205         }
1206
1207         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1208                 MCTXLOCK(ctx, &ctx->lock);
1209                 mem_putunlocked(ctx, ptr, size);
1210         } else {
1211                 mem_put(ctx, ptr, size);
1212                 MCTXLOCK(ctx, &ctx->lock);
1213                 mem_putstats(ctx, ptr, size);
1214         }
1215
1216         DELETE_TRACE(ctx, ptr, size, file, line);
1217         INSIST(ctx->references > 0);
1218         ctx->references--;
1219         if (ctx->references == 0)
1220                 want_destroy = ISC_TRUE;
1221
1222         MCTXUNLOCK(ctx, &ctx->lock);
1223
1224         if (want_destroy)
1225                 destroy(ctx);
1226 }
1227
1228 ISC_MEMFUNC_SCOPE void
1229 isc__mem_destroy(isc_mem_t **ctxp) {
1230         isc__mem_t *ctx;
1231
1232         /*
1233          * This routine provides legacy support for callers who use mctxs
1234          * without attaching/detaching.
1235          */
1236
1237         REQUIRE(ctxp != NULL);
1238         ctx = (isc__mem_t *)*ctxp;
1239         REQUIRE(VALID_CONTEXT(ctx));
1240
1241         MCTXLOCK(ctx, &ctx->lock);
1242 #if ISC_MEM_TRACKLINES
1243         if (ctx->references != 1)
1244                 print_active(ctx, stderr);
1245 #endif
1246         REQUIRE(ctx->references == 1);
1247         ctx->references--;
1248         MCTXUNLOCK(ctx, &ctx->lock);
1249
1250         destroy(ctx);
1251
1252         *ctxp = NULL;
1253 }
1254
1255 ISC_MEMFUNC_SCOPE isc_result_t
1256 isc__mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) {
1257         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1258         isc_result_t res;
1259
1260         MCTXLOCK(ctx, &ctx->lock);
1261         res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1262         MCTXUNLOCK(ctx, &ctx->lock);
1263
1264         return (res);
1265 }
1266
1267 ISC_MEMFUNC_SCOPE void *
1268 isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
1269         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1270         void *ptr;
1271         isc_boolean_t call_water = ISC_FALSE;
1272
1273         REQUIRE(VALID_CONTEXT(ctx));
1274
1275         if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1276                 return (isc__mem_allocate(ctx0, size FLARG_PASS));
1277
1278         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1279                 MCTXLOCK(ctx, &ctx->lock);
1280                 ptr = mem_getunlocked(ctx, size);
1281         } else {
1282                 ptr = mem_get(ctx, size);
1283                 MCTXLOCK(ctx, &ctx->lock);
1284                 if (ptr != NULL)
1285                         mem_getstats(ctx, size);
1286         }
1287
1288         ADD_TRACE(ctx, ptr, size, file, line);
1289         if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1290             !ctx->is_overmem) {
1291                 ctx->is_overmem = ISC_TRUE;
1292         }
1293         if (ctx->hi_water != 0U && !ctx->hi_called &&
1294             ctx->inuse > ctx->hi_water) {
1295                 call_water = ISC_TRUE;
1296         }
1297         if (ctx->inuse > ctx->maxinuse) {
1298                 ctx->maxinuse = ctx->inuse;
1299                 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1300                     (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1301                         fprintf(stderr, "maxinuse = %lu\n",
1302                                 (unsigned long)ctx->inuse);
1303         }
1304         MCTXUNLOCK(ctx, &ctx->lock);
1305
1306         if (call_water)
1307                 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1308
1309         return (ptr);
1310 }
1311
1312 ISC_MEMFUNC_SCOPE void
1313 isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1314         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1315         isc_boolean_t call_water = ISC_FALSE;
1316         size_info *si;
1317         size_t oldsize;
1318
1319         REQUIRE(VALID_CONTEXT(ctx));
1320         REQUIRE(ptr != NULL);
1321
1322         if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1323                 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1324                         si = &(((size_info *)ptr)[-1]);
1325                         oldsize = si->u.size - ALIGNMENT_SIZE;
1326                         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1327                                 oldsize -= ALIGNMENT_SIZE;
1328                         INSIST(oldsize == size);
1329                 }
1330                 isc_mem_free((isc_mem_t *)ctx, ptr);
1331                 return;
1332         }
1333
1334         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1335                 MCTXLOCK(ctx, &ctx->lock);
1336                 mem_putunlocked(ctx, ptr, size);
1337         } else {
1338                 mem_put(ctx, ptr, size);
1339                 MCTXLOCK(ctx, &ctx->lock);
1340                 mem_putstats(ctx, ptr, size);
1341         }
1342
1343         DELETE_TRACE(ctx, ptr, size, file, line);
1344
1345         /*
1346          * The check against ctx->lo_water == 0 is for the condition
1347          * when the context was pushed over hi_water but then had
1348          * isc_mem_setwater() called with 0 for hi_water and lo_water.
1349          */
1350         if (ctx->is_overmem &&
1351             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1352                 ctx->is_overmem = ISC_FALSE;
1353         }
1354         if (ctx->hi_called &&
1355             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1356                 if (ctx->water != NULL)
1357                         call_water = ISC_TRUE;
1358         }
1359         MCTXUNLOCK(ctx, &ctx->lock);
1360
1361         if (call_water)
1362                 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1363 }
1364
1365 ISC_MEMFUNC_SCOPE void
1366 isc__mem_waterack(isc_mem_t *ctx0, int flag) {
1367         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1368
1369         REQUIRE(VALID_CONTEXT(ctx));
1370
1371         MCTXLOCK(ctx, &ctx->lock);
1372         if (flag == ISC_MEM_LOWATER)
1373                 ctx->hi_called = ISC_FALSE;
1374         else if (flag == ISC_MEM_HIWATER)
1375                 ctx->hi_called = ISC_TRUE;
1376         MCTXUNLOCK(ctx, &ctx->lock);
1377 }
1378
1379 #if ISC_MEM_TRACKLINES
1380 static void
1381 print_active(isc__mem_t *mctx, FILE *out) {
1382         if (mctx->debuglist != NULL) {
1383                 debuglink_t *dl;
1384                 unsigned int i, j;
1385                 const char *format;
1386                 isc_boolean_t found;
1387
1388                 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1389                                             ISC_MSG_DUMPALLOC,
1390                                             "Dump of all outstanding "
1391                                             "memory allocations:\n"));
1392                 found = ISC_FALSE;
1393                 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1394                                         ISC_MSG_PTRFILELINE,
1395                                         "\tptr %p size %u file %s line %u\n");
1396                 for (i = 0; i <= mctx->max_size; i++) {
1397                         dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1398
1399                         if (dl != NULL)
1400                                 found = ISC_TRUE;
1401
1402                         while (dl != NULL) {
1403                                 for (j = 0; j < DEBUGLIST_COUNT; j++)
1404                                         if (dl->ptr[j] != NULL)
1405                                                 fprintf(out, format,
1406                                                         dl->ptr[j],
1407                                                         dl->size[j],
1408                                                         dl->file[j],
1409                                                         dl->line[j]);
1410                                 dl = ISC_LIST_NEXT(dl, link);
1411                         }
1412                 }
1413                 if (!found)
1414                         fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1415                                                     ISC_MSG_NONE, "\tNone.\n"));
1416         }
1417 }
1418 #endif
1419
1420 /*
1421  * Print the stats[] on the stream "out" with suitable formatting.
1422  */
1423 ISC_MEMFUNC_SCOPE void
1424 isc__mem_stats(isc_mem_t *ctx0, FILE *out) {
1425         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1426         size_t i;
1427         const struct stats *s;
1428         const isc__mempool_t *pool;
1429
1430         REQUIRE(VALID_CONTEXT(ctx));
1431         MCTXLOCK(ctx, &ctx->lock);
1432
1433         for (i = 0; i <= ctx->max_size; i++) {
1434                 s = &ctx->stats[i];
1435
1436                 if (s->totalgets == 0U && s->gets == 0U)
1437                         continue;
1438                 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1439                         (i == ctx->max_size) ? ">=" : "  ",
1440                         (unsigned long) i, s->totalgets, s->gets);
1441                 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1442                     (s->blocks != 0U || s->freefrags != 0U))
1443                         fprintf(out, " (%lu bl, %lu ff)",
1444                                 s->blocks, s->freefrags);
1445                 fputc('\n', out);
1446         }
1447
1448         /*
1449          * Note that since a pool can be locked now, these stats might be
1450          * somewhat off if the pool is in active use at the time the stats
1451          * are dumped.  The link fields are protected by the isc_mem_t's
1452          * lock, however, so walking this list and extracting integers from
1453          * stats fields is always safe.
1454          */
1455         pool = ISC_LIST_HEAD(ctx->pools);
1456         if (pool != NULL) {
1457                 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1458                                             ISC_MSG_POOLSTATS,
1459                                             "[Pool statistics]\n"));
1460                 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1461                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1462                                        ISC_MSG_POOLNAME, "name"),
1463                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1464                                        ISC_MSG_POOLSIZE, "size"),
1465                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1466                                        ISC_MSG_POOLMAXALLOC, "maxalloc"),
1467                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1468                                        ISC_MSG_POOLALLOCATED, "allocated"),
1469                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1470                                        ISC_MSG_POOLFREECOUNT, "freecount"),
1471                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1472                                        ISC_MSG_POOLFREEMAX, "freemax"),
1473                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1474                                        ISC_MSG_POOLFILLCOUNT, "fillcount"),
1475                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1476                                        ISC_MSG_POOLGETS, "gets"),
1477                         "L");
1478         }
1479         while (pool != NULL) {
1480                 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1481                         pool->name, (unsigned long) pool->size, pool->maxalloc,
1482                         pool->allocated, pool->freecount, pool->freemax,
1483                         pool->fillcount, pool->gets,
1484                         (pool->lock == NULL ? "N" : "Y"));
1485                 pool = ISC_LIST_NEXT(pool, link);
1486         }
1487
1488 #if ISC_MEM_TRACKLINES
1489         print_active(ctx, out);
1490 #endif
1491
1492         MCTXUNLOCK(ctx, &ctx->lock);
1493 }
1494
1495 /*
1496  * Replacements for malloc() and free() -- they implicitly remember the
1497  * size of the object allocated (with some additional overhead).
1498  */
1499
1500 static void *
1501 isc__mem_allocateunlocked(isc_mem_t *ctx0, size_t size) {
1502         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1503         size_info *si;
1504
1505         size += ALIGNMENT_SIZE;
1506         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1507                 size += ALIGNMENT_SIZE;
1508
1509         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1510                 si = mem_getunlocked(ctx, size);
1511         else
1512                 si = mem_get(ctx, size);
1513
1514         if (si == NULL)
1515                 return (NULL);
1516         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1517                 si->u.ctx = ctx;
1518                 si++;
1519         }
1520         si->u.size = size;
1521         return (&si[1]);
1522 }
1523
1524 ISC_MEMFUNC_SCOPE void *
1525 isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
1526         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1527         size_info *si;
1528         isc_boolean_t call_water = ISC_FALSE;
1529
1530         REQUIRE(VALID_CONTEXT(ctx));
1531
1532         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1533                 MCTXLOCK(ctx, &ctx->lock);
1534                 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size);
1535         } else {
1536                 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size);
1537                 MCTXLOCK(ctx, &ctx->lock);
1538                 if (si != NULL)
1539                         mem_getstats(ctx, si[-1].u.size);
1540         }
1541
1542 #if ISC_MEM_TRACKLINES
1543         ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1544 #endif
1545         if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1546             !ctx->is_overmem) {
1547                 ctx->is_overmem = ISC_TRUE;
1548         }
1549
1550         if (ctx->hi_water != 0U && !ctx->hi_called &&
1551             ctx->inuse > ctx->hi_water) {
1552                 ctx->hi_called = ISC_TRUE;
1553                 call_water = ISC_TRUE;
1554         }
1555         if (ctx->inuse > ctx->maxinuse) {
1556                 ctx->maxinuse = ctx->inuse;
1557                 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1558                     (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1559                         fprintf(stderr, "maxinuse = %lu\n",
1560                                 (unsigned long)ctx->inuse);
1561         }
1562         MCTXUNLOCK(ctx, &ctx->lock);
1563
1564         if (call_water)
1565                 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1566
1567         return (si);
1568 }
1569
1570 ISC_MEMFUNC_SCOPE void *
1571 isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1572         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1573         void *new_ptr = NULL;
1574         size_t oldsize, copysize;
1575
1576         REQUIRE(VALID_CONTEXT(ctx));
1577
1578         /*
1579          * This function emulates the realloc(3) standard library function:
1580          * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1581          *   as much of the old contents to the new buffer and free the old one.
1582          *   Note that when allocation fails the original pointer is intact;
1583          *   the caller must free it.
1584          * - if size is 0 and ptr is non NULL, simply free the given ptr.
1585          * - this function returns:
1586          *     pointer to the newly allocated memory, or
1587          *     NULL if allocation fails or doesn't happen.
1588          */
1589         if (size > 0U) {
1590                 new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS);
1591                 if (new_ptr != NULL && ptr != NULL) {
1592                         oldsize = (((size_info *)ptr)[-1]).u.size;
1593                         INSIST(oldsize >= ALIGNMENT_SIZE);
1594                         oldsize -= ALIGNMENT_SIZE;
1595                         copysize = oldsize > size ? size : oldsize;
1596                         memcpy(new_ptr, ptr, copysize);
1597                         isc__mem_free(ctx0, ptr FLARG_PASS);
1598                 }
1599         } else if (ptr != NULL)
1600                 isc__mem_free(ctx0, ptr FLARG_PASS);
1601
1602         return (new_ptr);
1603 }
1604
1605 ISC_MEMFUNC_SCOPE void
1606 isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
1607         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1608         size_info *si;
1609         size_t size;
1610         isc_boolean_t call_water= ISC_FALSE;
1611
1612         REQUIRE(VALID_CONTEXT(ctx));
1613         REQUIRE(ptr != NULL);
1614
1615         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1616                 si = &(((size_info *)ptr)[-2]);
1617                 REQUIRE(si->u.ctx == ctx);
1618                 size = si[1].u.size;
1619         } else {
1620                 si = &(((size_info *)ptr)[-1]);
1621                 size = si->u.size;
1622         }
1623
1624         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1625                 MCTXLOCK(ctx, &ctx->lock);
1626                 mem_putunlocked(ctx, si, size);
1627         } else {
1628                 mem_put(ctx, si, size);
1629                 MCTXLOCK(ctx, &ctx->lock);
1630                 mem_putstats(ctx, si, size);
1631         }
1632
1633         DELETE_TRACE(ctx, ptr, size, file, line);
1634
1635         /*
1636          * The check against ctx->lo_water == 0 is for the condition
1637          * when the context was pushed over hi_water but then had
1638          * isc_mem_setwater() called with 0 for hi_water and lo_water.
1639          */
1640         if (ctx->is_overmem &&
1641             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1642                 ctx->is_overmem = ISC_FALSE;
1643         }
1644
1645         if (ctx->hi_called &&
1646             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1647                 ctx->hi_called = ISC_FALSE;
1648
1649                 if (ctx->water != NULL)
1650                         call_water = ISC_TRUE;
1651         }
1652         MCTXUNLOCK(ctx, &ctx->lock);
1653
1654         if (call_water)
1655                 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1656 }
1657
1658
1659 /*
1660  * Other useful things.
1661  */
1662
1663 ISC_MEMFUNC_SCOPE char *
1664 isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
1665         isc__mem_t *mctx = (isc__mem_t *)mctx0;
1666         size_t len;
1667         char *ns;
1668
1669         REQUIRE(VALID_CONTEXT(mctx));
1670         REQUIRE(s != NULL);
1671
1672         len = strlen(s);
1673
1674         ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS);
1675
1676         if (ns != NULL)
1677                 strncpy(ns, s, len + 1);
1678
1679         return (ns);
1680 }
1681
1682 ISC_MEMFUNC_SCOPE void
1683 isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) {
1684         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1685
1686         REQUIRE(VALID_CONTEXT(ctx));
1687         MCTXLOCK(ctx, &ctx->lock);
1688
1689         ctx->checkfree = flag;
1690
1691         MCTXUNLOCK(ctx, &ctx->lock);
1692 }
1693
1694 /*
1695  * Quotas
1696  */
1697
1698 ISC_MEMFUNC_SCOPE void
1699 isc__mem_setquota(isc_mem_t *ctx0, size_t quota) {
1700         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1701
1702         REQUIRE(VALID_CONTEXT(ctx));
1703         MCTXLOCK(ctx, &ctx->lock);
1704
1705         ctx->quota = quota;
1706
1707         MCTXUNLOCK(ctx, &ctx->lock);
1708 }
1709
1710 ISC_MEMFUNC_SCOPE size_t
1711 isc__mem_getquota(isc_mem_t *ctx0) {
1712         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1713         size_t quota;
1714
1715         REQUIRE(VALID_CONTEXT(ctx));
1716         MCTXLOCK(ctx, &ctx->lock);
1717
1718         quota = ctx->quota;
1719
1720         MCTXUNLOCK(ctx, &ctx->lock);
1721
1722         return (quota);
1723 }
1724
1725 ISC_MEMFUNC_SCOPE size_t
1726 isc__mem_inuse(isc_mem_t *ctx0) {
1727         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1728         size_t inuse;
1729
1730         REQUIRE(VALID_CONTEXT(ctx));
1731         MCTXLOCK(ctx, &ctx->lock);
1732
1733         inuse = ctx->inuse;
1734
1735         MCTXUNLOCK(ctx, &ctx->lock);
1736
1737         return (inuse);
1738 }
1739
1740 ISC_MEMFUNC_SCOPE void
1741 isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg,
1742                  size_t hiwater, size_t lowater)
1743 {
1744         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1745         isc_boolean_t callwater = ISC_FALSE;
1746         isc_mem_water_t oldwater;
1747         void *oldwater_arg;
1748
1749         REQUIRE(VALID_CONTEXT(ctx));
1750         REQUIRE(hiwater >= lowater);
1751
1752         MCTXLOCK(ctx, &ctx->lock);
1753         oldwater = ctx->water;
1754         oldwater_arg = ctx->water_arg;
1755         if (water == NULL) {
1756                 callwater = ctx->hi_called;
1757                 ctx->water = NULL;
1758                 ctx->water_arg = NULL;
1759                 ctx->hi_water = 0;
1760                 ctx->lo_water = 0;
1761                 ctx->hi_called = ISC_FALSE;
1762         } else {
1763                 if (ctx->hi_called &&
1764                     (ctx->water != water || ctx->water_arg != water_arg ||
1765                      ctx->inuse < lowater || lowater == 0U))
1766                         callwater = ISC_TRUE;
1767                 ctx->water = water;
1768                 ctx->water_arg = water_arg;
1769                 ctx->hi_water = hiwater;
1770                 ctx->lo_water = lowater;
1771                 ctx->hi_called = ISC_FALSE;
1772         }
1773         MCTXUNLOCK(ctx, &ctx->lock);
1774
1775         if (callwater && oldwater != NULL)
1776                 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1777 }
1778
1779 ISC_MEMFUNC_SCOPE isc_boolean_t
1780 isc__mem_isovermem(isc_mem_t *ctx0) {
1781         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1782
1783         REQUIRE(VALID_CONTEXT(ctx));
1784
1785         /*
1786          * We don't bother to lock the context because 100% accuracy isn't
1787          * necessary (and even if we locked the context the returned value
1788          * could be different from the actual state when it's used anyway)
1789          */
1790         return (ctx->is_overmem);
1791 }
1792
1793 ISC_MEMFUNC_SCOPE void
1794 isc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) {
1795         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1796
1797         REQUIRE(VALID_CONTEXT(ctx));
1798
1799         LOCK(&ctx->lock);
1800         memset(ctx->name, 0, sizeof(ctx->name));
1801         strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1802         ctx->tag = tag;
1803         UNLOCK(&ctx->lock);
1804 }
1805
1806 ISC_MEMFUNC_SCOPE const char *
1807 isc__mem_getname(isc_mem_t *ctx0) {
1808         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1809
1810         REQUIRE(VALID_CONTEXT(ctx));
1811
1812         return (ctx->name);
1813 }
1814
1815 ISC_MEMFUNC_SCOPE void *
1816 isc__mem_gettag(isc_mem_t *ctx0) {
1817         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1818
1819         REQUIRE(VALID_CONTEXT(ctx));
1820
1821         return (ctx->tag);
1822 }
1823
1824 /*
1825  * Memory pool stuff
1826  */
1827
1828 ISC_MEMFUNC_SCOPE isc_result_t
1829 isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
1830         isc__mem_t *mctx = (isc__mem_t *)mctx0;
1831         isc__mempool_t *mpctx;
1832
1833         REQUIRE(VALID_CONTEXT(mctx));
1834         REQUIRE(size > 0U);
1835         REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1836
1837         /*
1838          * Allocate space for this pool, initialize values, and if all works
1839          * well, attach to the memory context.
1840          */
1841         mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t));
1842         if (mpctx == NULL)
1843                 return (ISC_R_NOMEMORY);
1844
1845         mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods;
1846         mpctx->common.impmagic = MEMPOOL_MAGIC;
1847         mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
1848         mpctx->lock = NULL;
1849         mpctx->mctx = mctx;
1850         mpctx->size = size;
1851         mpctx->maxalloc = UINT_MAX;
1852         mpctx->allocated = 0;
1853         mpctx->freecount = 0;
1854         mpctx->freemax = 1;
1855         mpctx->fillcount = 1;
1856         mpctx->gets = 0;
1857 #if ISC_MEMPOOL_NAMES
1858         mpctx->name[0] = 0;
1859 #endif
1860         mpctx->items = NULL;
1861
1862         *mpctxp = (isc_mempool_t *)mpctx;
1863
1864         MCTXLOCK(mctx, &mctx->lock);
1865         ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1866         mctx->poolcnt++;
1867         MCTXUNLOCK(mctx, &mctx->lock);
1868
1869         return (ISC_R_SUCCESS);
1870 }
1871
1872 ISC_MEMFUNC_SCOPE void
1873 isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) {
1874         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1875
1876         REQUIRE(name != NULL);
1877         REQUIRE(VALID_MEMPOOL(mpctx));
1878
1879 #if ISC_MEMPOOL_NAMES
1880         if (mpctx->lock != NULL)
1881                 LOCK(mpctx->lock);
1882
1883         strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1884         mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1885
1886         if (mpctx->lock != NULL)
1887                 UNLOCK(mpctx->lock);
1888 #else
1889         UNUSED(mpctx);
1890         UNUSED(name);
1891 #endif
1892 }
1893
1894 ISC_MEMFUNC_SCOPE void
1895 isc__mempool_destroy(isc_mempool_t **mpctxp) {
1896         isc__mempool_t *mpctx;
1897         isc__mem_t *mctx;
1898         isc_mutex_t *lock;
1899         element *item;
1900
1901         REQUIRE(mpctxp != NULL);
1902         mpctx = (isc__mempool_t *)*mpctxp;
1903         REQUIRE(VALID_MEMPOOL(mpctx));
1904 #if ISC_MEMPOOL_NAMES
1905         if (mpctx->allocated > 0)
1906                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1907                                  "isc__mempool_destroy(): mempool %s "
1908                                  "leaked memory",
1909                                  mpctx->name);
1910 #endif
1911         REQUIRE(mpctx->allocated == 0);
1912
1913         mctx = mpctx->mctx;
1914
1915         lock = mpctx->lock;
1916
1917         if (lock != NULL)
1918                 LOCK(lock);
1919
1920         /*
1921          * Return any items on the free list
1922          */
1923         MCTXLOCK(mctx, &mctx->lock);
1924         while (mpctx->items != NULL) {
1925                 INSIST(mpctx->freecount > 0);
1926                 mpctx->freecount--;
1927                 item = mpctx->items;
1928                 mpctx->items = item->next;
1929
1930                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1931                         mem_putunlocked(mctx, item, mpctx->size);
1932                 } else {
1933                         mem_put(mctx, item, mpctx->size);
1934                         mem_putstats(mctx, item, mpctx->size);
1935                 }
1936         }
1937         MCTXUNLOCK(mctx, &mctx->lock);
1938
1939         /*
1940          * Remove our linked list entry from the memory context.
1941          */
1942         MCTXLOCK(mctx, &mctx->lock);
1943         ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1944         mctx->poolcnt--;
1945         MCTXUNLOCK(mctx, &mctx->lock);
1946
1947         mpctx->common.impmagic = 0;
1948         mpctx->common.magic = 0;
1949
1950         isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t));
1951
1952         if (lock != NULL)
1953                 UNLOCK(lock);
1954
1955         *mpctxp = NULL;
1956 }
1957
1958 ISC_MEMFUNC_SCOPE void
1959 isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) {
1960         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1961
1962         REQUIRE(VALID_MEMPOOL(mpctx));
1963         REQUIRE(mpctx->lock == NULL);
1964         REQUIRE(lock != NULL);
1965
1966         mpctx->lock = lock;
1967 }
1968
1969 ISC_MEMFUNC_SCOPE void *
1970 isc___mempool_get(isc_mempool_t *mpctx0 FLARG) {
1971         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1972         element *item;
1973         isc__mem_t *mctx;
1974         unsigned int i;
1975
1976         REQUIRE(VALID_MEMPOOL(mpctx));
1977
1978         mctx = mpctx->mctx;
1979
1980         if (mpctx->lock != NULL)
1981                 LOCK(mpctx->lock);
1982
1983         /*
1984          * Don't let the caller go over quota
1985          */
1986         if (mpctx->allocated >= mpctx->maxalloc) {
1987                 item = NULL;
1988                 goto out;
1989         }
1990
1991         /*
1992          * if we have a free list item, return the first here
1993          */
1994         item = mpctx->items;
1995         if (item != NULL) {
1996                 mpctx->items = item->next;
1997                 INSIST(mpctx->freecount > 0);
1998                 mpctx->freecount--;
1999                 mpctx->gets++;
2000                 mpctx->allocated++;
2001                 goto out;
2002         }
2003
2004         /*
2005          * We need to dip into the well.  Lock the memory context here and
2006          * fill up our free list.
2007          */
2008         MCTXLOCK(mctx, &mctx->lock);
2009         for (i = 0; i < mpctx->fillcount; i++) {
2010                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2011                         item = mem_getunlocked(mctx, mpctx->size);
2012                 } else {
2013                         item = mem_get(mctx, mpctx->size);
2014                         if (item != NULL)
2015                                 mem_getstats(mctx, mpctx->size);
2016                 }
2017                 if (item == NULL)
2018                         break;
2019                 item->next = mpctx->items;
2020                 mpctx->items = item;
2021                 mpctx->freecount++;
2022         }
2023         MCTXUNLOCK(mctx, &mctx->lock);
2024
2025         /*
2026          * If we didn't get any items, return NULL.
2027          */
2028         item = mpctx->items;
2029         if (item == NULL)
2030                 goto out;
2031
2032         mpctx->items = item->next;
2033         mpctx->freecount--;
2034         mpctx->gets++;
2035         mpctx->allocated++;
2036
2037  out:
2038         if (mpctx->lock != NULL)
2039                 UNLOCK(mpctx->lock);
2040
2041 #if ISC_MEM_TRACKLINES
2042         if (item != NULL) {
2043                 MCTXLOCK(mctx, &mctx->lock);
2044                 ADD_TRACE(mctx, item, mpctx->size, file, line);
2045                 MCTXUNLOCK(mctx, &mctx->lock);
2046         }
2047 #endif /* ISC_MEM_TRACKLINES */
2048
2049         return (item);
2050 }
2051
2052 ISC_MEMFUNC_SCOPE void
2053 isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
2054         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2055         isc__mem_t *mctx;
2056         element *item;
2057
2058         REQUIRE(VALID_MEMPOOL(mpctx));
2059         REQUIRE(mem != NULL);
2060
2061         mctx = mpctx->mctx;
2062
2063         if (mpctx->lock != NULL)
2064                 LOCK(mpctx->lock);
2065
2066         INSIST(mpctx->allocated > 0);
2067         mpctx->allocated--;
2068
2069 #if ISC_MEM_TRACKLINES
2070         MCTXLOCK(mctx, &mctx->lock);
2071         DELETE_TRACE(mctx, mem, mpctx->size, file, line);
2072         MCTXUNLOCK(mctx, &mctx->lock);
2073 #endif /* ISC_MEM_TRACKLINES */
2074
2075         /*
2076          * If our free list is full, return this to the mctx directly.
2077          */
2078         if (mpctx->freecount >= mpctx->freemax) {
2079                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2080                         MCTXLOCK(mctx, &mctx->lock);
2081                         mem_putunlocked(mctx, mem, mpctx->size);
2082                         MCTXUNLOCK(mctx, &mctx->lock);
2083                 } else {
2084                         mem_put(mctx, mem, mpctx->size);
2085                         MCTXLOCK(mctx, &mctx->lock);
2086                         mem_putstats(mctx, mem, mpctx->size);
2087                         MCTXUNLOCK(mctx, &mctx->lock);
2088                 }
2089                 if (mpctx->lock != NULL)
2090                         UNLOCK(mpctx->lock);
2091                 return;
2092         }
2093
2094         /*
2095          * Otherwise, attach it to our free list and bump the counter.
2096          */
2097         mpctx->freecount++;
2098         item = (element *)mem;
2099         item->next = mpctx->items;
2100         mpctx->items = item;
2101
2102         if (mpctx->lock != NULL)
2103                 UNLOCK(mpctx->lock);
2104 }
2105
2106 /*
2107  * Quotas
2108  */
2109
2110 ISC_MEMFUNC_SCOPE void
2111 isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) {
2112         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2113
2114         REQUIRE(VALID_MEMPOOL(mpctx));
2115
2116         if (mpctx->lock != NULL)
2117                 LOCK(mpctx->lock);
2118
2119         mpctx->freemax = limit;
2120
2121         if (mpctx->lock != NULL)
2122                 UNLOCK(mpctx->lock);
2123 }
2124
2125 ISC_MEMFUNC_SCOPE unsigned int
2126 isc__mempool_getfreemax(isc_mempool_t *mpctx0) {
2127         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2128         unsigned int freemax;
2129
2130         REQUIRE(VALID_MEMPOOL(mpctx));
2131
2132         if (mpctx->lock != NULL)
2133                 LOCK(mpctx->lock);
2134
2135         freemax = mpctx->freemax;
2136
2137         if (mpctx->lock != NULL)
2138                 UNLOCK(mpctx->lock);
2139
2140         return (freemax);
2141 }
2142
2143 ISC_MEMFUNC_SCOPE unsigned int
2144 isc__mempool_getfreecount(isc_mempool_t *mpctx0) {
2145         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2146         unsigned int freecount;
2147
2148         REQUIRE(VALID_MEMPOOL(mpctx));
2149
2150         if (mpctx->lock != NULL)
2151                 LOCK(mpctx->lock);
2152
2153         freecount = mpctx->freecount;
2154
2155         if (mpctx->lock != NULL)
2156                 UNLOCK(mpctx->lock);
2157
2158         return (freecount);
2159 }
2160
2161 ISC_MEMFUNC_SCOPE void
2162 isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
2163         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2164
2165         REQUIRE(limit > 0);
2166
2167         REQUIRE(VALID_MEMPOOL(mpctx));
2168
2169         if (mpctx->lock != NULL)
2170                 LOCK(mpctx->lock);
2171
2172         mpctx->maxalloc = limit;
2173
2174         if (mpctx->lock != NULL)
2175                 UNLOCK(mpctx->lock);
2176 }
2177
2178 ISC_MEMFUNC_SCOPE unsigned int
2179 isc__mempool_getmaxalloc(isc_mempool_t *mpctx0) {
2180         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2181         unsigned int maxalloc;
2182
2183         REQUIRE(VALID_MEMPOOL(mpctx));
2184
2185         if (mpctx->lock != NULL)
2186                 LOCK(mpctx->lock);
2187
2188         maxalloc = mpctx->maxalloc;
2189
2190         if (mpctx->lock != NULL)
2191                 UNLOCK(mpctx->lock);
2192
2193         return (maxalloc);
2194 }
2195
2196 ISC_MEMFUNC_SCOPE unsigned int
2197 isc__mempool_getallocated(isc_mempool_t *mpctx0) {
2198         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2199         unsigned int allocated;
2200
2201         REQUIRE(VALID_MEMPOOL(mpctx));
2202
2203         if (mpctx->lock != NULL)
2204                 LOCK(mpctx->lock);
2205
2206         allocated = mpctx->allocated;
2207
2208         if (mpctx->lock != NULL)
2209                 UNLOCK(mpctx->lock);
2210
2211         return (allocated);
2212 }
2213
2214 ISC_MEMFUNC_SCOPE void
2215 isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
2216         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2217
2218         REQUIRE(limit > 0);
2219         REQUIRE(VALID_MEMPOOL(mpctx));
2220
2221         if (mpctx->lock != NULL)
2222                 LOCK(mpctx->lock);
2223
2224         mpctx->fillcount = limit;
2225
2226         if (mpctx->lock != NULL)
2227                 UNLOCK(mpctx->lock);
2228 }
2229
2230 ISC_MEMFUNC_SCOPE unsigned int
2231 isc__mempool_getfillcount(isc_mempool_t *mpctx0) {
2232         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2233
2234         unsigned int fillcount;
2235
2236         REQUIRE(VALID_MEMPOOL(mpctx));
2237
2238         if (mpctx->lock != NULL)
2239                 LOCK(mpctx->lock);
2240
2241         fillcount = mpctx->fillcount;
2242
2243         if (mpctx->lock != NULL)
2244                 UNLOCK(mpctx->lock);
2245
2246         return (fillcount);
2247 }
2248
2249 #ifdef USE_MEMIMPREGISTER
2250 isc_result_t
2251 isc__mem_register() {
2252         return (isc_mem_register(isc__mem_create2));
2253 }
2254 #endif
2255
2256 #ifdef BIND9
2257 ISC_MEMFUNC_SCOPE void
2258 isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
2259         isc__mem_t *ctx = (isc__mem_t *)ctx0;
2260
2261         REQUIRE(VALID_CONTEXT(ctx));
2262         REQUIRE(file != NULL);
2263
2264 #if !ISC_MEM_TRACKLINES
2265         UNUSED(ctx);
2266         UNUSED(file);
2267 #else
2268         print_active(ctx, file);
2269 #endif
2270 }
2271
2272 ISC_MEMFUNC_SCOPE void
2273 isc__mem_printallactive(FILE *file) {
2274 #if !ISC_MEM_TRACKLINES
2275         UNUSED(file);
2276 #else
2277         isc__mem_t *ctx;
2278
2279         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2280
2281         LOCK(&lock);
2282         for (ctx = ISC_LIST_HEAD(contexts);
2283              ctx != NULL;
2284              ctx = ISC_LIST_NEXT(ctx, link)) {
2285                 fprintf(file, "context: %p\n", ctx);
2286                 print_active(ctx, file);
2287         }
2288         UNLOCK(&lock);
2289 #endif
2290 }
2291
2292 ISC_MEMFUNC_SCOPE void
2293 isc__mem_checkdestroyed(FILE *file) {
2294
2295         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2296
2297         LOCK(&lock);
2298         if (!ISC_LIST_EMPTY(contexts))  {
2299 #if ISC_MEM_TRACKLINES
2300                 isc__mem_t *ctx;
2301
2302                 for (ctx = ISC_LIST_HEAD(contexts);
2303                      ctx != NULL;
2304                      ctx = ISC_LIST_NEXT(ctx, link)) {
2305                         fprintf(file, "context: %p\n", ctx);
2306                         print_active(ctx, file);
2307                 }
2308                 fflush(file);
2309 #endif
2310                 INSIST(0);
2311         }
2312         UNLOCK(&lock);
2313 }
2314
2315 ISC_MEMFUNC_SCOPE unsigned int
2316 isc_mem_references(isc_mem_t *ctx0) {
2317         isc__mem_t *ctx = (isc__mem_t *)ctx0;
2318         unsigned int references;
2319
2320         REQUIRE(VALID_CONTEXT(ctx));
2321
2322         MCTXLOCK(ctx, &ctx->lock);
2323         references = ctx->references;
2324         MCTXUNLOCK(ctx, &ctx->lock);
2325
2326         return (references);
2327 }
2328
2329 #ifdef HAVE_LIBXML2
2330
2331 typedef struct summarystat {
2332         isc_uint64_t    total;
2333         isc_uint64_t    inuse;
2334         isc_uint64_t    blocksize;
2335         isc_uint64_t    contextsize;
2336 } summarystat_t;
2337
2338 static void
2339 renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2340         REQUIRE(VALID_CONTEXT(ctx));
2341
2342         xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
2343
2344         xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
2345         xmlTextWriterWriteFormatString(writer, "%p", ctx);
2346         xmlTextWriterEndElement(writer); /* id */
2347
2348         if (ctx->name[0] != 0) {
2349                 xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
2350                 xmlTextWriterWriteFormatString(writer, "%s", ctx->name);
2351                 xmlTextWriterEndElement(writer); /* name */
2352         }
2353
2354         REQUIRE(VALID_CONTEXT(ctx));
2355         MCTXLOCK(ctx, &ctx->lock);
2356
2357         summary->contextsize += sizeof(*ctx) +
2358                 (ctx->max_size + 1) * sizeof(struct stats) +
2359                 ctx->max_size * sizeof(element *) +
2360                 ctx->basic_table_count * sizeof(char *);
2361 #if ISC_MEM_TRACKLINES
2362         if (ctx->debuglist != NULL) {
2363                 summary->contextsize +=
2364                         (ctx->max_size + 1) * sizeof(debuglist_t) +
2365                         ctx->debuglistcnt * sizeof(debuglink_t);
2366         }
2367 #endif
2368         xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
2369         xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
2370         xmlTextWriterEndElement(writer); /* references */
2371
2372         summary->total += ctx->total;
2373         xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
2374         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2375                                        (isc_uint64_t)ctx->total);
2376         xmlTextWriterEndElement(writer); /* total */
2377
2378         summary->inuse += ctx->inuse;
2379         xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse");
2380         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2381                                        (isc_uint64_t)ctx->inuse);
2382         xmlTextWriterEndElement(writer); /* inuse */
2383
2384         xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse");
2385         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2386                                        (isc_uint64_t)ctx->maxinuse);
2387         xmlTextWriterEndElement(writer); /* maxinuse */
2388
2389         xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize");
2390         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2391                 summary->blocksize += ctx->basic_table_count *
2392                         NUM_BASIC_BLOCKS * ctx->mem_target;
2393                 xmlTextWriterWriteFormatString(writer,
2394                                                "%" ISC_PRINT_QUADFORMAT "u",
2395                                                (isc_uint64_t)
2396                                                ctx->basic_table_count *
2397                                                NUM_BASIC_BLOCKS *
2398                                                ctx->mem_target);
2399         } else
2400                 xmlTextWriterWriteFormatString(writer, "%s", "-");
2401         xmlTextWriterEndElement(writer); /* blocksize */
2402
2403         xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
2404         xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
2405         xmlTextWriterEndElement(writer); /* pools */
2406         summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2407
2408         xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
2409         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2410                                        (isc_uint64_t)ctx->hi_water);
2411         xmlTextWriterEndElement(writer); /* hiwater */
2412
2413         xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
2414         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2415                                        (isc_uint64_t)ctx->lo_water);
2416         xmlTextWriterEndElement(writer); /* lowater */
2417
2418         MCTXUNLOCK(ctx, &ctx->lock);
2419
2420         xmlTextWriterEndElement(writer); /* context */
2421 }
2422
2423 void
2424 isc_mem_renderxml(xmlTextWriterPtr writer) {
2425         isc__mem_t *ctx;
2426         summarystat_t summary;
2427         isc_uint64_t lost;
2428
2429         memset(&summary, 0, sizeof(summary));
2430
2431         xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts");
2432
2433         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2434
2435         LOCK(&lock);
2436         lost = totallost;
2437         for (ctx = ISC_LIST_HEAD(contexts);
2438              ctx != NULL;
2439              ctx = ISC_LIST_NEXT(ctx, link)) {
2440                 renderctx(ctx, &summary, writer);
2441         }
2442         UNLOCK(&lock);
2443
2444         xmlTextWriterEndElement(writer); /* contexts */
2445
2446         xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary");
2447
2448         xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse");
2449         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2450                                        summary.total);
2451         xmlTextWriterEndElement(writer); /* TotalUse */
2452
2453         xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse");
2454         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2455                                        summary.inuse);
2456         xmlTextWriterEndElement(writer); /* InUse */
2457
2458         xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize");
2459         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2460                                        summary.blocksize);
2461         xmlTextWriterEndElement(writer); /* BlockSize */
2462
2463         xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize");
2464         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2465                                        summary.contextsize);
2466         xmlTextWriterEndElement(writer); /* ContextSize */
2467
2468         xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost");
2469         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2470                                        lost);
2471         xmlTextWriterEndElement(writer); /* Lost */
2472
2473         xmlTextWriterEndElement(writer); /* summary */
2474 }
2475
2476 #endif /* HAVE_LIBXML2 */
2477 #endif /* BIND9 */