source: rtems/cpukit/score/src/heapfree.c @ 5472ad41

4.115
Last change on this file since 5472ad41 was dacdda30, checked in by Ralf Corsepius <ralf.corsepius@…>, on 05/24/11 at 02:44:58

Remove white-spaces.

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreHeap
5 *
6 * @brief Heap Handler implementation.
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-2007.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.com/license/LICENSE.
16 *
17 *  $Id$
18 */
19
20#if HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#include <rtems/system.h>
25#include <rtems/score/heap.h>
26
27#ifndef HEAP_PROTECTION
28  #define _Heap_Protection_determine_block_free( heap, block ) true
29#else
30  static void _Heap_Protection_delay_block_free(
31    Heap_Control *heap,
32    Heap_Block *block
33  )
34  {
35    uintptr_t *const pattern_begin = (uintptr_t *)
36      _Heap_Alloc_area_of_block( block );
37    uintptr_t *const pattern_end = (uintptr_t *)
38      ((uintptr_t) block + _Heap_Block_size( block ) + HEAP_ALLOC_BONUS);
39    uintptr_t const delayed_free_block_count =
40      heap->Protection.delayed_free_block_count;
41    uintptr_t *current = NULL;
42
43    block->Protection_begin.next_delayed_free_block = block;
44    block->Protection_begin.task = _Thread_Executing;
45
46    if ( delayed_free_block_count > 0 ) {
47      Heap_Block *const last = heap->Protection.last_delayed_free_block;
48
49      last->Protection_begin.next_delayed_free_block = block;
50    } else {
51      heap->Protection.first_delayed_free_block = block;
52    }
53    heap->Protection.last_delayed_free_block = block;
54    heap->Protection.delayed_free_block_count = delayed_free_block_count + 1;
55
56    for ( current = pattern_begin; current != pattern_end; ++current ) {
57      *current = HEAP_FREE_PATTERN;
58    }
59  }
60
61  static void _Heap_Protection_check_free_block(
62    Heap_Control *heap,
63    Heap_Block *block
64  )
65  {
66    uintptr_t *const pattern_begin = (uintptr_t *)
67      _Heap_Alloc_area_of_block( block );
68    uintptr_t *const pattern_end = (uintptr_t *)
69      ((uintptr_t) block + _Heap_Block_size( block ) + HEAP_ALLOC_BONUS);
70    uintptr_t *current = NULL;
71
72    for ( current = pattern_begin; current != pattern_end; ++current ) {
73      if ( *current != HEAP_FREE_PATTERN ) {
74        _Heap_Protection_block_error( heap, block );
75        break;
76      }
77    }
78  }
79
80  static bool _Heap_Protection_determine_block_free(
81    Heap_Control *heap,
82    Heap_Block *block
83  )
84  {
85    bool do_free = true;
86
87    /*
88     * Sometimes after a free the allocated area is still in use.  An example
89     * is the task stack of a thread that deletes itself.  The thread dispatch
90     * disable level is a way to detect this use case.
91     */
92    if ( !_Thread_Dispatch_in_critical_section() ) {
93      Heap_Block *const next = block->Protection_begin.next_delayed_free_block;
94      if ( next == NULL ) {
95        _Heap_Protection_delay_block_free( heap, block );
96        do_free = false;
97      } else if ( next == HEAP_PROTECTION_OBOLUS ) {
98        _Heap_Protection_check_free_block( heap, block );
99      } else {
100        _Heap_Protection_block_error( heap, block );
101      }
102    }
103
104    return do_free;
105  }
106#endif
107
108bool _Heap_Free( Heap_Control *heap, void *alloc_begin_ptr )
109{
110  Heap_Statistics *const stats = &heap->stats;
111  uintptr_t alloc_begin;
112  Heap_Block *block;
113  Heap_Block *next_block = NULL;
114  uintptr_t block_size = 0;
115  uintptr_t next_block_size = 0;
116  bool next_is_free = false;
117
118  /*
119   * If NULL return true so a free on NULL is considered a valid release. This
120   * is a special case that could be handled by the in heap check how-ever that
121   * would result in false being returned which is wrong.
122   */
123  if ( alloc_begin_ptr == NULL ) {
124    return true;
125  }
126
127  alloc_begin = (uintptr_t) alloc_begin_ptr;
128  block = _Heap_Block_of_alloc_area( alloc_begin, heap->page_size );
129
130  if ( !_Heap_Is_block_in_heap( heap, block ) ) {
131    return false;
132  }
133
134  _Heap_Protection_block_check( heap, block );
135
136  block_size = _Heap_Block_size( block );
137  next_block = _Heap_Block_at( block, block_size );
138
139  if ( !_Heap_Is_block_in_heap( heap, next_block ) ) {
140    return false;
141  }
142
143  _Heap_Protection_block_check( heap, next_block );
144
145  if ( !_Heap_Is_prev_used( next_block ) ) {
146    _Heap_Protection_block_error( heap, block );
147    return false;
148  }
149
150  if ( !_Heap_Protection_determine_block_free( heap, block ) ) {
151    return true;
152  }
153
154  next_block_size = _Heap_Block_size( next_block );
155  next_is_free = next_block != heap->last_block
156    && !_Heap_Is_prev_used( _Heap_Block_at( next_block, next_block_size ));
157
158  if ( !_Heap_Is_prev_used( block ) ) {
159    uintptr_t const prev_size = block->prev_size;
160    Heap_Block * const prev_block = _Heap_Block_at( block, -prev_size );
161
162    if ( !_Heap_Is_block_in_heap( heap, prev_block ) ) {
163      _HAssert( false );
164      return( false );
165    }
166
167    /* As we always coalesce free blocks, the block that preceedes prev_block
168       must have been used. */
169    if ( !_Heap_Is_prev_used ( prev_block) ) {
170      _HAssert( false );
171      return( false );
172    }
173
174    if ( next_is_free ) {       /* coalesce both */
175      uintptr_t const size = block_size + prev_size + next_block_size;
176      _Heap_Free_list_remove( next_block );
177      stats->free_blocks -= 1;
178      prev_block->size_and_flag = size | HEAP_PREV_BLOCK_USED;
179      next_block = _Heap_Block_at( prev_block, size );
180      _HAssert(!_Heap_Is_prev_used( next_block));
181      next_block->prev_size = size;
182    } else {                      /* coalesce prev */
183      uintptr_t const size = block_size + prev_size;
184      prev_block->size_and_flag = size | HEAP_PREV_BLOCK_USED;
185      next_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED;
186      next_block->prev_size = size;
187    }
188  } else if ( next_is_free ) {    /* coalesce next */
189    uintptr_t const size = block_size + next_block_size;
190    _Heap_Free_list_replace( next_block, block );
191    block->size_and_flag = size | HEAP_PREV_BLOCK_USED;
192    next_block  = _Heap_Block_at( block, size );
193    next_block->prev_size = size;
194  } else {                        /* no coalesce */
195    /* Add 'block' to the head of the free blocks list as it tends to
196       produce less fragmentation than adding to the tail. */
197    _Heap_Free_list_insert_after( _Heap_Free_list_head( heap), block );
198    block->size_and_flag = block_size | HEAP_PREV_BLOCK_USED;
199    next_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED;
200    next_block->prev_size = block_size;
201
202    /* Statistics */
203    ++stats->free_blocks;
204    if ( stats->max_free_blocks < stats->free_blocks ) {
205      stats->max_free_blocks = stats->free_blocks;
206    }
207  }
208
209  /* Statistics */
210  --stats->used_blocks;
211  ++stats->frees;
212  stats->free_size += block_size;
213
214  return( true );
215}
Note: See TracBrowser for help on using the repository browser.