Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:22

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSAPIRBHeap
0007  *
0008  * @brief This source file contains the implementation of
0009  *   rtems_rbheap_allocate(), rtems_rbheap_extend_descriptors_never(),
0010  *   rtems_rbheap_extend_descriptors_with_malloc(), rtems_rbheap_free(), and
0011  *   rtems_rbheap_initialize().
0012  */
0013 
0014 /*
0015  * Copyright (C) 2012, 2015 embedded brains GmbH & Co. KG
0016  *
0017  * Redistribution and use in source and binary forms, with or without
0018  * modification, are permitted provided that the following conditions
0019  * are met:
0020  * 1. Redistributions of source code must retain the above copyright
0021  *    notice, this list of conditions and the following disclaimer.
0022  * 2. Redistributions in binary form must reproduce the above copyright
0023  *    notice, this list of conditions and the following disclaimer in the
0024  *    documentation and/or other materials provided with the distribution.
0025  *
0026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0027  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0029  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0030  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0031  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0032  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0035  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0036  * POSSIBILITY OF SUCH DAMAGE.
0037  */
0038 
0039 #ifdef HAVE_CONFIG_H
0040 #include "config.h"
0041 #endif
0042 
0043 #include <rtems/rbheap.h>
0044 
0045 #include <stdlib.h>
0046 
0047 static uintptr_t align_up(uintptr_t alignment, uintptr_t value)
0048 {
0049   uintptr_t excess = value % alignment;
0050 
0051   if (excess > 0) {
0052     value += alignment - excess;
0053   }
0054 
0055   return value;
0056 }
0057 
0058 static uintptr_t align_down(uintptr_t alignment, uintptr_t value)
0059 {
0060   uintptr_t excess = value % alignment;
0061 
0062   return value - excess;
0063 }
0064 
0065 static rtems_rbtree_compare_result chunk_compare(
0066   const rtems_rbtree_node *a,
0067   const rtems_rbtree_node *b
0068 )
0069 {
0070   const rtems_rbheap_chunk *left = rtems_rbheap_chunk_of_node(a);
0071   const rtems_rbheap_chunk *right = rtems_rbheap_chunk_of_node(b);
0072 
0073   return (rtems_rbtree_compare_result)
0074     ((left->begin >> 1) - (right->begin >> 1));
0075 }
0076 
0077 static rtems_rbheap_chunk *get_chunk(rtems_rbheap_control *control)
0078 {
0079   rtems_chain_control *chain = &control->spare_descriptor_chain;
0080   rtems_chain_node *chunk = rtems_chain_get_unprotected(chain);
0081 
0082   if (chunk == NULL) {
0083     (*control->extend_descriptors)(control);
0084     chunk = rtems_chain_get_unprotected(chain);
0085   }
0086 
0087   return (rtems_rbheap_chunk *) chunk;
0088 }
0089 
0090 static void add_to_chain(
0091   rtems_chain_control *chain,
0092   rtems_rbheap_chunk *chunk
0093 )
0094 {
0095   rtems_chain_initialize_node(&chunk->chain_node);
0096   rtems_chain_prepend_unprotected(chain, &chunk->chain_node);
0097 }
0098 
0099 static void insert_into_tree(
0100   rtems_rbtree_control *tree,
0101   rtems_rbheap_chunk *chunk
0102 )
0103 {
0104   rtems_rbtree_insert(tree, &chunk->tree_node, chunk_compare, true);
0105 }
0106 
0107 rtems_status_code rtems_rbheap_initialize(
0108   rtems_rbheap_control *control,
0109   void *area_begin,
0110   uintptr_t area_size,
0111   uintptr_t alignment,
0112   rtems_rbheap_extend_descriptors extend_descriptors,
0113   void *handler_arg
0114 )
0115 {
0116   rtems_status_code sc = RTEMS_SUCCESSFUL;
0117   uintptr_t begin = (uintptr_t) area_begin;
0118   uintptr_t end = begin + area_size;
0119   uintptr_t aligned_begin;
0120   uintptr_t aligned_end;
0121 
0122   /*
0123    * Ensure that the alignment is at least two, so that we can keep
0124    * chunk_compare() that simple.
0125    */
0126   alignment = alignment < 2 ? 2 : alignment;
0127 
0128   aligned_begin = align_up(alignment, begin);
0129   aligned_end = align_down(alignment, end);
0130 
0131   if (begin < end && begin <= aligned_begin && aligned_begin < aligned_end) {
0132     rtems_chain_control *free_chain = &control->free_chunk_chain;
0133     rtems_rbtree_control *chunk_tree = &control->chunk_tree;
0134     rtems_rbheap_chunk *first = NULL;
0135 
0136     rtems_chain_initialize_empty(free_chain);
0137     rtems_chain_initialize_empty(&control->spare_descriptor_chain);
0138     rtems_rbtree_initialize_empty(chunk_tree);
0139     control->alignment = alignment;
0140     control->handler_arg = handler_arg;
0141     control->extend_descriptors = extend_descriptors;
0142 
0143     first = get_chunk(control);
0144     if (first != NULL) {
0145       first->begin = aligned_begin;
0146       first->size = aligned_end - aligned_begin;
0147       add_to_chain(free_chain, first);
0148       insert_into_tree(chunk_tree, first);
0149     } else {
0150       sc = RTEMS_NO_MEMORY;
0151     }
0152   } else {
0153     sc = RTEMS_INVALID_ADDRESS;
0154   }
0155 
0156   return sc;
0157 }
0158 
0159 static rtems_rbheap_chunk *search_free_chunk(
0160   rtems_chain_control *free_chain,
0161   size_t size
0162 )
0163 {
0164   rtems_chain_node *current = rtems_chain_first(free_chain);
0165   const rtems_chain_node *tail = rtems_chain_tail(free_chain);
0166   rtems_rbheap_chunk *big_enough = NULL;
0167 
0168   while (current != tail && big_enough == NULL) {
0169     rtems_rbheap_chunk *free_chunk = (rtems_rbheap_chunk *) current;
0170 
0171     if (free_chunk->size >= size) {
0172       big_enough = free_chunk;
0173     }
0174 
0175     current = rtems_chain_next(current);
0176   }
0177 
0178   return big_enough;
0179 }
0180 
0181 void *rtems_rbheap_allocate(rtems_rbheap_control *control, size_t size)
0182 {
0183   void *ptr = NULL;
0184   rtems_chain_control *free_chain = &control->free_chunk_chain;
0185   rtems_rbtree_control *chunk_tree = &control->chunk_tree;
0186   uintptr_t alignment = control->alignment;
0187   uintptr_t aligned_size = align_up(alignment, size);
0188 
0189   if (size > 0 && size <= aligned_size) {
0190     rtems_rbheap_chunk *free_chunk = search_free_chunk(free_chain, aligned_size);
0191 
0192     if (free_chunk != NULL) {
0193       uintptr_t free_size = free_chunk->size;
0194 
0195       if (free_size > aligned_size) {
0196         rtems_rbheap_chunk *new_chunk = get_chunk(control);
0197 
0198         if (new_chunk != NULL) {
0199           uintptr_t new_free_size = free_size - aligned_size;
0200 
0201           free_chunk->size = new_free_size;
0202           new_chunk->begin = free_chunk->begin + new_free_size;
0203           new_chunk->size = aligned_size;
0204           rtems_chain_set_off_chain(&new_chunk->chain_node);
0205           insert_into_tree(chunk_tree, new_chunk);
0206           ptr = (void *) new_chunk->begin;
0207         }
0208       } else {
0209         rtems_chain_extract_unprotected(&free_chunk->chain_node);
0210         rtems_chain_set_off_chain(&free_chunk->chain_node);
0211         ptr = (void *) free_chunk->begin;
0212       }
0213     }
0214   }
0215 
0216   return ptr;
0217 }
0218 
0219 #define NULL_PAGE rtems_rbheap_chunk_of_node(NULL)
0220 
0221 static rtems_rbheap_chunk *find(rtems_rbtree_control *chunk_tree, uintptr_t key)
0222 {
0223   rtems_rbheap_chunk chunk = { .begin = key };
0224 
0225   return rtems_rbheap_chunk_of_node(
0226     rtems_rbtree_find(chunk_tree, &chunk.tree_node, chunk_compare, true)
0227   );
0228 }
0229 
0230 static rtems_rbheap_chunk *pred(const rtems_rbheap_chunk *chunk)
0231 {
0232   return rtems_rbheap_chunk_of_node(
0233     rtems_rbtree_predecessor(&chunk->tree_node)
0234   );
0235 }
0236 
0237 static rtems_rbheap_chunk *succ(const rtems_rbheap_chunk *chunk)
0238 {
0239   return rtems_rbheap_chunk_of_node(
0240     rtems_rbtree_successor(&chunk->tree_node)
0241   );
0242 }
0243 
0244 static void check_and_merge(
0245   rtems_rbheap_control *control,
0246   rtems_rbheap_chunk *a,
0247   rtems_rbheap_chunk *b,
0248   rtems_rbheap_chunk *c
0249 )
0250 {
0251   if (c != NULL_PAGE && rtems_rbheap_is_chunk_free(c)) {
0252     a->size += b->size;
0253     rtems_chain_extract_unprotected(&b->chain_node);
0254     rtems_rbheap_add_to_spare_descriptor_chain(control, b);
0255     rtems_rbtree_extract(&control->chunk_tree, &b->tree_node);
0256   }
0257 }
0258 
0259 rtems_status_code rtems_rbheap_free(rtems_rbheap_control *control, void *ptr)
0260 {
0261   rtems_status_code sc = RTEMS_SUCCESSFUL;
0262 
0263   if (ptr != NULL) {
0264     rtems_rbheap_chunk *chunk = find(&control->chunk_tree, (uintptr_t) ptr);
0265 
0266     if (chunk != NULL_PAGE) {
0267       if (!rtems_rbheap_is_chunk_free(chunk)) {
0268         rtems_rbheap_chunk *other;
0269 
0270         add_to_chain(&control->free_chunk_chain, chunk);
0271         other = succ(chunk);
0272         check_and_merge(control, chunk, other, other);
0273         other = pred(chunk);
0274         check_and_merge(control, other, chunk, other);
0275       } else {
0276         sc = RTEMS_INCORRECT_STATE;
0277       }
0278     } else {
0279       sc = RTEMS_INVALID_ID;
0280     }
0281   }
0282 
0283   return sc;
0284 }
0285 
0286 void rtems_rbheap_extend_descriptors_never(rtems_rbheap_control *control)
0287 {
0288   /* Do nothing */
0289 }
0290 
0291 void rtems_rbheap_extend_descriptors_with_malloc(rtems_rbheap_control *control)
0292 {
0293   rtems_rbheap_chunk *chunk = malloc(sizeof(*chunk));
0294 
0295   if (chunk != NULL) {
0296     rtems_rbheap_add_to_spare_descriptor_chain(control, chunk);
0297   }
0298 }