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