source: rtems/cpukit/include/rtems/score/heap.h @ 7ebce359

Last change on this file since 7ebce359 was 7ebce359, checked in by Joel Sherrill <joel@…>, on 02/16/22 at 21:15:58

cpukit/include/rtems/score/[a-r]*.h: Change license to BSD-2

Updates #3053.

  • Property mode set to 100644
File size: 15.3 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSScoreHeap
7 *
8 * @brief This header file provides interfaces of the
9 *   @ref RTEMSScoreHeap which are used by the implementation and the
10 *   @ref RTEMSImplApplConfig.
11 */
12
13/*
14 *  COPYRIGHT (c) 1989-2006.
15 *  On-Line Applications Research Corporation (OAR).
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 *    notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 *    notice, this list of conditions and the following disclaimer in the
24 *    documentation and/or other materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#ifndef _RTEMS_SCORE_HEAP_H
40#define _RTEMS_SCORE_HEAP_H
41
42#include <rtems/score/cpu.h>
43#include <rtems/score/heapinfo.h>
44
45#ifdef __cplusplus
46extern "C" {
47#endif
48
49#ifdef RTEMS_DEBUG
50  #define HEAP_PROTECTION
51#endif
52
53/**
54 * @defgroup RTEMSScoreHeap Heap Handler
55 *
56 * @ingroup RTEMSScore
57 *
58 * @brief This group contains the Heap Handler implementation.
59 *
60 * A heap is a doubly linked list of variable size blocks which are allocated
61 * using the first fit method.  Garbage collection is performed each time a
62 * block is returned to the heap by coalescing neighbor blocks.  Control
63 * information for both allocated and free blocks is contained in the heap
64 * area.  A heap control structure contains control information for the heap.
65 *
66 * The alignment routines could be made faster should we require only powers of
67 * two to be supported for page size, alignment and boundary arguments.  The
68 * minimum alignment requirement for pages is currently CPU_ALIGNMENT and this
69 * value is only required to be multiple of two and explicitly not required to
70 * be a power of two.
71 *
72 * There are two kinds of blocks.  One sort describes a free block from which
73 * we can allocate memory.  The other blocks are used and provide an allocated
74 * memory area.  The free blocks are accessible via a list of free blocks.
75 *
76 * Blocks or areas cover a continuous set of memory addresses. They have a
77 * begin and end address.  The end address is not part of the set.  The size of
78 * a block or area equals the distance between the begin and end address in
79 * units of bytes.
80 *
81 * Free blocks look like:
82 * <table>
83 *   <tr>
84 *     <td rowspan=4>@ref Heap_Block</td><td>previous block size in case the
85 *       previous block is free, <br> otherwise it may contain data used by
86 *       the previous block</td>
87 *   </tr>
88 *   <tr>
89 *     <td>block size and a flag which indicates if the previous block is free
90 *       or used, <br> this field contains always valid data regardless of the
91 *       block usage</td>
92 *   </tr>
93 *   <tr><td>pointer to next block (this field is page size aligned)</td></tr>
94 *   <tr><td>pointer to previous block</td></tr>
95 *   <tr><td colspan=2>free space</td></tr>
96 * </table>
97 *
98 * Used blocks look like:
99 * <table>
100 *   <tr>
101 *     <td rowspan=4>@ref Heap_Block</td><td>previous block size in case the
102 *       previous block is free,<br>otherwise it may contain data used by
103 *       the previous block</td>
104 *   </tr>
105 *   <tr>
106 *     <td>block size and a flag which indicates if the previous block is free
107 *       or used, <br> this field contains always valid data regardless of the
108 *       block usage</td>
109 *   </tr>
110 *   <tr><td>begin of allocated area (this field is page size aligned)</td></tr>
111 *   <tr><td>allocated space</td></tr>
112 *   <tr><td colspan=2>allocated space</td></tr>
113 * </table>
114 *
115 * The heap area after initialization contains two blocks and looks like:
116 * <table>
117 *   <tr><th>Label</th><th colspan=2>Content</th></tr>
118 *   <tr><td>heap->area_begin</td><td colspan=2>heap area begin address</td></tr>
119 *   <tr>
120 *     <td>first_block->prev_size</td>
121 *     <td colspan=2>
122 *       subordinate heap area end address (this will be used to maintain a
123 *       linked list of scattered heap areas)
124 *     </td>
125 *   </tr>
126 *   <tr>
127 *     <td>first_block->size</td>
128 *     <td colspan=2>size available for allocation
129 *       | @c HEAP_PREV_BLOCK_USED</td>
130 *   </tr>
131 *   <tr>
132 *     <td>first_block->next</td><td>_Heap_Free_list_tail(heap)</td>
133 *     <td rowspan=3>memory area available for allocation</td>
134 *   </tr>
135 *   <tr><td>first_block->prev</td><td>_Heap_Free_list_head(heap)</td></tr>
136 *   <tr><td>...</td></tr>
137 *   <tr>
138 *     <td>last_block->prev_size</td><td colspan=2>size of first block</td>
139 *   </tr>
140 *   <tr>
141 *     <td>last_block->size</td>
142 *     <td colspan=2>first block begin address - last block begin address</td>
143 *   </tr>
144 *   <tr><td>heap->area_end</td><td colspan=2>heap area end address</td></tr>
145 * </table>
146 * The next block of the last block is the first block.  Since the first
147 * block indicates that the previous block is used, this ensures that the
148 * last block appears as used for the _Heap_Is_used() and _Heap_Is_free()
149 * functions.
150 *
151 * @{
152 */
153
154typedef struct Heap_Control Heap_Control;
155
156typedef struct Heap_Block Heap_Block;
157
158/**
159 * @brief The heap error reason.
160 *
161 * @see _Heap_Protection_block_error().
162 */
163typedef enum {
164  /**
165   * @brief There is an unexpected value in the heap block protector area.
166   */
167  HEAP_ERROR_BROKEN_PROTECTOR,
168
169  /**
170   * @brief There is an unexpected value in the free pattern of a free heap
171   * block.
172   */
173  HEAP_ERROR_FREE_PATTERN,
174
175  /**
176   * @brief There is was an attempt to free the same block twice.
177   */
178  HEAP_ERROR_DOUBLE_FREE,
179
180  /**
181   * @brief The next block of a supposed to be used block does not indicate that
182   * the block is used.
183   */
184  HEAP_ERROR_BAD_USED_BLOCK,
185
186  /**
187   * @brief A supposed to be free block is not inside the heap memory area.
188   */
189  HEAP_ERROR_BAD_FREE_BLOCK
190} Heap_Error_reason;
191
192/**
193 * @brief Context of a heap error.
194 *
195 * @see _Heap_Protection_block_error().
196 */
197typedef struct {
198  /**
199   * @brief The heap of the block.
200   */
201  Heap_Control *heap;
202
203  /**
204   * @brief The heap block causing the error.
205   */
206  Heap_Block *block;
207
208  /**
209   * @brief The heap error reason.
210   */
211  Heap_Error_reason reason;
212} Heap_Error_context;
213
214#ifndef HEAP_PROTECTION
215  #define HEAP_PROTECTION_HEADER_SIZE 0
216#else
217  #define HEAP_PROTECTOR_COUNT 2
218
219  #define HEAP_BEGIN_PROTECTOR_0 ((uintptr_t) 0xfd75a98f)
220  #define HEAP_BEGIN_PROTECTOR_1 ((uintptr_t) 0xbfa1f177)
221  #define HEAP_END_PROTECTOR_0 ((uintptr_t) 0xd6b8855e)
222  #define HEAP_END_PROTECTOR_1 ((uintptr_t) 0x13a44a5b)
223
224  #define HEAP_FREE_PATTERN ((uintptr_t) 0xe7093cdf)
225
226  #define HEAP_PROTECTION_OBOLUS ((Heap_Block *) 1)
227
228  typedef void (*_Heap_Protection_handler)(
229     Heap_Control *heap,
230     Heap_Block *block
231  );
232
233  typedef void (*_Heap_Protection_error_handler)(
234     Heap_Control *heap,
235     Heap_Block *block,
236     Heap_Error_reason reason
237  );
238
239  typedef struct {
240    _Heap_Protection_handler block_initialize;
241    _Heap_Protection_handler block_check;
242    _Heap_Protection_error_handler block_error;
243    void *handler_data;
244    Heap_Block *first_delayed_free_block;
245    Heap_Block *last_delayed_free_block;
246    uintptr_t delayed_free_block_count;
247    uintptr_t delayed_free_fraction;
248  } Heap_Protection;
249
250  struct _Thread_Control;
251
252  typedef struct {
253    uintptr_t protector [HEAP_PROTECTOR_COUNT];
254    Heap_Block *next_delayed_free_block;
255    struct _Thread_Control *task;
256    void *tag;
257  } Heap_Protection_block_begin;
258
259  typedef struct {
260    uintptr_t protector [HEAP_PROTECTOR_COUNT];
261  } Heap_Protection_block_end;
262
263  #define HEAP_PROTECTION_HEADER_SIZE \
264    (sizeof(Heap_Protection_block_begin) + sizeof(Heap_Protection_block_end))
265#endif
266
267/**
268 * @brief The block header consists of the two size fields
269 * (@ref Heap_Block.prev_size and @ref Heap_Block.size_and_flag).
270 */
271#define HEAP_BLOCK_HEADER_SIZE \
272  (2 * sizeof(uintptr_t) + HEAP_PROTECTION_HEADER_SIZE)
273
274/**
275 * @brief Description for free or used blocks.
276 */
277struct Heap_Block {
278  /**
279   * @brief Size of the previous block or part of the allocated area of the
280   * previous block.
281   *
282   * This field is only valid if the previous block is free.  This case is
283   * indicated by a cleared @c HEAP_PREV_BLOCK_USED flag in the
284   * @a size_and_flag field of the current block.
285   *
286   * In a used block only the @a size_and_flag field needs to be valid.  The
287   * @a prev_size field of the current block is maintained by the previous
288   * block.  The current block can use the @a prev_size field in the next block
289   * for allocation.
290   */
291  uintptr_t prev_size;
292
293  #ifdef HEAP_PROTECTION
294    Heap_Protection_block_begin Protection_begin;
295  #endif
296
297  /**
298   * @brief Contains the size of the current block and a flag which indicates
299   * if the previous block is free or used.
300   *
301   * If the flag @c HEAP_PREV_BLOCK_USED is set, then the previous block is
302   * used, otherwise the previous block is free.  A used previous block may
303   * claim the @a prev_size field for allocation.  This trick allows to
304   * decrease the overhead in the used blocks by the size of the @a prev_size
305   * field.  As sizes are required to be multiples of two, the least
306   * significant bits would be always zero. We use this bit to store the flag.
307   *
308   * This field is always valid.
309   */
310  uintptr_t size_and_flag;
311
312  #ifdef HEAP_PROTECTION
313    Heap_Protection_block_end Protection_end;
314  #endif
315
316  /**
317   * @brief Pointer to the next free block or part of the allocated area.
318   *
319   * This field is page size aligned and begins of the allocated area in case
320   * the block is used.
321   *
322   * This field is only valid if the block is free and thus part of the free
323   * block list.
324   */
325  Heap_Block *next;
326
327  /**
328   * @brief Pointer to the previous free block or part of the allocated area.
329   *
330   * This field is only valid if the block is free and thus part of the free
331   * block list.
332   */
333  Heap_Block *prev;
334};
335
336/**
337 * @brief Control block used to manage a heap.
338 */
339struct Heap_Control {
340  Heap_Block free_list;
341  uintptr_t page_size;
342  uintptr_t min_block_size;
343  uintptr_t area_begin;
344  uintptr_t area_end;
345  Heap_Block *first_block;
346  Heap_Block *last_block;
347  Heap_Statistics stats;
348  #ifdef HEAP_PROTECTION
349    Heap_Protection Protection;
350  #endif
351};
352
353/**
354 * @brief Heap area structure for table based heap initialization and
355 * extension.
356 *
357 * @see Heap_Initialization_or_extend_handler.
358 */
359typedef struct {
360  void *begin;
361  uintptr_t size;
362} Heap_Area;
363
364/**
365 * @brief Heap initialization and extend handler type.
366 *
367 * This helps to do a table based heap initialization and extension.  Create a
368 * table of Heap_Area elements and iterate through it.  Set the handler to
369 * _Heap_Initialize() in the first iteration and then to _Heap_Extend().
370 *
371 * @see Heap_Area, _Heap_Initialize(), _Heap_Extend(), or _Heap_No_extend().
372 */
373typedef uintptr_t (*Heap_Initialization_or_extend_handler)(
374  Heap_Control *heap,
375  void *area_begin,
376  uintptr_t area_size,
377  uintptr_t page_size_or_unused
378);
379
380/**
381 * @brief Extends the memory available for the heap.
382 *
383 * There are no alignment requirements for the memory area.  The memory area
384 * must be big enough to contain some maintenance blocks.  It must not overlap
385 * parts of the current heap memory areas.  Disconnected memory areas added to
386 * the heap will lead to used blocks which cover the gaps.  Extending with an
387 * inappropriate memory area will corrupt the heap resulting in undefined
388 * behaviour.
389 *
390 * @param[in, out] heap The heap to extend.
391 * @param[out] area_begin The start address of the area to extend the @a heap with.
392 * @param area_size The size of the area in bytes.
393 * @param unused Is not used, only provided to have the same signature as _Heap_Initialize().
394 *
395 * @retval some_value The extended space available for allocation after successful extension.
396 * @retval 0 The heap extension failed.
397 *
398 * @see Heap_Initialization_or_extend_handler.
399 */
400uintptr_t _Heap_Extend(
401  Heap_Control *heap,
402  void *area_begin,
403  uintptr_t area_size,
404  uintptr_t unused
405);
406
407/**
408 * @brief This function returns always zero.
409 *
410 * This function only returns zero and does nothing else.
411 *
412 * @param unused_0 This parameter does nothing.
413 * @param unused_1 This parameter does nothing.
414 * @param unused_2 This parameter does nothing.
415 * @param unused_3 This parameter does nothing.
416 *
417 * @see Heap_Initialization_or_extend_handler.
418 */
419uintptr_t _Heap_No_extend(
420  Heap_Control *unused_0,
421  void *unused_1,
422  uintptr_t unused_2,
423  uintptr_t unused_3
424);
425
426/**
427 * @brief Aligns the value to a given alignment, rounding up.
428 *
429 * @param value The value to be aligned.
430 * @param alignment The alignment for the value.
431 *
432 * @return The @a value aligned to the given @a alignment, rounded up.
433 */
434RTEMS_INLINE_ROUTINE uintptr_t _Heap_Align_up(
435  uintptr_t value,
436  uintptr_t alignment
437)
438{
439  uintptr_t remainder = value % alignment;
440
441  if ( remainder != 0 ) {
442    return value - remainder + alignment;
443  } else {
444    return value;
445  }
446}
447
448/**
449 * @brief Returns the minimal Heap Block size for the given page_size.
450 *
451 * @param page_size The page size for the heap.
452 *
453 * @return The minimal Heap Block size for the given @a page_size.
454 */
455RTEMS_INLINE_ROUTINE uintptr_t _Heap_Min_block_size( uintptr_t page_size )
456{
457  return _Heap_Align_up( sizeof( Heap_Block ), page_size );
458}
459
460/**
461 * @brief Returns the worst case overhead to manage a memory area.
462 *
463 * @param page_size The page size to calculate the worst case memory manage overhead.
464 *
465 * @return The worst case overhead to manage a memory area.
466 */
467RTEMS_INLINE_ROUTINE uintptr_t _Heap_Area_overhead(
468  uintptr_t page_size
469)
470{
471  if ( page_size != 0 ) {
472    page_size = _Heap_Align_up( page_size, CPU_ALIGNMENT );
473  } else {
474    page_size = CPU_ALIGNMENT;
475  }
476
477  /*
478   * Account for a potential alignment of the area begin address to a page
479   * boundary, the first block, and the last block.  The last block consists
480   * only of a block header.
481   */
482  return page_size - 1 + _Heap_Min_block_size( page_size ) +
483    HEAP_BLOCK_HEADER_SIZE;
484}
485
486/**
487 * @brief Returns the size with administration and alignment overhead for one
488 * allocation.
489 *
490 * @param page_size The page size for the allocation.
491 * @param size The size to allocate.
492 * @param alignment The alignment that needs to be considered.
493 *
494 * @return The size with administration and alignment overhead for one allocation.
495 */
496RTEMS_INLINE_ROUTINE uintptr_t _Heap_Size_with_overhead(
497  uintptr_t page_size,
498  uintptr_t size,
499  uintptr_t alignment
500)
501{
502  if ( page_size != 0 ) {
503    page_size = _Heap_Align_up( page_size, CPU_ALIGNMENT );
504  } else {
505    page_size = CPU_ALIGNMENT;
506  }
507
508  if ( page_size < alignment ) {
509    page_size = alignment;
510  }
511
512  return HEAP_BLOCK_HEADER_SIZE + page_size - 1 + size;
513}
514
515/** @} */
516
517#ifdef __cplusplus
518}
519#endif
520
521#endif
522/* end of include file */
Note: See TracBrowser for help on using the repository browser.