OLD | NEW |
| (Empty) |
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 static bool g_sk_malloc_will_throw = true; | |
29 | |
30 #ifdef SK_TAG_BLOCKS | |
31 | |
32 #include "SkThread.h" | |
33 | |
34 // size this (as a multiple of 4) so that the total offset to the internal data | |
35 // is at least a multiple of 8 (since some clients of our malloc may require | |
36 // that. | |
37 static const char kBlockHeaderTag[] = { 's', 'k', 'i', 'a', '1', '2', '3', '4' }
; | |
38 static const char kBlockTrailerTag[] = { 'a', 'i', 'k', 's' }; | |
39 #define kByteFill 0xCD | |
40 #define kDeleteFill 0xEF | |
41 | |
42 static SkMutex gBlockMutex; | |
43 static struct SkBlockHeader* gHeader; | |
44 | |
45 struct SkBlockHeader { | |
46 SkBlockHeader* fNext; | |
47 #ifdef SK_CHECK_TAGS | |
48 SkBlockHeader** fTop; // set to verify in debugger that block was alloc'd /
freed with same gHeader | |
49 SkBlockHeader* fPrevious; // set to see in debugger previous block when corr
uption happens | |
50 #endif | |
51 size_t fSize; | |
52 char fHeader[sizeof(kBlockHeaderTag)]; | |
53 // data goes here. The offset to this point must be a multiple of 8 | |
54 char fTrailer[sizeof(kBlockTrailerTag)]; | |
55 | |
56 void* add(size_t realSize) | |
57 { | |
58 SkAutoMutexAcquire ac(gBlockMutex); | |
59 InMutexValidate(); | |
60 fNext = gHeader; | |
61 #ifdef SK_CHECK_TAGS | |
62 fTop = &gHeader; | |
63 fPrevious = NULL; | |
64 if (fNext != NULL) | |
65 fNext->fPrevious = this; | |
66 #endif | |
67 gHeader = this; | |
68 fSize = realSize; | |
69 memcpy(fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)); | |
70 void* result = fTrailer; | |
71 void* trailer = (char*)result + realSize; | |
72 memcpy(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)); | |
73 return result; | |
74 } | |
75 | |
76 static void Dump() | |
77 { | |
78 SkAutoMutexAcquire ac(gBlockMutex); | |
79 InMutexValidate(); | |
80 SkBlockHeader* header = gHeader; | |
81 int count = 0; | |
82 size_t size = 0; | |
83 while (header != NULL) { | |
84 char scratch[256]; | |
85 char* pos = scratch; | |
86 size_t size = header->fSize; | |
87 int* data = (int*)(void*)header->fTrailer; | |
88 pos += sprintf(pos, "%p 0x%08zx (%7zd) ", | |
89 data, size, size); | |
90 size >>= 2; | |
91 size_t ints = size > 4 ? 4 : size; | |
92 size_t index; | |
93 for (index = 0; index < ints; index++) | |
94 pos += sprintf(pos, "0x%08x ", data[index]); | |
95 pos += sprintf(pos, " ("); | |
96 for (index = 0; index < ints; index++) | |
97 pos += sprintf(pos, "%g ", data[index] / 65536.0f); | |
98 if (ints > 0) | |
99 --pos; | |
100 pos += sprintf(pos, ") \""); | |
101 size_t chars = size > 16 ? 16 : size; | |
102 char* chPtr = (char*) data; | |
103 for (index = 0; index < chars; index++) { | |
104 char ch = chPtr[index]; | |
105 pos += sprintf(pos, "%c", ch >= ' ' && ch < 0x7f ? ch : '?'); | |
106 } | |
107 pos += sprintf(pos, "\""); | |
108 SkDebugf("%s\n", scratch); | |
109 count++; | |
110 size += header->fSize; | |
111 header = header->fNext; | |
112 } | |
113 SkDebugf("--- count %d size 0x%08x (%zd) ---\n", count, size, size); | |
114 } | |
115 | |
116 void remove() const | |
117 { | |
118 SkAutoMutexAcquire ac(gBlockMutex); | |
119 SkBlockHeader** findPtr = &gHeader; | |
120 do { | |
121 SkBlockHeader* find = *findPtr; | |
122 SkASSERT(find != NULL); | |
123 if (find == this) { | |
124 *findPtr = fNext; | |
125 break; | |
126 } | |
127 findPtr = &find->fNext; | |
128 } while (true); | |
129 InMutexValidate(); | |
130 SkASSERT(memcmp(fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)) == 0)
; | |
131 const char* trailer = fTrailer + fSize; | |
132 SkASSERT(memcmp(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)) ==
0); | |
133 } | |
134 | |
135 static void Validate() | |
136 { | |
137 SkAutoMutexAcquire ac(gBlockMutex); | |
138 InMutexValidate(); | |
139 } | |
140 | |
141 private: | |
142 static void InMutexValidate() | |
143 { | |
144 SkBlockHeader* header = gHeader; | |
145 while (header != NULL) { | |
146 SkASSERT(memcmp(header->fHeader, kBlockHeaderTag, sizeof(kBlockHeade
rTag)) == 0); | |
147 char* trailer = header->fTrailer + header->fSize; | |
148 SkASSERT(memcmp(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag))
== 0); | |
149 header = header->fNext; | |
150 } | |
151 } | |
152 }; | |
153 | |
154 void Dump() | |
155 { | |
156 SkBlockHeader::Dump(); | |
157 } | |
158 | |
159 void ValidateHeap() | |
160 { | |
161 SkBlockHeader::Validate(); | |
162 } | |
163 #else | |
164 void Dump() {} | |
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 if (!(flags & SK_MALLOC_THROW)) { | |
263 g_sk_malloc_will_throw = false; | |
264 } | |
265 void* p = malloc(size); | |
266 if (!(flags & SK_MALLOC_THROW)) { | |
267 g_sk_malloc_will_throw = true; | |
268 } | |
269 if (p == NULL) | |
270 { | |
271 if (flags & SK_MALLOC_THROW) | |
272 sk_throw(); | |
273 } | |
274 #ifdef SK_TAG_BLOCKS | |
275 else | |
276 { | |
277 SkBlockHeader* header = (SkBlockHeader*) p; | |
278 p = header->add(realSize); | |
279 memset(p, kByteFill, realSize); | |
280 #ifdef SK_TRACK_ALLOC | |
281 printf("sk_malloc_flags %p size=%zd\n", p, realSize); | |
282 #endif | |
283 } | |
284 #endif | |
285 ValidateHeap(); | |
286 return p; | |
287 } | |
288 | |
289 bool sk_malloc_will_throw() | |
290 { | |
291 return g_sk_malloc_will_throw; | |
292 } | |
OLD | NEW |