source: rtems/cpukit/score/src/heapfree.c @ 2d7ae960

4.115
Last change on this file since 2d7ae960 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

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