source: rtems/cpukit/score/src/heapallocate.c @ c499856

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreHeap
5 *
6 * @brief Heap Handler implementation.
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-1999.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  Copyright (c) 2009 embedded brains GmbH.
14 *
15 *  The license and distribution terms for this file may be
16 *  found in the file LICENSE in this distribution or at
17 *  http://www.rtems.org/license/LICENSE.
18 */
19
20#if HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#include <rtems/system.h>
25#include <rtems/score/heapimpl.h>
26
27#ifndef HEAP_PROTECTION
28  #define _Heap_Protection_free_delayed_blocks( heap, alloc_begin ) false
29#else
30  static bool _Heap_Protection_free_delayed_blocks(
31    Heap_Control *heap,
32    uintptr_t alloc_begin
33  )
34  {
35    bool search_again = false;
36    uintptr_t const blocks_to_free_count =
37      (heap->Protection.delayed_free_block_count + 1) / 2;
38
39    if ( alloc_begin == 0 && blocks_to_free_count > 0 ) {
40      Heap_Block *block_to_free = heap->Protection.first_delayed_free_block;
41      uintptr_t count = 0;
42
43      for ( count = 0; count < blocks_to_free_count; ++count ) {
44        Heap_Block *next_block_to_free =
45          block_to_free->Protection_begin.next_delayed_free_block;
46
47        block_to_free->Protection_begin.next_delayed_free_block =
48          HEAP_PROTECTION_OBOLUS;
49
50        _Heap_Free(
51          heap,
52          (void *) _Heap_Alloc_area_of_block( block_to_free )
53        );
54
55        block_to_free = next_block_to_free;
56      }
57
58      heap->Protection.delayed_free_block_count -= blocks_to_free_count;
59      heap->Protection.first_delayed_free_block = block_to_free;
60
61      search_again = true;
62    }
63
64    return search_again;
65  }
66#endif
67
68#ifdef RTEMS_HEAP_DEBUG
69  static void _Heap_Check_allocation(
70    const Heap_Control *heap,
71    const Heap_Block *block,
72    uintptr_t alloc_begin,
73    uintptr_t alloc_size,
74    uintptr_t alignment,
75    uintptr_t boundary
76  )
77  {
78    uintptr_t const min_block_size = heap->min_block_size;
79    uintptr_t const page_size = heap->page_size;
80
81    uintptr_t const block_begin = (uintptr_t) block;
82    uintptr_t const block_size = _Heap_Block_size( block );
83    uintptr_t const block_end = block_begin + block_size;
84
85    uintptr_t const alloc_end = alloc_begin + alloc_size;
86
87    uintptr_t const alloc_area_begin = _Heap_Alloc_area_of_block( block );
88    uintptr_t const alloc_area_offset = alloc_begin - alloc_area_begin;
89
90    _HAssert( block_size >= min_block_size );
91    _HAssert( block_begin < block_end );
92    _HAssert(
93      _Heap_Is_aligned( block_begin + HEAP_BLOCK_HEADER_SIZE, page_size )
94    );
95    _HAssert(
96      _Heap_Is_aligned( block_size, page_size )
97    );
98
99    _HAssert( alloc_end <= block_end + HEAP_ALLOC_BONUS );
100    _HAssert( alloc_area_begin == block_begin + HEAP_BLOCK_HEADER_SIZE);
101    _HAssert( alloc_area_offset < page_size );
102
103    _HAssert( _Heap_Is_aligned( alloc_area_begin, page_size ) );
104    if ( alignment == 0 ) {
105      _HAssert( alloc_begin == alloc_area_begin );
106    } else {
107      _HAssert( _Heap_Is_aligned( alloc_begin, alignment ) );
108    }
109
110    if ( boundary != 0 ) {
111      uintptr_t boundary_line = _Heap_Align_down( alloc_end, boundary );
112
113      _HAssert( alloc_size <= boundary );
114      _HAssert( boundary_line <= alloc_begin || alloc_end <= boundary_line );
115    }
116  }
117#else
118  #define _Heap_Check_allocation( h, b, ab, as, ag, bd ) ((void) 0)
119#endif
120
121static uintptr_t _Heap_Check_block(
122  const Heap_Control *heap,
123  const Heap_Block *block,
124  uintptr_t alloc_size,
125  uintptr_t alignment,
126  uintptr_t boundary
127)
128{
129  uintptr_t const page_size = heap->page_size;
130  uintptr_t const min_block_size = heap->min_block_size;
131
132  uintptr_t const block_begin = (uintptr_t) block;
133  uintptr_t const block_size = _Heap_Block_size( block );
134  uintptr_t const block_end = block_begin + block_size;
135
136  uintptr_t const alloc_begin_floor = _Heap_Alloc_area_of_block( block );
137  uintptr_t const alloc_begin_ceiling = block_end - min_block_size
138    + HEAP_BLOCK_HEADER_SIZE + page_size - 1;
139
140  uintptr_t alloc_end = block_end + HEAP_ALLOC_BONUS;
141  uintptr_t alloc_begin = alloc_end - alloc_size;
142
143  alloc_begin = _Heap_Align_down( alloc_begin, alignment );
144
145  /* Ensure that the we have a valid new block at the end */
146  if ( alloc_begin > alloc_begin_ceiling ) {
147    alloc_begin = _Heap_Align_down( alloc_begin_ceiling, alignment );
148  }
149
150  alloc_end = alloc_begin + alloc_size;
151
152  /* Ensure boundary constaint */
153  if ( boundary != 0 ) {
154    uintptr_t const boundary_floor = alloc_begin_floor + alloc_size;
155    uintptr_t boundary_line = _Heap_Align_down( alloc_end, boundary );
156
157    while ( alloc_begin < boundary_line && boundary_line < alloc_end ) {
158      if ( boundary_line < boundary_floor ) {
159        return 0;
160      }
161      alloc_begin = boundary_line - alloc_size;
162      alloc_begin = _Heap_Align_down( alloc_begin, alignment );
163      alloc_end = alloc_begin + alloc_size;
164      boundary_line = _Heap_Align_down( alloc_end, boundary );
165    }
166  }
167
168  /* Ensure that the we have a valid new block at the beginning */
169  if ( alloc_begin >= alloc_begin_floor ) {
170    uintptr_t const alloc_block_begin =
171      (uintptr_t) _Heap_Block_of_alloc_area( alloc_begin, page_size );
172    uintptr_t const free_size = alloc_block_begin - block_begin;
173
174    if ( free_size >= min_block_size || free_size == 0 ) {
175      return alloc_begin;
176    }
177  }
178
179  return 0;
180}
181
182void *_Heap_Allocate_aligned_with_boundary(
183  Heap_Control *heap,
184  uintptr_t alloc_size,
185  uintptr_t alignment,
186  uintptr_t boundary
187)
188{
189  Heap_Statistics *const stats = &heap->stats;
190  uintptr_t const block_size_floor = alloc_size + HEAP_BLOCK_HEADER_SIZE
191    - HEAP_ALLOC_BONUS;
192  uintptr_t const page_size = heap->page_size;
193  Heap_Block *block = NULL;
194  uintptr_t alloc_begin = 0;
195  uint32_t search_count = 0;
196  bool search_again = false;
197
198  if ( block_size_floor < alloc_size ) {
199    /* Integer overflow occured */
200    return NULL;
201  }
202
203  if ( boundary != 0 ) {
204    if ( boundary < alloc_size ) {
205      return NULL;
206    }
207
208    if ( alignment == 0 ) {
209      alignment = page_size;
210    }
211  }
212
213  do {
214    Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap );
215
216    block = _Heap_Free_list_first( heap );
217    while ( block != free_list_tail ) {
218      _HAssert( _Heap_Is_prev_used( block ) );
219
220      _Heap_Protection_block_check( heap, block );
221
222      /*
223       * The HEAP_PREV_BLOCK_USED flag is always set in the block size_and_flag
224       * field.  Thus the value is about one unit larger than the real block
225       * size.  The greater than operator takes this into account.
226       */
227      if ( block->size_and_flag > block_size_floor ) {
228        if ( alignment == 0 ) {
229          alloc_begin = _Heap_Alloc_area_of_block( block );
230        } else {
231          alloc_begin = _Heap_Check_block(
232            heap,
233            block,
234            alloc_size,
235            alignment,
236            boundary
237          );
238        }
239      }
240
241      /* Statistics */
242      ++search_count;
243
244      if ( alloc_begin != 0 ) {
245        break;
246      }
247
248      block = block->next;
249    }
250
251    search_again = _Heap_Protection_free_delayed_blocks( heap, alloc_begin );
252  } while ( search_again );
253
254  if ( alloc_begin != 0 ) {
255    /* Statistics */
256    ++stats->allocs;
257    stats->searches += search_count;
258
259    block = _Heap_Block_allocate( heap, block, alloc_begin, alloc_size );
260
261    _Heap_Check_allocation(
262      heap,
263      block,
264      alloc_begin,
265      alloc_size,
266      alignment,
267      boundary
268    );
269  }
270
271  /* Statistics */
272  if ( stats->max_search < search_count ) {
273    stats->max_search = search_count;
274  }
275
276  return (void *) alloc_begin;
277}
Note: See TracBrowser for help on using the repository browser.