Rev 7520 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 7520 | Rev 7537 | ||
---|---|---|---|
Line 14... | Line 14... | ||
14 | 14 | ||
Line 15... | Line 15... | ||
15 | #define UINT_MAX (4294967295U) |
15 | #define UINT_MAX (4294967295U) |
16 | 16 | ||
- | 17 | #ifndef NDEBUG |
|
- | 18 | #include |
|
- | 19 | # ifdef __TINYC__ |
|
- | 20 | # include |
|
- | 21 | # define TRACE1(s, a) { char buf[400]; sprintf(buf, s, a); debug_out_str(buf); } |
|
17 | #ifndef NDEBUG |
22 | # define TRACE2(s, a, b) { char buf[400]; sprintf(buf, s, a, b); debug_out_str(buf); } |
18 | #include |
23 | # else |
- | 24 | # define TRACE1(s, a) printf(s, a) |
|
19 | # define TRACE1(s, a) printf(s, a) |
25 | # define TRACE2(s, a, b) printf(s, a, b) |
20 | # define TRACE2(s, a, b) printf(s, a, b) |
26 | # endif |
21 | #else |
27 | #else |
22 | # define TRACE1(s, a) (void)0 |
28 | # define TRACE1(s, a) (void)0 |
Line -... | Line 29... | ||
- | 29 | # define TRACE2(s, a, b) (void)0 |
|
- | 30 | #endif |
|
- | 31 | ||
23 | # define TRACE2(s, a, b) (void)0 |
32 | |
24 | #endif |
33 | |
Line 25... | Line 34... | ||
25 | 34 | ||
26 | // get address, fromwhere function was called |
35 | // get address, fromwhere function was called |
Line 43... | Line 52... | ||
43 | 52 | ||
44 | 53 | ||
45 | static char *__freebase = NULL; // begin of free area |
54 | static char *__freebase = NULL; // begin of free area |
- | 55 | static char *__freetop = NULL; // after last byte of free area |
|
- | 56 | static struct hdrfree *__firstfree = NULL; // ptr to first node in dual-link list |
|
- | 57 | ||
- | 58 | static struct { |
|
- | 59 | uint32_t malloc_calls; |
|
- | 60 | uint32_t malloc_max; |
|
- | 61 | uint32_t malloc_sum; |
|
- | 62 | ||
- | 63 | uint32_t sysalloc_calls; |
|
- | 64 | uint32_t sysalloc_max; |
|
46 | static char *__freetop = NULL; // after last byte of free area |
65 | uint32_t sysalloc_sum; |
- | 66 | ||
- | 67 | uint32_t crtfreeblocks; // number of free blocks, checking corruptions |
|
Line 47... | Line 68... | ||
47 | static struct hdrfree *__firstfree = NULL; // ptr to first node in dual-link list |
68 | uint32_t freeblocks_sum; |
48 | static unsigned __crtfreeblocks = 0; // number of free blocks, checking corruptions |
69 | } wtalloc_stat; |
49 | 70 | ||
50 | 71 | ||
51 | void *wtmalloc(size_t sz) |
72 | void *wtmalloc(size_t sz) |
Line -... | Line 73... | ||
- | 73 | { |
|
- | 74 | struct hdrfree *fndnode, *newnode; |
|
- | 75 | sz = (sizeof(struct hdrused) + sz + 15) & ~15; // align 16bytes |
|
- | 76 | //TRACE1("_call alloc(%d)\n", sz); |
|
- | 77 | ||
52 | { |
78 | //statistics |
53 | struct hdrfree *fndnode, *newnode; |
79 | wtalloc_stat.malloc_calls++; |
54 | sz = (sizeof(struct hdrused) + sz + 15) & ~15; // align 16bytes |
80 | if (sz > wtalloc_stat.malloc_max) wtalloc_stat.malloc_max = sz; |
55 | //TRACE1("_call alloc(%d)\n", sz); |
81 | wtalloc_stat.malloc_sum += sz; |
56 | 82 | ||
Line 72... | Line 98... | ||
72 | if (fndnode) // found free block |
98 | if (fndnode) // found free block |
73 | { |
99 | { |
74 | if (fndnode->size - sz > 15) // split smaller size, move free node |
100 | if (fndnode->size - sz > 15) // split smaller size, move free node |
75 | { |
101 | { |
76 | //TRACE2("alloc(%d) split (%x)\n", sz, fndnode); |
102 | //TRACE2("alloc(%d) split (%x)\n", sz, fndnode); |
- | 103 | wtalloc_stat.freeblocks_sum -= sz; |
|
77 | newnode = (struct hdrfree*)((char*)fndnode + sz); |
104 | newnode = (struct hdrfree*)((char*)fndnode + sz); |
78 | newnode->mark = c_free; |
105 | newnode->mark = c_free; |
79 | newnode->size = fndnode->size - sz; |
106 | newnode->size = fndnode->size - sz; |
80 | newnode->next = fndnode->next; |
107 | newnode->next = fndnode->next; |
81 | newnode->prev = fndnode->prev; |
108 | newnode->prev = fndnode->prev; |
Line 82... | Line 109... | ||
82 | 109 | ||
83 | if (fndnode->next) |
110 | if (fndnode->next) |
Line 84... | Line 111... | ||
84 | fndnode->next->prev = newnode; |
111 | fndnode->next->prev = newnode; |
85 | 112 | ||
86 | //перед может быть не нода, а 1й указатель |
- | |
87 | if (!fndnode->prev) |
- | |
88 | __firstfree = newnode; |
113 | //перед может быть не нода, а 1й указатель |
- | 114 | if (fndnode->prev) |
|
- | 115 | newnode->prev->next = newnode; |
|
89 | else |
116 | else |
90 | newnode->prev->next = newnode; |
117 | __firstfree = newnode; |
91 | } else // nothing to split, just exclude |
118 | } else // nothing to split, just exclude |
Line 92... | Line 119... | ||
92 | { |
119 | { |
- | 120 | //TRACE1("alloc(%d) remove freenode\n", sz); |
|
93 | //TRACE1("alloc(%d) remove freenode\n", sz); |
121 | |
94 | 122 | wtalloc_stat.crtfreeblocks--; |
|
95 | __crtfreeblocks--; |
123 | wtalloc_stat.freeblocks_sum -= fndnode->size; |
96 | if (fndnode->next) |
124 | if (fndnode->next) |
97 | fndnode->next->prev = fndnode->prev; |
- | |
98 | //перед может быть не нода, а 1й указатель |
- | |
99 | if (!fndnode->prev) |
125 | fndnode->next->prev = fndnode->prev; |
- | 126 | //перед может быть не нода, а 1й указатель |
|
- | 127 | if (fndnode->prev) |
|
100 | __firstfree = fndnode->next; |
128 | fndnode->prev->next = fndnode->next; |
Line 101... | Line 129... | ||
101 | else |
129 | else |
102 | fndnode->prev->next = fndnode->next; |
130 | __firstfree = fndnode->next; |
103 | } |
131 | } |
Line 110... | Line 138... | ||
110 | char *ptr; |
138 | char *ptr; |
111 | // free block not found, try to add @end |
139 | // free block not found, try to add @end |
112 | if (__freetop - __freebase < sz) // not enough memory - call system |
140 | if (__freetop - __freebase < sz) // not enough memory - call system |
113 | { |
141 | { |
114 | if (sz > UINT_MAX - 16) return NULL; // check 32-bit heap overflow |
142 | if (sz > UINT_MAX - 16) return NULL; // check 32-bit heap overflow |
115 | size_t new_heap_size = (__freetop - __freebase + sz + 4095) & ~4095; |
143 | // size_t new_heap_size = (__freetop - __freebase + sz + 4095) & ~4095; |
- | 144 | size_t new_heap_size = (sz + sz / 5 + 4095) & ~4095; // 20% reserved |
|
- | 145 | ||
- | 146 | //statistics |
|
- | 147 | wtalloc_stat.sysalloc_calls++; |
|
- | 148 | if (new_heap_size > wtalloc_stat.malloc_max) wtalloc_stat.sysalloc_max = new_heap_size; |
|
- | 149 | wtalloc_stat.sysalloc_sum += new_heap_size; |
|
- | 150 | ||
Line 116... | Line 151... | ||
116 | 151 | ||
117 | //хвост сунуть в свободные, а фритоп и базу перености на новый кусок |
152 | //хвост сунуть в свободные, а фритоп и базу перености на новый кусок |
118 | ptr = sysmalloc(new_heap_size); // rounded 4k |
153 | ptr = sysmalloc(new_heap_size); // rounded 4k |
119 | //TRACE2("call systemalloc(%d) returned %x\n", new_heap_size, ptr); |
154 | //TRACE2("call systemalloc(%d) returned %x\n", new_heap_size, ptr); |
Line 131... | Line 166... | ||
131 | newnode->next = __firstfree; |
166 | newnode->next = __firstfree; |
132 | newnode->prev = NULL; |
167 | newnode->prev = NULL; |
133 | if (__firstfree) |
168 | if (__firstfree) |
134 | __firstfree->prev = newnode; |
169 | __firstfree->prev = newnode; |
135 | __firstfree = newnode; |
170 | __firstfree = newnode; |
136 | __crtfreeblocks++; |
171 | wtalloc_stat.crtfreeblocks++; |
- | 172 | wtalloc_stat.freeblocks_sum += newnode->size; |
|
137 | //TRACE2("alloc(%d) add tail %d to freenode", sz, newnode->size); |
173 | //TRACE2("alloc(%d) add tail %d to freenode", sz, newnode->size); |
138 | //TRACE1(".tail [%x]\n", newnode); |
174 | //TRACE1(".tail [%x]\n", newnode); |
139 | } |
175 | } |
140 | // we don't save allocated block from system, so cant free them ltr |
176 | // we don't save allocated block from system, so cant free them ltr |
Line 147... | Line 183... | ||
147 | ((struct hdrused*)__freebase)->mark = c_used; |
183 | ((struct hdrused*)__freebase)->mark = c_used; |
148 | ((struct hdrused*)__freebase)->size = sz; |
184 | ((struct hdrused*)__freebase)->size = sz; |
149 | __freebase += sz; |
185 | __freebase += sz; |
150 | //TRACE1("__freebase [%x]\n", __freebase); |
186 | //TRACE1("__freebase [%x]\n", __freebase); |
Line -... | Line 187... | ||
- | 187 | ||
- | 188 | ||
- | 189 | // check list availability |
|
- | 190 | /* |
|
- | 191 | int maxfree = 0; |
|
- | 192 | for (fndnode = __firstfree; fndnode; fndnode = fndnode->next) |
|
- | 193 | { |
|
- | 194 | if (fndnode->size > maxfree) maxfree = fndnode->size; |
|
- | 195 | } |
|
- | 196 | ||
- | 197 | TRACE2("alloc(%d) from freebase, maxfree = %d,", sz, maxfree); |
|
- | 198 | TRACE1(" freelist len = %u \n", wtalloc_stat.crtfreeblocks); |
|
151 | 199 | */ |
|
152 | return ptr; |
200 | return ptr; |
Line 153... | Line 201... | ||
153 | } |
201 | } |
154 | 202 | ||
155 | void wtfree(void *ptr) |
203 | void wtfree(void *ptr) |
Line -... | Line 204... | ||
- | 204 | { |
|
- | 205 | if (!ptr) return; |
|
156 | { |
206 | |
157 | if (!ptr) return; |
207 | //TRACE1("free() to freenode, sized %d\n", ((struct hdrused*)((char*)ptr - 8))->size); |
158 | 208 | ||
159 | #ifndef NDEBUG |
209 | #ifndef NDEBUG |
160 | if (((struct hdrused*)((char*)ptr - 8))->mark != c_used) |
210 | if (((struct hdrused*)((char*)ptr - 8))->mark != c_used) |
161 | { |
211 | { |
162 | TRACE2("try free unallocated block ptr = %x bytes EIP@%x\n", ptr, CALLEDFROM(ptr)); |
212 | TRACE2("try free unallocated block ptr = %x bytes EIP@%x\n", ptr, CALLEDFROM(ptr)); |
163 | assert(0); |
213 | assert(0); |
164 | } |
214 | } |
165 | #endif |
215 | #endif |
- | 216 | struct hdrfree *newnode = (struct hdrfree*)((char*)ptr - 8); |
|
- | 217 | newnode->mark = c_free; |
|
- | 218 | //size stays |
|
- | 219 | newnode->next = NULL; |
|
- | 220 | newnode->prev = NULL; |
|
- | 221 | ||
- | 222 | ||
- | 223 | // experimental - try to merge, if adjanced from bottom is also freeblock |
|
- | 224 | int reorganized = 0; |
|
- | 225 | struct hdrfree *higher; |
|
- | 226 | { |
|
- | 227 | struct hdrfree *p1; |
|
- | 228 | higher = NULL; |
|
- | 229 | for (p1 = __firstfree; p1; p1 = p1->next) |
|
- | 230 | { |
|
- | 231 | higher = (struct hdrfree *)((char*)p1 + p1->size); |
|
- | 232 | if (higher == newnode) break; |
|
- | 233 | } |
|
- | 234 | if (p1) // yes, it is |
|
- | 235 | { |
|
- | 236 | wtalloc_stat.freeblocks_sum += newnode->size; |
|
- | 237 | p1->size += newnode->size; |
|
- | 238 | // p1->prev, p1->next already OK |
|
- | 239 | newnode->mark = 0; // for safety |
|
- | 240 | newnode = p1; // continue optimization |
|
- | 241 | //TRACE2("free block merged w/bottom sized %u bytes, list len %u\n", p1->size, wtalloc_stat.crtfreeblocks); |
|
- | 242 | reorganized = 1; |
|
- | 243 | } |
|
- | 244 | } |
|
- | 245 | ||
- | 246 | ||
- | 247 | /* removed, as very seldom succeeds */ |
|
- | 248 | // experimental - try to merge, if adjanced from top is also freeblock |
|
- | 249 | higher = (struct hdrfree *)((char*)newnode + newnode->size); |
|
- | 250 | // dont work - we try to read after our memory |
|
- | 251 | // if ((char*)higher < (char*)__freetop && // saves from reading out of our memory |
|
- | 252 | // higher->mark == c_free) // only suspisious, must be in list |
|
- | 253 | { |
|
- | 254 | struct hdrfree *p1; |
|
- | 255 | for (p1 = __firstfree; p1 && p1 != higher; p1 = p1->next); |
|
- | 256 | if (p1) // yes, it is |
|
- | 257 | { |
|
- | 258 | if (newnode->next || newnode->prev) // optimized 1st stage, must remove from list and readd later |
|
- | 259 | { |
|
- | 260 | wtalloc_stat.crtfreeblocks--; |
|
- | 261 | wtalloc_stat.freeblocks_sum -= newnode->size; |
|
- | 262 | if (newnode->next) |
|
- | 263 | newnode->next->prev = newnode->prev; |
|
- | 264 | if (newnode->prev) |
|
- | 265 | newnode->prev->next = newnode->next; |
|
- | 266 | else |
|
- | 267 | __firstfree = newnode->next; |
|
- | 268 | } |
|
- | 269 | wtalloc_stat.freeblocks_sum += newnode->size; |
|
- | 270 | newnode->size += higher->size; |
|
- | 271 | newnode->prev = higher->prev; |
|
- | 272 | newnode->next = higher->next; |
|
- | 273 | higher->mark = 0; // for safety |
|
- | 274 | if (higher->next) |
|
- | 275 | higher->next->prev = newnode; |
|
- | 276 | if (higher->prev) |
|
- | 277 | higher->prev->next = newnode; |
|
- | 278 | else |
|
- | 279 | __firstfree = newnode; |
|
- | 280 | //TRACE1("free block merged w/top\n", 0); |
|
- | 281 | reorganized = 1; |
|
- | 282 | } |
|
- | 283 | } |
|
- | 284 | ||
- | 285 | if (reorganized) return; // experimental reorganized do all work |
|
- | 286 | ||
- | 287 | //TRACE1("free block added\n", 0); |
|
166 | struct hdrfree *newnode = (struct hdrfree*)((char*)ptr - 8); |
288 | wtalloc_stat.crtfreeblocks++; |
167 | newnode->mark = c_free; |
289 | wtalloc_stat.freeblocks_sum += newnode->size; |
168 | //size stays |
290 | |
169 | newnode->next = __firstfree; |
291 | newnode->next = __firstfree; |
170 | newnode->prev = NULL; |
292 | newnode->prev = NULL; |
171 | if (__firstfree) |
- | |
172 | __firstfree->prev = newnode; |
- | |
173 | __firstfree = newnode; |
293 | if (__firstfree) |
Line 174... | Line 294... | ||
174 | __crtfreeblocks++; |
294 | __firstfree->prev = newnode; |
175 | //TRACE1("free to freenode\n", 0); |
295 | __firstfree = newnode; |
Line 190... | Line 310... | ||
190 | } |
310 | } |
191 | #endif |
311 | #endif |
Line 192... | Line 312... | ||
192 | 312 | ||
Line -... | Line 313... | ||
- | 313 | if (oldptr->size - 8 >= sz) return ptr; // enough room in this block, ex from freelist |
|
- | 314 | ||
- | 315 | /* experimental growth last block */ |
|
- | 316 | int growth = (oldptr->size + sz + 15) & ~15; |
|
- | 317 | if ((char*)oldptr + oldptr->size == __freebase && |
|
- | 318 | __freetop - __freebase + oldptr->size >= growth ) // we at top, can grow up |
|
- | 319 | { |
|
- | 320 | wtalloc_stat.malloc_sum += growth - oldptr->size; |
|
- | 321 | __freebase += growth - oldptr->size; |
|
- | 322 | oldptr->size = growth; |
|
- | 323 | return ptr; |
|
193 | if (oldptr->size - 8 >= sz) return ptr; // enough room in this block, ex from freelist |
324 | } |
194 | 325 | ||
195 | void *newptr = wtmalloc(sz); |
326 | void *newptr = wtmalloc(sz); |
196 | if (newptr) |
327 | if (newptr) |
197 | { |
328 | { |
198 | memcpy(newptr, (char*)oldptr +8, oldptr->size -8); // why -8 dont fail test?!? |
329 | memcpy(newptr, (char*)oldptr +8, oldptr->size -8); // why forgeting -8 dont fail test?!? |
199 | wtfree((char*)oldptr +8); |
330 | wtfree((char*)oldptr +8); |
Line 200... | Line 331... | ||
200 | return newptr; |
331 | return newptr; |
Line 235... | Line 366... | ||
235 | { |
366 | { |
236 | TRACE1("allocated memory freelist check fail, ptr = %x\n", ptr); |
367 | TRACE1("allocated memory freelist check fail, ptr = %x\n", ptr); |
237 | return 0; |
368 | return 0; |
238 | } |
369 | } |
239 | } |
370 | } |
240 | if (cnt != __crtfreeblocks) |
371 | if (cnt != wtalloc_stat.crtfreeblocks) |
241 | { |
372 | { |
242 | TRACE1("allocated memory freelist check fail, length must be = %u\n", __crtfreeblocks); |
373 | TRACE2("allocated memory freelist check fail, length must be = %u but is %u\n", wtalloc_stat.crtfreeblocks, cnt); |
243 | return 0; |
374 | return 0; |
244 | } |
375 | } |
245 | return 1; |
376 | return 1; |
246 | } |
377 | } |
Line -... | Line 378... | ||
- | 378 | ||
- | 379 | void wtmalloc_freelist_print() |
|
- | 380 | { |
|
- | 381 | struct hdrfree *ptr = __firstfree; |
|
- | 382 | for(;ptr; ptr = ptr->next) |
|
- | 383 | { |
|
- | 384 | TRACE2("(%x[%u])", ptr, ptr->size); |
|
- | 385 | } |
|
- | 386 | TRACE1("\n", 0); |
|
- | 387 | ||
- | 388 | } |
|
247 | 389 | ||
248 | int wtmalloc_poiner_check(void *ptr) |
390 | int wtmalloc_poiner_check(void *ptr) |
249 | //контроль указателя - mark OK == 1 |
391 | //контроль указателя - mark OK == 1 |
250 | { |
392 | { |
251 | if (((struct hdrused*)((char*)ptr - 8))->mark != c_used) |
393 | if (((struct hdrused*)((char*)ptr - 8))->mark != c_used) |
252 | { |
394 | { |
253 | TRACE2("pointer watermark check fail ptr = %x bytes EIP@%x\n", ptr, CALLEDFROM(ptr)); |
395 | TRACE2("pointer watermark check fail ptr = %x bytes EIP@%x\n", ptr, CALLEDFROM(ptr)); |
254 | return 0; |
396 | return 0; |
255 | } |
397 | } |
256 | return 1; |
398 | return 1; |
- | 399 | } |
|
- | 400 | ||
- | 401 | void wtdump_alloc_stats() |
|
- | 402 | { |
|
- | 403 | TRACE1("----Watermark allocator stats:----\n", 0); |
|
- | 404 | TRACE2("allocated %u calls, max of %u bytes\n", wtalloc_stat.malloc_calls, wtalloc_stat.malloc_max); |
|
- | 405 | TRACE2("total %u bytes, average call %u bytes\n", wtalloc_stat.malloc_sum, wtalloc_stat.malloc_sum / wtalloc_stat.malloc_calls); |
|
- | 406 | TRACE1("SYSTEM:\n", 0); |
|
- | 407 | TRACE2("allocated %u calls, max of %u bytes\n", wtalloc_stat.sysalloc_calls, wtalloc_stat.sysalloc_max); |
|
- | 408 | TRACE2("total %u bytes, average call %u bytes\n", wtalloc_stat.sysalloc_sum, wtalloc_stat.sysalloc_sum / wtalloc_stat.sysalloc_calls); |
|
- | 409 | TRACE2("free list %u bytes, length %u chunks\n", wtalloc_stat.freeblocks_sum, wtalloc_stat.crtfreeblocks); |