source: rtems/cpukit/sapi/src/rbheap.c @ 60fe374

4.115
Last change on this file since 60fe374 was 60fe374, checked in by Sebastian Huber <sebastian.huber@…>, on 08/03/14 at 11:02:58

rbtree: Add and use RBTree_Compare_result

  • Property mode set to 100644
File size: 7.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RBHeap
5 *
6 * @brief Red-Black Tree Heap implementation.
7 */
8
9/*
10 * Copyright (c) 2012 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Obere Lagerstr. 30
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 *get_next(
214  const rtems_rbheap_chunk *chunk,
215  RBTree_Direction dir
216)
217{
218  return rtems_rbheap_chunk_of_node(
219    _RBTree_Next(&chunk->tree_node, dir)
220  );
221}
222
223static void check_and_merge(
224  rtems_chain_control *free_chain,
225  rtems_rbtree_control *chunk_tree,
226  rtems_rbheap_chunk *a,
227  rtems_rbheap_chunk *b
228)
229{
230  if (b != NULL_PAGE && rtems_rbheap_is_chunk_free(b)) {
231    if (b->begin < a->begin) {
232      rtems_rbheap_chunk *t = a;
233
234      a = b;
235      b = t;
236    }
237
238    a->size += b->size;
239    rtems_chain_extract_unprotected(&b->chain_node);
240    add_to_chain(free_chain, b);
241    rtems_rbtree_extract(chunk_tree, &b->tree_node);
242  }
243}
244
245rtems_status_code rtems_rbheap_free(rtems_rbheap_control *control, void *ptr)
246{
247  rtems_status_code sc = RTEMS_SUCCESSFUL;
248
249  if (ptr != NULL) {
250    rtems_chain_control *free_chain = &control->free_chunk_chain;
251    rtems_rbtree_control *chunk_tree = &control->chunk_tree;
252    rtems_rbheap_chunk *chunk = find(chunk_tree, (uintptr_t) ptr);
253
254    if (chunk != NULL_PAGE) {
255      if (!rtems_rbheap_is_chunk_free(chunk)) {
256        rtems_rbheap_chunk *pred = get_next(chunk, RBT_LEFT);
257        rtems_rbheap_chunk *succ = get_next(chunk, RBT_RIGHT);
258
259        check_and_merge(free_chain, chunk_tree, chunk, succ);
260        add_to_chain(free_chain, chunk);
261        check_and_merge(free_chain, chunk_tree, chunk, pred);
262      } else {
263        sc = RTEMS_INCORRECT_STATE;
264      }
265    } else {
266      sc = RTEMS_INVALID_ID;
267    }
268  }
269
270  return sc;
271}
272
273void rtems_rbheap_extend_descriptors_never(rtems_rbheap_control *control)
274{
275  /* Do nothing */
276}
277
278void rtems_rbheap_extend_descriptors_with_malloc(rtems_rbheap_control *control)
279{
280  rtems_rbheap_chunk *chunk = malloc(sizeof(*chunk));
281
282  if (chunk != NULL) {
283    rtems_rbheap_add_to_spare_descriptor_chain(control, chunk);
284  }
285}
Note: See TracBrowser for help on using the repository browser.