source: rtems/cpukit/sapi/src/rbheap.c @ 599d71f

5
Last change on this file since 599d71f was 10c4636, checked in by Sebastian Huber <sebastian.huber@…>, on 09/11/15 at 08:42:06

rbheap: Fix rtems_rbheap_free()

Remove unused descriptor of merged free chunks from the free chain and
add them to the spare descriptors.

Close #2417.

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RBHeap
5 *
6 * @brief Red-Black Tree Heap implementation.
7 */
8
9/*
10 * Copyright (c) 2012-2015 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#if HAVE_CONFIG_H
24  #include "config.h"
25#endif
26
27#include <rtems/rbheap.h>
28
29#include <stdlib.h>
30
31static uintptr_t align_up(uintptr_t alignment, uintptr_t value)
32{
33  uintptr_t excess = value % alignment;
34
35  if (excess > 0) {
36    value += alignment - excess;
37  }
38
39  return value;
40}
41
42static uintptr_t align_down(uintptr_t alignment, uintptr_t value)
43{
44  uintptr_t excess = value % alignment;
45
46  return value - excess;
47}
48
49static rtems_rbtree_compare_result chunk_compare(
50  const rtems_rbtree_node *a,
51  const rtems_rbtree_node *b
52)
53{
54  const rtems_rbheap_chunk *left = rtems_rbheap_chunk_of_node(a);
55  const rtems_rbheap_chunk *right = rtems_rbheap_chunk_of_node(b);
56
57  return (rtems_rbtree_compare_result)
58    ((left->begin >> 1) - (right->begin >> 1));
59}
60
61static rtems_rbheap_chunk *get_chunk(rtems_rbheap_control *control)
62{
63  rtems_chain_control *chain = &control->spare_descriptor_chain;
64  rtems_chain_node *chunk = rtems_chain_get_unprotected(chain);
65
66  if (chunk == NULL) {
67    (*control->extend_descriptors)(control);
68    chunk = rtems_chain_get_unprotected(chain);
69  }
70
71  return (rtems_rbheap_chunk *) chunk;
72}
73
74static void add_to_chain(
75  rtems_chain_control *chain,
76  rtems_rbheap_chunk *chunk
77)
78{
79  rtems_chain_prepend_unprotected(chain, &chunk->chain_node);
80}
81
82static void insert_into_tree(
83  rtems_rbtree_control *tree,
84  rtems_rbheap_chunk *chunk
85)
86{
87  rtems_rbtree_insert(tree, &chunk->tree_node, chunk_compare, true);
88}
89
90rtems_status_code rtems_rbheap_initialize(
91  rtems_rbheap_control *control,
92  void *area_begin,
93  uintptr_t area_size,
94  uintptr_t alignment,
95  rtems_rbheap_extend_descriptors extend_descriptors,
96  void *handler_arg
97)
98{
99  rtems_status_code sc = RTEMS_SUCCESSFUL;
100  uintptr_t begin = (uintptr_t) area_begin;
101  uintptr_t end = begin + area_size;
102  uintptr_t aligned_begin;
103  uintptr_t aligned_end;
104
105  /*
106   * Ensure that the alignment is at least two, so that we can keep
107   * chunk_compare() that simple.
108   */
109  alignment = alignment < 2 ? 2 : alignment;
110
111  aligned_begin = align_up(alignment, begin);
112  aligned_end = align_down(alignment, end);
113
114  if (begin < end && begin <= aligned_begin && aligned_begin < aligned_end) {
115    rtems_chain_control *free_chain = &control->free_chunk_chain;
116    rtems_rbtree_control *chunk_tree = &control->chunk_tree;
117    rtems_rbheap_chunk *first = NULL;
118
119    rtems_chain_initialize_empty(free_chain);
120    rtems_chain_initialize_empty(&control->spare_descriptor_chain);
121    rtems_rbtree_initialize_empty(chunk_tree);
122    control->alignment = alignment;
123    control->handler_arg = handler_arg;
124    control->extend_descriptors = extend_descriptors;
125
126    first = get_chunk(control);
127    if (first != NULL) {
128      first->begin = aligned_begin;
129      first->size = aligned_end - aligned_begin;
130      add_to_chain(free_chain, first);
131      insert_into_tree(chunk_tree, first);
132    } else {
133      sc = RTEMS_NO_MEMORY;
134    }
135  } else {
136    sc = RTEMS_INVALID_ADDRESS;
137  }
138
139  return sc;
140}
141
142static rtems_rbheap_chunk *search_free_chunk(
143  rtems_chain_control *free_chain,
144  size_t size
145)
146{
147  rtems_chain_node *current = rtems_chain_first(free_chain);
148  const rtems_chain_node *tail = rtems_chain_tail(free_chain);
149  rtems_rbheap_chunk *big_enough = NULL;
150
151  while (current != tail && big_enough == NULL) {
152    rtems_rbheap_chunk *free_chunk = (rtems_rbheap_chunk *) current;
153
154    if (free_chunk->size >= size) {
155      big_enough = free_chunk;
156    }
157
158    current = rtems_chain_next(current);
159  }
160
161  return big_enough;
162}
163
164void *rtems_rbheap_allocate(rtems_rbheap_control *control, size_t size)
165{
166  void *ptr = NULL;
167  rtems_chain_control *free_chain = &control->free_chunk_chain;
168  rtems_rbtree_control *chunk_tree = &control->chunk_tree;
169  uintptr_t alignment = control->alignment;
170  uintptr_t aligned_size = align_up(alignment, size);
171
172  if (size > 0 && size <= aligned_size) {
173    rtems_rbheap_chunk *free_chunk = search_free_chunk(free_chain, aligned_size);
174
175    if (free_chunk != NULL) {
176      uintptr_t free_size = free_chunk->size;
177
178      if (free_size > aligned_size) {
179        rtems_rbheap_chunk *new_chunk = get_chunk(control);
180
181        if (new_chunk != NULL) {
182          uintptr_t new_free_size = free_size - aligned_size;
183
184          free_chunk->size = new_free_size;
185          new_chunk->begin = free_chunk->begin + new_free_size;
186          new_chunk->size = aligned_size;
187          rtems_chain_set_off_chain(&new_chunk->chain_node);
188          insert_into_tree(chunk_tree, new_chunk);
189          ptr = (void *) new_chunk->begin;
190        }
191      } else {
192        rtems_chain_extract_unprotected(&free_chunk->chain_node);
193        rtems_chain_set_off_chain(&free_chunk->chain_node);
194        ptr = (void *) free_chunk->begin;
195      }
196    }
197  }
198
199  return ptr;
200}
201
202#define NULL_PAGE rtems_rbheap_chunk_of_node(NULL)
203
204static rtems_rbheap_chunk *find(rtems_rbtree_control *chunk_tree, uintptr_t key)
205{
206  rtems_rbheap_chunk chunk = { .begin = key };
207
208  return rtems_rbheap_chunk_of_node(
209    rtems_rbtree_find(chunk_tree, &chunk.tree_node, chunk_compare, true)
210  );
211}
212
213static rtems_rbheap_chunk *pred(const rtems_rbheap_chunk *chunk)
214{
215  return rtems_rbheap_chunk_of_node(
216    rtems_rbtree_predecessor(&chunk->tree_node)
217  );
218}
219
220static rtems_rbheap_chunk *succ(const rtems_rbheap_chunk *chunk)
221{
222  return rtems_rbheap_chunk_of_node(
223    rtems_rbtree_successor(&chunk->tree_node)
224  );
225}
226
227static void check_and_merge(
228  rtems_rbheap_control *control,
229  rtems_rbheap_chunk *a,
230  rtems_rbheap_chunk *b,
231  rtems_rbheap_chunk *c
232)
233{
234  if (c != NULL_PAGE && rtems_rbheap_is_chunk_free(c)) {
235    a->size += b->size;
236    rtems_chain_extract_unprotected(&b->chain_node);
237    rtems_rbheap_add_to_spare_descriptor_chain(control, b);
238    rtems_rbtree_extract(&control->chunk_tree, &b->tree_node);
239  }
240}
241
242rtems_status_code rtems_rbheap_free(rtems_rbheap_control *control, void *ptr)
243{
244  rtems_status_code sc = RTEMS_SUCCESSFUL;
245
246  if (ptr != NULL) {
247    rtems_rbheap_chunk *chunk = find(&control->chunk_tree, (uintptr_t) ptr);
248
249    if (chunk != NULL_PAGE) {
250      if (!rtems_rbheap_is_chunk_free(chunk)) {
251        rtems_rbheap_chunk *other;
252
253        add_to_chain(&control->free_chunk_chain, chunk);
254        other = succ(chunk);
255        check_and_merge(control, chunk, other, other);
256        other = pred(chunk);
257        check_and_merge(control, other, chunk, other);
258      } else {
259        sc = RTEMS_INCORRECT_STATE;
260      }
261    } else {
262      sc = RTEMS_INVALID_ID;
263    }
264  }
265
266  return sc;
267}
268
269void rtems_rbheap_extend_descriptors_never(rtems_rbheap_control *control)
270{
271  /* Do nothing */
272}
273
274void rtems_rbheap_extend_descriptors_with_malloc(rtems_rbheap_control *control)
275{
276  rtems_rbheap_chunk *chunk = malloc(sizeof(*chunk));
277
278  if (chunk != NULL) {
279    rtems_rbheap_add_to_spare_descriptor_chain(control, chunk);
280  }
281}
Note: See TracBrowser for help on using the repository browser.