source: rtems/cpukit/score/src/heapresizeblock.c @ b72e847b

4.8
Last change on this file since b72e847b was 2ff7d00, checked in by Ralf Corsepius <ralf.corsepius@…>, on 05/08/07 at 15:34:14

Add HAVE_CONFIG_H magic.

  • Property mode set to 100644
File size: 6.0 KB
Line 
1/*
2 *  Heap Handler
3 *
4 *  COPYRIGHT (c) 1989-1999.
5 *  On-Line Applications Research Corporation (OAR).
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.com/license/LICENSE.
10 *
11 *  $Id$
12 */
13
14#if HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18#include <rtems/system.h>
19#include <rtems/score/sysstate.h>
20#include <rtems/score/heap.h>
21
22/*
23 *  _Heap_Resize_block
24 *
25 *  DESCRIPTION:
26 *
27 *  This routine tries to resize in place the block that is pointed to by the
28 *  'starting_address' to the new 'size'.
29 *
30 *  Input parameters:
31 *    the_heap         - pointer to heap header
32 *    starting_address - starting address of the memory block
33 *    size             - new size
34 *
35 *  Output parameters:
36 *    'old_mem_size'   - the size of the user memory area of the block before
37 *                       resizing.
38 *    'avail_mem_size' - the size of the user memory area of the free block
39 *                       that has been enlarged or created due to resizing,
40 *                       0 if none.
41 *    Returns
42 *      HEAP_RESIZE_SUCCESSFUL  - if success
43 *      HEAP_RESIZE_UNSATISFIED - if the block can't be resized in place
44 *      HEAP_RESIZE_FATAL_ERROR - if failure
45 */
46
47Heap_Resize_status _Heap_Resize_block(
48  Heap_Control *the_heap,
49  void         *starting_address,
50  size_t        size,
51  uint32_t     *old_mem_size,
52  uint32_t     *avail_mem_size
53)
54{
55  Heap_Block *the_block;
56  Heap_Block *next_block;
57  uint32_t   next_block_size;
58  boolean    next_is_used;
59  Heap_Block *next_next_block;
60  uint32_t   old_block_size;
61  uint32_t   old_user_size;
62  uint32_t   prev_used_flag;
63  Heap_Statistics *const stats = &the_heap->stats;
64  uint32_t const min_block_size = the_heap->min_block_size;
65  uint32_t const page_size = the_heap->page_size;
66
67  *old_mem_size = 0;
68  *avail_mem_size = 0;
69
70  _Heap_Start_of_block(the_heap, starting_address, &the_block);
71  _HAssert(_Heap_Is_block_in(the_heap, the_block));
72  if (!_Heap_Is_block_in(the_heap, the_block))
73    return HEAP_RESIZE_FATAL_ERROR;
74
75  prev_used_flag = the_block->size & HEAP_PREV_USED;
76  old_block_size = _Heap_Block_size(the_block);
77  next_block = _Heap_Block_at(the_block, old_block_size);
78
79  _HAssert(_Heap_Is_block_in(the_heap, next_block));
80  _HAssert(_Heap_Is_prev_used(next_block));
81  if ( !_Heap_Is_block_in(the_heap, next_block) ||
82       !_Heap_Is_prev_used(next_block))
83    return HEAP_RESIZE_FATAL_ERROR;
84
85  next_block_size = _Heap_Block_size(next_block);
86  next_next_block = _Heap_Block_at(next_block, next_block_size);
87  next_is_used    = (next_block == the_heap->final) ||
88                     _Heap_Is_prev_used(next_next_block);
89
90  /* See _Heap_Size_of_user_area() source for explanations */
91  old_user_size = _Addresses_Subtract(next_block, starting_address)
92    + HEAP_BLOCK_HEADER_OFFSET;
93
94  *old_mem_size = old_user_size;
95
96  if (size > old_user_size) {
97    /* Need to extend the block: allocate part of the next block and then
98       merge 'the_block' and allocated block together. */
99    if (next_is_used)    /* Next block is in use, -- no way to extend */
100      return HEAP_RESIZE_UNSATISFIED;
101    else {
102      uint32_t add_block_size = size - old_user_size;
103      _Heap_Align_up(&add_block_size, page_size);
104      if (add_block_size < min_block_size)
105        add_block_size = min_block_size;
106      if (add_block_size > next_block_size)
107        return HEAP_RESIZE_UNSATISFIED; /* Next block is too small or none. */
108      add_block_size =
109        _Heap_Block_allocate(the_heap, next_block, add_block_size);
110      /* Merge two subsequent blocks */
111      the_block->size = (old_block_size + add_block_size) | prev_used_flag;
112      --stats->used_blocks;
113    }
114  } else {
115
116    /* Calculate how much memory we could free */
117    uint32_t free_block_size = old_user_size - size;
118    _Heap_Align_down(&free_block_size, page_size);
119
120    if (free_block_size > 0) {
121
122      /* To free some memory the block should be shortened so that it can
123         can hold 'size' user bytes and still remain not shorter than
124         'min_block_size'. */
125
126      uint32_t new_block_size = old_block_size - free_block_size;
127
128      if (new_block_size < min_block_size) {
129        uint32_t delta = min_block_size - new_block_size;
130        _HAssert(free_block_size >= delta);
131        free_block_size -= delta;
132        if (free_block_size == 0) {
133          ++stats->resizes;
134          return HEAP_RESIZE_SUCCESSFUL;
135        }
136        new_block_size += delta;
137      }
138
139      _HAssert(new_block_size >= min_block_size);
140      _HAssert(new_block_size + free_block_size == old_block_size);
141      _HAssert(_Heap_Is_aligned(new_block_size, page_size));
142      _HAssert(_Heap_Is_aligned(free_block_size, page_size));
143
144      if (!next_is_used) {
145        /* Extend the next block to the low addresses by 'free_block_size' */
146        Heap_Block *const new_next_block =
147          _Heap_Block_at(the_block, new_block_size);
148        uint32_t const new_next_block_size =
149          next_block_size + free_block_size;
150        _HAssert(_Heap_Is_block_in(the_heap, next_next_block));
151        the_block->size = new_block_size | prev_used_flag;
152        new_next_block->size = new_next_block_size | HEAP_PREV_USED;
153        next_next_block->prev_size = new_next_block_size;
154        _Heap_Block_replace(next_block, new_next_block);
155        the_heap->stats.free_size += free_block_size;
156        *avail_mem_size = new_next_block_size - HEAP_BLOCK_USED_OVERHEAD;
157
158      } else if (free_block_size >= min_block_size) {
159        /* Split the block into 2 used  parts, then free the second one. */
160        the_block->size = new_block_size | prev_used_flag;
161        next_block = _Heap_Block_at(the_block, new_block_size);
162        next_block->size = free_block_size | HEAP_PREV_USED;
163        ++stats->used_blocks; /* We have created used block */
164        --stats->frees;       /* Don't count next call in stats */
165        _Heap_Free(the_heap, _Heap_User_area(next_block));
166        *avail_mem_size = free_block_size - HEAP_BLOCK_USED_OVERHEAD;
167      }
168    }
169  }
170
171  ++stats->resizes;
172  return HEAP_RESIZE_SUCCESSFUL;
173}
Note: See TracBrowser for help on using the repository browser.