source: rtems/cpukit/sapi/src/rbheap.c

Last change on this file was bcef89f2, checked in by Sebastian Huber <sebastian.huber@…>, on 05/19/23 at 06:18:25

Update company name

The embedded brains GmbH & Co. KG is the legal successor of embedded
brains GmbH.

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSAPIRBHeap
7 *
8 * @brief This source file contains the implementation of
9 *   rtems_rbheap_allocate(), rtems_rbheap_extend_descriptors_never(),
10 *   rtems_rbheap_extend_descriptors_with_malloc(), rtems_rbheap_free(), and
11 *   rtems_rbheap_initialize().
12 */
13
14/*
15 * Copyright (C) 2012, 2015 embedded brains GmbH & Co. KG
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 *    notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 *    notice, this list of conditions and the following disclaimer in the
24 *    documentation and/or other materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
42
43#include <rtems/rbheap.h>
44
45#include <stdlib.h>
46
47static uintptr_t align_up(uintptr_t alignment, uintptr_t value)
48{
49  uintptr_t excess = value % alignment;
50
51  if (excess > 0) {
52    value += alignment - excess;
53  }
54
55  return value;
56}
57
58static uintptr_t align_down(uintptr_t alignment, uintptr_t value)
59{
60  uintptr_t excess = value % alignment;
61
62  return value - excess;
63}
64
65static rtems_rbtree_compare_result chunk_compare(
66  const rtems_rbtree_node *a,
67  const rtems_rbtree_node *b
68)
69{
70  const rtems_rbheap_chunk *left = rtems_rbheap_chunk_of_node(a);
71  const rtems_rbheap_chunk *right = rtems_rbheap_chunk_of_node(b);
72
73  return (rtems_rbtree_compare_result)
74    ((left->begin >> 1) - (right->begin >> 1));
75}
76
77static rtems_rbheap_chunk *get_chunk(rtems_rbheap_control *control)
78{
79  rtems_chain_control *chain = &control->spare_descriptor_chain;
80  rtems_chain_node *chunk = rtems_chain_get_unprotected(chain);
81
82  if (chunk == NULL) {
83    (*control->extend_descriptors)(control);
84    chunk = rtems_chain_get_unprotected(chain);
85  }
86
87  return (rtems_rbheap_chunk *) chunk;
88}
89
90static void add_to_chain(
91  rtems_chain_control *chain,
92  rtems_rbheap_chunk *chunk
93)
94{
95  rtems_chain_initialize_node(&chunk->chain_node);
96  rtems_chain_prepend_unprotected(chain, &chunk->chain_node);
97}
98
99static void insert_into_tree(
100  rtems_rbtree_control *tree,
101  rtems_rbheap_chunk *chunk
102)
103{
104  rtems_rbtree_insert(tree, &chunk->tree_node, chunk_compare, true);
105}
106
107rtems_status_code rtems_rbheap_initialize(
108  rtems_rbheap_control *control,
109  void *area_begin,
110  uintptr_t area_size,
111  uintptr_t alignment,
112  rtems_rbheap_extend_descriptors extend_descriptors,
113  void *handler_arg
114)
115{
116  rtems_status_code sc = RTEMS_SUCCESSFUL;
117  uintptr_t begin = (uintptr_t) area_begin;
118  uintptr_t end = begin + area_size;
119  uintptr_t aligned_begin;
120  uintptr_t aligned_end;
121
122  /*
123   * Ensure that the alignment is at least two, so that we can keep
124   * chunk_compare() that simple.
125   */
126  alignment = alignment < 2 ? 2 : alignment;
127
128  aligned_begin = align_up(alignment, begin);
129  aligned_end = align_down(alignment, end);
130
131  if (begin < end && begin <= aligned_begin && aligned_begin < aligned_end) {
132    rtems_chain_control *free_chain = &control->free_chunk_chain;
133    rtems_rbtree_control *chunk_tree = &control->chunk_tree;
134    rtems_rbheap_chunk *first = NULL;
135
136    rtems_chain_initialize_empty(free_chain);
137    rtems_chain_initialize_empty(&control->spare_descriptor_chain);
138    rtems_rbtree_initialize_empty(chunk_tree);
139    control->alignment = alignment;
140    control->handler_arg = handler_arg;
141    control->extend_descriptors = extend_descriptors;
142
143    first = get_chunk(control);
144    if (first != NULL) {
145      first->begin = aligned_begin;
146      first->size = aligned_end - aligned_begin;
147      add_to_chain(free_chain, first);
148      insert_into_tree(chunk_tree, first);
149    } else {
150      sc = RTEMS_NO_MEMORY;
151    }
152  } else {
153    sc = RTEMS_INVALID_ADDRESS;
154  }
155
156  return sc;
157}
158
159static rtems_rbheap_chunk *search_free_chunk(
160  rtems_chain_control *free_chain,
161  size_t size
162)
163{
164  rtems_chain_node *current = rtems_chain_first(free_chain);
165  const rtems_chain_node *tail = rtems_chain_tail(free_chain);
166  rtems_rbheap_chunk *big_enough = NULL;
167
168  while (current != tail && big_enough == NULL) {
169    rtems_rbheap_chunk *free_chunk = (rtems_rbheap_chunk *) current;
170
171    if (free_chunk->size >= size) {
172      big_enough = free_chunk;
173    }
174
175    current = rtems_chain_next(current);
176  }
177
178  return big_enough;
179}
180
181void *rtems_rbheap_allocate(rtems_rbheap_control *control, size_t size)
182{
183  void *ptr = NULL;
184  rtems_chain_control *free_chain = &control->free_chunk_chain;
185  rtems_rbtree_control *chunk_tree = &control->chunk_tree;
186  uintptr_t alignment = control->alignment;
187  uintptr_t aligned_size = align_up(alignment, size);
188
189  if (size > 0 && size <= aligned_size) {
190    rtems_rbheap_chunk *free_chunk = search_free_chunk(free_chain, aligned_size);
191
192    if (free_chunk != NULL) {
193      uintptr_t free_size = free_chunk->size;
194
195      if (free_size > aligned_size) {
196        rtems_rbheap_chunk *new_chunk = get_chunk(control);
197
198        if (new_chunk != NULL) {
199          uintptr_t new_free_size = free_size - aligned_size;
200
201          free_chunk->size = new_free_size;
202          new_chunk->begin = free_chunk->begin + new_free_size;
203          new_chunk->size = aligned_size;
204          rtems_chain_set_off_chain(&new_chunk->chain_node);
205          insert_into_tree(chunk_tree, new_chunk);
206          ptr = (void *) new_chunk->begin;
207        }
208      } else {
209        rtems_chain_extract_unprotected(&free_chunk->chain_node);
210        rtems_chain_set_off_chain(&free_chunk->chain_node);
211        ptr = (void *) free_chunk->begin;
212      }
213    }
214  }
215
216  return ptr;
217}
218
219#define NULL_PAGE rtems_rbheap_chunk_of_node(NULL)
220
221static rtems_rbheap_chunk *find(rtems_rbtree_control *chunk_tree, uintptr_t key)
222{
223  rtems_rbheap_chunk chunk = { .begin = key };
224
225  return rtems_rbheap_chunk_of_node(
226    rtems_rbtree_find(chunk_tree, &chunk.tree_node, chunk_compare, true)
227  );
228}
229
230static rtems_rbheap_chunk *pred(const rtems_rbheap_chunk *chunk)
231{
232  return rtems_rbheap_chunk_of_node(
233    rtems_rbtree_predecessor(&chunk->tree_node)
234  );
235}
236
237static rtems_rbheap_chunk *succ(const rtems_rbheap_chunk *chunk)
238{
239  return rtems_rbheap_chunk_of_node(
240    rtems_rbtree_successor(&chunk->tree_node)
241  );
242}
243
244static void check_and_merge(
245  rtems_rbheap_control *control,
246  rtems_rbheap_chunk *a,
247  rtems_rbheap_chunk *b,
248  rtems_rbheap_chunk *c
249)
250{
251  if (c != NULL_PAGE && rtems_rbheap_is_chunk_free(c)) {
252    a->size += b->size;
253    rtems_chain_extract_unprotected(&b->chain_node);
254    rtems_rbheap_add_to_spare_descriptor_chain(control, b);
255    rtems_rbtree_extract(&control->chunk_tree, &b->tree_node);
256  }
257}
258
259rtems_status_code rtems_rbheap_free(rtems_rbheap_control *control, void *ptr)
260{
261  rtems_status_code sc = RTEMS_SUCCESSFUL;
262
263  if (ptr != NULL) {
264    rtems_rbheap_chunk *chunk = find(&control->chunk_tree, (uintptr_t) ptr);
265
266    if (chunk != NULL_PAGE) {
267      if (!rtems_rbheap_is_chunk_free(chunk)) {
268        rtems_rbheap_chunk *other;
269
270        add_to_chain(&control->free_chunk_chain, chunk);
271        other = succ(chunk);
272        check_and_merge(control, chunk, other, other);
273        other = pred(chunk);
274        check_and_merge(control, other, chunk, other);
275      } else {
276        sc = RTEMS_INCORRECT_STATE;
277      }
278    } else {
279      sc = RTEMS_INVALID_ID;
280    }
281  }
282
283  return sc;
284}
285
286void rtems_rbheap_extend_descriptors_never(rtems_rbheap_control *control)
287{
288  /* Do nothing */
289}
290
291void rtems_rbheap_extend_descriptors_with_malloc(rtems_rbheap_control *control)
292{
293  rtems_rbheap_chunk *chunk = malloc(sizeof(*chunk));
294
295  if (chunk != NULL) {
296    rtems_rbheap_add_to_spare_descriptor_chain(control, chunk);
297  }
298}
Note: See TracBrowser for help on using the repository browser.