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

4.115
Last change on this file since d7c3883 was 4d73c38, checked in by Sebastian Huber <sebastian.huber@…>, on 08/25/10 at 12:35:52

2010-08-25 Sebastian Huber <sebastian.huber@…>

PR 1672/cpukit

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