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