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
RevLine 
[bd2e898]1/* SPDX-License-Identifier: BSD-2-Clause */
2
[e752630]3/**
4 * @file
5 *
[3db9c820]6 * @ingroup RTEMSAPIRBHeap
[e752630]7 *
[3db9c820]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().
[e752630]12 */
13
14/*
[bcef89f2]15 * Copyright (C) 2012, 2015 embedded brains GmbH & Co. KG
[e752630]16 *
[bd2e898]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.
[e752630]37 */
38
[80cf60e]39#ifdef HAVE_CONFIG_H
40#include "config.h"
[e752630]41#endif
42
43#include <rtems/rbheap.h>
44
45#include <stdlib.h>
46
[5c51ba1]47static uintptr_t align_up(uintptr_t alignment, uintptr_t value)
[e752630]48{
[5c51ba1]49  uintptr_t excess = value % alignment;
[e752630]50
51  if (excess > 0) {
[5c51ba1]52    value += alignment - excess;
[e752630]53  }
54
55  return value;
56}
57
[5c51ba1]58static uintptr_t align_down(uintptr_t alignment, uintptr_t value)
[e752630]59{
[5c51ba1]60  uintptr_t excess = value % alignment;
[e752630]61
62  return value - excess;
63}
64
[60fe374]65static rtems_rbtree_compare_result chunk_compare(
66  const rtems_rbtree_node *a,
67  const rtems_rbtree_node *b
68)
[e752630]69{
[5c51ba1]70  const rtems_rbheap_chunk *left = rtems_rbheap_chunk_of_node(a);
71  const rtems_rbheap_chunk *right = rtems_rbheap_chunk_of_node(b);
[e752630]72
[60fe374]73  return (rtems_rbtree_compare_result)
74    ((left->begin >> 1) - (right->begin >> 1));
[e752630]75}
76
[5c51ba1]77static rtems_rbheap_chunk *get_chunk(rtems_rbheap_control *control)
[e752630]78{
[5c51ba1]79  rtems_chain_control *chain = &control->spare_descriptor_chain;
80  rtems_chain_node *chunk = rtems_chain_get_unprotected(chain);
[e752630]81
[5c51ba1]82  if (chunk == NULL) {
83    (*control->extend_descriptors)(control);
84    chunk = rtems_chain_get_unprotected(chain);
[e752630]85  }
86
[5c51ba1]87  return (rtems_rbheap_chunk *) chunk;
[e752630]88}
89
90static void add_to_chain(
91  rtems_chain_control *chain,
[5c51ba1]92  rtems_rbheap_chunk *chunk
[e752630]93)
94{
[059529e]95  rtems_chain_initialize_node(&chunk->chain_node);
[5c51ba1]96  rtems_chain_prepend_unprotected(chain, &chunk->chain_node);
[e752630]97}
98
99static void insert_into_tree(
100  rtems_rbtree_control *tree,
[5c51ba1]101  rtems_rbheap_chunk *chunk
[e752630]102)
103{
[64939bc]104  rtems_rbtree_insert(tree, &chunk->tree_node, chunk_compare, true);
[e752630]105}
106
107rtems_status_code rtems_rbheap_initialize(
108  rtems_rbheap_control *control,
109  void *area_begin,
110  uintptr_t area_size,
[5c51ba1]111  uintptr_t alignment,
112  rtems_rbheap_extend_descriptors extend_descriptors,
[e752630]113  void *handler_arg
114)
115{
116  rtems_status_code sc = RTEMS_SUCCESSFUL;
[60fe374]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);
[e752630]149    } else {
[60fe374]150      sc = RTEMS_NO_MEMORY;
[e752630]151    }
152  } else {
[60fe374]153    sc = RTEMS_INVALID_ADDRESS;
[e752630]154  }
155
156  return sc;
157}
158
[5c51ba1]159static rtems_rbheap_chunk *search_free_chunk(
[e752630]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);
[5c51ba1]166  rtems_rbheap_chunk *big_enough = NULL;
[e752630]167
168  while (current != tail && big_enough == NULL) {
[5c51ba1]169    rtems_rbheap_chunk *free_chunk = (rtems_rbheap_chunk *) current;
[e752630]170
[5c51ba1]171    if (free_chunk->size >= size) {
172      big_enough = free_chunk;
[e752630]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;
[5c51ba1]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);
[e752630]188
189  if (size > 0 && size <= aligned_size) {
[5c51ba1]190    rtems_rbheap_chunk *free_chunk = search_free_chunk(free_chain, aligned_size);
[e752630]191
[5c51ba1]192    if (free_chunk != NULL) {
193      uintptr_t free_size = free_chunk->size;
[e752630]194
195      if (free_size > aligned_size) {
[5c51ba1]196        rtems_rbheap_chunk *new_chunk = get_chunk(control);
[e752630]197
[5c51ba1]198        if (new_chunk != NULL) {
[e752630]199          uintptr_t new_free_size = free_size - aligned_size;
200
[5c51ba1]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;
[e752630]207        }
208      } else {
[5c51ba1]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;
[e752630]212      }
213    }
214  }
215
216  return ptr;
217}
218
[5c51ba1]219#define NULL_PAGE rtems_rbheap_chunk_of_node(NULL)
[e752630]220
[5c51ba1]221static rtems_rbheap_chunk *find(rtems_rbtree_control *chunk_tree, uintptr_t key)
[e752630]222{
[5c51ba1]223  rtems_rbheap_chunk chunk = { .begin = key };
[e752630]224
[5c51ba1]225  return rtems_rbheap_chunk_of_node(
[64939bc]226    rtems_rbtree_find(chunk_tree, &chunk.tree_node, chunk_compare, true)
[e752630]227  );
228}
229
[c72f132]230static rtems_rbheap_chunk *pred(const rtems_rbheap_chunk *chunk)
[e752630]231{
[5c51ba1]232  return rtems_rbheap_chunk_of_node(
[c72f132]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)
[e752630]241  );
242}
243
244static void check_and_merge(
[10c4636]245  rtems_rbheap_control *control,
[5c51ba1]246  rtems_rbheap_chunk *a,
[10c4636]247  rtems_rbheap_chunk *b,
248  rtems_rbheap_chunk *c
[e752630]249)
250{
[10c4636]251  if (c != NULL_PAGE && rtems_rbheap_is_chunk_free(c)) {
[e752630]252    a->size += b->size;
253    rtems_chain_extract_unprotected(&b->chain_node);
[10c4636]254    rtems_rbheap_add_to_spare_descriptor_chain(control, b);
255    rtems_rbtree_extract(&control->chunk_tree, &b->tree_node);
[e752630]256  }
257}
258
259rtems_status_code rtems_rbheap_free(rtems_rbheap_control *control, void *ptr)
260{
261  rtems_status_code sc = RTEMS_SUCCESSFUL;
[5c51ba1]262
263  if (ptr != NULL) {
[10c4636]264    rtems_rbheap_chunk *chunk = find(&control->chunk_tree, (uintptr_t) ptr);
[5c51ba1]265
266    if (chunk != NULL_PAGE) {
267      if (!rtems_rbheap_is_chunk_free(chunk)) {
[10c4636]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);
[5c51ba1]275      } else {
276        sc = RTEMS_INCORRECT_STATE;
277      }
[e752630]278    } else {
[5c51ba1]279      sc = RTEMS_INVALID_ID;
[e752630]280    }
281  }
282
283  return sc;
284}
285
[5c51ba1]286void rtems_rbheap_extend_descriptors_never(rtems_rbheap_control *control)
[e752630]287{
288  /* Do nothing */
289}
290
[5c51ba1]291void rtems_rbheap_extend_descriptors_with_malloc(rtems_rbheap_control *control)
[e752630]292{
[5c51ba1]293  rtems_rbheap_chunk *chunk = malloc(sizeof(*chunk));
[e752630]294
[5c51ba1]295  if (chunk != NULL) {
296    rtems_rbheap_add_to_spare_descriptor_chain(control, chunk);
[e752630]297  }
298}
Note: See TracBrowser for help on using the repository browser.