00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00045
00046 #include <cfg/os.h>
00047 #include <sys/heap.h>
00048
00049 #include <string.h>
00050 #include <stdint.h>
00051
00052 #ifdef NUTDEBUG_HEAP
00053 #include <sys/nutdebug.h>
00054 #endif
00055
00056
00057
00058
00059 #ifdef NUTMEM_GUARD
00060 #ifndef NUTMEM_GUARD_PATTERN
00061 #define NUTMEM_GUARD_PATTERN ((int)(0xDEADBEEF))
00062 #endif
00063 #define NUTMEM_GUARD_BYTES sizeof(NUTMEM_GUARD_PATTERN)
00064 #else
00065 #define NUTMEM_GUARD_BYTES 0
00066 #endif
00067
00069 #define NUT_HEAP_OVERHEAD (sizeof(HEAPNODE) - sizeof(HEAPNODE *))
00070
00072 #ifndef NUTMEM_HEAPNODE_MIN
00073 #define NUTMEM_HEAPNODE_MIN (sizeof(HEAPNODE) + (2 * NUTMEM_GUARD_BYTES))
00074 #endif
00075
00079 HEAPNODE *heapFreeList;
00080
00081 #ifdef NUTMEM_SPLIT_FAST
00082
00085 HEAPNODE *heapFastMemFreeList;
00086 #endif
00087
00088 #ifdef NUTDEBUG_HEAP
00089
00092 static HEAPNODE *heapAllocList;
00093 #endif
00094
00095
00096
00097
00098
00099
00100
00101 static INLINE void *PrepareUserArea(HEAPNODE * node)
00102 {
00103 int *tp = (int *) (uintptr_t) &node->hn_next;
00104 #ifdef NUTMEM_GUARD
00105 size_t off = (node->hn_size - NUT_HEAP_OVERHEAD) / sizeof(int) - 2;
00106
00107 *tp++ = NUTMEM_GUARD_PATTERN;
00108 *(tp + off) = NUTMEM_GUARD_PATTERN;
00109 #endif
00110 return tp;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 #ifdef NUTDEBUG_HEAP
00124 static INLINE int DebugValidateUserArea(HEAPNODE * node, CONST char *file, int line)
00125 #else
00126 static INLINE int ValidateUserArea(HEAPNODE * node)
00127 #endif
00128 {
00129 #ifdef NUTMEM_GUARD
00130 size_t off = (node->hn_size - NUT_HEAP_OVERHEAD) / sizeof(int) - 1;
00131 int *tp = (int *) (uintptr_t) &node->hn_next;
00132
00133 #ifdef NUTDEBUG_HEAP
00134 if (*tp != NUTMEM_GUARD_PATTERN) {
00135 NUTPANIC("%s:%d: Bad memory block at %p\n", file, line, tp + 1);
00136 return -1;
00137 }
00138 if (*(tp + off) != NUTMEM_GUARD_PATTERN) {
00139 NUTPANIC("%s:%d: Bad memory block at %p with %u bytes allocated in %s:%d\n", file, line, tp + 1, node->ht_size, node->ht_file, node->ht_line);
00140 return -1;
00141 }
00142 #else
00143 if (*tp != NUTMEM_GUARD_PATTERN || *(tp + off) != NUTMEM_GUARD_PATTERN) {
00144 return -1;
00145 }
00146 #endif
00147 #endif
00148 return 0;
00149 }
00150
00151 #ifdef NUTDEBUG_HEAP
00152
00153
00154
00155 static void DebugUnalloc(HEAPNODE * entry, CONST char *file, int line)
00156 {
00157 HEAPNODE *ht = heapAllocList;
00158 HEAPNODE **htp = &heapAllocList;
00159
00160 while (ht && ht != entry) {
00161 htp = &ht->ht_next;
00162 ht = ht->ht_next;
00163 }
00164 if (ht) {
00165 *htp = entry->ht_next;
00166 } else {
00167 NUTPANIC("%s:%d: Memory block at %p never alloced\n", file, line, entry);
00168 }
00169 }
00170 #endif
00171
00198 #ifdef NUTDEBUG_HEAP
00199 void *NutHeapDebugRootAlloc(HEAPNODE ** root, size_t size, CONST char *file, int line)
00200 #else
00201 void *NutHeapRootAlloc(HEAPNODE ** root, size_t size)
00202 #endif
00203 {
00204 HEAPNODE *node;
00205 HEAPNODE **npp;
00206 HEAPNODE *fit = NULL;
00207 HEAPNODE **fpp = NULL;
00208 size_t need;
00209
00210
00211
00212 need = size + NUT_HEAP_OVERHEAD + 2 * NUTMEM_GUARD_BYTES;
00213 if (need < sizeof(HEAPNODE)) {
00214 need = sizeof(HEAPNODE);
00215 }
00216 need = NUTMEM_TOP_ALIGN(need);
00217
00218
00219
00220
00221 node = *root;
00222 npp = root;
00223 while (node) {
00224
00225 if (node->hn_size >= need) {
00226
00227
00228 if (fit == NULL || fit->hn_size > node->hn_size) {
00229
00230 fit = node;
00231 fpp = npp;
00232
00233 if (node->hn_size == need) {
00234
00235 break;
00236 }
00237 }
00238 }
00239 npp = &node->hn_next;
00240 node = node->hn_next;
00241 }
00242
00243 if (fit) {
00244
00245
00246 if (fit->hn_size - need >= NUTMEM_HEAPNODE_MIN) {
00247
00248 node = (HEAPNODE *) ((uintptr_t) fit + need);
00249 node->hn_size = fit->hn_size - need;
00250 node->hn_next = fit->hn_next;
00251 fit->hn_size = need;
00252 *fpp = node;
00253 } else {
00254
00255 *fpp = fit->hn_next;
00256 }
00257 #ifdef NUTDEBUG_HEAP
00258
00259 fit->ht_size = size;
00260 fit->ht_file = file;
00261 fit->ht_line = line;
00262
00263 fit->ht_next = heapAllocList;
00264 heapAllocList = fit;
00265 #endif
00266 fit = (HEAPNODE *) PrepareUserArea(fit);
00267 }
00268 return fit;
00269 }
00270
00285 #ifdef NUTDEBUG_HEAP
00286 void *NutHeapDebugRootAllocClear(HEAPNODE ** root, size_t size, CONST char *file, int line)
00287 {
00288 void *ptr;
00289
00290 if ((ptr = NutHeapDebugRootAlloc(root, size, file, line)) != 0)
00291 memset(ptr, 0, size);
00292
00293 return ptr;
00294 }
00295 #else
00296 void *NutHeapRootAllocClear(HEAPNODE ** root, size_t size)
00297 {
00298 void *ptr;
00299
00300 if ((ptr = NutHeapRootAlloc(root, size)) != 0)
00301 memset(ptr, 0, size);
00302
00303 return ptr;
00304 }
00305 #endif
00306
00325 #ifdef NUTDEBUG_HEAP
00326 int NutHeapDebugRootFree(HEAPNODE ** root, void *block, CONST char *file, int line)
00327 #else
00328 int NutHeapRootFree(HEAPNODE ** root, void *block)
00329 #endif
00330 {
00331 HEAPNODE *node;
00332 HEAPNODE **npp;
00333 HEAPNODE *fnode;
00334
00335
00336
00337
00338 if (block == NULL) {
00339 return -3;
00340 }
00341
00342
00343 fnode = (HEAPNODE *) ((uintptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES));
00344
00345
00346 #ifdef NUTDEBUG_HEAP
00347
00348 if (DebugValidateUserArea(fnode, file, line)) {
00349 return -2;
00350 }
00351
00352 if (file) {
00353 DebugUnalloc(fnode, file, line);
00354 }
00355 #else
00356 if (ValidateUserArea(fnode)) {
00357 return -2;
00358 }
00359 #endif
00360
00361
00362
00363
00364
00365 node = *root;
00366 npp = root;
00367 while (node) {
00368
00369 if ((uintptr_t) node + node->hn_size == (uintptr_t) fnode) {
00370 node->hn_size += fnode->hn_size;
00371
00372
00373
00374
00375 if (((uintptr_t) node + node->hn_size) == (uintptr_t) node->hn_next) {
00376 node->hn_size += node->hn_next->hn_size;
00377 node->hn_next = node->hn_next->hn_next;
00378 }
00379 break;
00380 }
00381
00382
00383
00384
00385 if ((uintptr_t) node > (uintptr_t) fnode) {
00386 *npp = fnode;
00387
00388
00389
00390
00391 if (((uintptr_t) fnode + fnode->hn_size) == (uintptr_t) node) {
00392 fnode->hn_size += node->hn_size;
00393 fnode->hn_next = node->hn_next;
00394 } else
00395 fnode->hn_next = node;
00396 break;
00397 }
00398
00399
00400
00401
00402
00403
00404 if (((uintptr_t) node + node->hn_size) > (uintptr_t) fnode) {
00405 #ifdef NUTDEBUG_HEAP
00406 NUTPANIC("Trying to release free heap memory at %p in %s:%d\n", file, line);
00407 #endif
00408 return -1;
00409 }
00410
00411 npp = &node->hn_next;
00412 node = node->hn_next;
00413 }
00414
00415
00416
00417
00418 if (node == NULL) {
00419 fnode->hn_next = node;
00420 *npp = fnode;
00421 }
00422 return 0;
00423 }
00424
00435 void NutHeapRootAdd(HEAPNODE ** root, void *addr, size_t size)
00436 {
00437 HEAPNODE *node = (HEAPNODE *) NUTMEM_TOP_ALIGN((uintptr_t) addr);
00438
00439 node->hn_size = NUTMEM_BOTTOM_ALIGN(size - ((uintptr_t) node - (uintptr_t) addr));
00440 #ifdef NUTDEBUG_HEAP
00441 NutHeapDebugRootFree(root, PrepareUserArea(node), NULL, 0);
00442 #else
00443 NutHeapRootFree(root, PrepareUserArea(node));
00444 #endif
00445 }
00446
00452 size_t NutHeapRootAvailable(HEAPNODE ** root)
00453 {
00454 size_t rc = 0;
00455 HEAPNODE *node;
00456
00457
00458 for (node = *root; node; node = node->hn_next) {
00459
00460 rc += node->hn_size - NUT_HEAP_OVERHEAD;
00461 }
00462 return rc;
00463 }
00464
00470 size_t NutHeapRootRegionAvailable(HEAPNODE ** root)
00471 {
00472 size_t rc = 0;
00473 HEAPNODE *node;
00474
00475
00476 for (node = *root; node; node = node->hn_next) {
00477 if (rc < node->hn_size) {
00478 rc = node->hn_size;
00479 }
00480 }
00481
00482 return rc - NUT_HEAP_OVERHEAD;
00483 }
00484
00498 #ifdef NUTDEBUG_HEAP
00499 void *NutHeapDebugRootRealloc(HEAPNODE ** root, void *block, size_t size, CONST char *file, int line)
00500 #else
00501 void *NutHeapRootRealloc(HEAPNODE ** root, void *block, size_t size)
00502 #endif
00503 {
00504 HEAPNODE *node;
00505 HEAPNODE **npp;
00506 HEAPNODE *fnode;
00507 void *newmem;
00508
00509 #ifdef NUTDEBUG_HEAP
00510
00511 if (block == NULL) {
00512 return NutHeapDebugRootAlloc(root, size, file, line);
00513 }
00514
00515 if (size == 0) {
00516 if (NutHeapDebugRootFree(root, block, file, line)) {
00517 return NULL;
00518 }
00519 return block;
00520 }
00521
00522
00523 fnode = (HEAPNODE *) ((uintptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES));
00524
00525
00526 if (DebugValidateUserArea(fnode, file, line)) {
00527 return NULL;
00528 }
00529 #else
00530 if (block == NULL) {
00531 return NutHeapRootAlloc(root, size);
00532 }
00533 if (size == 0) {
00534 if (NutHeapRootFree(root, block)) {
00535 return NULL;
00536 }
00537 return block;
00538 }
00539 fnode = (HEAPNODE *) ((uintptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES));
00540 if (ValidateUserArea(fnode)) {
00541 return NULL;
00542 }
00543 #endif
00544
00545
00546
00547 size += NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES * 2;
00548 if (size < sizeof(HEAPNODE)) {
00549 size = sizeof(HEAPNODE);
00550 }
00551 size = NUTMEM_TOP_ALIGN(size);
00552
00553
00554
00555
00556 if (size > fnode->hn_size) {
00557 size_t size_miss = size - fnode->hn_size;
00558
00559
00560 node = *root;
00561 npp = root;
00562 while (node && node < fnode) {
00563 npp = &node->hn_next;
00564 node = node->hn_next;
00565 }
00566
00567
00568
00569 if (node && node->hn_size >= size_miss &&
00570 (uintptr_t) fnode + fnode->hn_size == (uintptr_t) node) {
00571
00572 if (node->hn_size - size_miss >= NUTMEM_HEAPNODE_MIN) {
00573
00574 fnode->hn_size += size_miss;
00575
00576 *npp = (HEAPNODE *) ((uintptr_t) node + size_miss);
00577
00578
00579 (*npp)->hn_next = node->hn_next;
00580 (*npp)->hn_size = node->hn_size - size_miss;
00581 PrepareUserArea(fnode);
00582 } else {
00583
00584 fnode->hn_size += node->hn_size;
00585 PrepareUserArea(fnode);
00586
00587 *npp = node->hn_next;
00588 }
00589
00590 return block;
00591 }
00592
00593
00594 #ifdef NUTDEBUG_HEAP
00595 newmem = NutHeapDebugRootAlloc(root, size, file, line);
00596 #else
00597 newmem = NutHeapRootAlloc(root, size);
00598 #endif
00599 if (newmem) {
00600 memcpy(newmem, block,
00601 fnode->hn_size - NUT_HEAP_OVERHEAD - 2 * NUTMEM_GUARD_BYTES);
00602 #ifdef NUTDEBUG_HEAP
00603 NutHeapDebugRootFree(root, block, file, line);
00604 #else
00605 NutHeapRootFree(root, block);
00606 #endif
00607 }
00608 return newmem;
00609 }
00610
00611
00612
00613
00614 if (size < fnode->hn_size - NUTMEM_HEAPNODE_MIN) {
00615
00616 node = (HEAPNODE *) ((uintptr_t) fnode + size);
00617 node->hn_size = fnode->hn_size - size;
00618 #ifdef NUTDEBUG_HEAP
00619 NutHeapDebugRootFree(root, PrepareUserArea(node), NULL, 0);
00620 #else
00621 NutHeapRootFree(root, PrepareUserArea(node));
00622 #endif
00623
00624 fnode->hn_size = size;
00625 PrepareUserArea(fnode);
00626 }
00627 return block;
00628 }
00629
00638 int NutHeapCheck(void)
00639 {
00640 #ifdef NUTDEBUG_HEAP
00641 HEAPNODE *node;
00642
00643 for (node = heapAllocList; node; node = node->ht_next) {
00644 if (DebugValidateUserArea(node, __FILE__, __LINE__)) {
00645 return -1;
00646 }
00647 }
00648 #endif
00649 return 0;
00650 }
00651
00652 #include <stdio.h>
00653
00657 void NutHeapDump(void * stream)
00658 {
00659 HEAPNODE *node;
00660
00661 #ifdef NUTMEM_SPLIT_FAST
00662 for (node = heapFastMemFreeList; node; node = node->hn_next) {
00663 fprintf(stream, "%p(%d)\n", node, (int) node->hn_size);
00664 }
00665 #endif
00666
00667 for (node = heapFreeList; node; node = node->hn_next) {
00668 fprintf(stream, "%p(%d)\n", node, (int) node->hn_size);
00669 }
00670
00671 #ifdef NUTDEBUG_HEAP
00672 for (node = heapAllocList; node; node = node->ht_next) {
00673 fprintf(stream, "%p(%u) %s:%d\n", node, (int) node->ht_size, node->ht_file, node->ht_line);
00674 }
00675 #endif
00676 }
00677