Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2006 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include "SkTypes.h"
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 
     14 #ifdef SK_DEBUG
     15     #define SK_TAG_BLOCKS
     16     // #define SK_TRACK_ALLOC  // enable to see a printf for every alloc/free
     17     // #define SK_CHECK_TAGS   // enable to double-check debugging link list
     18 #endif
     19 
     20 #ifdef SK_TAG_BLOCKS
     21 
     22 #include "SkThread.h"
     23 
     24 // size this (as a multiple of 4) so that the total offset to the internal data
     25 // is at least a multiple of 8 (since some clients of our malloc may require
     26 // that.
     27 static const char kBlockHeaderTag[] = { 's', 'k', 'i', 'a', '1', '2', '3', '4' };
     28 static const char kBlockTrailerTag[] = { 'a', 'i', 'k', 's' };
     29 #define kByteFill 0xCD
     30 #define kDeleteFill 0xEF
     31 
     32 static SkBaseMutex& get_block_mutex() {
     33     static SkMutex* gBlockMutex;
     34     if (NULL == gBlockMutex) {
     35         gBlockMutex = new SkMutex;
     36     }
     37     return *gBlockMutex;
     38 }
     39 
     40 static struct SkBlockHeader* gHeader;
     41 
     42 struct SkBlockHeader {
     43     SkBlockHeader* fNext;
     44 #ifdef SK_CHECK_TAGS
     45     SkBlockHeader** fTop; // set to verify in debugger that block was alloc'd / freed with same gHeader
     46     SkBlockHeader* fPrevious; // set to see in debugger previous block when corruption happens
     47 #endif
     48     size_t fSize;
     49     char fHeader[sizeof(kBlockHeaderTag)];
     50     // data goes here. The offset to this point must be a multiple of 8
     51     char fTrailer[sizeof(kBlockTrailerTag)];
     52 
     53     void* add(size_t realSize)
     54     {
     55         SkAutoMutexAcquire  ac(get_block_mutex());
     56         InMutexValidate();
     57         fNext = gHeader;
     58 #ifdef SK_CHECK_TAGS
     59         fTop = &gHeader;
     60         fPrevious = NULL;
     61         if (fNext != NULL)
     62             fNext->fPrevious = this;
     63 #endif
     64         gHeader = this;
     65         fSize = realSize;
     66         memcpy(fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag));
     67         void* result = fTrailer;
     68         void* trailer = (char*)result + realSize;
     69         memcpy(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag));
     70         return result;
     71     }
     72 
     73     static void Dump()
     74     {
     75         SkAutoMutexAcquire  ac(get_block_mutex());
     76         InMutexValidate();
     77         SkBlockHeader* header = gHeader;
     78         int count = 0;
     79         size_t size = 0;
     80         while (header != NULL) {
     81             char scratch[256];
     82             char* pos = scratch;
     83             size_t size = header->fSize;
     84             int* data = (int*)(void*)header->fTrailer;
     85             pos += sprintf(pos, "%p 0x%08zx (%7zd)  ",
     86                 data, size, size);
     87             size >>= 2;
     88             size_t ints = size > 4 ? 4 : size;
     89             size_t index;
     90             for (index = 0; index < ints; index++)
     91                 pos += sprintf(pos, "0x%08x ", data[index]);
     92             pos += sprintf(pos, " (");
     93             for (index = 0; index < ints; index++)
     94                 pos += sprintf(pos, "%g ", data[index] / 65536.0f);
     95             if (ints > 0)
     96                 --pos;
     97             pos += sprintf(pos, ") \"");
     98             size_t chars = size > 16 ? 16 : size;
     99             char* chPtr = (char*) data;
    100             for (index = 0; index < chars; index++) {
    101                 char ch = chPtr[index];
    102                 pos += sprintf(pos, "%c", ch >= ' ' && ch < 0x7f ? ch : '?');
    103             }
    104             pos += sprintf(pos, "\"");
    105             SkDebugf("%s\n", scratch);
    106             count++;
    107             size += header->fSize;
    108             header = header->fNext;
    109         }
    110         SkDebugf("--- count %d  size 0x%08x (%zd) ---\n", count, size, size);
    111     }
    112 
    113     void remove() const
    114     {
    115         SkAutoMutexAcquire  ac(get_block_mutex());
    116         SkBlockHeader** findPtr = &gHeader;
    117         do {
    118             SkBlockHeader* find = *findPtr;
    119             SkASSERT(find != NULL);
    120             if (find == this) {
    121                 *findPtr = fNext;
    122                 break;
    123             }
    124             findPtr = &find->fNext;
    125         } while (true);
    126         InMutexValidate();
    127         SkASSERT(memcmp(fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)) == 0);
    128         const char* trailer = fTrailer + fSize;
    129         SkASSERT(memcmp(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)) == 0);
    130     }
    131 
    132     static void Validate()
    133     {
    134         SkAutoMutexAcquire  ac(get_block_mutex());
    135         InMutexValidate();
    136     }
    137 
    138 private:
    139     static void InMutexValidate()
    140     {
    141         SkBlockHeader* header = gHeader;
    142         while (header != NULL) {
    143             SkASSERT(memcmp(header->fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)) == 0);
    144             char* trailer = header->fTrailer + header->fSize;
    145             SkASSERT(memcmp(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)) == 0);
    146             header = header->fNext;
    147         }
    148     }
    149 };
    150 
    151 void ValidateHeap();
    152 void ValidateHeap()
    153 {
    154     SkBlockHeader::Validate();
    155 }
    156 #else
    157 void ValidateHeap() {}
    158 #endif
    159 
    160 void sk_throw()
    161 {
    162     SkDEBUGFAIL("sk_throw");
    163     abort();
    164 }
    165 
    166 void sk_out_of_memory(void)
    167 {
    168     SkDEBUGFAIL("sk_out_of_memory");
    169     abort();
    170 }
    171 
    172 void* sk_malloc_throw(size_t size)
    173 {
    174     return sk_malloc_flags(size, SK_MALLOC_THROW);
    175 }
    176 
    177 void* sk_realloc_throw(void* addr, size_t size)
    178 {
    179 #ifdef SK_TAG_BLOCKS
    180     ValidateHeap();
    181     if (addr != NULL) {
    182         SkBlockHeader* header = (SkBlockHeader*)
    183             ((char*)addr - SK_OFFSETOF(SkBlockHeader, fTrailer));
    184         header->remove();
    185 #ifdef SK_TRACK_ALLOC
    186         printf("sk_realloc_throw %p oldSize=%zd\n", addr, header->fSize);
    187 #endif
    188         addr = header;
    189     }
    190     size_t realSize = size;
    191     if (size)
    192         size += sizeof(SkBlockHeader);
    193 #endif
    194 
    195     void* p = realloc(addr, size);
    196     if (size == 0)
    197     {
    198         ValidateHeap();
    199         return p;
    200     }
    201 
    202     if (p == NULL)
    203         sk_throw();
    204 #ifdef SK_TAG_BLOCKS
    205     else
    206     {
    207         SkBlockHeader* header = (SkBlockHeader*) p;
    208         p = header->add(realSize);
    209 #ifdef SK_TRACK_ALLOC
    210         printf("sk_realloc_throw %p size=%zd\n", p, realSize);
    211 #endif
    212     }
    213 #endif
    214     ValidateHeap();
    215     return p;
    216 }
    217 
    218 void sk_free(void* p)
    219 {
    220     if (p)
    221     {
    222         ValidateHeap();
    223 #ifdef SK_TAG_BLOCKS
    224         SkBlockHeader* header = (SkBlockHeader*)
    225             ((char*)p - SK_OFFSETOF(SkBlockHeader, fTrailer));
    226         header->remove();
    227 #ifdef SK_TRACK_ALLOC
    228         printf("sk_free %p size=%zd\n", p, header->fSize);
    229 #endif
    230         size_t size = header->fSize + sizeof(SkBlockHeader);
    231         memset(header, kDeleteFill, size);
    232         p = header;
    233 #endif
    234         ValidateHeap();
    235         free(p);
    236         ValidateHeap();
    237     }
    238 }
    239 
    240 void* sk_malloc_flags(size_t size, unsigned flags)
    241 {
    242     ValidateHeap();
    243 #ifdef SK_TAG_BLOCKS
    244     size_t realSize = size;
    245     size += sizeof(SkBlockHeader);
    246 #endif
    247 
    248     void* p = malloc(size);
    249     if (p == NULL)
    250     {
    251         if (flags & SK_MALLOC_THROW)
    252             sk_throw();
    253     }
    254 #ifdef SK_TAG_BLOCKS
    255     else
    256     {
    257         SkBlockHeader* header = (SkBlockHeader*) p;
    258         p = header->add(realSize);
    259         memset(p, kByteFill, realSize);
    260 #ifdef SK_TRACK_ALLOC
    261         printf("sk_malloc_flags %p size=%zd\n", p, realSize);
    262 #endif
    263     }
    264 #endif
    265     ValidateHeap();
    266     return p;
    267 }
    268 
    269