source: rtems/cpukit/sapi/src/rbheap.c @ 38f8e548

Last change on this file since 38f8e548 was 38f8e548, checked in by Sebastian Huber <sebastian.huber@…>, on 04/10/12 at 09:19:39

rbheap: New files

In the Red-Black Tree Heap the administration data structures are not
contained in the managed memory area. This can be used for example in a
task stack allocator which protects the task stacks from access by other
tasks.

  • 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 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.com/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 page_alignment, uintptr_t value)
32{
33  uintptr_t excess = value % page_alignment;
34
35  if (excess > 0) {
36    value += page_alignment - excess;
37  }
38
39  return value;
40}
41
42static uintptr_t align_down(uintptr_t page_alignment, uintptr_t value)
43{
44  uintptr_t excess = value % page_alignment;
45
46  return value - excess;
47}
48
49static int page_compare(const rtems_rbtree_node *a, const rtems_rbtree_node *b)
50{
51  const rtems_rbheap_page *left = rtems_rbheap_page_of_node(a);
52  const rtems_rbheap_page *right = rtems_rbheap_page_of_node(b);
53
54  return (int) (left->begin - right->begin);
55}
56
57static rtems_rbheap_page *get_page(rtems_rbheap_control *control)
58{
59  rtems_chain_control *pool_chain = &control->pool_chain;
60  rtems_chain_node *page = rtems_chain_get(pool_chain);
61
62  if (page == NULL) {
63    (*control->extend_page_pool)(control);
64    page = rtems_chain_get(pool_chain);
65  }
66
67  return (rtems_rbheap_page *) page;
68}
69
70static void add_to_chain(
71  rtems_chain_control *chain,
72  rtems_rbheap_page *page
73)
74{
75  rtems_chain_prepend_unprotected(chain, &page->chain_node);
76}
77
78static void insert_into_tree(
79  rtems_rbtree_control *tree,
80  rtems_rbheap_page *page
81)
82{
83  _RBTree_Insert_unprotected(tree, &page->tree_node);
84}
85
86rtems_status_code rtems_rbheap_initialize(
87  rtems_rbheap_control *control,
88  void *area_begin,
89  uintptr_t area_size,
90  uintptr_t page_alignment,
91  rtems_rbheap_extend_page_pool extend_page_pool,
92  void *handler_arg
93)
94{
95  rtems_status_code sc = RTEMS_SUCCESSFUL;
96
97  if (page_alignment > 0) {
98    uintptr_t begin = (uintptr_t) area_begin;
99    uintptr_t end = begin + area_size;
100    uintptr_t aligned_begin = align_up(page_alignment, begin);
101    uintptr_t aligned_end = align_down(page_alignment, end);
102
103    if (begin < end && begin <= aligned_begin && aligned_begin < aligned_end) {
104      rtems_chain_control *free_chain = &control->free_chain;
105      rtems_rbtree_control *page_tree = &control->page_tree;
106      rtems_rbheap_page *first = NULL;
107
108      rtems_chain_initialize_empty(free_chain);
109      rtems_chain_initialize_empty(&control->pool_chain);
110      rtems_rbtree_initialize_empty(page_tree, page_compare, true);
111      control->page_alignment = page_alignment;
112      control->handler_arg = handler_arg;
113      control->extend_page_pool = extend_page_pool;
114
115      first = get_page(control);
116      if (first != NULL) {
117        first->begin = aligned_begin;
118        first->size = aligned_end - aligned_begin;
119        add_to_chain(free_chain, first);
120        insert_into_tree(page_tree, first);
121      } else {
122        sc = RTEMS_NO_MEMORY;
123      }
124    } else {
125      sc = RTEMS_INVALID_ADDRESS;
126    }
127  } else {
128    sc = RTEMS_INVALID_NUMBER;
129  }
130
131  return sc;
132}
133
134static rtems_rbheap_page *search_free_page(
135  rtems_chain_control *free_chain,
136  size_t size
137)
138{
139  rtems_chain_node *current = rtems_chain_first(free_chain);
140  const rtems_chain_node *tail = rtems_chain_tail(free_chain);
141  rtems_rbheap_page *big_enough = NULL;
142
143  while (current != tail && big_enough == NULL) {
144    rtems_rbheap_page *free_page = (rtems_rbheap_page *) current;
145
146    if (free_page->size >= size) {
147      big_enough = free_page;
148    }
149
150    current = rtems_chain_next(current);
151  }
152
153  return big_enough;
154}
155
156void *rtems_rbheap_allocate(rtems_rbheap_control *control, size_t size)
157{
158  void *ptr = NULL;
159  rtems_chain_control *free_chain = &control->free_chain;
160  rtems_rbtree_control *page_tree = &control->page_tree;
161  uintptr_t page_alignment = control->page_alignment;
162  uintptr_t aligned_size = align_up(page_alignment, size);
163
164  if (size > 0 && size <= aligned_size) {
165    rtems_rbheap_page *free_page = search_free_page(free_chain, aligned_size);
166
167    if (free_page != NULL) {
168      uintptr_t free_size = free_page->size;
169
170      if (free_size > aligned_size) {
171        rtems_rbheap_page *new_page = get_page(control);
172
173        if (new_page != NULL) {
174          uintptr_t new_free_size = free_size - aligned_size;
175
176          free_page->size = new_free_size;
177          new_page->begin = free_page->begin + new_free_size;
178          new_page->size = aligned_size;
179          rtems_chain_set_off_chain(&new_page->chain_node);
180          insert_into_tree(page_tree, new_page);
181          ptr = (void *) new_page->begin;
182        }
183      } else {
184        rtems_chain_extract_unprotected(&free_page->chain_node);
185        rtems_chain_set_off_chain(&free_page->chain_node);
186        ptr = (void *) free_page->begin;
187      }
188    }
189  }
190
191  return ptr;
192}
193
194#define NULL_PAGE rtems_rbheap_page_of_node(NULL)
195
196static rtems_rbheap_page *find(rtems_rbtree_control *page_tree, uintptr_t key)
197{
198  rtems_rbheap_page page = { .begin = key };
199
200  return rtems_rbheap_page_of_node(
201    _RBTree_Find_unprotected(page_tree, &page.tree_node)
202  );
203}
204
205static rtems_rbheap_page *get_next(
206  const rtems_rbtree_control *page_tree,
207  const rtems_rbheap_page *page,
208  RBTree_Direction dir
209)
210{
211  return rtems_rbheap_page_of_node(
212    _RBTree_Next(page_tree, &page->tree_node, dir)
213  );
214}
215
216static void check_and_merge(
217  rtems_chain_control *free_chain,
218  rtems_rbtree_control *page_tree,
219  rtems_rbheap_page *a,
220  rtems_rbheap_page *b
221)
222{
223  if (b != NULL_PAGE && rtems_rbheap_is_page_free(b)) {
224    if (b->begin < a->begin) {
225      rtems_rbheap_page *t = a;
226
227      a = b;
228      b = t;
229    }
230
231    a->size += b->size;
232    rtems_chain_extract_unprotected(&b->chain_node);
233    add_to_chain(free_chain, b);
234    _RBTree_Extract_unprotected(page_tree, &b->tree_node);
235  }
236}
237
238rtems_status_code rtems_rbheap_free(rtems_rbheap_control *control, void *ptr)
239{
240  rtems_status_code sc = RTEMS_SUCCESSFUL;
241  rtems_chain_control *free_chain = &control->free_chain;
242  rtems_rbtree_control *page_tree = &control->page_tree;
243  rtems_rbheap_page *page = find(page_tree, (uintptr_t) ptr);
244
245  if (page != NULL_PAGE) {
246    if (!rtems_rbheap_is_page_free(page)) {
247      rtems_rbheap_page *pred = get_next(page_tree, page, RBT_LEFT);
248      rtems_rbheap_page *succ = get_next(page_tree, page, RBT_RIGHT);
249
250      check_and_merge(free_chain, page_tree, page, succ);
251      add_to_chain(free_chain, page);
252      check_and_merge(free_chain, page_tree, page, pred);
253    } else {
254      sc = RTEMS_INCORRECT_STATE;
255    }
256  } else {
257    sc = RTEMS_INVALID_ID;
258  }
259
260  return sc;
261}
262
263void rtems_rbheap_extend_page_pool_never(rtems_rbheap_control *control)
264{
265  /* Do nothing */
266}
267
268void rtems_rbheap_extend_page_pool_with_malloc(rtems_rbheap_control *control)
269{
270  rtems_rbheap_page *page = malloc(sizeof(*page));
271
272  if (page != NULL) {
273    rtems_chain_control *pool_chain = rtems_rbheap_get_pool_chain(control);
274
275    add_to_chain(pool_chain, page);
276  }
277}
Note: See TracBrowser for help on using the repository browser.