heap.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /*
  2. * Copyright (C) 2009 by egnite GmbH
  3. * Copyright (C) 2001-2005 by egnite Software GmbH
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. /*
  36. * $Id: heap.c 4473 2012-08-20 15:12:45Z haraldkipp $
  37. */
  38. /*!
  39. * \addtogroup xgHeap
  40. */
  41. /*@{*/
  42. #include <cfg/os.h>
  43. #include <sys/heap.h>
  44. #include <string.h>
  45. #include <stdint.h>
  46. #ifdef NUTDEBUG_HEAP
  47. #include <sys/nutdebug.h>
  48. #endif
  49. /*
  50. * Set optional memory guard bytes.
  51. */
  52. #ifdef NUTMEM_GUARD
  53. #ifndef NUTMEM_GUARD_PATTERN
  54. #define NUTMEM_GUARD_PATTERN ((int)(0xDEADBEEF))
  55. #endif
  56. #define NUTMEM_GUARD_BYTES sizeof(NUTMEM_GUARD_PATTERN)
  57. #else /* NUTMEM_GUARD */
  58. #define NUTMEM_GUARD_BYTES 0
  59. #endif /* NUTMEM_GUARD */
  60. /*! \brief Number of bytes used for management information. */
  61. #define NUT_HEAP_OVERHEAD (sizeof(HEAPNODE) - sizeof(HEAPNODE *))
  62. /*! \brief Minimum size of a node. */
  63. #ifndef NUTMEM_HEAPNODE_MIN
  64. #define NUTMEM_HEAPNODE_MIN (sizeof(HEAPNODE) + (2 * NUTMEM_GUARD_BYTES))
  65. #endif
  66. /*!
  67. * \brief List of free nodes in normal memory.
  68. */
  69. HEAPNODE *heapFreeList;
  70. #ifdef NUTMEM_SPLIT_FAST
  71. /*!
  72. * \brief List of free nodes in fast memory.
  73. */
  74. HEAPNODE *heapFastMemFreeList;
  75. #endif
  76. #ifdef NUTDEBUG_HEAP
  77. /*!
  78. * \brief List of allocated nodes.
  79. */
  80. static HEAPNODE *heapAllocList;
  81. #endif
  82. /*
  83. * Prepare the user region.
  84. *
  85. * Returns a pointer to the memory block's user region, after optionally
  86. * having added guard patterns at both ends.
  87. */
  88. static INLINE void *PrepareUserArea(HEAPNODE * node)
  89. {
  90. int *tp = (int *) (uintptr_t) &node->hn_next;
  91. #ifdef NUTMEM_GUARD
  92. size_t off = (node->hn_size - NUT_HEAP_OVERHEAD) / sizeof(int) - 2;
  93. *tp++ = NUTMEM_GUARD_PATTERN;
  94. *(tp + off) = NUTMEM_GUARD_PATTERN;
  95. #endif
  96. return tp;
  97. }
  98. /*
  99. * Validate the user region.
  100. *
  101. * If we have guarded user regions, then this routine will do a sanity
  102. * check. If the guards had been overridden, then -1 is returned.
  103. * However, if running in debug mode, then NUTPANIC is called instead.
  104. *
  105. * If the guards are still OK or if guard protection is not available,
  106. * then zero is returned.
  107. */
  108. #ifdef NUTDEBUG_HEAP
  109. static INLINE int DebugValidateUserArea(HEAPNODE * node, const char *file, int line)
  110. #else
  111. static INLINE int ValidateUserArea(HEAPNODE * node)
  112. #endif
  113. {
  114. #ifdef NUTMEM_GUARD
  115. size_t off = (node->hn_size - NUT_HEAP_OVERHEAD) / sizeof(int) - 1;
  116. int *tp = (int *) (uintptr_t) &node->hn_next;
  117. #ifdef NUTDEBUG_HEAP
  118. if (*tp != NUTMEM_GUARD_PATTERN) {
  119. NUTPANIC("%s:%d: Bad memory block at %p\n", file, line, tp + 1);
  120. return -1;
  121. }
  122. if (*(tp + off) != NUTMEM_GUARD_PATTERN) {
  123. 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);
  124. return -1;
  125. }
  126. #else
  127. if (*tp != NUTMEM_GUARD_PATTERN || *(tp + off) != NUTMEM_GUARD_PATTERN) {
  128. return -1;
  129. }
  130. #endif
  131. #endif
  132. return 0;
  133. }
  134. #ifdef NUTDEBUG_HEAP
  135. /*
  136. * Remove a node from the allocation list.
  137. */
  138. static void DebugUnalloc(HEAPNODE * entry, const char *file, int line)
  139. {
  140. HEAPNODE *ht = heapAllocList;
  141. HEAPNODE **htp = &heapAllocList;
  142. while (ht && ht != entry) {
  143. htp = &ht->ht_next;
  144. ht = ht->ht_next;
  145. }
  146. if (ht) {
  147. *htp = entry->ht_next;
  148. } else {
  149. NUTPANIC("%s:%d: Memory block at %p never alloced\n", file, line, entry);
  150. }
  151. }
  152. #endif
  153. /*!
  154. * \brief Allocate a block from heap memory.
  155. *
  156. * This functions allocates a memory block of the specified size and
  157. * returns a pointer to that block.
  158. *
  159. * The actual size of the allocated block is larger than the requested
  160. * size because of space required for maintenance information. This
  161. * additional information is invisible to the application.
  162. *
  163. * The routine looks for the smallest block that will meet the required
  164. * size and releases it to the caller. If the block being requested is
  165. * usefully smaller than the smallest free block then the block from
  166. * which the request is being met is split in two. The unused portion is
  167. * put back into the free-list.
  168. *
  169. * The contents of the allocated block is unspecified. To allocate a
  170. * block with all bytes set to zero use NutHeapAllocClear().
  171. *
  172. * \param root Points to the linked list of free nodes.
  173. * \param size Size of the requested memory block.
  174. *
  175. * \return Pointer to the allocated memory block if the function is
  176. * successful or NULL if no free block of the requested size
  177. * is available.
  178. */
  179. #ifdef NUTDEBUG_HEAP
  180. void *NutHeapDebugRootAlloc(HEAPNODE ** root, size_t size, const char *file, int line)
  181. #else
  182. void *NutHeapRootAlloc(HEAPNODE ** root, size_t size)
  183. #endif
  184. {
  185. HEAPNODE *node;
  186. HEAPNODE **npp;
  187. HEAPNODE *fit = NULL;
  188. HEAPNODE **fpp = NULL;
  189. size_t need;
  190. /* Determine the minimum size. Add optional guard and alignment bytes.
  191. ** Make sure that a HEAPNODE structure fits. */
  192. need = size + NUT_HEAP_OVERHEAD + 2 * NUTMEM_GUARD_BYTES;
  193. if (need < sizeof(HEAPNODE)) {
  194. need = sizeof(HEAPNODE);
  195. }
  196. need = NUTMEM_TOP_ALIGN(need);
  197. /*
  198. * Walk through the linked list of free nodes and find the best fit.
  199. */
  200. node = *root;
  201. npp = root;
  202. while (node) {
  203. /* Found a note that fits? */
  204. if (node->hn_size >= need) {
  205. /* Is it the first one we found or was the previous
  206. ** one larger? */
  207. if (fit == NULL || fit->hn_size > node->hn_size) {
  208. /* This is the best fit so far. */
  209. fit = node;
  210. fpp = npp;
  211. /* Is this an exact match? */
  212. if (node->hn_size == need) {
  213. /* Exact match found. Stop searching. */
  214. break;
  215. }
  216. }
  217. }
  218. npp = &node->hn_next;
  219. node = node->hn_next;
  220. }
  221. if (fit) {
  222. /* Is remaining space of the node we found large enough for
  223. another node? Honor the specified threshold. */
  224. if (fit->hn_size - need >= NUTMEM_HEAPNODE_MIN) {
  225. /* Split the node. */
  226. node = (HEAPNODE *) ((uintptr_t) fit + need);
  227. node->hn_size = fit->hn_size - need;
  228. node->hn_next = fit->hn_next;
  229. fit->hn_size = need;
  230. *fpp = node;
  231. } else {
  232. /* Use the full node. */
  233. *fpp = fit->hn_next;
  234. }
  235. #ifdef NUTDEBUG_HEAP
  236. /* Add debug information. */
  237. fit->ht_size = size;
  238. fit->ht_file = file;
  239. fit->ht_line = line;
  240. /* Add to allocation list. */
  241. fit->ht_next = heapAllocList;
  242. heapAllocList = fit;
  243. #endif
  244. fit = (HEAPNODE *) PrepareUserArea(fit);
  245. }
  246. return fit;
  247. }
  248. /*!
  249. * \brief Allocate an initialized block from heap memory.
  250. *
  251. * This functions allocates a memory block of the specified
  252. * size with all bytes initialized to zero and returns a
  253. * pointer to that block.
  254. *
  255. * \param root Points to the linked list of free nodes.
  256. * \param size Size of the requested memory block.
  257. *
  258. * \return Pointer to the allocated memory block if the
  259. * function is successful or NULL if the requested
  260. * amount of memory is not available.
  261. */
  262. #ifdef NUTDEBUG_HEAP
  263. void *NutHeapDebugRootAllocClear(HEAPNODE ** root, size_t size, const char *file, int line)
  264. {
  265. void *ptr;
  266. if ((ptr = NutHeapDebugRootAlloc(root, size, file, line)) != 0)
  267. memset(ptr, 0, size);
  268. return ptr;
  269. }
  270. #else
  271. void *NutHeapRootAllocClear(HEAPNODE ** root, size_t size)
  272. {
  273. void *ptr;
  274. if ((ptr = NutHeapRootAlloc(root, size)) != 0)
  275. memset(ptr, 0, size);
  276. return ptr;
  277. }
  278. #endif
  279. /*!
  280. * \brief Return a block to heap memory.
  281. *
  282. * An application calls this function, when a previously allocated
  283. * memory block is no longer needed.
  284. *
  285. * The heap manager checks, if the released block adjoins any other
  286. * free regions. If it does, then the adjacent free regions are joined
  287. * together to form one larger region.
  288. *
  289. * \param root Points to the linked list of free nodes.
  290. * \param block Points to a memory block previously allocated.
  291. *
  292. * \return 0 on success, -1 if the caller tried to free a block which
  293. * had been previously released, -2 if the block had been
  294. * corrupted. Furthermore, -3 is returned if block is a NULL
  295. * pointer, but using this may change as C99 allows this.
  296. */
  297. #ifdef NUTDEBUG_HEAP
  298. int NutHeapDebugRootFree(HEAPNODE ** root, void *block, const char *file, int line)
  299. #else
  300. int NutHeapRootFree(HEAPNODE ** root, void *block)
  301. #endif
  302. {
  303. HEAPNODE *node;
  304. HEAPNODE **npp;
  305. HEAPNODE *fnode;
  306. /* IMHO, this should be removed. It adds additional code, which is
  307. useless for most applications. Those, who are interested, can
  308. easily do their own check. C99 declares this as a NUL op. */
  309. if (block == NULL) {
  310. return -3;
  311. }
  312. /* Revive our node pointer. */
  313. fnode = (HEAPNODE *) ((uintptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES));
  314. #ifdef NUTDEBUG_HEAP
  315. /* Sanity check. */
  316. if (DebugValidateUserArea(fnode, file, line)) {
  317. return -2;
  318. }
  319. /* Remove from allocation list. */
  320. if (file) {
  321. DebugUnalloc(fnode, file, line);
  322. }
  323. #else
  324. if (ValidateUserArea(fnode)) {
  325. return -2;
  326. }
  327. #endif
  328. /*
  329. * Walk through the linked list of free nodes and try
  330. * to link us in.
  331. */
  332. node = *root;
  333. npp = root;
  334. while (node) {
  335. /* If this node is directly in front of ours, merge it. */
  336. if ((uintptr_t) node + node->hn_size == (uintptr_t) fnode) {
  337. node->hn_size += fnode->hn_size;
  338. /*
  339. * If another free node is directly following us, merge it.
  340. */
  341. if (((uintptr_t) node + node->hn_size) == (uintptr_t) node->hn_next) {
  342. node->hn_size += node->hn_next->hn_size;
  343. node->hn_next = node->hn_next->hn_next;
  344. }
  345. break;
  346. }
  347. /*
  348. * If we walked past our address, link us to the list.
  349. */
  350. if ((uintptr_t) node > (uintptr_t) fnode) {
  351. *npp = fnode;
  352. /*
  353. * If a free node is following us, merge it.
  354. */
  355. if (((uintptr_t) fnode + fnode->hn_size) == (uintptr_t) node) {
  356. fnode->hn_size += node->hn_size;
  357. fnode->hn_next = node->hn_next;
  358. } else
  359. fnode->hn_next = node;
  360. break;
  361. }
  362. /* If we are within a free node, somebody may have tried to free
  363. a block twice. The panic below does not make much sense, because
  364. if we have NUTDEBUG_HEAP then we will also have NUTMEM_GUARD.
  365. In that case the guard will have been overridden by the link
  366. pointer, which is detected by the ValidateUserArea() above. */
  367. if (((uintptr_t) node + node->hn_size) > (uintptr_t) fnode) {
  368. #ifdef NUTDEBUG_HEAP
  369. NUTPANIC("Trying to release free heap memory at %p in %s:%d\n", file, line);
  370. #endif
  371. return -1;
  372. }
  373. npp = &node->hn_next;
  374. node = node->hn_next;
  375. }
  376. /*
  377. * If no link was found, put us at the end of the list
  378. */
  379. if (node == NULL) {
  380. fnode->hn_next = node;
  381. *npp = fnode;
  382. }
  383. return 0;
  384. }
  385. /*!
  386. * \brief Add a new memory region to the heap.
  387. *
  388. * This function can be called more than once to manage non-continous
  389. * memory regions. It is automatically called by Nut/OS during
  390. * initialization.
  391. *
  392. * \param addr Start address of the memory region.
  393. * \param size Number of bytes of the memory region.
  394. */
  395. void NutHeapRootAdd(HEAPNODE ** root, void *addr, size_t size)
  396. {
  397. HEAPNODE *node = (HEAPNODE *) NUTMEM_TOP_ALIGN((uintptr_t) addr);
  398. node->hn_size = NUTMEM_BOTTOM_ALIGN(size - ((uintptr_t) node - (uintptr_t) addr));
  399. #ifdef NUTDEBUG_HEAP
  400. NutHeapDebugRootFree(root, PrepareUserArea(node), NULL, 0);
  401. #else
  402. NutHeapRootFree(root, PrepareUserArea(node));
  403. #endif
  404. }
  405. /*!
  406. * \brief Return the total number of bytes available.
  407. *
  408. * \return Number of bytes.
  409. */
  410. size_t NutHeapRootAvailable(HEAPNODE ** root)
  411. {
  412. size_t rc = 0;
  413. HEAPNODE *node;
  414. /* Collect all free nodes. */
  415. for (node = *root; node; node = node->hn_next) {
  416. /* Reduce the size of each node by the required overhead. */
  417. rc += node->hn_size - NUT_HEAP_OVERHEAD;
  418. }
  419. return rc;
  420. }
  421. /*!
  422. * \brief Return the size of the largest block available.
  423. *
  424. * \return Number of bytes.
  425. */
  426. size_t NutHeapRootRegionAvailable(HEAPNODE ** root)
  427. {
  428. size_t rc = 0;
  429. HEAPNODE *node;
  430. /* Collect all free nodes. */
  431. for (node = *root; node; node = node->hn_next) {
  432. if (rc < node->hn_size) {
  433. rc = node->hn_size;
  434. }
  435. }
  436. /* Reduce the size by the required overhead. */
  437. return rc - NUT_HEAP_OVERHEAD;
  438. }
  439. /**
  440. * \brief Change the size of an allocated memory block.
  441. *
  442. * If more memory is requested than available at that block the data
  443. * is copied to a new, bigger block.
  444. *
  445. * \param block Points to a previously allocated memory block. If NULL,
  446. * then this call is equivalent to NutHeapRootAlloc().
  447. * \param size The requested new size. If 0, then this call is
  448. * equivalent to NutHeapRootFree().
  449. *
  450. * \return A pointer to the memory block on success or NULL on failures.
  451. */
  452. #ifdef NUTDEBUG_HEAP
  453. void *NutHeapDebugRootRealloc(HEAPNODE ** root, void *block, size_t size, const char *file, int line)
  454. #else
  455. void *NutHeapRootRealloc(HEAPNODE ** root, void *block, size_t size)
  456. #endif
  457. {
  458. HEAPNODE *node;
  459. HEAPNODE **npp;
  460. HEAPNODE *fnode;
  461. void *newmem;
  462. #ifdef NUTDEBUG_HEAP
  463. /* With NULL pointer the call is equivalent to alloc. */
  464. if (block == NULL) {
  465. return NutHeapDebugRootAlloc(root, size, file, line);
  466. }
  467. /* With zero size the call is equivalent to free. */
  468. if (size == 0) {
  469. if (NutHeapDebugRootFree(root, block, file, line)) {
  470. return NULL;
  471. }
  472. return block;
  473. }
  474. /* Revive our node pointer. */
  475. fnode = (HEAPNODE *) ((uintptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES));
  476. /* Sanity check. */
  477. if (DebugValidateUserArea(fnode, file, line)) {
  478. return NULL;
  479. }
  480. #else
  481. if (block == NULL) {
  482. return NutHeapRootAlloc(root, size);
  483. }
  484. if (size == 0) {
  485. if (NutHeapRootFree(root, block)) {
  486. return NULL;
  487. }
  488. return block;
  489. }
  490. fnode = (HEAPNODE *) ((uintptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES));
  491. if (ValidateUserArea(fnode)) {
  492. return NULL;
  493. }
  494. #endif
  495. /* Determine the minimum size. Add optional guard and alignment bytes.
  496. Make sure that a HEAPNODE structure fits. */
  497. size += NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES * 2;
  498. if (size < sizeof(HEAPNODE)) {
  499. size = sizeof(HEAPNODE);
  500. }
  501. size = NUTMEM_TOP_ALIGN(size);
  502. /*
  503. * Expansion.
  504. */
  505. if (size > fnode->hn_size) {
  506. size_t size_miss = size - fnode->hn_size;
  507. /* Find the free node following next. */
  508. node = *root;
  509. npp = root;
  510. while (node && node < fnode) {
  511. npp = &node->hn_next;
  512. node = node->hn_next;
  513. }
  514. /* If we found a node and if this node is large enough and
  515. if it directly follows without a gap, then use it. */
  516. if (node && node->hn_size >= size_miss && /* */
  517. (uintptr_t) fnode + fnode->hn_size == (uintptr_t) node) {
  518. /* Check if the following node is large enough to be split. */
  519. if (node->hn_size - size_miss >= NUTMEM_HEAPNODE_MIN) {
  520. /* Adjust the allocated size. */
  521. fnode->hn_size += size_miss;
  522. /* Insert the remaining part into the free list. */
  523. *npp = (HEAPNODE *) ((uintptr_t) node + size_miss);
  524. /* Due to possible overlapping it is important to set
  525. the pointer first, then the size. */
  526. (*npp)->hn_next = node->hn_next;
  527. (*npp)->hn_size = node->hn_size - size_miss;
  528. PrepareUserArea(fnode);
  529. } else {
  530. /* Adjust the allocated size. */
  531. fnode->hn_size += node->hn_size;
  532. PrepareUserArea(fnode);
  533. /* Remove the merged node from the free list. */
  534. *npp = node->hn_next;
  535. }
  536. /* Return the original pointer. */
  537. return block;
  538. }
  539. /* Relocate if no sufficiently large block follows. */
  540. #ifdef NUTDEBUG_HEAP
  541. newmem = NutHeapDebugRootAlloc(root, size, file, line);
  542. #else
  543. newmem = NutHeapRootAlloc(root, size);
  544. #endif
  545. if (newmem) {
  546. memcpy(newmem, block,
  547. fnode->hn_size - NUT_HEAP_OVERHEAD - 2 * NUTMEM_GUARD_BYTES);
  548. #ifdef NUTDEBUG_HEAP
  549. NutHeapDebugRootFree(root, block, file, line);
  550. #else
  551. NutHeapRootFree(root, block);
  552. #endif
  553. }
  554. return newmem;
  555. }
  556. /*
  557. * Reduction.
  558. */
  559. if (size < fnode->hn_size - NUTMEM_HEAPNODE_MIN) {
  560. /* Release the remaining part to the free list. */
  561. node = (HEAPNODE *) ((uintptr_t) fnode + size);
  562. node->hn_size = fnode->hn_size - size;
  563. #ifdef NUTDEBUG_HEAP
  564. NutHeapDebugRootFree(root, PrepareUserArea(node), NULL, 0);
  565. #else
  566. NutHeapRootFree(root, PrepareUserArea(node));
  567. #endif
  568. /* Adjust the allocated size. */
  569. fnode->hn_size = size;
  570. PrepareUserArea(fnode);
  571. }
  572. return block;
  573. }
  574. /*!
  575. * \brief Check consistency of heap.
  576. *
  577. * Right now this function will just return 0 unless \ref NUTDEBUG_HEAP
  578. * is defined.
  579. *
  580. * \return -1 if any error has been detected, 0 otherwise.
  581. */
  582. int NutHeapCheck(void)
  583. {
  584. #ifdef NUTDEBUG_HEAP
  585. HEAPNODE *node;
  586. for (node = heapAllocList; node; node = node->ht_next) {
  587. if (DebugValidateUserArea(node, __FILE__, __LINE__)) {
  588. return -1;
  589. }
  590. }
  591. #endif
  592. return 0;
  593. }
  594. #include <stdio.h>
  595. /*!
  596. * \brief Dump heap memory to a given stream.
  597. */
  598. void NutHeapDump(void * stream)
  599. {
  600. HEAPNODE *node;
  601. #ifdef NUTMEM_SPLIT_FAST
  602. for (node = heapFastMemFreeList; node; node = node->hn_next) {
  603. fprintf(stream, "%p(%d)\n", node, (int) node->hn_size);
  604. }
  605. #endif
  606. for (node = heapFreeList; node; node = node->hn_next) {
  607. fprintf(stream, "%p(%d)\n", node, (int) node->hn_size);
  608. }
  609. #ifdef NUTDEBUG_HEAP
  610. for (node = heapAllocList; node; node = node->ht_next) {
  611. fprintf(stream, "%p(%u) %s:%d\n", node, (int) node->ht_size, node->ht_file, node->ht_line);
  612. }
  613. #endif
  614. }
  615. /*@}*/