Annotation of embedaddon/mpd/src/contrib/libpdel/util/typed_mem.c, revision 1.1.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>