Annotation of embedaddon/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[i % ALIGNMENT];
                    215: 
                    216:        /* Done */
                    217:        typed_mem_enabled = 1;
                    218:        return (0);
                    219: }
                    220: 
                    221: /*
                    222:  * realloc(3) replacement
                    223:  */
                    224: void *
                    225: typed_mem_realloc(
                    226: #if TYPED_MEM_TRACE
                    227:        const char *file, u_int line,
                    228: #endif
                    229:        const char *typename, void *mem, size_t size)
                    230: {
                    231: #if TYPED_MEM_TRACE
                    232:        void *const omem = mem;
                    233: #endif
                    234:        struct mem_info *info;
                    235:        void *rtn = NULL;
                    236:        int errno_save;
                    237:        int removed;
                    238:        int r;
                    239: 
                    240:        /* Check if typed memory is active */
                    241:        typed_mem_started = 1;
                    242:        if (!typed_mem_enabled || typename == NULL)
                    243:                return (realloc(mem, size));
                    244: 
                    245:        /* Lock info */
                    246:        r = pthread_mutex_lock(&typed_mem_mutex);
                    247:        assert(r == 0);
                    248: 
                    249:        /* Initialize first */
                    250:        if (mem_tree == NULL) {
                    251:                if ((mem_tree = gtree_create(NULL, NULL,
                    252:                    mem_cmp, NULL, NULL, mem_print)) == NULL)
                    253:                        goto done;
                    254:                if ((type_tree = gtree_create(NULL, NULL,
                    255:                    type_cmp, NULL, NULL, type_print)) == NULL) {
                    256:                        gtree_destroy(&mem_tree);
                    257:                        goto done;
                    258:                }
                    259:                tree_node_size = gtree_node_size();
                    260:        }
                    261: 
                    262:        /* Find/create the memory descriptor block */
                    263:        if (mem == NULL) {
                    264:                struct mem_type *type;
                    265:                struct mem_type tkey;
                    266: 
                    267:                /* Get memory and new descriptor block */
                    268:                if ((info = malloc(sizeof(*info))) == NULL)
                    269:                        goto done;
                    270:                if ((info->mem = malloc(size
                    271:                    + 2 * sizeof(typed_mem_guard))) == NULL) {
                    272:                        errno_save = errno;
                    273:                        free(info);
                    274:                        errno = errno_save;
                    275:                        goto done;
                    276:                }
                    277:                info->size = size;
                    278: 
                    279:                /* Find/create type descriptor for this memory type */
                    280:                strncpy(tkey.name, typename, sizeof(tkey.name) - 1);
                    281:                tkey.name[sizeof(tkey.name) - 1] = '\0';
                    282:                if ((type = gtree_get(type_tree, &tkey)) == NULL) {
                    283:                        if ((type = malloc(sizeof(*type))) == NULL) {
                    284:                                errno_save = errno;
                    285:                                free(info->mem);
                    286:                                free(info);
                    287:                                errno = errno_save;
                    288:                                goto done;
                    289:                        }
                    290:                        strcpy(type->name, tkey.name);
                    291:                        type->count = 0;
                    292:                        type->total = 0;
                    293:                        if (gtree_put(type_tree, type) == -1) {
                    294:                                errno_save = errno;
                    295:                                free(type);
                    296:                                free(info->mem);
                    297:                                free(info);
                    298:                                errno = errno_save;
                    299:                                goto done;
                    300:                        }
                    301:                }
                    302:                info->type = type;
                    303: 
                    304:                /* Add block descriptor to mem tree */
                    305:                if (gtree_put(mem_tree, info) == -1) {
                    306:                        errno_save = errno;
                    307:                        if (type->count == 0) {         /* was a new type */
                    308:                                removed = gtree_remove(type_tree, type);
                    309:                                assert(removed);
                    310:                                free(type);
                    311:                        }
                    312:                        free(info->mem);
                    313:                        free(info);
                    314:                        errno = errno_save;
                    315:                        goto done;
                    316:                }
                    317:        } else {
                    318:                void *node;
                    319: 
                    320:                /* Find memory descriptor */
                    321: #if TYPED_MEM_TRACE
                    322:                info = typed_mem_find(file, line, mem, typename, "REALLOC");
                    323: #else
                    324:                info = typed_mem_find(mem, typename, "REALLOC");
                    325: #endif
                    326: 
                    327:                /* Pre-allocate mem tree node */
                    328:                if ((node = malloc(tree_node_size)) == NULL)
                    329:                        goto done;
                    330: 
                    331:                /* Get reallocated memory block */
                    332:                if ((mem = realloc(info->mem,
                    333:                    size + 2 * sizeof(typed_mem_guard))) == NULL) {
                    334:                        errno_save = errno;
                    335:                        free(node);
                    336:                        errno = errno_save;
                    337:                        goto done;
                    338:                }
                    339: 
                    340:                /* Subtract old block from type stats */
                    341:                info->type->total -= info->size;
                    342:                info->type->count--;
                    343: 
                    344:                /* Update block descriptor */
                    345:                info->size = size;
                    346:                if (info->mem != mem) {
                    347:                        removed = gtree_remove(mem_tree, info);
                    348:                        assert(removed);
                    349:                        info->mem = mem;
                    350:                        gtree_put_prealloc(mem_tree, info, node);
                    351:                } else
                    352:                        free(node);             /* we didn't need it */
                    353:        }
                    354: 
                    355:        /* Add new block to type stats */
                    356:        info->type->total += info->size;
                    357:        info->type->count++;
                    358: 
                    359:        /* Install guard bytes */
                    360:        memcpy(info->mem, typed_mem_guard, sizeof(typed_mem_guard));
                    361:        memcpy((u_char *)info->mem + sizeof(typed_mem_guard) + info->size,
                    362:            typed_mem_guard, sizeof(typed_mem_guard));
                    363: 
                    364: #if TYPED_MEM_TRACE
                    365:        /* Tracing */
                    366:        {
                    367:                const char *basename;
                    368: 
                    369:                if ((basename = strrchr(file, '/')) != NULL)
                    370:                        basename++;
                    371:                else
                    372:                        basename = file;
                    373:                fprintf(stderr, "%s:%u:ALLOC %p -> %p \"%s\" %u [%u]\n",
                    374:                    basename, line, omem, (u_char *)info->mem
                    375:                    + sizeof(typed_mem_guard), typename, size,
                    376:                    info->type->count);
                    377:        }
                    378: #endif
                    379: 
                    380:        /* Return memory block */
                    381:        rtn = (u_char *)info->mem + sizeof(typed_mem_guard);
                    382: 
                    383: done:
                    384:        /* Done */
                    385:        r = pthread_mutex_unlock(&typed_mem_mutex);
                    386:        assert(r == 0);
                    387:        return (rtn);
                    388: }
                    389: 
                    390: /*
                    391:  * reallocf(3) replacement
                    392:  */
                    393: void *
                    394: typed_mem_reallocf(
                    395: #if TYPED_MEM_TRACE
                    396:        const char *file, u_int line,
                    397: #endif
                    398:        const char *typename, void *mem, size_t size)
                    399: {
                    400:        void *p;
                    401: 
                    402: #if TYPED_MEM_TRACE
                    403:        if ((p = typed_mem_realloc(file, line, typename, mem, size)) == NULL)
                    404:                typed_mem_free(file, line, typename, mem);
                    405: #else
                    406:        if ((p = typed_mem_realloc(typename, mem, size)) == NULL)
                    407:                typed_mem_free(typename, mem);
                    408: #endif
                    409:        return (p);
                    410: }
                    411: 
                    412: /*
                    413:  * free(3) replacement
                    414:  *
                    415:  * Note: it is OK if "typedname" points to memory within the region
                    416:  * pointed to by "mem".
                    417:  */
                    418: void
                    419: typed_mem_free(
                    420: #if TYPED_MEM_TRACE
                    421:        const char *file, u_int line,
                    422: #endif
                    423:        const char *typename, void *mem)
                    424: {
                    425:        const int errno_save = errno;
                    426:        struct mem_info *info;
                    427:        int removed;
                    428:        int r;
                    429: 
                    430:        /* free(NULL) does nothing */
                    431:        if (mem == NULL)
                    432:                return;
                    433: 
                    434:        /* Check if typed memory is active */
                    435:        typed_mem_started = 1;
                    436:        if (!typed_mem_enabled || typename == NULL) {
                    437:                free(mem);
                    438:                return;
                    439:        }
                    440: 
                    441:        /* Lock info */
                    442:        r = pthread_mutex_lock(&typed_mem_mutex);
                    443:        assert(r == 0);
                    444: 
                    445:        /* Find memory descriptor */
                    446: #if TYPED_MEM_TRACE
                    447:        info = typed_mem_find(file, line, mem, typename, "FREE");
                    448: #else
                    449:        info = typed_mem_find(mem, typename, "FREE");
                    450: #endif
                    451: 
                    452: #if TYPED_MEM_TRACE
                    453:        /* Tracing */
                    454:        {
                    455:                const char *basename;
                    456: 
                    457:                if ((basename = strrchr(file, '/')) != NULL)
                    458:                        basename++;
                    459:                else
                    460:                        basename = file;
                    461:                fprintf(stderr, "%s:%u:FREE %p -> %p \"%s\" [%u]\n",
                    462:                    basename, line, mem, (void *)0,
                    463:                    typename, info->type->count);
                    464:        }
                    465: #endif
                    466: 
                    467:        /* Subtract block from descriptor info */
                    468:        info->type->total -= info->size;
                    469:        if (--info->type->count == 0) {
                    470:                assert(info->type->total == 0);
                    471:                removed = gtree_remove(type_tree, info->type);
                    472:                assert(removed);
                    473:                free(info->type);
                    474:        }
                    475: 
                    476:        /* Free memory and descriptor block */
                    477:        removed = gtree_remove(mem_tree, info);
                    478:        assert(removed);
                    479:        free(info->mem);
                    480:        free(info);
                    481: 
                    482:        /* Done */
                    483:        r = pthread_mutex_unlock(&typed_mem_mutex);
                    484:        assert(r == 0);
                    485:        errno = errno_save;
                    486: }
                    487: 
                    488: /*
                    489:  * calloc(3) replacement
                    490:  */
                    491: void *
                    492: typed_mem_calloc(
                    493: #if TYPED_MEM_TRACE
                    494:        const char *file, u_int line,
                    495: #endif
                    496:        const char *type, size_t num, size_t size)
                    497: {
                    498:        void *mem;
                    499: 
                    500:        size *= num;
                    501: #if TYPED_MEM_TRACE
                    502:        if ((mem = typed_mem_realloc(file, line, type, NULL, size)) == NULL)
                    503:                return (NULL);
                    504: #else
                    505:        if ((mem = typed_mem_realloc(type, NULL, size)) == NULL)
                    506:                return (NULL);
                    507: #endif
                    508:        memset(mem, 0, size);
                    509:        return (mem);
                    510: }
                    511: 
                    512: /*
                    513:  * strdup(3) replacement
                    514:  */
                    515: char *
                    516: typed_mem_strdup(
                    517: #if TYPED_MEM_TRACE
                    518:        const char *file, u_int line,
                    519: #endif
                    520:        const char *type, const char *string)
                    521: {
                    522:        const int slen = strlen(string) + 1;
                    523:        char *result;
                    524: 
                    525: #if TYPED_MEM_TRACE
                    526:        if ((result = typed_mem_realloc(file, line, type, NULL, slen)) == NULL)
                    527:                return (NULL);
                    528: #else
                    529:        if ((result = typed_mem_realloc(type, NULL, slen)) == NULL)
                    530:                return (NULL);
                    531: #endif
                    532:        memcpy(result, string, slen);
                    533:        return (result);
                    534: }
                    535: 
                    536: /*
                    537:  * asprintf(3) replacement
                    538:  */
                    539: int
                    540: typed_mem_asprintf(
                    541: #if TYPED_MEM_TRACE
                    542:        const char *file, u_int line,
                    543: #endif
                    544:        const char *type, char **ret, const char *fmt, ...)
                    545: {
                    546:        va_list args;
                    547:        int r;
                    548: 
                    549:        va_start(args, fmt);
                    550: #if TYPED_MEM_TRACE
                    551:        r = typed_mem_vasprintf(file, line, type, ret, fmt, args);
                    552: #else
                    553:        r = typed_mem_vasprintf(type, ret, fmt, args);
                    554: #endif
                    555:        va_end(args);
                    556:        return (r);
                    557: }
                    558: 
                    559: /*
                    560:  * vasprintf(3) replacement
                    561:  */
                    562: int
                    563: typed_mem_vasprintf(
                    564: #if TYPED_MEM_TRACE
                    565:        const char *file, u_int line,
                    566: #endif
                    567:        const char *type, char **ret, const char *fmt, va_list args)
                    568: {
                    569:        int errno_save;
                    570:        char *s;
                    571:        int r;
                    572: 
                    573:        if ((r = vasprintf(ret, fmt, args)) == -1)
                    574:                return (-1);
                    575:        s = *ret;
                    576: #if TYPED_MEM_TRACE
                    577:        *ret = typed_mem_strdup(file, line, type, s);
                    578: #else
                    579:        *ret = typed_mem_strdup(type, s);
                    580: #endif
                    581:        errno_save = errno;
                    582:        free(s);
                    583:        if (*ret == NULL) {
                    584:                errno = errno_save;
                    585:                return (-1);
                    586:        }
                    587:        return (r);
                    588: }
                    589: 
                    590: /*
                    591:  * Get type for a memory block.
                    592:  */
                    593: char *
                    594: typed_mem_type(const void *mem, char *typebuf)
                    595: {
                    596:        struct mem_info *info = NULL;
                    597:        struct mem_info ikey;
                    598:        int r;
                    599: 
                    600:        /* Are we enabled? */
                    601:        if (!typed_mem_enabled) {
                    602:                errno = ENXIO;
                    603:                return (NULL);
                    604:        }
                    605: 
                    606:        /* Lock info */
                    607:        r = pthread_mutex_lock(&typed_mem_mutex);
                    608:        assert(r == 0);
                    609: 
                    610:        /* Find memory descriptor */
                    611:        ikey.mem = (u_char *)mem - sizeof(typed_mem_guard);
                    612:        if (mem_tree == NULL || (info = gtree_get(mem_tree, &ikey)) == NULL) {
                    613:                errno = ENOENT;
                    614:                typebuf = NULL;
                    615:                goto done;
                    616:        }
                    617: 
                    618:        /* Copy type */
                    619:        strlcpy(typebuf, info->type->name, TYPED_MEM_TYPELEN);
                    620: 
                    621: done:
                    622:        /* Unlock info */
                    623:        r = pthread_mutex_unlock(&typed_mem_mutex);
                    624:        assert(r == 0);
                    625: 
                    626:        /* Done */
                    627:        return (typebuf);
                    628: }
                    629: 
                    630: /*
                    631:  * Return typed memory usage statistics. The caller must free the
                    632:  * array by calling "structs_free(&typed_mem_stats_type, NULL, stats)".
                    633:  *
                    634:  * Returns zero if successful, -1 (and sets errno) if not.
                    635:  * If typed memory is disabled, errno = ENXIO.
                    636:  */
                    637: int
                    638: typed_mem_usage(struct typed_mem_stats *stats)
                    639: {
                    640:        struct mem_type *type;
                    641:        int i;
                    642:        int r;
                    643: 
                    644:        /* Check if enabled */
                    645:        if (!typed_mem_enabled) {
                    646:                errno = ENXIO;
                    647:                return (-1);
                    648:        }
                    649: 
                    650:        /* Lock info */
                    651:        r = pthread_mutex_lock(&typed_mem_mutex);
                    652:        assert(r == 0);
                    653: 
                    654:        /* Allocate array */
                    655:        memset(stats, 0, sizeof(*stats));
                    656:        if ((stats->elems = typed_mem_realloc(
                    657: #if TYPED_MEM_TRACE
                    658:            __FILE__, __LINE__,
                    659: #endif
                    660:            TYPED_MEM_STATS_MTYPE, NULL, (gtree_size(type_tree) + 1)
                    661:            * sizeof(*stats->elems))) == NULL) {
                    662:                r = pthread_mutex_unlock(&typed_mem_mutex);
                    663:                assert(r == 0);
                    664:                return (-1);
                    665:        }
                    666: 
                    667:        /* Copy type stats */
                    668:        for (i = 0, type = gtree_first(type_tree);
                    669:            type != NULL; i++, type = gtree_next(type_tree, type)) {
                    670:                struct typed_mem_typestats *const elem = &stats->elems[i];
                    671: 
                    672:                strlcpy(elem->type, type->name, sizeof(elem->type));
                    673:                elem->allocs = type->count;
                    674:                elem->bytes = type->total;
                    675:        }
                    676:        stats->length = i;
                    677: 
                    678:        /* Unlock info */
                    679:        r = pthread_mutex_unlock(&typed_mem_mutex);
                    680:        assert(r == 0);
                    681: 
                    682:        /* Done */
                    683:        return (0);
                    684: }
                    685: 
                    686: #ifndef _KERNEL
                    687: 
                    688: /*
                    689:  * Return usage statistics in a malloc'd string of the specified type.
                    690:  */
                    691: void
                    692: typed_mem_dump(FILE *fp)
                    693: {
                    694:        u_long total_blocks = 0;
                    695:        u_long total_alloc = 0;
                    696:        struct mem_type *type;
                    697:        int r;
                    698: 
                    699:        /* Check if enabled */
                    700:        if (!typed_mem_enabled) {
                    701:                fprintf(fp, "Typed memory is not enabled.\n");
                    702:                return;
                    703:        }
                    704: 
                    705:        /* Print header */
                    706:        fprintf(fp, "   %-28s %10s %10s\n", "Type", "Count", "Total");
                    707:        fprintf(fp, "   %-28s %10s %10s\n", "----", "-----", "-----");
                    708: 
                    709:        /* Lock info */
                    710:        r = pthread_mutex_lock(&typed_mem_mutex);
                    711:        assert(r == 0);
                    712: 
                    713:        /* Print allocation types */
                    714:        for (type = gtree_first(type_tree);
                    715:            type != NULL; type = gtree_next(type_tree, type)) {
                    716:                fprintf(fp, "   %-28s %10u %10lu\n",
                    717:                    type->name, (int)type->count, (u_long)type->total);
                    718:                total_blocks += type->count;
                    719:                total_alloc += type->total;
                    720:        }
                    721: 
                    722:        /* Print totals */
                    723:        fprintf(fp, "   %-28s %10s %10s\n", "", "-----", "-----");
                    724:        fprintf(fp, "   %-28s %10lu %10lu\n",
                    725:            "Totals", total_blocks, total_alloc);
                    726: 
                    727:        /* Unlock info */
                    728:        r = pthread_mutex_unlock(&typed_mem_mutex);
                    729:        assert(r == 0);
                    730: }
                    731: 
                    732: #endif /* !_KERNEL */
                    733: 
                    734: /*
                    735:  * Find memory block info descriptor and verify guard bytes
                    736:  *
                    737:  * This assumes the mutex is locked.
                    738:  */
                    739: static struct mem_info *
                    740: typed_mem_find(
                    741: #if TYPED_MEM_TRACE
                    742:        const char *file, u_int line,
                    743: #endif
                    744:        void *mem, const char *typename, const char *func)
                    745: {
                    746:        struct mem_info *info = NULL;
                    747:        struct mem_info ikey;
                    748: 
                    749:        /* Find memory descriptor which must already exist */
                    750:        ikey.mem = (u_char *)mem - sizeof(typed_mem_guard);
                    751:        if (mem_tree == NULL || (info = gtree_get(mem_tree, &ikey)) == NULL) {
                    752: #if TYPED_MEM_TRACE
                    753:                WHINE("%s:%u: %s() of unallocated block:"
                    754:                    " ptr=%p type=\"%s\"", file, line, func, mem, typename);
                    755: #else
                    756:                WHINE("%s() of unallocated block:"
                    757:                    " ptr=%p type=\"%s\"", func, mem, typename);
                    758: #endif
                    759:                assert(0);
                    760:        }
                    761: 
                    762:        /* Check type is the same */
                    763:        if (strncmp(info->type->name, typename, TYPED_MEM_TYPELEN - 1) != 0) {
                    764: #if TYPED_MEM_TRACE
                    765:                WHINE("%s:%u: %s() with wrong type:"
                    766:                    " ptr=%p \"%s\" != \"%s\"", file, line,
                    767:                    func, mem, typename, info->type->name);
                    768: #else
                    769:                WHINE("%s() with wrong type:"
                    770:                    " ptr=%p \"%s\" != \"%s\"", 
                    771:                    func, mem, typename, info->type->name);
                    772: #endif
                    773:                assert(0);
                    774:        }
                    775: 
                    776:        /* Check ref count */
                    777:        assert(info->type->count > 0);
                    778: 
                    779:        /* Check guard bytes */
                    780:        if (memcmp(info->mem, typed_mem_guard, sizeof(typed_mem_guard)) != 0) {
                    781: #if TYPED_MEM_TRACE
                    782:                WHINE("%s:%u: %s(): %s guard violated ptr=%p type=\"%s\"",
                    783:                    file, line, func, "head", mem, typename);
                    784: #else
                    785:                WHINE("%s(): %s guard violated ptr=%p type=\"%s\"",
                    786:                    func, "head", mem, typename);
                    787: #endif
                    788:                assert(0);
                    789:        }
                    790:        if (memcmp((u_char *)info->mem + sizeof(typed_mem_guard) + info->size,
                    791:            typed_mem_guard, sizeof(typed_mem_guard)) != 0) {
                    792: #if TYPED_MEM_TRACE
                    793:                WHINE("%s:%u: %s(): %s guard violated ptr=%p type=\"%s\"",
                    794:                    file, line, func, "tail", mem, typename);
                    795: #else
                    796:                WHINE("%s(): %s guard violated ptr=%p type=\"%s\"",
                    797:                    func, "tail", mem, typename);
                    798: #endif
                    799:                assert(0);
                    800:        }
                    801: 
                    802:        /* Done */
                    803:        return (info);
                    804: }
                    805: 
                    806: /*
                    807:  * Sort type descriptors by type string.
                    808:  */
                    809: static int
                    810: type_cmp(struct gtree *g, const void *item1, const void *item2)
                    811: {
                    812:        const struct mem_type *const type1 = item1;
                    813:        const struct mem_type *const type2 = item2;
                    814: 
                    815:        return (strcmp(type1->name, type2->name));
                    816: }
                    817: 
                    818: /*
                    819:  * Print a type
                    820:  */
                    821: static const char *
                    822: type_print(struct gtree *g, const void *item)
                    823: {
                    824:        const struct mem_type *const type = item;
                    825: 
                    826:        return (type->name);
                    827: }
                    828: 
                    829: /*
                    830:  * Sort memory block descriptors by memory address.
                    831:  */
                    832: static int
                    833: mem_cmp(struct gtree *g, const void *item1, const void *item2)
                    834: {
                    835:        const struct mem_info *const info1 = item1;
                    836:        const struct mem_info *const info2 = item2;
                    837: 
                    838:        if (info1->mem < info2->mem)
                    839:                return (-1);
                    840:        if (info1->mem > info2->mem)
                    841:                return (1);
                    842:        return (0);
                    843: }
                    844: 
                    845: #ifndef _KERNEL
                    846: 
                    847: /*
                    848:  * Print a type
                    849:  */
                    850: static const char *
                    851: mem_print(struct gtree *g, const void *item)
                    852: {
                    853:        const struct mem_info *const info = item;
                    854:        static char buf[32];
                    855: 
                    856:        snprintf(buf, sizeof(buf), "%p", info->mem);
                    857:        return (buf);
                    858: }
                    859: 
                    860: #endif /* !_KERNEL */
                    861: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>