Annotation of embedaddon/mpd/src/contrib/libpdel/util/typed_mem.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (c) 2001-2002 Packet Design, LLC.
! 4: * All rights reserved.
! 5: *
! 6: * Subject to the following obligations and disclaimer of warranty,
! 7: * use and redistribution of this software, in source or object code
! 8: * forms, with or without modifications are expressly permitted by
! 9: * Packet Design; provided, however, that:
! 10: *
! 11: * (i) Any and all reproductions of the source or object code
! 12: * must include the copyright notice above and the following
! 13: * disclaimer of warranties; and
! 14: * (ii) No rights are granted, in any manner or form, to use
! 15: * Packet Design trademarks, including the mark "PACKET DESIGN"
! 16: * on advertising, endorsements, or otherwise except as such
! 17: * appears in the above copyright notice or in the software.
! 18: *
! 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
! 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
! 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
! 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
! 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
! 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
! 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
! 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
! 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
! 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
! 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
! 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
! 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
! 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
! 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
! 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
! 36: * THE POSSIBILITY OF SUCH DAMAGE.
! 37: *
! 38: * Author: Archie Cobbs <archie@freebsd.org>
! 39: */
! 40:
! 41: #include <sys/types.h>
! 42: #include <sys/param.h>
! 43:
! 44: #ifndef _KERNEL
! 45: #include <stdio.h>
! 46: #include <stddef.h>
! 47: #include <stdlib.h>
! 48: #include <stdarg.h>
! 49: #include <syslog.h>
! 50: #include <string.h>
! 51: #include <assert.h>
! 52: #include <errno.h>
! 53: #include <pthread.h>
! 54: #else
! 55: #include <sys/systm.h>
! 56: #include <machine/stdarg.h>
! 57: #include <malloc.h>
! 58: #include "util/kernelglue.h"
! 59: #endif
! 60:
! 61: #include "structs/structs.h"
! 62: #include "structs/type/array.h"
! 63: #include "structs/type/struct.h"
! 64: #include "structs/type/string.h"
! 65: #include "structs/type/int.h"
! 66: #include "util/gtree.h"
! 67: #include "util/typed_mem.h"
! 68:
! 69: /* Alignment, with a minimum of 4 bytes */
! 70: #if defined(__FreeBSD__)
! 71: #include <machine/param.h>
! 72: #define ALIGNMENT (_ALIGNBYTES + 1)
! 73: #else
! 74: #define ALIGNMENT 8 /* conservative guess */
! 75: #endif
! 76:
! 77: /* Summary information about a single type of memory */
! 78: struct mem_type {
! 79: char name[TYPED_MEM_TYPELEN];/* string for this type */
! 80: u_int32_t count; /* number of allocated blocks */
! 81: size_t total; /* total allocated bytes */
! 82: };
! 83:
! 84: /* Information about a single allocated block of memory */
! 85: struct mem_info {
! 86: void *mem; /* actual memory block */
! 87: size_t size; /* size of memory block */
! 88: struct mem_type *type; /* pointer to type info */
! 89: };
! 90:
! 91: /*
! 92: * Structs type for 'struct typed_mem_stats'
! 93: */
! 94: #define TYPED_MEM_STATS_MTYPE "typed_mem_stats"
! 95:
! 96: static const struct structs_type typebuf_type
! 97: = STRUCTS_FIXEDSTRING_TYPE(TYPED_MEM_TYPELEN);
! 98: static const struct structs_field typed_mem_typestats_fields[] = {
! 99: STRUCTS_STRUCT_FIELD(typed_mem_typestats, type, &typebuf_type),
! 100: STRUCTS_STRUCT_FIELD(typed_mem_typestats, allocs, &structs_type_uint),
! 101: STRUCTS_STRUCT_FIELD(typed_mem_typestats, bytes, &structs_type_uint),
! 102: STRUCTS_STRUCT_FIELD_END
! 103: };
! 104: static const struct structs_type typed_mem_typestats_type
! 105: = STRUCTS_STRUCT_TYPE(typed_mem_typestats, typed_mem_typestats_fields);
! 106: const struct structs_type typed_mem_stats_type
! 107: = STRUCTS_ARRAY_TYPE(&typed_mem_typestats_type,
! 108: TYPED_MEM_STATS_MTYPE, "type");
! 109:
! 110: /* We need to use the real functions in here */
! 111: #undef malloc
! 112: #undef calloc
! 113: #undef realloc
! 114: #undef reallocf
! 115: #undef free
! 116: #undef asprintf
! 117: #undef vasprintf
! 118:
! 119: /* How to print out problems */
! 120: #define WHINE(fmt, args...) (void)fprintf(stderr, fmt "\n" , ## args)
! 121:
! 122: /*
! 123: * Kernel glue
! 124: */
! 125: #ifdef _KERNEL
! 126:
! 127: #if TYPED_MEM_TRACE
! 128: #error TYPED_MEM_TRACE not supported in kernel mode
! 129: #endif
! 130:
! 131: #define malloc(x) kern_malloc(x)
! 132: #define realloc(x, y) kern_realloc(x, y)
! 133: #define free(x) kern_free(x)
! 134:
! 135: #define pthread_mutex_lock() 0
! 136: #define pthread_mutex_unlock() 0
! 137:
! 138: #undef WHINE
! 139: #define WHINE(fmt, args...) log(LOG_CRIT, fmt "\n" , ## args)
! 140:
! 141: #endif /* _KERNEL */
! 142:
! 143: /*
! 144: * Internal variables
! 145: */
! 146: static u_char typed_mem_started;
! 147: static u_char typed_mem_enabled;
! 148: static struct gtree *mem_tree;
! 149: static struct gtree *type_tree;
! 150: static u_int tree_node_size;
! 151:
! 152: #ifndef _KERNEL
! 153: static pthread_mutex_t typed_mem_mutex;
! 154: #endif
! 155:
! 156: /* Guard bytes. Should have an "aligned" length. */
! 157: static const u_char typed_mem_guard_data[] = { 0x34, 0x8e, 0x71, 0x9f };
! 158: static u_char typed_mem_guard[ALIGNMENT];
! 159:
! 160: /*
! 161: * Internal functions
! 162: */
! 163: static gtree_cmp_t type_cmp;
! 164: static gtree_print_t type_print;
! 165: static gtree_cmp_t mem_cmp;
! 166:
! 167: static struct mem_info *typed_mem_find(
! 168: #if TYPED_MEM_TRACE
! 169: const char *file, u_int line,
! 170: #endif
! 171: void *mem, const char *typename, const char *func);
! 172:
! 173: #ifndef _KERNEL
! 174: static gtree_print_t mem_print;
! 175: #else
! 176: #define mem_print NULL
! 177: #endif
! 178:
! 179: /*
! 180: * Enable typed memory.
! 181: */
! 182: int
! 183: typed_mem_enable(void)
! 184: {
! 185: pthread_mutexattr_t mattr;
! 186: int i;
! 187:
! 188: /* Already enabled? */
! 189: if (typed_mem_enabled)
! 190: return (0);
! 191:
! 192: /* Already started allocating memory? */
! 193: if (typed_mem_started) {
! 194: errno = EALREADY;
! 195: return (-1);
! 196: }
! 197:
! 198: /* Initialize recursive mutex */
! 199: if ((errno = pthread_mutexattr_init(&mattr)) != 0)
! 200: return (-1);
! 201: if ((errno = pthread_mutexattr_settype(&mattr,
! 202: PTHREAD_MUTEX_RECURSIVE)) != 0) {
! 203: pthread_mutexattr_destroy(&mattr);
! 204: return (-1);
! 205: }
! 206: if ((errno = pthread_mutex_init(&typed_mem_mutex, &mattr)) != 0) {
! 207: pthread_mutexattr_destroy(&mattr);
! 208: return (-1);
! 209: }
! 210: pthread_mutexattr_destroy(&mattr);
! 211:
! 212: /* Fill in guard bytes */
! 213: for (i = 0; i < ALIGNMENT; i++) {
! 214: typed_mem_guard[i] = typed_mem_guard_data[
! 215: i % sizeof(typed_mem_guard_data)];
! 216: }
! 217:
! 218: /* Done */
! 219: typed_mem_enabled = 1;
! 220: return (0);
! 221: }
! 222:
! 223: /*
! 224: * realloc(3) replacement
! 225: */
! 226: void *
! 227: typed_mem_realloc(
! 228: #if TYPED_MEM_TRACE
! 229: const char *file, u_int line,
! 230: #endif
! 231: const char *typename, void *mem, size_t size)
! 232: {
! 233: #if TYPED_MEM_TRACE
! 234: void *const omem = mem;
! 235: #endif
! 236: struct mem_info *info;
! 237: void *rtn = NULL;
! 238: int errno_save;
! 239: int removed;
! 240: int r;
! 241:
! 242: /* Check if typed memory is active */
! 243: typed_mem_started = 1;
! 244: if (!typed_mem_enabled || typename == NULL)
! 245: return (realloc(mem, size));
! 246:
! 247: /* Lock info */
! 248: r = pthread_mutex_lock(&typed_mem_mutex);
! 249: assert(r == 0);
! 250:
! 251: /* Initialize first */
! 252: if (mem_tree == NULL) {
! 253: if ((mem_tree = gtree_create(NULL, NULL,
! 254: mem_cmp, NULL, NULL, mem_print)) == NULL)
! 255: goto done;
! 256: if ((type_tree = gtree_create(NULL, NULL,
! 257: type_cmp, NULL, NULL, type_print)) == NULL) {
! 258: gtree_destroy(&mem_tree);
! 259: goto done;
! 260: }
! 261: tree_node_size = gtree_node_size();
! 262: }
! 263:
! 264: /* Find/create the memory descriptor block */
! 265: if (mem == NULL) {
! 266: struct mem_type *type;
! 267: struct mem_type tkey;
! 268:
! 269: /* Get memory and new descriptor block */
! 270: if ((info = malloc(sizeof(*info))) == NULL)
! 271: goto done;
! 272: if ((info->mem = malloc(size
! 273: + 2 * sizeof(typed_mem_guard))) == NULL) {
! 274: errno_save = errno;
! 275: free(info);
! 276: errno = errno_save;
! 277: goto done;
! 278: }
! 279: info->size = size;
! 280:
! 281: /* Find/create type descriptor for this memory type */
! 282: strncpy(tkey.name, typename, sizeof(tkey.name) - 1);
! 283: tkey.name[sizeof(tkey.name) - 1] = '\0';
! 284: if ((type = gtree_get(type_tree, &tkey)) == NULL) {
! 285: if ((type = malloc(sizeof(*type))) == NULL) {
! 286: errno_save = errno;
! 287: free(info->mem);
! 288: free(info);
! 289: errno = errno_save;
! 290: goto done;
! 291: }
! 292: strcpy(type->name, tkey.name);
! 293: type->count = 0;
! 294: type->total = 0;
! 295: if (gtree_put(type_tree, type) == -1) {
! 296: errno_save = errno;
! 297: free(type);
! 298: free(info->mem);
! 299: free(info);
! 300: errno = errno_save;
! 301: goto done;
! 302: }
! 303: }
! 304: info->type = type;
! 305:
! 306: /* Add block descriptor to mem tree */
! 307: if (gtree_put(mem_tree, info) == -1) {
! 308: errno_save = errno;
! 309: if (type->count == 0) { /* was a new type */
! 310: removed = gtree_remove(type_tree, type);
! 311: assert(removed);
! 312: free(type);
! 313: }
! 314: free(info->mem);
! 315: free(info);
! 316: errno = errno_save;
! 317: goto done;
! 318: }
! 319: } else {
! 320: void *node;
! 321:
! 322: /* Find memory descriptor */
! 323: #if TYPED_MEM_TRACE
! 324: info = typed_mem_find(file, line, mem, typename, "REALLOC");
! 325: #else
! 326: info = typed_mem_find(mem, typename, "REALLOC");
! 327: #endif
! 328:
! 329: /* Pre-allocate mem tree node */
! 330: if ((node = malloc(tree_node_size)) == NULL)
! 331: goto done;
! 332:
! 333: /* Get reallocated memory block */
! 334: if ((mem = realloc(info->mem,
! 335: size + 2 * sizeof(typed_mem_guard))) == NULL) {
! 336: errno_save = errno;
! 337: free(node);
! 338: errno = errno_save;
! 339: goto done;
! 340: }
! 341:
! 342: /* Subtract old block from type stats */
! 343: info->type->total -= info->size;
! 344: info->type->count--;
! 345:
! 346: /* Update block descriptor */
! 347: info->size = size;
! 348: if (info->mem != mem) {
! 349: removed = gtree_remove(mem_tree, info);
! 350: assert(removed);
! 351: info->mem = mem;
! 352: gtree_put_prealloc(mem_tree, info, node);
! 353: } else
! 354: free(node); /* we didn't need it */
! 355: }
! 356:
! 357: /* Add new block to type stats */
! 358: info->type->total += info->size;
! 359: info->type->count++;
! 360:
! 361: /* Install guard bytes */
! 362: memcpy(info->mem, typed_mem_guard, sizeof(typed_mem_guard));
! 363: memcpy((u_char *)info->mem + sizeof(typed_mem_guard) + info->size,
! 364: typed_mem_guard, sizeof(typed_mem_guard));
! 365:
! 366: #if TYPED_MEM_TRACE
! 367: /* Tracing */
! 368: {
! 369: const char *basename;
! 370:
! 371: if ((basename = strrchr(file, '/')) != NULL)
! 372: basename++;
! 373: else
! 374: basename = file;
! 375: fprintf(stderr, "%s:%u:ALLOC %p -> %p \"%s\" %u [%u]\n",
! 376: basename, line, omem, (u_char *)info->mem
! 377: + sizeof(typed_mem_guard), typename, size,
! 378: info->type->count);
! 379: }
! 380: #endif
! 381:
! 382: /* Return memory block */
! 383: rtn = (u_char *)info->mem + sizeof(typed_mem_guard);
! 384:
! 385: done:
! 386: /* Done */
! 387: r = pthread_mutex_unlock(&typed_mem_mutex);
! 388: assert(r == 0);
! 389: return (rtn);
! 390: }
! 391:
! 392: /*
! 393: * reallocf(3) replacement
! 394: */
! 395: void *
! 396: typed_mem_reallocf(
! 397: #if TYPED_MEM_TRACE
! 398: const char *file, u_int line,
! 399: #endif
! 400: const char *typename, void *mem, size_t size)
! 401: {
! 402: void *p;
! 403:
! 404: #if TYPED_MEM_TRACE
! 405: if ((p = typed_mem_realloc(file, line, typename, mem, size)) == NULL)
! 406: typed_mem_free(file, line, typename, mem);
! 407: #else
! 408: if ((p = typed_mem_realloc(typename, mem, size)) == NULL)
! 409: typed_mem_free(typename, mem);
! 410: #endif
! 411: return (p);
! 412: }
! 413:
! 414: /*
! 415: * free(3) replacement
! 416: *
! 417: * Note: it is OK if "typedname" points to memory within the region
! 418: * pointed to by "mem".
! 419: */
! 420: void
! 421: typed_mem_free(
! 422: #if TYPED_MEM_TRACE
! 423: const char *file, u_int line,
! 424: #endif
! 425: const char *typename, void *mem)
! 426: {
! 427: const int errno_save = errno;
! 428: struct mem_info *info;
! 429: int removed;
! 430: int r;
! 431:
! 432: /* free(NULL) does nothing */
! 433: if (mem == NULL)
! 434: return;
! 435:
! 436: /* Check if typed memory is active */
! 437: typed_mem_started = 1;
! 438: if (!typed_mem_enabled || typename == NULL) {
! 439: free(mem);
! 440: return;
! 441: }
! 442:
! 443: /* Lock info */
! 444: r = pthread_mutex_lock(&typed_mem_mutex);
! 445: assert(r == 0);
! 446:
! 447: /* Find memory descriptor */
! 448: #if TYPED_MEM_TRACE
! 449: info = typed_mem_find(file, line, mem, typename, "FREE");
! 450: #else
! 451: info = typed_mem_find(mem, typename, "FREE");
! 452: #endif
! 453:
! 454: #if TYPED_MEM_TRACE
! 455: /* Tracing */
! 456: {
! 457: const char *basename;
! 458:
! 459: if ((basename = strrchr(file, '/')) != NULL)
! 460: basename++;
! 461: else
! 462: basename = file;
! 463: fprintf(stderr, "%s:%u:FREE %p -> %p \"%s\" [%u]\n",
! 464: basename, line, mem, (void *)0,
! 465: typename, info->type->count);
! 466: }
! 467: #endif
! 468:
! 469: /* Subtract block from descriptor info */
! 470: info->type->total -= info->size;
! 471: if (--info->type->count == 0) {
! 472: assert(info->type->total == 0);
! 473: removed = gtree_remove(type_tree, info->type);
! 474: assert(removed);
! 475: free(info->type);
! 476: }
! 477:
! 478: /* Free memory and descriptor block */
! 479: removed = gtree_remove(mem_tree, info);
! 480: assert(removed);
! 481: free(info->mem);
! 482: free(info);
! 483:
! 484: /* Done */
! 485: r = pthread_mutex_unlock(&typed_mem_mutex);
! 486: assert(r == 0);
! 487: errno = errno_save;
! 488: }
! 489:
! 490: /*
! 491: * calloc(3) replacement
! 492: */
! 493: void *
! 494: typed_mem_calloc(
! 495: #if TYPED_MEM_TRACE
! 496: const char *file, u_int line,
! 497: #endif
! 498: const char *type, size_t num, size_t size)
! 499: {
! 500: void *mem;
! 501:
! 502: size *= num;
! 503: #if TYPED_MEM_TRACE
! 504: if ((mem = typed_mem_realloc(file, line, type, NULL, size)) == NULL)
! 505: return (NULL);
! 506: #else
! 507: if ((mem = typed_mem_realloc(type, NULL, size)) == NULL)
! 508: return (NULL);
! 509: #endif
! 510: memset(mem, 0, size);
! 511: return (mem);
! 512: }
! 513:
! 514: /*
! 515: * strdup(3) replacement
! 516: */
! 517: char *
! 518: typed_mem_strdup(
! 519: #if TYPED_MEM_TRACE
! 520: const char *file, u_int line,
! 521: #endif
! 522: const char *type, const char *string)
! 523: {
! 524: const int slen = strlen(string) + 1;
! 525: char *result;
! 526:
! 527: #if TYPED_MEM_TRACE
! 528: if ((result = typed_mem_realloc(file, line, type, NULL, slen)) == NULL)
! 529: return (NULL);
! 530: #else
! 531: if ((result = typed_mem_realloc(type, NULL, slen)) == NULL)
! 532: return (NULL);
! 533: #endif
! 534: memcpy(result, string, slen);
! 535: return (result);
! 536: }
! 537:
! 538: /*
! 539: * asprintf(3) replacement
! 540: */
! 541: int
! 542: typed_mem_asprintf(
! 543: #if TYPED_MEM_TRACE
! 544: const char *file, u_int line,
! 545: #endif
! 546: const char *type, char **ret, const char *fmt, ...)
! 547: {
! 548: va_list args;
! 549: int r;
! 550:
! 551: va_start(args, fmt);
! 552: #if TYPED_MEM_TRACE
! 553: r = typed_mem_vasprintf(file, line, type, ret, fmt, args);
! 554: #else
! 555: r = typed_mem_vasprintf(type, ret, fmt, args);
! 556: #endif
! 557: va_end(args);
! 558: return (r);
! 559: }
! 560:
! 561: /*
! 562: * vasprintf(3) replacement
! 563: */
! 564: int
! 565: typed_mem_vasprintf(
! 566: #if TYPED_MEM_TRACE
! 567: const char *file, u_int line,
! 568: #endif
! 569: const char *type, char **ret, const char *fmt, va_list args)
! 570: {
! 571: int errno_save;
! 572: char *s;
! 573: int r;
! 574:
! 575: if ((r = vasprintf(ret, fmt, args)) == -1) {
! 576: *ret = NULL;
! 577: return (-1);
! 578: }
! 579: if (!typed_mem_enabled)
! 580: return r;
! 581: s = *ret;
! 582: #if TYPED_MEM_TRACE
! 583: *ret = typed_mem_strdup(file, line, type, s);
! 584: #else
! 585: *ret = typed_mem_strdup(type, s);
! 586: #endif
! 587: errno_save = errno;
! 588: free(s);
! 589: if (*ret == NULL) {
! 590: errno = errno_save;
! 591: return (-1);
! 592: }
! 593: return (r);
! 594: }
! 595:
! 596: /*
! 597: * Get type for a memory block.
! 598: */
! 599: char *
! 600: typed_mem_type(const void *mem, char *typebuf)
! 601: {
! 602: struct mem_info *info = NULL;
! 603: struct mem_info ikey;
! 604: int r;
! 605:
! 606: /* Are we enabled? */
! 607: if (!typed_mem_enabled) {
! 608: errno = ENXIO;
! 609: return (NULL);
! 610: }
! 611:
! 612: /* Lock info */
! 613: r = pthread_mutex_lock(&typed_mem_mutex);
! 614: assert(r == 0);
! 615:
! 616: /* Find memory descriptor */
! 617: ikey.mem = (u_char *)mem - sizeof(typed_mem_guard);
! 618: if (mem_tree == NULL || (info = gtree_get(mem_tree, &ikey)) == NULL) {
! 619: errno = ENOENT;
! 620: typebuf = NULL;
! 621: goto done;
! 622: }
! 623:
! 624: /* Copy type */
! 625: strlcpy(typebuf, info->type->name, TYPED_MEM_TYPELEN);
! 626:
! 627: done:
! 628: /* Unlock info */
! 629: r = pthread_mutex_unlock(&typed_mem_mutex);
! 630: assert(r == 0);
! 631:
! 632: /* Done */
! 633: return (typebuf);
! 634: }
! 635:
! 636: /*
! 637: * Return typed memory usage statistics. The caller must free the
! 638: * array by calling "structs_free(&typed_mem_stats_type, NULL, stats)".
! 639: *
! 640: * Returns zero if successful, -1 (and sets errno) if not.
! 641: * If typed memory is disabled, errno = ENXIO.
! 642: */
! 643: int
! 644: typed_mem_usage(struct typed_mem_stats *stats)
! 645: {
! 646: struct mem_type *type;
! 647: int i;
! 648: int r;
! 649:
! 650: /* Check if enabled */
! 651: if (!typed_mem_enabled) {
! 652: errno = ENXIO;
! 653: return (-1);
! 654: }
! 655:
! 656: /* Lock info */
! 657: r = pthread_mutex_lock(&typed_mem_mutex);
! 658: assert(r == 0);
! 659:
! 660: /* Allocate array */
! 661: memset(stats, 0, sizeof(*stats));
! 662: if ((stats->elems = typed_mem_realloc(
! 663: #if TYPED_MEM_TRACE
! 664: __FILE__, __LINE__,
! 665: #endif
! 666: TYPED_MEM_STATS_MTYPE, NULL, (gtree_size(type_tree) + 1)
! 667: * sizeof(*stats->elems))) == NULL) {
! 668: r = pthread_mutex_unlock(&typed_mem_mutex);
! 669: assert(r == 0);
! 670: return (-1);
! 671: }
! 672:
! 673: /* Copy type stats */
! 674: for (i = 0, type = gtree_first(type_tree);
! 675: type != NULL; i++, type = gtree_next(type_tree, type)) {
! 676: struct typed_mem_typestats *const elem = &stats->elems[i];
! 677:
! 678: strlcpy(elem->type, type->name, sizeof(elem->type));
! 679: elem->allocs = type->count;
! 680: elem->bytes = type->total;
! 681: }
! 682: stats->length = i;
! 683:
! 684: /* Unlock info */
! 685: r = pthread_mutex_unlock(&typed_mem_mutex);
! 686: assert(r == 0);
! 687:
! 688: /* Done */
! 689: return (0);
! 690: }
! 691:
! 692: #ifndef _KERNEL
! 693:
! 694: /*
! 695: * Return usage statistics in a malloc'd string of the specified type.
! 696: */
! 697: void
! 698: typed_mem_dump(FILE *fp)
! 699: {
! 700: u_long total_blocks = 0;
! 701: u_long total_alloc = 0;
! 702: struct mem_type *type;
! 703: int r;
! 704:
! 705: /* Check if enabled */
! 706: if (!typed_mem_enabled) {
! 707: fprintf(fp, "Typed memory is not enabled.\n");
! 708: return;
! 709: }
! 710:
! 711: /* Print header */
! 712: fprintf(fp, " %-28s %10s %10s\n", "Type", "Count", "Total");
! 713: fprintf(fp, " %-28s %10s %10s\n", "----", "-----", "-----");
! 714:
! 715: /* Lock info */
! 716: r = pthread_mutex_lock(&typed_mem_mutex);
! 717: assert(r == 0);
! 718:
! 719: /* Print allocation types */
! 720: for (type = gtree_first(type_tree);
! 721: type != NULL; type = gtree_next(type_tree, type)) {
! 722: fprintf(fp, " %-28s %10u %10lu\n",
! 723: type->name, (int)type->count, (u_long)type->total);
! 724: total_blocks += type->count;
! 725: total_alloc += type->total;
! 726: }
! 727:
! 728: /* Print totals */
! 729: fprintf(fp, " %-28s %10s %10s\n", "", "-----", "-----");
! 730: fprintf(fp, " %-28s %10lu %10lu\n",
! 731: "Totals", total_blocks, total_alloc);
! 732:
! 733: /* Unlock info */
! 734: r = pthread_mutex_unlock(&typed_mem_mutex);
! 735: assert(r == 0);
! 736: }
! 737:
! 738: #endif /* !_KERNEL */
! 739:
! 740: /*
! 741: * Find memory block info descriptor and verify guard bytes
! 742: *
! 743: * This assumes the mutex is locked.
! 744: */
! 745: static struct mem_info *
! 746: typed_mem_find(
! 747: #if TYPED_MEM_TRACE
! 748: const char *file, u_int line,
! 749: #endif
! 750: void *mem, const char *typename, const char *func)
! 751: {
! 752: struct mem_info *info = NULL;
! 753: struct mem_info ikey;
! 754:
! 755: /* Find memory descriptor which must already exist */
! 756: ikey.mem = (u_char *)mem - sizeof(typed_mem_guard);
! 757: if (mem_tree == NULL || (info = gtree_get(mem_tree, &ikey)) == NULL) {
! 758: #if TYPED_MEM_TRACE
! 759: WHINE("%s:%u: %s() of unallocated block:"
! 760: " ptr=%p type=\"%s\"", file, line, func, mem, typename);
! 761: #else
! 762: WHINE("%s() of unallocated block:"
! 763: " ptr=%p type=\"%s\"", func, mem, typename);
! 764: #endif
! 765: assert(0);
! 766: }
! 767:
! 768: /* Check type is the same */
! 769: if (strncmp(info->type->name, typename, TYPED_MEM_TYPELEN - 1) != 0) {
! 770: #if TYPED_MEM_TRACE
! 771: WHINE("%s:%u: %s() with wrong type:"
! 772: " ptr=%p \"%s\" != \"%s\"", file, line,
! 773: func, mem, typename, info->type->name);
! 774: #else
! 775: WHINE("%s() with wrong type:"
! 776: " ptr=%p \"%s\" != \"%s\"",
! 777: func, mem, typename, info->type->name);
! 778: #endif
! 779: assert(0);
! 780: }
! 781:
! 782: /* Check ref count */
! 783: assert(info->type->count > 0);
! 784:
! 785: /* Check guard bytes */
! 786: if (memcmp(info->mem, typed_mem_guard, sizeof(typed_mem_guard)) != 0) {
! 787: #if TYPED_MEM_TRACE
! 788: WHINE("%s:%u: %s(): %s guard violated ptr=%p type=\"%s\"",
! 789: file, line, func, "head", mem, typename);
! 790: #else
! 791: WHINE("%s(): %s guard violated ptr=%p type=\"%s\"",
! 792: func, "head", mem, typename);
! 793: #endif
! 794: assert(0);
! 795: }
! 796: if (memcmp((u_char *)info->mem + sizeof(typed_mem_guard) + info->size,
! 797: typed_mem_guard, sizeof(typed_mem_guard)) != 0) {
! 798: #if TYPED_MEM_TRACE
! 799: WHINE("%s:%u: %s(): %s guard violated ptr=%p type=\"%s\"",
! 800: file, line, func, "tail", mem, typename);
! 801: #else
! 802: WHINE("%s(): %s guard violated ptr=%p type=\"%s\"",
! 803: func, "tail", mem, typename);
! 804: #endif
! 805: assert(0);
! 806: }
! 807:
! 808: /* Done */
! 809: return (info);
! 810: }
! 811:
! 812: /*
! 813: * Sort type descriptors by type string.
! 814: */
! 815: static int
! 816: type_cmp(struct gtree *g, const void *item1, const void *item2)
! 817: {
! 818: const struct mem_type *const type1 = item1;
! 819: const struct mem_type *const type2 = item2;
! 820:
! 821: return (strcmp(type1->name, type2->name));
! 822: }
! 823:
! 824: /*
! 825: * Print a type
! 826: */
! 827: static const char *
! 828: type_print(struct gtree *g, const void *item)
! 829: {
! 830: const struct mem_type *const type = item;
! 831:
! 832: return (type->name);
! 833: }
! 834:
! 835: /*
! 836: * Sort memory block descriptors by memory address.
! 837: */
! 838: static int
! 839: mem_cmp(struct gtree *g, const void *item1, const void *item2)
! 840: {
! 841: const struct mem_info *const info1 = item1;
! 842: const struct mem_info *const info2 = item2;
! 843:
! 844: if (info1->mem < info2->mem)
! 845: return (-1);
! 846: if (info1->mem > info2->mem)
! 847: return (1);
! 848: return (0);
! 849: }
! 850:
! 851: #ifndef _KERNEL
! 852:
! 853: /*
! 854: * Print a type
! 855: */
! 856: static const char *
! 857: mem_print(struct gtree *g, const void *item)
! 858: {
! 859: const struct mem_info *const info = item;
! 860: static char buf[32];
! 861:
! 862: snprintf(buf, sizeof(buf), "%p", info->mem);
! 863: return (buf);
! 864: }
! 865:
! 866: #endif /* !_KERNEL */
! 867:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>