mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-09-01 13:42:51 +08:00
2005-01-20 Sergei Organov <osv@topconrd.ru>
PR 536/rtems Heap manager re-implementation to consume less memory and still satisfy alignment requirements. * score/src/heap.c, score/src/heapallocate.c, score/src/heapextend.c, score/src/heapfree.c, score/src/heapgetinfo.c, score/src/heapgetfreeinfo.c, core/src/heapsizeofuserarea.c, score/src/heapwalk.c, core/macros/rtems/score/heap.inl, score/inline/rtems/score/heap.inl, score/include/rtems/score/heap.h: Reimplemented. * score/src/heapallocatealigned.c: new file * score/Makefile.am: HEAP_C_FILES: add score/src/heapallocatealigned.c
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,7 @@ RTEMS_INLINE_ROUTINE Heap_Block *_Heap_Head (
|
||||
Heap_Control *the_heap
|
||||
)
|
||||
{
|
||||
return (Heap_Block *)&the_heap->start;
|
||||
return &the_heap->free_list;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,129 +45,246 @@ RTEMS_INLINE_ROUTINE Heap_Block *_Heap_Tail (
|
||||
Heap_Control *the_heap
|
||||
)
|
||||
{
|
||||
return (Heap_Block *)&the_heap->final;
|
||||
return &the_heap->free_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the address of the block which physically
|
||||
* precedes the_block in memory.
|
||||
* Return the first free block of the specified heap.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE Heap_Block *_Heap_Previous_block (
|
||||
Heap_Block *the_block
|
||||
RTEMS_INLINE_ROUTINE Heap_Block *_Heap_First (
|
||||
Heap_Control *the_heap
|
||||
)
|
||||
{
|
||||
return (Heap_Block *) _Addresses_Subtract_offset(
|
||||
(void *)the_block,
|
||||
the_block->back_flag & ~ HEAP_BLOCK_USED
|
||||
);
|
||||
return _Heap_Head(the_heap)->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the address of the block which physically
|
||||
* follows the_block in memory.
|
||||
/*PAGE
|
||||
*
|
||||
* @note Next_block assumes that the block is free.
|
||||
* _Heap_Last
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Return the last free block of the specified heap.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE Heap_Block *_Heap_Next_block (
|
||||
RTEMS_INLINE_ROUTINE Heap_Block *_Heap_Last (
|
||||
Heap_Control *the_heap
|
||||
)
|
||||
{
|
||||
return _Heap_Tail(the_heap)->prev;
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Block_remove
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function removes 'the_block' from doubly-linked list.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Heap_Block_remove (
|
||||
Heap_Block *the_block
|
||||
)
|
||||
{
|
||||
return (Heap_Block *) _Addresses_Add_offset(
|
||||
(void *)the_block,
|
||||
the_block->front_flag & ~ HEAP_BLOCK_USED
|
||||
);
|
||||
Heap_Block *block = the_block;
|
||||
|
||||
Heap_Block *next = block->next;
|
||||
Heap_Block *prev = block->prev;
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function replaces @a old_block by @a new_block in doubly-linked list.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Heap_Block_replace (
|
||||
Heap_Block *old_block,
|
||||
Heap_Block *new_block
|
||||
)
|
||||
{
|
||||
Heap_Block *block = old_block;
|
||||
Heap_Block *next = block->next;
|
||||
Heap_Block *prev = block->prev;
|
||||
|
||||
block = new_block;
|
||||
block->next = next;
|
||||
block->prev = prev;
|
||||
next->prev = prev->next = block;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function inserts @a the_block after @a prev_block
|
||||
* in doubly-linked list.
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE void _Heap_Block_insert_after (
|
||||
Heap_Block *prev_block,
|
||||
Heap_Block *the_block
|
||||
)
|
||||
{
|
||||
Heap_Block *prev = prev_block;
|
||||
Heap_Block *block = the_block;
|
||||
|
||||
Heap_Block *next = prev->next;
|
||||
block->next = next;
|
||||
block->prev = prev;
|
||||
next->prev = prev->next = block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return TRUE if @a value is a multiple of @a alignment, FALSE otherwise
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE boolean _Heap_Is_aligned (
|
||||
uint32_t value,
|
||||
uint32_t alignment
|
||||
)
|
||||
{
|
||||
return (value % alignment) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Align @a *value up to the nearest multiple of @a alignment.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Heap_Align_up (
|
||||
uint32_t *value,
|
||||
uint32_t alignment
|
||||
)
|
||||
{
|
||||
uint32_t v = *value;
|
||||
uint32_t a = alignment;
|
||||
uint32_t r = v % a;
|
||||
*value = r ? v - r + a : v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Align @a *value down to the nearest multiple of @a alignment.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Heap_Align_down (
|
||||
uint32_t *value,
|
||||
uint32_t alignment
|
||||
)
|
||||
{
|
||||
uint32_t v = *value;
|
||||
*value = v - (v % alignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return TRUE if @a ptr is aligned at @a alignment boundary,
|
||||
* FALSE otherwise
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE boolean _Heap_Is_aligned_ptr (
|
||||
void *ptr,
|
||||
uint32_t alignment
|
||||
)
|
||||
{
|
||||
return (_H_p2u(ptr) % alignment) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Align @a *value up to the nearest multiple of @a alignment.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Heap_Align_up_uptr (
|
||||
_H_uptr_t *value,
|
||||
uint32_t alignment
|
||||
)
|
||||
{
|
||||
_H_uptr_t v = *value;
|
||||
uint32_t a = alignment;
|
||||
_H_uptr_t r = v % a;
|
||||
*value = r ? v - r + a : v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Align @a *value down to the nearest multiple of @a alignment.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Heap_Align_down_uptr (
|
||||
_H_uptr_t *value,
|
||||
uint32_t alignment
|
||||
)
|
||||
{
|
||||
_H_uptr_t v = *value;
|
||||
*value = v - (v % alignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculates and returns a block's location (address)
|
||||
* in the heap based upon a base address and an offset.
|
||||
* in the heap based upon a base address @a base and an @a offset.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE Heap_Block *_Heap_Block_at(
|
||||
void *base,
|
||||
uint32_t offset
|
||||
uint32_t offset
|
||||
)
|
||||
{
|
||||
return (Heap_Block *) _Addresses_Add_offset( (void *)base, offset );
|
||||
return (Heap_Block *) _Addresses_Add_offset( base, offset );
|
||||
}
|
||||
|
||||
/**
|
||||
* XXX
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE Heap_Block *_Heap_User_block_at(
|
||||
void *base
|
||||
)
|
||||
{
|
||||
uint32_t offset;
|
||||
|
||||
offset = *(((uint32_t *) base) - 1);
|
||||
return _Heap_Block_at( base, -offset + -HEAP_BLOCK_USED_OVERHEAD);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns TRUE if the previous block of the_block
|
||||
* is free, and FALSE otherwise.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE boolean _Heap_Is_previous_block_free (
|
||||
Heap_Block *the_block
|
||||
)
|
||||
{
|
||||
return !(the_block->back_flag & HEAP_BLOCK_USED);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns TRUE if the block is free, and FALSE otherwise.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE boolean _Heap_Is_block_free (
|
||||
Heap_Block *the_block
|
||||
)
|
||||
{
|
||||
return !(the_block->front_flag & HEAP_BLOCK_USED);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns TRUE if the block is currently allocated,
|
||||
* and FALSE otherwise.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE boolean _Heap_Is_block_used (
|
||||
Heap_Block *the_block
|
||||
)
|
||||
{
|
||||
return (the_block->front_flag & HEAP_BLOCK_USED);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the size of the_block in bytes.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE uint32_t _Heap_Block_size (
|
||||
Heap_Block *the_block
|
||||
)
|
||||
{
|
||||
return (the_block->front_flag & ~HEAP_BLOCK_USED);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the starting address of the portion of the block
|
||||
* This function returns the starting address of the portion of @a the_block
|
||||
* which the user may access.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE void *_Heap_Start_of_user_area (
|
||||
RTEMS_INLINE_ROUTINE void *_Heap_User_area (
|
||||
Heap_Block *the_block
|
||||
)
|
||||
{
|
||||
return (void *) &the_block->next;
|
||||
return (void *) _Addresses_Add_offset ( the_block, HEAP_BLOCK_USER_OFFSET );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns TRUE if the_block is within the memory area
|
||||
* managed by the_heap, and FALSE otherwise.
|
||||
* Fill @a *the_block with the address of the beginning of the block given
|
||||
* pointer to the user accessible area @a base.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Heap_Start_of_block (
|
||||
Heap_Control *the_heap,
|
||||
void *base,
|
||||
Heap_Block **the_block
|
||||
)
|
||||
{
|
||||
_H_uptr_t addr = _H_p2u(base);
|
||||
/* The address passed could be greater than the block address plus
|
||||
* HEAP_BLOCK_USER_OFFSET as _Heap_Allocate_aligned() may produce such user
|
||||
* pointers. To get rid of this offset we need to align the address down
|
||||
* to the nearest 'page_size' boundary. */
|
||||
_Heap_Align_down_uptr ( &addr, the_heap->page_size );
|
||||
*the_block = (Heap_Block *)(addr - HEAP_BLOCK_USER_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns TRUE if the previous block of @a the_block
|
||||
* is in use, and FALSE otherwise.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE boolean _Heap_Is_prev_used (
|
||||
Heap_Block *the_block
|
||||
)
|
||||
{
|
||||
return (the_block->size & HEAP_PREV_USED);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the size of @a the_block in bytes.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE uint32_t _Heap_Block_size (
|
||||
Heap_Block *the_block
|
||||
)
|
||||
{
|
||||
return (the_block->size & ~HEAP_PREV_USED);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns TRUE if @a the_block is within the memory area
|
||||
* managed by @a the_heap, and FALSE otherwise.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE boolean _Heap_Is_block_in (
|
||||
@@ -178,35 +295,6 @@ RTEMS_INLINE_ROUTINE boolean _Heap_Is_block_in (
|
||||
return _Addresses_Is_in_range( the_block, the_heap->start, the_heap->final );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function validates a specified heap page size. If the page size
|
||||
* is 0 or if lies outside a page size alignment boundary it is invalid
|
||||
* and FALSE is returned. Otherwise, the page size is valid and TRUE is
|
||||
* returned.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE boolean _Heap_Is_page_size_valid(
|
||||
uint32_t page_size
|
||||
)
|
||||
{
|
||||
return ((page_size != 0) &&
|
||||
((page_size % CPU_HEAP_ALIGNMENT) == 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the block flag composed of size and in_use_flag.
|
||||
* The flag returned is suitable for use as a back or front flag in a
|
||||
* heap block.
|
||||
*/
|
||||
|
||||
RTEMS_INLINE_ROUTINE uint32_t _Heap_Build_flag (
|
||||
uint32_t size,
|
||||
uint32_t in_use_flag
|
||||
)
|
||||
{
|
||||
return size | in_use_flag;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
#ifndef __HEAP_inl
|
||||
#define __HEAP_inl
|
||||
|
||||
/*
|
||||
* WARNING: this file is only visually checked against
|
||||
* '../../../inline/rtems/score/heap.inl'. Use those file for reference
|
||||
* if encounter problems.
|
||||
*/
|
||||
|
||||
#include <rtems/score/address.h>
|
||||
|
||||
/*PAGE
|
||||
@@ -23,40 +29,140 @@
|
||||
* _Heap_Head
|
||||
*/
|
||||
|
||||
#define _Heap_Head( _the_heap ) \
|
||||
((Heap_Block *)&(_the_heap)->start)
|
||||
#define _Heap_Head( _the_heap ) (&(_the_heap)->free_list)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Tail
|
||||
*/
|
||||
|
||||
#define _Heap_Tail( _the_heap ) \
|
||||
((Heap_Block *)&(_the_heap)->final)
|
||||
#define _Heap_Tail( _the_heap ) (&(_the_heap)->free_list)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Previous_block
|
||||
* _Heap_First
|
||||
*/
|
||||
|
||||
#define _Heap_Previous_block( _the_block ) \
|
||||
( (Heap_Block *) _Addresses_Subtract_offset( \
|
||||
(void *)(_the_block), \
|
||||
(_the_block)->back_flag & ~ HEAP_BLOCK_USED \
|
||||
) \
|
||||
)
|
||||
#define _Heap_First( _the_heap ) (_Heap_Head(_the_heap)->next)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Next_block
|
||||
* _Heap_Last
|
||||
*/
|
||||
|
||||
#define _Heap_Next_block( _the_block ) \
|
||||
( (Heap_Block *) _Addresses_Add_offset( \
|
||||
(void *)(_the_block), \
|
||||
(_the_block)->front_flag & ~ HEAP_BLOCK_USED \
|
||||
) \
|
||||
)
|
||||
#define _Heap_Last( _the_heap ) (_Heap_Tail(_the_heap)->prev)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Block_remove
|
||||
*
|
||||
*/
|
||||
|
||||
#define _Heap_Block_remove( _the_block ) \
|
||||
do { \
|
||||
Heap_Block *block = (_the_block); \
|
||||
Heap_Block *next = block->next; \
|
||||
Heap_Block *prev = block->prev; \
|
||||
prev->next = next; \
|
||||
next->prev = prev; \
|
||||
} while(0)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Block_replace
|
||||
*
|
||||
*/
|
||||
|
||||
#define _Heap_Block_replace( _old_block, _new_block ) \
|
||||
do { \
|
||||
Heap_Block *block = (_old_block); \
|
||||
Heap_Block *next = block->next; \
|
||||
Heap_Block *prev = block->prev; \
|
||||
block = (_new_block); \
|
||||
block->next = next; \
|
||||
block->prev = prev; \
|
||||
next->prev = prev->next = block; \
|
||||
} while(0)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Block_insert_after
|
||||
*
|
||||
*/
|
||||
|
||||
#define _Heap_Block_insert_after( _prev_block, _the_block ) \
|
||||
do { \
|
||||
Heap_Block *prev = (_prev_block); \
|
||||
Heap_Block *block = (_the_block); \
|
||||
Heap_Block *next = prev->next; \
|
||||
block->next = next; \
|
||||
block->prev = prev; \
|
||||
next->prev = prev->next = block; \
|
||||
} while(0)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Is_aligned
|
||||
*/
|
||||
|
||||
#define _Heap_Is_aligned( _value, _alignment ) \
|
||||
(((_value) % (_alignment)) == 0)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Align_up
|
||||
*/
|
||||
|
||||
#define _Heap_Align_up( _value, _alignment ) \
|
||||
do { \
|
||||
unsigned32 v = *(_value); \
|
||||
unsigned32 a = (_alignment); \
|
||||
unsigned32 r = v % a; \
|
||||
*(_value) = r ? v - r + a : v; \
|
||||
} while(0)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Align_down
|
||||
*/
|
||||
|
||||
#define _Heap_Align_down( _value, _alignment ) \
|
||||
do { \
|
||||
unsigned32 v = *(_value); \
|
||||
*(_value) = v - (v % (_alignment)); \
|
||||
} while(0)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Is_aligned_ptr
|
||||
*/
|
||||
|
||||
#define _Heap_Is_aligned_ptr( _ptr, _alignment ) \
|
||||
((_H_p2u(_ptr) % (_alignment)) == 0)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Align_up_uptr
|
||||
*/
|
||||
|
||||
#define _Heap_Align_up_uptr( _value, _alignment ) \
|
||||
do { \
|
||||
_H_uptr_t v = *(_value); \
|
||||
unsigned32 a = (_alignment); \
|
||||
_H_uptr_t r = v % a; \
|
||||
*(_value) = r ? v - r + a : v; \
|
||||
} while(0)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Align_down_uptr
|
||||
*/
|
||||
|
||||
#define _Heap_Align_down_uptr( _value, _alignment ) \
|
||||
do { \
|
||||
_H_uptr_t v = *(_value); \
|
||||
*(_value) = v - (v % (_alignment)); \
|
||||
} while(0)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
@@ -64,44 +170,35 @@
|
||||
*/
|
||||
|
||||
#define _Heap_Block_at( _base, _offset ) \
|
||||
( (Heap_Block *) \
|
||||
_Addresses_Add_offset( (void *)(_base), (_offset) ) )
|
||||
( (Heap_Block *) _Addresses_Add_offset( (_base), (_offset) ) )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_User_block_at
|
||||
* _Heap_User_area
|
||||
*/
|
||||
|
||||
#define _Heap_User_area( _the_block ) \
|
||||
((void *) _Addresses_Add_offset( (_the_block), HEAP_BLOCK_USER_OFFSET ))
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Start_of_block
|
||||
*/
|
||||
|
||||
#define _Heap_User_block_at( _base ) \
|
||||
_Heap_Block_at( \
|
||||
(_base), \
|
||||
-*(((uint32_t *) (_base)) - 1) + -HEAP_BLOCK_USED_OVERHEAD \
|
||||
)
|
||||
#define _Heap_Start_of_block( _the_heap, _base, _the_block_ptr ) \
|
||||
do { \
|
||||
_H_uptr_t addr = _H_p2u(_base); \
|
||||
_Heap_Align_down( &addr, (_the_heap)->page_size ); \
|
||||
*(_the_block_ptr) = (Heap_Block *)(addr - HEAP_BLOCK_USER_OFFSET); \
|
||||
} while(0)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Is_previous_block_free
|
||||
* _Heap_Is_prev_used
|
||||
*/
|
||||
|
||||
#define _Heap_Is_previous_block_free( _the_block ) \
|
||||
( !((_the_block)->back_flag & HEAP_BLOCK_USED) )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Is_block_free
|
||||
*/
|
||||
|
||||
#define _Heap_Is_block_free( _the_block ) \
|
||||
( !((_the_block)->front_flag & HEAP_BLOCK_USED) )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Is_block_used
|
||||
*/
|
||||
|
||||
#define _Heap_Is_block_used( _the_block ) \
|
||||
((_the_block)->front_flag & HEAP_BLOCK_USED)
|
||||
#define _Heap_Is_prev_used( _the_block ) \
|
||||
((_the_block)->size & HEAP_PREV_USED)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
@@ -109,15 +206,7 @@
|
||||
*/
|
||||
|
||||
#define _Heap_Block_size( _the_block ) \
|
||||
((_the_block)->front_flag & ~HEAP_BLOCK_USED)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Start_of_user_area
|
||||
*/
|
||||
|
||||
#define _Heap_Start_of_user_area( _the_block ) \
|
||||
((void *) &(_the_block)->next)
|
||||
((_the_block)->size & ~HEAP_PREV_USED)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
@@ -125,25 +214,8 @@
|
||||
*/
|
||||
|
||||
#define _Heap_Is_block_in( _the_heap, _the_block ) \
|
||||
( ((_the_block) >= (_the_heap)->start) && \
|
||||
((_the_block) <= (_the_heap)->final) )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Is_page_size_valid
|
||||
*/
|
||||
|
||||
#define _Heap_Is_page_size_valid( _page_size ) \
|
||||
( ((_page_size) != 0) && \
|
||||
(((_page_size) % CPU_HEAP_ALIGNMENT) == 0) )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Build_flag
|
||||
*/
|
||||
|
||||
#define _Heap_Build_flag( _size, _in_use_flag ) \
|
||||
( (_size) | (_in_use_flag))
|
||||
( _Addresses_Is_in_range( (_the_block), \
|
||||
(_the_heap)->start, (_the_heap)->final ) )
|
||||
|
||||
#endif
|
||||
/* end of include file */
|
||||
|
||||
+206
-37
@@ -16,6 +16,8 @@
|
||||
#include <rtems/score/sysstate.h>
|
||||
#include <rtems/score/heap.h>
|
||||
|
||||
static uint32_t instance = 0;
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Heap_Initialize
|
||||
@@ -32,27 +34,77 @@
|
||||
* returns - maximum memory available if RTEMS_SUCCESSFUL
|
||||
* 0 - otherwise
|
||||
*
|
||||
* This is what a heap looks like in memory immediately
|
||||
* after initialization:
|
||||
* This is what a heap looks like in memory immediately after initialization:
|
||||
*
|
||||
* +--------------------------------+
|
||||
* 0 | size = 0 | status = used | a.k.a. dummy back flag
|
||||
* +--------------------------------+
|
||||
* 4 | size = size-8 | status = free | a.k.a. front flag
|
||||
* +--------------------------------+
|
||||
* 8 | next = PERM HEAP_TAIL |
|
||||
* +--------------------------------+
|
||||
* 12 | previous = PERM HEAP_HEAD |
|
||||
* +--------------------------------+
|
||||
*
|
||||
* +--------------------------------+ <- begin = starting_address
|
||||
* | unused space due to alignment |
|
||||
* | size < page_size |
|
||||
* 0 +--------------------------------+ <- first block
|
||||
* | prev_size = 1 (arbitrary) |
|
||||
* 4 +--------------------------------+
|
||||
* | size = size0 | 1 |
|
||||
* 8 +---------------------+----------+ <- aligned on page_size
|
||||
* | next = HEAP_TAIL | |
|
||||
* 12 +---------------------+ |
|
||||
* | prev = HEAP_HEAD | memory |
|
||||
* +---------------------+ |
|
||||
* | available |
|
||||
* | |
|
||||
* | memory available |
|
||||
* | for allocation |
|
||||
* | for allocation |
|
||||
* | |
|
||||
* +--------------------------------+
|
||||
* size - 8 | size = size-8 | status = free | a.k.a. back flag
|
||||
* +--------------------------------+
|
||||
* size - 4 | size = 0 | status = used | a.k.a. dummy front flag
|
||||
* +--------------------------------+
|
||||
* size0 +--------------------------------+ <- last dummy block
|
||||
* | prev_size = size0 |
|
||||
* +4 +--------------------------------+
|
||||
* | size = 0 (arbitrary) | 0 | <- prev block is free
|
||||
* +8 +--------------------------------+ <- aligned on page_size
|
||||
* | unused space due to alignment |
|
||||
* | size < page_size |
|
||||
* +--------------------------------+ <- end = begin + size
|
||||
*
|
||||
* This is what a heap looks like after first allocation of SIZE bytes.
|
||||
* BSIZE stands for SIZE + 4 aligned up on 'page_size' boundary if allocation
|
||||
* has been performed by _Heap_Allocate(). If allocation has been performed
|
||||
* by _Heap_Allocate_aligned(), the block size BSIZE is defined differently
|
||||
* (see 'heapallocatealigned.c' for details).
|
||||
*
|
||||
* +--------------------------------+ <- begin = starting_address
|
||||
* | unused space due to alignment |
|
||||
* | size < page_size |
|
||||
* 0 +--------------------------------+ <- first block
|
||||
* | prev_size = 1 (arbitrary) |
|
||||
* 4 +--------------------------------+
|
||||
* | size = S = size0 - BSIZE | 1 |
|
||||
* 8 +---------------------+----------+ <- aligned on page_size
|
||||
* | next = HEAP_TAIL | |
|
||||
* 12 +---------------------+ |
|
||||
* | prev = HEAP_HEAD | memory |
|
||||
* +---------------------+ |
|
||||
* | available |
|
||||
* | |
|
||||
* | for allocation |
|
||||
* | |
|
||||
* S +--------------------------------+ <- used block
|
||||
* | prev_size = size0 - BSIZE |
|
||||
* +4 +--------------------------------+
|
||||
* | size = BSIZE | 0 | <- prev block is free
|
||||
* +8 +--------------------------------+ <- aligned on page_size
|
||||
* | . | Pointer returned to the user
|
||||
* | . | is (S+8) for _Heap_Allocate()
|
||||
* | . | and is in range
|
||||
* S + 8 + | user-accessible | [S+8,S+8+page_size) for
|
||||
* page_size+- - - - - -+ _Heap_Allocate_aligned()
|
||||
* | area |
|
||||
* | . |
|
||||
* S + BSIZE +- - - - - . - - - - -+ <- last dummy block
|
||||
* | . |
|
||||
* +4 +--------------------------------+
|
||||
* | size = 0 (arbitrary) | 1 | <- prev block is used
|
||||
* +8 +--------------------------------+ <- aligned on page_size
|
||||
* | unused space due to alignment |
|
||||
* | size < page_size |
|
||||
* +--------------------------------+ <- end = begin + size
|
||||
*
|
||||
*/
|
||||
|
||||
uint32_t _Heap_Initialize(
|
||||
@@ -62,31 +114,148 @@ uint32_t _Heap_Initialize(
|
||||
uint32_t page_size
|
||||
)
|
||||
{
|
||||
Heap_Block *the_block;
|
||||
uint32_t the_size;
|
||||
Heap_Block *the_block;
|
||||
uint32_t the_size;
|
||||
_H_uptr_t start;
|
||||
_H_uptr_t aligned_start;
|
||||
uint32_t overhead;
|
||||
Heap_Statistics *const stats = &the_heap->stats;
|
||||
|
||||
if ( !_Heap_Is_page_size_valid( page_size ) ||
|
||||
(size < HEAP_MINIMUM_SIZE) )
|
||||
return 0;
|
||||
if(page_size == 0)
|
||||
page_size = CPU_ALIGNMENT;
|
||||
else
|
||||
_Heap_Align_up( &page_size, CPU_ALIGNMENT );
|
||||
|
||||
/* Calculate aligned_start so that aligned_start + HEAP_BLOCK_USER_OFFSET
|
||||
(value of user pointer) is aligned on 'page_size' boundary. Make sure
|
||||
resulting 'aligned_start' is not below 'starting_address'. */
|
||||
start = _H_p2u(starting_address);
|
||||
aligned_start = start + HEAP_BLOCK_USER_OFFSET;
|
||||
_Heap_Align_up_uptr ( &aligned_start, page_size );
|
||||
aligned_start -= HEAP_BLOCK_USER_OFFSET;
|
||||
|
||||
/* Calculate 'min_block_size'. It's HEAP_MIN_BLOCK_SIZE aligned up to the
|
||||
nearest multiple of 'page_size'. */
|
||||
the_heap->min_block_size = HEAP_MIN_BLOCK_SIZE;
|
||||
_Heap_Align_up ( &the_heap->min_block_size, page_size );
|
||||
|
||||
/* Calculate 'the_size' -- size of the first block so that there is enough
|
||||
space at the end for the permanent last block. It is equal to 'size'
|
||||
minus total overhead aligned down to the nearest multiple of
|
||||
'page_size'. */
|
||||
overhead = HEAP_OVERHEAD + (aligned_start - start);
|
||||
if ( size < overhead )
|
||||
return 0; /* Too small area for the heap */
|
||||
the_size = size - overhead;
|
||||
_Heap_Align_down ( &the_size, page_size );
|
||||
if ( the_size == 0 )
|
||||
return 0; /* Too small area for the heap */
|
||||
|
||||
the_heap->page_size = page_size;
|
||||
the_size = size - HEAP_OVERHEAD;
|
||||
the_heap->begin = starting_address;
|
||||
the_heap->end = starting_address + size;
|
||||
|
||||
the_block = (Heap_Block *) starting_address;
|
||||
the_block->back_flag = HEAP_DUMMY_FLAG;
|
||||
the_block->front_flag = the_size;
|
||||
the_block->next = _Heap_Tail( the_heap );
|
||||
the_block->previous = _Heap_Head( the_heap );
|
||||
the_block = (Heap_Block *) aligned_start;
|
||||
|
||||
the_heap->start = the_block;
|
||||
the_heap->first = the_block;
|
||||
the_heap->permanent_null = NULL;
|
||||
the_heap->last = the_block;
|
||||
the_block->prev_size = HEAP_PREV_USED;
|
||||
the_block->size = the_size | HEAP_PREV_USED;
|
||||
the_block->next = _Heap_Tail( the_heap );
|
||||
the_block->prev = _Heap_Head( the_heap );
|
||||
_Heap_Head(the_heap)->next = the_block;
|
||||
_Heap_Tail(the_heap)->prev = the_block;
|
||||
the_heap->start = the_block;
|
||||
|
||||
the_block = _Heap_Next_block( the_block );
|
||||
the_block->back_flag = the_size;
|
||||
the_block->front_flag = HEAP_DUMMY_FLAG;
|
||||
the_heap->final = the_block;
|
||||
_HAssert(_Heap_Is_aligned(the_heap->page_size, CPU_ALIGNMENT));
|
||||
_HAssert(_Heap_Is_aligned(the_heap->min_block_size, page_size));
|
||||
_HAssert(_Heap_Is_aligned_ptr(_Heap_User_area(the_block), page_size));
|
||||
|
||||
|
||||
the_block = _Heap_Block_at( the_block, the_size );
|
||||
the_heap->final = the_block; /* Permanent final block of the heap */
|
||||
the_block->prev_size = the_size; /* Previous block is free */
|
||||
the_block->size = 0; /* This is the only block with size=0 */
|
||||
|
||||
stats->size = size;
|
||||
stats->free_size = the_size;
|
||||
stats->min_free_size = the_size;
|
||||
stats->free_blocks = 1;
|
||||
stats->max_free_blocks = 1;
|
||||
stats->used_blocks = 0;
|
||||
stats->max_search = 0;
|
||||
stats->allocs = 0;
|
||||
stats->searches = 0;
|
||||
stats->frees = 0;
|
||||
stats->instance = instance++;
|
||||
|
||||
return ( the_size - HEAP_BLOCK_USED_OVERHEAD );
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* Internal routines shared by _Heap_Allocate() and _Heap_Allocate_aligned().
|
||||
*
|
||||
* Note: there is no reason to put them into a separate file(s) as they are
|
||||
* always required for heap to be usefull.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Convert user requested 'size' of memory block to the block size.
|
||||
* Return block size on success, 0 if overflow occured
|
||||
*/
|
||||
uint32_t _Heap_Calc_block_size(
|
||||
uint32_t size,
|
||||
uint32_t page_size,
|
||||
uint32_t min_size)
|
||||
{
|
||||
uint32_t block_size = size + HEAP_BLOCK_USED_OVERHEAD;
|
||||
_Heap_Align_up(&block_size, page_size);
|
||||
if(block_size < min_size) block_size = min_size;
|
||||
return (block_size > size) ? block_size : 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate block of size 'alloc_size' from 'the_block' belonging to
|
||||
* 'the_heap'. Either split 'the_block' or allocate it entirely.
|
||||
* Return the block allocated.
|
||||
*/
|
||||
Heap_Block* _Heap_Block_allocate(
|
||||
Heap_Control* the_heap,
|
||||
Heap_Block* the_block,
|
||||
uint32_t alloc_size)
|
||||
{
|
||||
Heap_Statistics *const stats = &the_heap->stats;
|
||||
uint32_t const block_size = _Heap_Block_size(the_block);
|
||||
uint32_t const the_rest = block_size - alloc_size;
|
||||
|
||||
_HAssert(_Heap_Is_aligned(block_size, the_heap->page_size));
|
||||
_HAssert(_Heap_Is_aligned(alloc_size, the_heap->page_size));
|
||||
_HAssert(alloc_size <= block_size);
|
||||
|
||||
if(the_rest >= the_heap->min_block_size) {
|
||||
/* Split the block so that lower part is still free, and upper part
|
||||
becomes used. */
|
||||
the_block->size = the_rest | HEAP_PREV_USED;
|
||||
the_block = _Heap_Block_at(the_block, the_rest);
|
||||
the_block->prev_size = the_rest;
|
||||
the_block->size = alloc_size;
|
||||
}
|
||||
else {
|
||||
/* Don't split the block as remainder is either zero or too small to be
|
||||
used as a separate free block. Change 'alloc_size' to the size of the
|
||||
block and remove the block from the list of free blocks. */
|
||||
_Heap_Block_remove(the_block);
|
||||
alloc_size = block_size;
|
||||
stats->free_blocks -= 1;
|
||||
}
|
||||
/* Mark the block as used (in the next block). */
|
||||
_Heap_Block_at(the_block, alloc_size)->size |= HEAP_PREV_USED;
|
||||
/* Update statistics */
|
||||
stats->free_size -= alloc_size;
|
||||
if(stats->min_free_size > stats->free_size)
|
||||
stats->min_free_size = stats->free_size;
|
||||
stats->used_blocks += 1;
|
||||
return the_block;
|
||||
}
|
||||
|
||||
@@ -36,78 +36,43 @@ void *_Heap_Allocate(
|
||||
uint32_t size
|
||||
)
|
||||
{
|
||||
uint32_t excess;
|
||||
uint32_t the_size;
|
||||
uint32_t the_size;
|
||||
uint32_t search_count;
|
||||
Heap_Block *the_block;
|
||||
Heap_Block *next_block;
|
||||
Heap_Block *temporary_block;
|
||||
void *ptr;
|
||||
uint32_t offset;
|
||||
void *ptr = NULL;
|
||||
Heap_Statistics *const stats = &the_heap->stats;
|
||||
Heap_Block *const tail = _Heap_Tail(the_heap);
|
||||
|
||||
/*
|
||||
* Catch the case of a user allocating close to the limit of the
|
||||
* uint32_t .
|
||||
*/
|
||||
the_size =
|
||||
_Heap_Calc_block_size(size, the_heap->page_size, the_heap->min_block_size);
|
||||
if(the_size == 0)
|
||||
return NULL;
|
||||
|
||||
if ( size >= (-1 - HEAP_BLOCK_USED_OVERHEAD) )
|
||||
return( NULL );
|
||||
|
||||
excess = size % the_heap->page_size;
|
||||
the_size = size + the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD;
|
||||
|
||||
if ( excess )
|
||||
the_size += the_heap->page_size - excess;
|
||||
|
||||
if ( the_size < sizeof( Heap_Block ) )
|
||||
the_size = sizeof( Heap_Block );
|
||||
|
||||
for ( the_block = the_heap->first;
|
||||
;
|
||||
the_block = the_block->next ) {
|
||||
if ( the_block == _Heap_Tail( the_heap ) )
|
||||
return( NULL );
|
||||
if ( the_block->front_flag >= the_size )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( (the_block->front_flag - the_size) >
|
||||
(the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD) ) {
|
||||
the_block->front_flag -= the_size;
|
||||
next_block = _Heap_Next_block( the_block );
|
||||
next_block->back_flag = the_block->front_flag;
|
||||
|
||||
temporary_block = _Heap_Block_at( next_block, the_size );
|
||||
temporary_block->back_flag =
|
||||
next_block->front_flag = _Heap_Build_flag( the_size,
|
||||
HEAP_BLOCK_USED );
|
||||
ptr = _Heap_Start_of_user_area( next_block );
|
||||
} else {
|
||||
next_block = _Heap_Next_block( the_block );
|
||||
next_block->back_flag = _Heap_Build_flag( the_block->front_flag,
|
||||
HEAP_BLOCK_USED );
|
||||
the_block->front_flag = next_block->back_flag;
|
||||
the_block->next->previous = the_block->previous;
|
||||
the_block->previous->next = the_block->next;
|
||||
ptr = _Heap_Start_of_user_area( the_block );
|
||||
}
|
||||
|
||||
/*
|
||||
* round ptr up to a multiple of page size
|
||||
* Have to save the bump amount in the buffer so that free can figure it out
|
||||
*/
|
||||
|
||||
offset = the_heap->page_size - (((uint32_t ) ptr) & (the_heap->page_size - 1));
|
||||
ptr = _Addresses_Add_offset( ptr, offset );
|
||||
*(((uint32_t *) ptr) - 1) = offset;
|
||||
|
||||
#ifdef RTEMS_DEBUG
|
||||
/* Find large enough free block. */
|
||||
for(the_block = _Heap_First(the_heap), search_count = 0;
|
||||
the_block != tail;
|
||||
the_block = the_block->next, ++search_count)
|
||||
{
|
||||
uint32_t ptr_u32;
|
||||
ptr_u32 = (uint32_t ) ptr;
|
||||
if (ptr_u32 & (the_heap->page_size - 1))
|
||||
abort();
|
||||
/* As we always coalesce free blocks, prev block must have been used. */
|
||||
_HAssert(_Heap_Is_prev_used(the_block));
|
||||
|
||||
/* Don't bother to mask out the HEAP_PREV_USED bit as it won't change the
|
||||
result of the comparison. */
|
||||
if(the_block->size >= the_size) {
|
||||
the_block = _Heap_Block_allocate(the_heap, the_block, the_size );
|
||||
|
||||
ptr = _Heap_User_area(the_block);
|
||||
|
||||
stats->allocs += 1;
|
||||
stats->searches += search_count + 1;
|
||||
|
||||
_HAssert(_Heap_Is_aligned_ptr(ptr, the_heap->page_size));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(stats->max_search < search_count)
|
||||
stats->max_search = search_count;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ Heap_Extend_status _Heap_Extend(
|
||||
uint32_t *amount_extended
|
||||
)
|
||||
{
|
||||
Heap_Block *the_block;
|
||||
uint32_t *p;
|
||||
uint32_t the_size;
|
||||
Heap_Statistics *const stats = &the_heap->stats;
|
||||
|
||||
/*
|
||||
* The overhead was taken from the original heap memory.
|
||||
@@ -62,22 +62,13 @@ Heap_Extend_status _Heap_Extend(
|
||||
* As noted, this code only supports (4).
|
||||
*/
|
||||
|
||||
if ( starting_address >= (void *) the_heap->start && /* case 3 */
|
||||
starting_address <= (void *) the_heap->final
|
||||
if ( starting_address >= the_heap->begin && /* case 3 */
|
||||
starting_address < the_heap->end
|
||||
)
|
||||
return HEAP_EXTEND_ERROR;
|
||||
|
||||
if ( starting_address < (void *) the_heap->start ) { /* cases 1 and 2 */
|
||||
|
||||
return HEAP_EXTEND_NOT_IMPLEMENTED; /* cases 1 and 2 */
|
||||
|
||||
} else { /* cases 4 and 5 */
|
||||
|
||||
the_block = (Heap_Block *)
|
||||
_Addresses_Subtract_offset( starting_address, HEAP_OVERHEAD );
|
||||
if ( the_block != the_heap->final )
|
||||
return HEAP_EXTEND_NOT_IMPLEMENTED; /* case 5 */
|
||||
}
|
||||
if ( starting_address != the_heap->end )
|
||||
return HEAP_EXTEND_NOT_IMPLEMENTED; /* cases 1, 2, and 5 */
|
||||
|
||||
/*
|
||||
* Currently only case 4 should make it to this point.
|
||||
@@ -85,27 +76,26 @@ Heap_Extend_status _Heap_Extend(
|
||||
* block and free it.
|
||||
*/
|
||||
|
||||
old_final = the_heap->final;
|
||||
the_heap->end = _Addresses_Add_offset( the_heap->end, size );
|
||||
the_size = _Addresses_Subtract( the_heap->end, old_final ) - HEAP_OVERHEAD;
|
||||
_Heap_Align_down( &the_size, the_heap->page_size );
|
||||
|
||||
*amount_extended = size;
|
||||
|
||||
old_final = the_heap->final;
|
||||
new_final = _Addresses_Add_offset( old_final, size );
|
||||
/* SAME AS: _Addresses_Add_offset( starting_address, size-HEAP_OVERHEAD ); */
|
||||
if( the_size < the_heap->min_block_size )
|
||||
return HEAP_EXTEND_SUCCESSFUL;
|
||||
|
||||
old_final->size = the_size | (old_final->size & HEAP_PREV_USED);
|
||||
new_final = _Heap_Block_at( old_final, the_size );
|
||||
new_final->size = HEAP_PREV_USED;
|
||||
the_heap->final = new_final;
|
||||
|
||||
old_final->front_flag =
|
||||
new_final->back_flag = _Heap_Build_flag( size, HEAP_BLOCK_USED );
|
||||
new_final->front_flag = HEAP_DUMMY_FLAG;
|
||||
stats->size += size;
|
||||
stats->used_blocks += 1;
|
||||
stats->frees -= 1; /* Don't count subsequent call as actual free() */
|
||||
|
||||
/*
|
||||
* Must pass in address of "user" area
|
||||
* So add in the offset field.
|
||||
*/
|
||||
|
||||
p = (uint32_t *) &old_final->next;
|
||||
*p = sizeof(uint32_t );
|
||||
p++;
|
||||
_Heap_Free( the_heap, p );
|
||||
_Heap_Free( the_heap, _Heap_User_area( old_final ) );
|
||||
|
||||
return HEAP_EXTEND_SUCCESSFUL;
|
||||
}
|
||||
|
||||
+71
-46
@@ -39,65 +39,90 @@ boolean _Heap_Free(
|
||||
{
|
||||
Heap_Block *the_block;
|
||||
Heap_Block *next_block;
|
||||
Heap_Block *new_next_block;
|
||||
Heap_Block *previous_block;
|
||||
Heap_Block *temporary_block;
|
||||
uint32_t the_size;
|
||||
uint32_t the_size;
|
||||
uint32_t next_size;
|
||||
Heap_Statistics *const stats = &the_heap->stats;
|
||||
boolean next_is_free;
|
||||
|
||||
the_block = _Heap_User_block_at( starting_address );
|
||||
_Heap_Start_of_block( the_heap, starting_address, &the_block );
|
||||
|
||||
if ( !_Heap_Is_block_in( the_heap, the_block ) ||
|
||||
_Heap_Is_block_free( the_block ) ) {
|
||||
return( FALSE );
|
||||
if ( !_Heap_Is_block_in( the_heap, the_block ) ) {
|
||||
_HAssert(starting_address == NULL);
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
the_size = _Heap_Block_size( the_block );
|
||||
the_size = _Heap_Block_size( the_block );
|
||||
next_block = _Heap_Block_at( the_block, the_size );
|
||||
|
||||
if ( !_Heap_Is_block_in( the_heap, next_block ) ||
|
||||
(the_block->front_flag != next_block->back_flag) ) {
|
||||
if ( !_Heap_Is_prev_used( next_block ) ) {
|
||||
_HAssert(FALSE);
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
if ( !_Heap_Is_block_in( the_heap, next_block ) ) {
|
||||
_HAssert(FALSE);
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
next_size = _Heap_Block_size( next_block );
|
||||
next_is_free = next_block < the_heap->final &&
|
||||
!_Heap_Is_prev_used(_Heap_Block_at(next_block, next_size));
|
||||
|
||||
if ( !_Heap_Is_prev_used( the_block ) ) {
|
||||
uint32_t const prev_size = the_block->prev_size;
|
||||
Heap_Block *const prev_block = _Heap_Block_at( the_block, -prev_size );
|
||||
|
||||
if ( !_Heap_Is_block_in( the_heap, prev_block ) ) {
|
||||
_HAssert(FALSE);
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
if ( _Heap_Is_previous_block_free( the_block ) ) {
|
||||
previous_block = _Heap_Previous_block( the_block );
|
||||
|
||||
if ( !_Heap_Is_block_in( the_heap, previous_block ) ) {
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
if ( _Heap_Is_block_free( next_block ) ) { /* coalesce both */
|
||||
previous_block->front_flag += next_block->front_flag + the_size;
|
||||
temporary_block = _Heap_Next_block( previous_block );
|
||||
temporary_block->back_flag = previous_block->front_flag;
|
||||
next_block->next->previous = next_block->previous;
|
||||
next_block->previous->next = next_block->next;
|
||||
/* As we always coalesce free blocks, the block that preceedes prev_block
|
||||
must have been used. */
|
||||
if ( !_Heap_Is_prev_used ( prev_block) ) {
|
||||
_HAssert(FALSE);
|
||||
return( FALSE );
|
||||
}
|
||||
else { /* coalesce prev */
|
||||
previous_block->front_flag =
|
||||
next_block->back_flag = previous_block->front_flag + the_size;
|
||||
}
|
||||
}
|
||||
else if ( _Heap_Is_block_free( next_block ) ) { /* coalesce next */
|
||||
the_block->front_flag = the_size + next_block->front_flag;
|
||||
new_next_block = _Heap_Next_block( the_block );
|
||||
new_next_block->back_flag = the_block->front_flag;
|
||||
the_block->next = next_block->next;
|
||||
the_block->previous = next_block->previous;
|
||||
next_block->previous->next = the_block;
|
||||
next_block->next->previous = the_block;
|
||||
|
||||
if (the_heap->first == next_block)
|
||||
the_heap->first = the_block;
|
||||
if ( next_is_free ) { /* coalesce both */
|
||||
uint32_t const size = the_size + prev_size + next_size;
|
||||
_Heap_Block_remove( next_block );
|
||||
stats->free_blocks -= 1;
|
||||
prev_block->size = size | HEAP_PREV_USED;
|
||||
next_block = _Heap_Block_at( prev_block, size );
|
||||
_HAssert(!_Heap_Is_prev_used( next_block));
|
||||
next_block->prev_size = size;
|
||||
}
|
||||
else { /* coalesce prev */
|
||||
uint32_t const size = the_size + prev_size;
|
||||
prev_block->size = size | HEAP_PREV_USED;
|
||||
next_block->size &= ~HEAP_PREV_USED;
|
||||
next_block->prev_size = size;
|
||||
}
|
||||
}
|
||||
else { /* no coalesce */
|
||||
next_block->back_flag =
|
||||
the_block->front_flag = the_size;
|
||||
the_block->previous = _Heap_Head( the_heap );
|
||||
the_block->next = the_heap->first;
|
||||
the_heap->first = the_block;
|
||||
the_block->next->previous = the_block;
|
||||
else if ( next_is_free ) { /* coalesce next */
|
||||
uint32_t const size = the_size + next_size;
|
||||
_Heap_Block_replace( next_block, the_block );
|
||||
the_block->size = size | HEAP_PREV_USED;
|
||||
next_block = _Heap_Block_at( the_block, size );
|
||||
next_block->prev_size = size;
|
||||
}
|
||||
else { /* no coalesce */
|
||||
/* Add 'the_block' to the head of the free blocks list as it tends to
|
||||
produce less fragmentation than adding to the tail. */
|
||||
_Heap_Block_insert_after( _Heap_Head( the_heap), the_block );
|
||||
the_block->size = the_size | HEAP_PREV_USED;
|
||||
next_block->size &= ~HEAP_PREV_USED;
|
||||
next_block->prev_size = the_size;
|
||||
|
||||
stats->free_blocks += 1;
|
||||
if ( stats->max_free_blocks < stats->free_blocks )
|
||||
stats->max_free_blocks = stats->free_blocks;
|
||||
}
|
||||
|
||||
stats->used_blocks -= 1;
|
||||
stats->free_size += the_size;
|
||||
stats->frees += 1;
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
@@ -37,21 +37,24 @@ void _Heap_Get_free_information(
|
||||
)
|
||||
{
|
||||
Heap_Block *the_block;
|
||||
Heap_Block *const tail = _Heap_Tail(the_heap);
|
||||
|
||||
info->number = 0;
|
||||
info->largest = 0;
|
||||
info->total = 0;
|
||||
|
||||
for ( the_block = the_heap->first;
|
||||
;
|
||||
the_block = the_block->next ) {
|
||||
if ( the_block == _Heap_Tail( the_heap ) )
|
||||
return;
|
||||
|
||||
info->number++;
|
||||
info->total += the_block->front_flag;
|
||||
for(the_block = _Heap_First(the_heap);
|
||||
the_block != tail;
|
||||
the_block = the_block->next)
|
||||
{
|
||||
uint32_t const the_size = _Heap_Block_size(the_block);
|
||||
|
||||
if ( the_block->front_flag >= info->largest )
|
||||
info->largest = the_block->front_flag;
|
||||
/* As we always coalesce free blocks, prev block must have been used. */
|
||||
_HAssert(_Heap_Is_prev_used(the_block));
|
||||
|
||||
info->number++;
|
||||
info->total += the_size;
|
||||
if ( info->largest < the_size )
|
||||
info->largest = the_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
@@ -37,11 +38,11 @@ Heap_Get_information_status _Heap_Get_information(
|
||||
Heap_Information_block *the_info
|
||||
)
|
||||
{
|
||||
Heap_Block *the_block = 0; /* avoid warnings */
|
||||
Heap_Block *next_block = 0; /* avoid warnings */
|
||||
int notdone = 1;
|
||||
uint32_t size;
|
||||
Heap_Block *the_block = the_heap->start;
|
||||
Heap_Block *const end = the_heap->final;
|
||||
|
||||
_HAssert(the_block->prev_size == HEAP_PREV_USED);
|
||||
_HAssert(_Heap_Is_prev_used(the_block));
|
||||
|
||||
the_info->Free.number = 0;
|
||||
the_info->Free.total = 0;
|
||||
@@ -50,60 +51,31 @@ Heap_Get_information_status _Heap_Get_information(
|
||||
the_info->Used.total = 0;
|
||||
the_info->Used.largest = 0;
|
||||
|
||||
/*
|
||||
* We don't want to allow walking the heap until we have
|
||||
* transferred control to the user task so we watch the
|
||||
* system state.
|
||||
*/
|
||||
while ( the_block != end ) {
|
||||
uint32_t const the_size = _Heap_Block_size(the_block);
|
||||
Heap_Block *const next_block = _Heap_Block_at(the_block, the_size);
|
||||
|
||||
if ( !_System_state_Is_up( _System_state_Get() ) )
|
||||
return HEAP_GET_INFORMATION_SYSTEM_STATE_ERROR;
|
||||
if ( _Heap_Is_prev_used(next_block) ) {
|
||||
the_info->Used.number++;
|
||||
the_info->Used.total += the_size;
|
||||
if ( the_info->Used.largest < the_size )
|
||||
the_info->Used.largest = the_size;
|
||||
} else {
|
||||
the_info->Free.number++;
|
||||
the_info->Free.total += the_size;
|
||||
if ( the_info->Free.largest < the_size )
|
||||
the_info->Free.largest = the_size;
|
||||
if ( the_size != next_block->prev_size )
|
||||
return HEAP_GET_INFORMATION_BLOCK_ERROR;
|
||||
}
|
||||
|
||||
the_block = the_heap->start;
|
||||
|
||||
/*
|
||||
* Handle the 1st block
|
||||
*/
|
||||
|
||||
if ( the_block->back_flag != HEAP_DUMMY_FLAG ) {
|
||||
return HEAP_GET_INFORMATION_BLOCK_ERROR;
|
||||
the_block = next_block;
|
||||
}
|
||||
|
||||
while (notdone) {
|
||||
|
||||
/*
|
||||
* Accumulate size
|
||||
*/
|
||||
|
||||
size = _Heap_Block_size(the_block);
|
||||
if ( _Heap_Is_block_free(the_block) ) {
|
||||
the_info->Free.number++;
|
||||
the_info->Free.total += size;
|
||||
if ( size > the_info->Free.largest )
|
||||
the_info->Free.largest = size;
|
||||
} else {
|
||||
the_info->Used.number++;
|
||||
the_info->Used.total += size;
|
||||
if ( size > the_info->Used.largest )
|
||||
the_info->Used.largest = size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the last block
|
||||
*/
|
||||
|
||||
if ( the_block->front_flag != HEAP_DUMMY_FLAG ) {
|
||||
next_block = _Heap_Next_block(the_block);
|
||||
if ( the_block->front_flag != next_block->back_flag ) {
|
||||
return HEAP_GET_INFORMATION_BLOCK_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if ( the_block->front_flag == HEAP_DUMMY_FLAG )
|
||||
notdone = 0;
|
||||
else
|
||||
the_block = next_block;
|
||||
} /* while(notdone) */
|
||||
/* Handle the last dummy block. Don't consider this block to be
|
||||
"used" as client never allocated it. Make 'Used.total' contain this
|
||||
blocks' overhead though. */
|
||||
the_info->Used.total += HEAP_OVERHEAD;
|
||||
|
||||
return HEAP_GET_INFORMATION_SUCCESSFUL;
|
||||
}
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
*
|
||||
* _Heap_Size_of_user_area
|
||||
*
|
||||
* This kernel routine returns the size of the memory area
|
||||
* given heap block.
|
||||
* This kernel routine sets '*size' to the size of the block of memory
|
||||
* which begins at 'starting_address'.
|
||||
* It returns TRUE if the 'starting_address' is in the heap, and FALSE
|
||||
* otherwise.
|
||||
*
|
||||
* Input parameters:
|
||||
* the_heap - pointer to heap header
|
||||
* starting_address - starting address of the memory block to free.
|
||||
* starting_address - starting address of the memory block
|
||||
* size - pointer to size of area
|
||||
*
|
||||
* Output parameters:
|
||||
@@ -37,7 +39,7 @@
|
||||
boolean _Heap_Size_of_user_area(
|
||||
Heap_Control *the_heap,
|
||||
void *starting_address,
|
||||
uint32_t *size
|
||||
size_t *size
|
||||
)
|
||||
{
|
||||
Heap_Block *the_block;
|
||||
@@ -48,22 +50,32 @@ boolean _Heap_Size_of_user_area(
|
||||
starting_address, (void *)the_heap->start, (void *)the_heap->final ) )
|
||||
return( FALSE );
|
||||
|
||||
the_block = _Heap_User_block_at( starting_address );
|
||||
|
||||
if ( !_Heap_Is_block_in( the_heap, the_block ) )
|
||||
return( FALSE );
|
||||
_Heap_Start_of_block( the_heap, starting_address, &the_block );
|
||||
|
||||
if ( _Heap_Is_block_free( the_block ) )
|
||||
if ( !_Heap_Is_block_in( the_heap, the_block ) )
|
||||
return( FALSE );
|
||||
|
||||
the_size = _Heap_Block_size( the_block );
|
||||
next_block = _Heap_Block_at( the_block, the_size );
|
||||
|
||||
if ( !_Heap_Is_block_in( the_heap, next_block ) ||
|
||||
(the_block->front_flag != next_block->back_flag) )
|
||||
if (
|
||||
!_Heap_Is_block_in( the_heap, next_block ) ||
|
||||
!_Heap_Is_prev_used( next_block )
|
||||
)
|
||||
return( FALSE );
|
||||
|
||||
*size = the_size;
|
||||
/* 'starting_address' could be greater than 'the_block' address plus
|
||||
HEAP_BLOCK_USER_OFFSET as _Heap_Allocate_aligned() may produce such user
|
||||
pointers. To get rid of this offset we calculate user size as difference
|
||||
between the end of 'the_block' (='next_block') and 'starting_address'
|
||||
and then add correction equal to the offset of the 'size' field of the
|
||||
'Heap_Block' structure. The correction is due to the fact that
|
||||
'prev_size' field of the next block is actually used as user accessible
|
||||
area of 'the_block'. */
|
||||
|
||||
*size = _Addresses_Subtract ( next_block, starting_address )
|
||||
+ HEAP_BLOCK_HEADER_OFFSET;
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
|
||||
+104
-80
@@ -30,32 +30,32 @@
|
||||
* Output parameters: NONE
|
||||
*/
|
||||
|
||||
#ifndef RTEMS_DEBUG
|
||||
#if !defined(RTEMS_HEAP_DEBUG)
|
||||
|
||||
void _Heap_Walk(
|
||||
boolean _Heap_Walk(
|
||||
Heap_Control *the_heap,
|
||||
int source,
|
||||
boolean do_dump
|
||||
)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#else
|
||||
#else /* defined(RTEMS_HEAP_DEBUG) */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void _Heap_Walk(
|
||||
boolean _Heap_Walk(
|
||||
Heap_Control *the_heap,
|
||||
int source,
|
||||
boolean do_dump
|
||||
)
|
||||
{
|
||||
Heap_Block *the_block = 0; /* avoid warnings */
|
||||
Heap_Block *next_block = 0; /* avoid warnings */
|
||||
int notdone = 1;
|
||||
int error = 0;
|
||||
int passes = 0;
|
||||
Heap_Block *the_block = the_heap->start;
|
||||
Heap_Block *const end = the_heap->final;
|
||||
Heap_Block *const tail = _Heap_Tail(the_heap);
|
||||
int error = 0;
|
||||
int passes = 0;
|
||||
|
||||
/*
|
||||
* We don't want to allow walking the heap until we have
|
||||
@@ -64,86 +64,110 @@ void _Heap_Walk(
|
||||
*/
|
||||
|
||||
if ( !_System_state_Is_up( _System_state_Get() ) )
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
the_block = the_heap->start;
|
||||
if (source < 0)
|
||||
source = the_heap->stats.instance;
|
||||
|
||||
if (do_dump == TRUE) {
|
||||
printf("\nPASS: %d start @ 0x%p final 0x%p, first 0x%p last 0x%p\n",
|
||||
source, the_heap->start, the_heap->final,
|
||||
the_heap->first, the_heap->last
|
||||
);
|
||||
}
|
||||
if (do_dump == TRUE)
|
||||
printf("\nPASS: %d start %p final %p first %p last %p begin %p end %p\n",
|
||||
source, the_block, end,
|
||||
_Heap_First(the_heap), _Heap_Last(the_heap),
|
||||
the_heap->begin, the_heap->end);
|
||||
|
||||
/*
|
||||
* Handle the 1st block
|
||||
*/
|
||||
|
||||
if (the_block->back_flag != HEAP_DUMMY_FLAG) {
|
||||
printf("PASS: %d Back flag of 1st block isn't HEAP_DUMMY_FLAG\n", source);
|
||||
if (!_Heap_Is_prev_used(the_block)) {
|
||||
printf("PASS: %d !HEAP_PREV_USED flag of 1st block isn't set\n", source);
|
||||
error = 1;
|
||||
}
|
||||
|
||||
while (notdone) {
|
||||
passes++;
|
||||
if (error && (passes > 10))
|
||||
abort();
|
||||
|
||||
if (do_dump == TRUE) {
|
||||
printf("PASS: %d Block @ 0x%p Back %d, Front %d",
|
||||
source, the_block,
|
||||
the_block->back_flag, the_block->front_flag);
|
||||
if ( _Heap_Is_block_free(the_block) ) {
|
||||
printf( " Prev 0x%p, Next 0x%p\n",
|
||||
the_block->previous, the_block->next);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the last block
|
||||
*/
|
||||
|
||||
if ( the_block->front_flag != HEAP_DUMMY_FLAG ) {
|
||||
next_block = _Heap_Next_block(the_block);
|
||||
if ( the_block->front_flag != next_block->back_flag ) {
|
||||
error = 1;
|
||||
printf("PASS: %d Front and back flags don't match\n", source);
|
||||
printf(" Current Block (%p): Back - %d, Front - %d",
|
||||
the_block, the_block->back_flag, the_block->front_flag);
|
||||
if (do_dump == TRUE) {
|
||||
if (_Heap_Is_block_free(the_block)) {
|
||||
printf(" Prev 0x%p, Next 0x%p\n",
|
||||
the_block->previous, the_block->next);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
printf(" Next Block (%p): Back - %d, Front - %d",
|
||||
next_block, next_block->back_flag, next_block->front_flag);
|
||||
if (do_dump == TRUE) {
|
||||
if (_Heap_Is_block_free(next_block)) {
|
||||
printf(" Prev 0x%p, Next 0x%p\n",
|
||||
the_block->previous, the_block->next);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (the_block->front_flag == HEAP_DUMMY_FLAG)
|
||||
notdone = 0;
|
||||
else
|
||||
the_block = next_block;
|
||||
if (the_block->prev_size != HEAP_PREV_USED) {
|
||||
printf("PASS: %d !prev_size of 1st block isn't HEAP_PREV_USED\n", source);
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if (error)
|
||||
abort();
|
||||
while ( the_block < end ) {
|
||||
uint32_t const the_size = _Heap_Block_size(the_block);
|
||||
Heap_Block *const next_block = _Heap_Block_at(the_block, the_size);
|
||||
boolean prev_used = _Heap_Is_prev_used(the_block);
|
||||
|
||||
if (do_dump) {
|
||||
printf("PASS: %d block %p size %d(%c)",
|
||||
source, the_block, the_size, (prev_used ? 'U' : 'F'));
|
||||
if (prev_used)
|
||||
printf(" prev_size %d", the_block->prev_size);
|
||||
else
|
||||
printf(" (prev_size) %d", the_block->prev_size);
|
||||
}
|
||||
|
||||
if (!_Heap_Is_block_in(the_heap, next_block)) {
|
||||
if (do_dump) printf("\n");
|
||||
printf("PASS: %d !block %p is out of heap\n", source, next_block);
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_Heap_Is_prev_used(next_block)) {
|
||||
if (do_dump)
|
||||
printf( " prev %p next %p", the_block->prev, the_block->next);
|
||||
if (_Heap_Block_size(the_block) != next_block->prev_size) {
|
||||
if (do_dump) printf("\n");
|
||||
printf("PASS: %d !front and back sizes don't match", source);
|
||||
error = 1;
|
||||
}
|
||||
if (!prev_used) {
|
||||
if (do_dump || error) printf("\n");
|
||||
printf("PASS: %d !two consecutive blocks are free", source);
|
||||
error = 1;
|
||||
}
|
||||
|
||||
{ /* Check if 'the_block' is in the free block list */
|
||||
Heap_Block* block = _Heap_First(the_heap);
|
||||
while(block != the_block && block != tail)
|
||||
block = block->next;
|
||||
if(block != the_block) {
|
||||
if (do_dump || error) printf("\n");
|
||||
printf("PASS: %d !the_block not in the free list", source);
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (do_dump || error) printf("\n");
|
||||
|
||||
if (the_size < the_heap->min_block_size) {
|
||||
printf("PASS: %d !block size is too small\n", source);
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
if (!_Heap_Is_aligned( the_size, the_heap->page_size)) {
|
||||
printf("PASS: %d !block size is misaligned\n", source);
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if (++passes > (do_dump ? 10 : 0) && error)
|
||||
break;
|
||||
|
||||
the_block = next_block;
|
||||
}
|
||||
|
||||
if (the_block != end) {
|
||||
printf("PASS: %d !last block address isn't equal to 'final'\n", source);
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if (_Heap_Block_size(the_block) != 0) {
|
||||
printf("PASS: %d !last block's size isn't 0\n", source);
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if(do_dump && error)
|
||||
abort();
|
||||
|
||||
return error == 0;
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif /* defined(RTEMS_HEAP_DEBUG) */
|
||||
|
||||
Reference in New Issue
Block a user