OLD | NEW |
| (Empty) |
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 corr
uption 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(kBlockHeade
rTag)) == 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 } | |
OLD | NEW |