Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:12

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreHeap
0007  *
0008  * @brief This header file provides interfaces of the
0009  *   @ref RTEMSScoreHeap which are used by the implementation and the
0010  *   @ref RTEMSImplApplConfig.
0011  */
0012 
0013 /*
0014  *  COPYRIGHT (c) 1989-2006.
0015  *  On-Line Applications Research Corporation (OAR).
0016  *
0017  * Redistribution and use in source and binary forms, with or without
0018  * modification, are permitted provided that the following conditions
0019  * are met:
0020  * 1. Redistributions of source code must retain the above copyright
0021  *    notice, this list of conditions and the following disclaimer.
0022  * 2. Redistributions in binary form must reproduce the above copyright
0023  *    notice, this list of conditions and the following disclaimer in the
0024  *    documentation and/or other materials provided with the distribution.
0025  *
0026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0027  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0029  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0030  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0031  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0032  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0035  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0036  * POSSIBILITY OF SUCH DAMAGE.
0037  */
0038 
0039 #ifndef _RTEMS_SCORE_HEAP_H
0040 #define _RTEMS_SCORE_HEAP_H
0041 
0042 #include <rtems/score/cpu.h>
0043 #include <rtems/score/heapinfo.h>
0044 
0045 #ifdef __cplusplus
0046 extern "C" {
0047 #endif
0048 
0049 #ifdef RTEMS_DEBUG
0050   #define HEAP_PROTECTION
0051 #endif
0052 
0053 /**
0054  * @defgroup RTEMSScoreHeap Heap Handler
0055  *
0056  * @ingroup RTEMSScore
0057  *
0058  * @brief This group contains the Heap Handler implementation.
0059  *
0060  * A heap is a doubly linked list of variable size blocks which are allocated
0061  * using the first fit method.  Garbage collection is performed each time a
0062  * block is returned to the heap by coalescing neighbor blocks.  Control
0063  * information for both allocated and free blocks is contained in the heap
0064  * area.  A heap control structure contains control information for the heap.
0065  *
0066  * The alignment routines could be made faster should we require only powers of
0067  * two to be supported for page size, alignment and boundary arguments.  The
0068  * minimum alignment requirement for pages is currently CPU_ALIGNMENT and this
0069  * value is only required to be multiple of two and explicitly not required to
0070  * be a power of two.
0071  *
0072  * There are two kinds of blocks.  One sort describes a free block from which
0073  * we can allocate memory.  The other blocks are used and provide an allocated
0074  * memory area.  The free blocks are accessible via a list of free blocks.
0075  *
0076  * Blocks or areas cover a continuous set of memory addresses. They have a
0077  * begin and end address.  The end address is not part of the set.  The size of
0078  * a block or area equals the distance between the begin and end address in
0079  * units of bytes.
0080  *
0081  * Free blocks look like:
0082  * <table>
0083  *   <tr>
0084  *     <td rowspan=4>@ref Heap_Block</td><td>previous block size in case the
0085  *       previous block is free, <br> otherwise it may contain data used by
0086  *       the previous block</td>
0087  *   </tr>
0088  *   <tr>
0089  *     <td>block size and a flag which indicates if the previous block is free
0090  *       or used, <br> this field contains always valid data regardless of the
0091  *       block usage</td>
0092  *   </tr>
0093  *   <tr><td>pointer to next block (this field is page size aligned)</td></tr>
0094  *   <tr><td>pointer to previous block</td></tr>
0095  *   <tr><td colspan=2>free space</td></tr>
0096  * </table>
0097  *
0098  * Used blocks look like:
0099  * <table>
0100  *   <tr>
0101  *     <td rowspan=4>@ref Heap_Block</td><td>previous block size in case the
0102  *       previous block is free,<br>otherwise it may contain data used by
0103  *       the previous block</td>
0104  *   </tr>
0105  *   <tr>
0106  *     <td>block size and a flag which indicates if the previous block is free
0107  *       or used, <br> this field contains always valid data regardless of the
0108  *       block usage</td>
0109  *   </tr>
0110  *   <tr><td>begin of allocated area (this field is page size aligned)</td></tr>
0111  *   <tr><td>allocated space</td></tr>
0112  *   <tr><td colspan=2>allocated space</td></tr>
0113  * </table>
0114  *
0115  * The heap area after initialization contains two blocks and looks like:
0116  * <table>
0117  *   <tr><th>Label</th><th colspan=2>Content</th></tr>
0118  *   <tr><td>heap->area_begin</td><td colspan=2>heap area begin address</td></tr>
0119  *   <tr>
0120  *     <td>first_block->prev_size</td>
0121  *     <td colspan=2>
0122  *       subordinate heap area end address (this will be used to maintain a
0123  *       linked list of scattered heap areas)
0124  *     </td>
0125  *   </tr>
0126  *   <tr>
0127  *     <td>first_block->size</td>
0128  *     <td colspan=2>size available for allocation
0129  *       | @c HEAP_PREV_BLOCK_USED</td>
0130  *   </tr>
0131  *   <tr>
0132  *     <td>first_block->next</td><td>_Heap_Free_list_tail(heap)</td>
0133  *     <td rowspan=3>memory area available for allocation</td>
0134  *   </tr>
0135  *   <tr><td>first_block->prev</td><td>_Heap_Free_list_head(heap)</td></tr>
0136  *   <tr><td>...</td></tr>
0137  *   <tr>
0138  *     <td>last_block->prev_size</td><td colspan=2>size of first block</td>
0139  *   </tr>
0140  *   <tr>
0141  *     <td>last_block->size</td>
0142  *     <td colspan=2>first block begin address - last block begin address</td>
0143  *   </tr>
0144  *   <tr><td>heap->area_end</td><td colspan=2>heap area end address</td></tr>
0145  * </table>
0146  * The next block of the last block is the first block.  Since the first
0147  * block indicates that the previous block is used, this ensures that the
0148  * last block appears as used for the _Heap_Is_used() and _Heap_Is_free()
0149  * functions.
0150  *
0151  * @{
0152  */
0153 
0154 typedef struct Heap_Control Heap_Control;
0155 
0156 typedef struct Heap_Block Heap_Block;
0157 
0158 /**
0159  * @brief The heap error reason.
0160  *
0161  * @see _Heap_Protection_block_error().
0162  */
0163 typedef enum {
0164   /**
0165    * @brief There is an unexpected value in the heap block protector area.
0166    */
0167   HEAP_ERROR_BROKEN_PROTECTOR,
0168 
0169   /**
0170    * @brief There is an unexpected value in the free pattern of a free heap
0171    * block.
0172    */
0173   HEAP_ERROR_FREE_PATTERN,
0174 
0175   /**
0176    * @brief There is was an attempt to free the same block twice.
0177    */
0178   HEAP_ERROR_DOUBLE_FREE,
0179 
0180   /**
0181    * @brief The next block of a supposed to be used block does not indicate that
0182    * the block is used.
0183    */
0184   HEAP_ERROR_BAD_USED_BLOCK,
0185 
0186   /**
0187    * @brief A supposed to be free block is not inside the heap memory area.
0188    */
0189   HEAP_ERROR_BAD_FREE_BLOCK
0190 } Heap_Error_reason;
0191 
0192 /**
0193  * @brief Context of a heap error.
0194  *
0195  * @see _Heap_Protection_block_error().
0196  */
0197 typedef struct {
0198   /**
0199    * @brief The heap of the block.
0200    */
0201   Heap_Control *heap;
0202 
0203   /**
0204    * @brief The heap block causing the error.
0205    */
0206   Heap_Block *block;
0207 
0208   /**
0209    * @brief The heap error reason.
0210    */
0211   Heap_Error_reason reason;
0212 } Heap_Error_context;
0213 
0214 #ifndef HEAP_PROTECTION
0215   #define HEAP_PROTECTION_HEADER_SIZE 0
0216 #else
0217   #define HEAP_PROTECTOR_COUNT 2
0218 
0219   #define HEAP_BEGIN_PROTECTOR_0 ((uintptr_t) 0xfd75a98f)
0220   #define HEAP_BEGIN_PROTECTOR_1 ((uintptr_t) 0xbfa1f177)
0221   #define HEAP_END_PROTECTOR_0 ((uintptr_t) 0xd6b8855e)
0222   #define HEAP_END_PROTECTOR_1 ((uintptr_t) 0x13a44a5b)
0223 
0224   #define HEAP_FREE_PATTERN ((uintptr_t) 0xe7093cdf)
0225 
0226   #define HEAP_PROTECTION_OBOLUS ((Heap_Block *) 1)
0227 
0228   typedef void (*_Heap_Protection_handler)(
0229      Heap_Control *heap,
0230      Heap_Block *block
0231   );
0232 
0233   typedef void (*_Heap_Protection_error_handler)(
0234      Heap_Control *heap,
0235      Heap_Block *block,
0236      Heap_Error_reason reason
0237   );
0238 
0239   typedef struct {
0240     _Heap_Protection_handler block_initialize;
0241     _Heap_Protection_handler block_check;
0242     _Heap_Protection_error_handler block_error;
0243     void *handler_data;
0244     Heap_Block *first_delayed_free_block;
0245     Heap_Block *last_delayed_free_block;
0246     uintptr_t delayed_free_block_count;
0247     uintptr_t delayed_free_fraction;
0248   } Heap_Protection;
0249 
0250   struct _Thread_Control;
0251 
0252   typedef struct {
0253     uintptr_t protector [HEAP_PROTECTOR_COUNT];
0254     Heap_Block *next_delayed_free_block;
0255     struct _Thread_Control *task;
0256     void *tag;
0257   } Heap_Protection_block_begin;
0258 
0259   typedef struct {
0260     uintptr_t protector [HEAP_PROTECTOR_COUNT];
0261   } Heap_Protection_block_end;
0262 
0263   #define HEAP_PROTECTION_HEADER_SIZE \
0264     (sizeof(Heap_Protection_block_begin) + sizeof(Heap_Protection_block_end))
0265 #endif
0266 
0267 /**
0268  * @brief The block header consists of the two size fields
0269  * (@ref Heap_Block.prev_size and @ref Heap_Block.size_and_flag).
0270  */
0271 #define HEAP_BLOCK_HEADER_SIZE \
0272   (2 * sizeof(uintptr_t) + HEAP_PROTECTION_HEADER_SIZE)
0273 
0274 /**
0275  * @brief Description for free or used blocks.
0276  */
0277 struct Heap_Block {
0278   /**
0279    * @brief Size of the previous block or part of the allocated area of the
0280    * previous block.
0281    *
0282    * This field is only valid if the previous block is free.  This case is
0283    * indicated by a cleared @c HEAP_PREV_BLOCK_USED flag in the
0284    * @a size_and_flag field of the current block.
0285    *
0286    * In a used block only the @a size_and_flag field needs to be valid.  The
0287    * @a prev_size field of the current block is maintained by the previous
0288    * block.  The current block can use the @a prev_size field in the next block
0289    * for allocation.
0290    */
0291   uintptr_t prev_size;
0292 
0293   #ifdef HEAP_PROTECTION
0294     Heap_Protection_block_begin Protection_begin;
0295   #endif
0296 
0297   /**
0298    * @brief Contains the size of the current block and a flag which indicates
0299    * if the previous block is free or used.
0300    *
0301    * If the flag @c HEAP_PREV_BLOCK_USED is set, then the previous block is
0302    * used, otherwise the previous block is free.  A used previous block may
0303    * claim the @a prev_size field for allocation.  This trick allows to
0304    * decrease the overhead in the used blocks by the size of the @a prev_size
0305    * field.  As sizes are required to be multiples of two, the least
0306    * significant bits would be always zero. We use this bit to store the flag.
0307    *
0308    * This field is always valid.
0309    */
0310   uintptr_t size_and_flag;
0311 
0312   #ifdef HEAP_PROTECTION
0313     Heap_Protection_block_end Protection_end;
0314   #endif
0315 
0316   /**
0317    * @brief Pointer to the next free block or part of the allocated area.
0318    *
0319    * This field is page size aligned and begins of the allocated area in case
0320    * the block is used.
0321    *
0322    * This field is only valid if the block is free and thus part of the free
0323    * block list.
0324    */
0325   Heap_Block *next;
0326 
0327   /**
0328    * @brief Pointer to the previous free block or part of the allocated area.
0329    *
0330    * This field is only valid if the block is free and thus part of the free
0331    * block list.
0332    */
0333   Heap_Block *prev;
0334 };
0335 
0336 /**
0337  * @brief Control block used to manage a heap.
0338  */
0339 struct Heap_Control {
0340   Heap_Block free_list;
0341   uintptr_t page_size;
0342   uintptr_t min_block_size;
0343   uintptr_t area_begin;
0344   uintptr_t area_end;
0345   Heap_Block *first_block;
0346   Heap_Block *last_block;
0347   Heap_Statistics stats;
0348   #ifdef HEAP_PROTECTION
0349     Heap_Protection Protection;
0350   #endif
0351 };
0352 
0353 /**
0354  * @brief Heap area structure for table based heap initialization and
0355  * extension.
0356  *
0357  * @see Heap_Initialization_or_extend_handler.
0358  */
0359 typedef struct {
0360   void *begin;
0361   uintptr_t size;
0362 } Heap_Area;
0363 
0364 /**
0365  * @brief Heap initialization and extend handler type.
0366  *
0367  * This helps to do a table based heap initialization and extension.  Create a
0368  * table of Heap_Area elements and iterate through it.  Set the handler to
0369  * _Heap_Initialize() in the first iteration and then to _Heap_Extend().
0370  *
0371  * @see Heap_Area, _Heap_Initialize(), _Heap_Extend(), or _Heap_No_extend().
0372  */
0373 typedef uintptr_t (*Heap_Initialization_or_extend_handler)(
0374   Heap_Control *heap,
0375   void *area_begin,
0376   uintptr_t area_size,
0377   uintptr_t page_size_or_unused
0378 );
0379 
0380 /**
0381  * @brief Extends the memory available for the heap.
0382  *
0383  * There are no alignment requirements for the memory area.  The memory area
0384  * must be big enough to contain some maintenance blocks.  It must not overlap
0385  * parts of the current heap memory areas.  Disconnected memory areas added to
0386  * the heap will lead to used blocks which cover the gaps.  Extending with an
0387  * inappropriate memory area will corrupt the heap resulting in undefined
0388  * behaviour.
0389  *
0390  * @param[in, out] heap The heap to extend.
0391  * @param[out] area_begin The start address of the area to extend the @a heap with.
0392  * @param area_size The size of the area in bytes.
0393  * @param unused Is not used, only provided to have the same signature as _Heap_Initialize().
0394  *
0395  * @retval some_value The extended space available for allocation after successful extension.
0396  * @retval 0 The heap extension failed.
0397  *
0398  * @see Heap_Initialization_or_extend_handler.
0399  */
0400 uintptr_t _Heap_Extend(
0401   Heap_Control *heap,
0402   void *area_begin,
0403   uintptr_t area_size,
0404   uintptr_t unused
0405 );
0406 
0407 /**
0408  * @brief This function returns always zero.
0409  *
0410  * This function only returns zero and does nothing else.
0411  *
0412  * @param unused_0 This parameter does nothing.
0413  * @param unused_1 This parameter does nothing.
0414  * @param unused_2 This parameter does nothing.
0415  * @param unused_3 This parameter does nothing.
0416  *
0417  * @see Heap_Initialization_or_extend_handler.
0418  */
0419 uintptr_t _Heap_No_extend(
0420   Heap_Control *unused_0,
0421   void *unused_1,
0422   uintptr_t unused_2,
0423   uintptr_t unused_3
0424 );
0425 
0426 /**
0427  * @brief Aligns the value to a given alignment, rounding up.
0428  *
0429  * @param value The value to be aligned.
0430  * @param alignment The alignment for the value.
0431  *
0432  * @return The @a value aligned to the given @a alignment, rounded up.
0433  */
0434 static inline uintptr_t _Heap_Align_up(
0435   uintptr_t value,
0436   uintptr_t alignment
0437 )
0438 {
0439   uintptr_t remainder = value % alignment;
0440 
0441   if ( remainder != 0 ) {
0442     return value - remainder + alignment;
0443   } else {
0444     return value;
0445   }
0446 }
0447 
0448 /**
0449  * @brief Returns the minimal Heap Block size for the given page_size.
0450  *
0451  * @param page_size The page size for the heap.
0452  *
0453  * @return The minimal Heap Block size for the given @a page_size.
0454  */
0455 static inline uintptr_t _Heap_Min_block_size( uintptr_t page_size )
0456 {
0457   return _Heap_Align_up( sizeof( Heap_Block ), page_size );
0458 }
0459 
0460 /**
0461  * @brief Returns the worst case overhead to manage a memory area.
0462  *
0463  * @param page_size The page size to calculate the worst case memory manage overhead.
0464  *
0465  * @return The worst case overhead to manage a memory area.
0466  */
0467 static inline uintptr_t _Heap_Area_overhead(
0468   uintptr_t page_size
0469 )
0470 {
0471   if ( page_size != 0 ) {
0472     page_size = _Heap_Align_up( page_size, CPU_ALIGNMENT );
0473   } else {
0474     page_size = CPU_ALIGNMENT;
0475   }
0476 
0477   /*
0478    * Account for a potential alignment of the area begin address to a page
0479    * boundary, the first block, and the last block.  The last block consists
0480    * only of a block header.
0481    */
0482   return page_size - 1 + _Heap_Min_block_size( page_size ) +
0483     HEAP_BLOCK_HEADER_SIZE;
0484 }
0485 
0486 /**
0487  * @brief Returns the size with administration and alignment overhead for one
0488  * allocation.
0489  *
0490  * @param page_size The page size for the allocation.
0491  * @param size The size to allocate.
0492  * @param alignment The alignment that needs to be considered.
0493  *
0494  * @return The size with administration and alignment overhead for one allocation.
0495  */
0496 static inline uintptr_t _Heap_Size_with_overhead(
0497   uintptr_t page_size,
0498   uintptr_t size,
0499   uintptr_t alignment
0500 )
0501 {
0502   if ( page_size != 0 ) {
0503     page_size = _Heap_Align_up( page_size, CPU_ALIGNMENT );
0504   } else {
0505     page_size = CPU_ALIGNMENT;
0506   }
0507 
0508   if ( page_size < alignment ) {
0509     page_size = alignment;
0510   }
0511 
0512   return HEAP_BLOCK_HEADER_SIZE + page_size - 1 + size;
0513 }
0514 
0515 /** @} */
0516 
0517 #ifdef __cplusplus
0518 }
0519 #endif
0520 
0521 #endif
0522 /* end of include file */