Annotation of embedaddon/mpd/src/contrib/libpdel/util/typed_mem.c, revision 1.1

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

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