source: rtems/cpukit/score/src/heapextend.c

Last change on this file was bcef89f2, checked in by Sebastian Huber <sebastian.huber@…>, on 05/19/23 at 06:18:25

Update company name

The embedded brains GmbH & Co. KG is the legal successor of embedded
brains GmbH.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSScoreHeap
7 *
8 * @brief This source file contains the implementation of
9 *   _Heap_Extend().
10 */
11
12/*
13 *  COPYRIGHT (c) 1989-1999.
14 *  On-Line Applications Research Corporation (OAR).
15 *
16 *  Copyright (c) 2010 embedded brains GmbH & Co. KG
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#ifdef HAVE_CONFIG_H
41#include "config.h"
42#endif
43
44#include <rtems/score/heapimpl.h>
45
46static void _Heap_Free_block( Heap_Control *heap, Heap_Block *block )
47{
48  Heap_Statistics *const stats = &heap->stats;
49  Heap_Block *first_free;
50
51  /* Statistics */
52  ++stats->used_blocks;
53  --stats->frees;
54
55  /*
56   * The _Heap_Free() will place the block to the head of free list.  We want
57   * the new block at the end of the free list.  So that initial and earlier
58   * areas are consumed first.
59   */
60  _Heap_Free( heap, (void *) _Heap_Alloc_area_of_block( block ) );
61  _Heap_Protection_free_all_delayed_blocks( heap );
62  first_free = _Heap_Free_list_first( heap );
63  _Heap_Free_list_remove( first_free );
64  _Heap_Free_list_insert_before( _Heap_Free_list_tail( heap ), first_free );
65}
66
67static void _Heap_Merge_below(
68  Heap_Control *heap,
69  uintptr_t extend_area_begin,
70  Heap_Block *first_block
71)
72{
73  uintptr_t const page_size = heap->page_size;
74  uintptr_t const new_first_block_alloc_begin =
75    _Heap_Align_up( extend_area_begin + HEAP_BLOCK_HEADER_SIZE, page_size );
76  uintptr_t const new_first_block_begin =
77    new_first_block_alloc_begin - HEAP_BLOCK_HEADER_SIZE;
78  uintptr_t const first_block_begin = (uintptr_t) first_block;
79  uintptr_t const new_first_block_size =
80    first_block_begin - new_first_block_begin;
81  Heap_Block *const new_first_block = (Heap_Block *) new_first_block_begin;
82
83  new_first_block->prev_size = first_block->prev_size;
84  new_first_block->size_and_flag = new_first_block_size | HEAP_PREV_BLOCK_USED;
85
86  _Heap_Free_block( heap, new_first_block );
87}
88
89static void _Heap_Merge_above(
90  Heap_Control *heap,
91  Heap_Block *last_block,
92  uintptr_t extend_area_end
93)
94{
95  uintptr_t const page_size = heap->page_size;
96  uintptr_t const last_block_begin = (uintptr_t) last_block;
97  uintptr_t const last_block_new_size = _Heap_Align_down(
98    extend_area_end - last_block_begin - HEAP_BLOCK_HEADER_SIZE,
99    page_size
100  );
101  Heap_Block *const new_last_block =
102    _Heap_Block_at( last_block, last_block_new_size );
103
104  new_last_block->size_and_flag =
105    (last_block->size_and_flag - last_block_new_size)
106      | HEAP_PREV_BLOCK_USED;
107
108  _Heap_Block_set_size( last_block, last_block_new_size );
109
110  _Heap_Free_block( heap, last_block );
111}
112
113static void _Heap_Link_below(
114  Heap_Block *link,
115  Heap_Block *last_block
116)
117{
118  uintptr_t const last_block_begin = (uintptr_t) last_block;
119  uintptr_t const link_begin = (uintptr_t) link;
120
121  last_block->size_and_flag =
122    (link_begin - last_block_begin) | HEAP_PREV_BLOCK_USED;
123}
124
125static void _Heap_Link_above(
126  Heap_Block *link,
127  Heap_Block *first_block,
128  Heap_Block *last_block
129)
130{
131  uintptr_t const link_begin = (uintptr_t) link;
132  uintptr_t const first_block_begin = (uintptr_t) first_block;
133
134  _Heap_Block_set_size( link, first_block_begin - link_begin );
135
136  last_block->size_and_flag |= HEAP_PREV_BLOCK_USED;
137}
138
139uintptr_t _Heap_Extend(
140  Heap_Control *heap,
141  void *extend_area_begin_ptr,
142  uintptr_t extend_area_size,
143  uintptr_t unused RTEMS_UNUSED
144)
145{
146  Heap_Statistics *const stats = &heap->stats;
147  Heap_Block *const first_block = heap->first_block;
148  Heap_Block *start_block = first_block;
149  Heap_Block *merge_below_block = NULL;
150  Heap_Block *merge_above_block = NULL;
151  Heap_Block *link_below_block = NULL;
152  Heap_Block *link_above_block = NULL;
153  Heap_Block *extend_first_block = NULL;
154  Heap_Block *extend_last_block = NULL;
155  uintptr_t const page_size = heap->page_size;
156  uintptr_t const min_block_size = heap->min_block_size;
157  uintptr_t const extend_area_begin = (uintptr_t) extend_area_begin_ptr;
158  uintptr_t const extend_area_end = extend_area_begin + extend_area_size;
159  uintptr_t const free_size = stats->free_size;
160  uintptr_t extend_first_block_size = 0;
161  uintptr_t extended_size = 0;
162  bool extend_area_ok = false;
163
164  if ( extend_area_end < extend_area_begin ) {
165    return 0;
166  }
167
168  extend_area_ok = _Heap_Get_first_and_last_block(
169    extend_area_begin,
170    extend_area_size,
171    page_size,
172    min_block_size,
173    &extend_first_block,
174    &extend_last_block
175  );
176  if (!extend_area_ok ) {
177    /* For simplicity we reject extend areas that are too small */
178    return 0;
179  }
180
181  do {
182    uintptr_t const sub_area_begin = (start_block != first_block) ?
183      (uintptr_t) start_block : heap->area_begin;
184    uintptr_t const sub_area_end = start_block->prev_size;
185    Heap_Block *const end_block =
186      _Heap_Block_of_alloc_area( sub_area_end, page_size );
187
188    if (
189      sub_area_end > extend_area_begin && extend_area_end > sub_area_begin
190    ) {
191      return 0;
192    }
193
194    if ( extend_area_end == sub_area_begin ) {
195      merge_below_block = start_block;
196    } else if ( extend_area_end < sub_area_end ) {
197      link_below_block = start_block;
198    }
199
200    if ( sub_area_end == extend_area_begin ) {
201      start_block->prev_size = extend_area_end;
202
203      merge_above_block = end_block;
204    } else if ( sub_area_end < extend_area_begin ) {
205      link_above_block = end_block;
206    }
207
208    start_block = _Heap_Block_at( end_block, _Heap_Block_size( end_block ) );
209  } while ( start_block != first_block );
210
211  if ( extend_area_begin < heap->area_begin ) {
212    heap->area_begin = extend_area_begin;
213  } else if ( heap->area_end < extend_area_end ) {
214    heap->area_end = extend_area_end;
215  }
216
217  extend_first_block_size =
218    (uintptr_t) extend_last_block - (uintptr_t) extend_first_block;
219
220  extend_first_block->prev_size = extend_area_end;
221  extend_first_block->size_and_flag =
222    extend_first_block_size | HEAP_PREV_BLOCK_USED;
223  _Heap_Protection_block_initialize( heap, extend_first_block );
224
225  extend_last_block->prev_size = extend_first_block_size;
226  extend_last_block->size_and_flag = 0;
227  _Heap_Protection_block_initialize( heap, extend_last_block );
228
229  if ( (uintptr_t) extend_first_block < (uintptr_t) heap->first_block ) {
230    heap->first_block = extend_first_block;
231  } else if ( (uintptr_t) extend_last_block > (uintptr_t) heap->last_block ) {
232    heap->last_block = extend_last_block;
233  }
234
235  if ( merge_below_block != NULL ) {
236    _Heap_Merge_below( heap, extend_area_begin, merge_below_block );
237  } else if ( link_below_block != NULL ) {
238    _Heap_Link_below(
239      link_below_block,
240      extend_last_block
241    );
242  }
243
244  if ( merge_above_block != NULL ) {
245    _Heap_Merge_above( heap, merge_above_block, extend_area_end );
246  } else if ( link_above_block != NULL ) {
247    _Heap_Link_above(
248      link_above_block,
249      extend_first_block,
250      extend_last_block
251    );
252  }
253
254  if ( merge_below_block == NULL && merge_above_block == NULL ) {
255    _Heap_Free_block( heap, extend_first_block );
256  }
257
258  _Heap_Set_last_block_size( heap );
259
260  extended_size = stats->free_size - free_size;
261
262  /* Statistics */
263  stats->size += extended_size;
264
265  return extended_size;
266}
Note: See TracBrowser for help on using the repository browser.