Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2012, 2015 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include "tmacros.h"
0033 
0034 #include <rtems.h>
0035 #include <rtems/rbheap.h>
0036 #include <rtems/malloc.h>
0037 #include <rtems/score/rbtreeimpl.h>
0038 
0039 const char rtems_test_name[] = "RBHEAP 1";
0040 
0041 /* forward declarations to avoid warnings */
0042 static rtems_task Init(rtems_task_argument argument);
0043 
0044 #define TEST_PAGE_SIZE 1024
0045 
0046 #define TEST_PAGE_COUNT 8
0047 
0048 static char area [TEST_PAGE_SIZE * TEST_PAGE_COUNT + TEST_PAGE_SIZE - 1];
0049 
0050 static rtems_rbheap_chunk chunks [TEST_PAGE_COUNT];
0051 
0052 static void extend_descriptors(rtems_rbheap_control *control)
0053 {
0054   rtems_chain_control *chain =
0055     rtems_rbheap_get_spare_descriptor_chain(control);
0056 
0057   rtems_rbheap_set_extend_descriptors(
0058     control,
0059     rtems_rbheap_extend_descriptors_never
0060   );
0061 
0062   rtems_chain_initialize(
0063     chain,
0064     chunks,
0065     TEST_PAGE_COUNT,
0066     sizeof(chunks [0])
0067   );
0068 }
0069 
0070 static uintptr_t idx(const rtems_rbheap_chunk *chunk)
0071 {
0072   uintptr_t base = (uintptr_t) area;
0073   uintptr_t excess = base % TEST_PAGE_SIZE;
0074 
0075   if (excess > 0) {
0076     base += TEST_PAGE_SIZE - excess;
0077   }
0078 
0079   return (chunk->begin - base) / TEST_PAGE_SIZE;
0080 }
0081 
0082 typedef struct {
0083   uintptr_t index;
0084   bool free;
0085 } chunk_descriptor;
0086 
0087 typedef struct {
0088   const chunk_descriptor *chunk_current;
0089   const chunk_descriptor *chunk_end;
0090 } chunk_visitor_context;
0091 
0092 static bool chunk_visitor(
0093   const RBTree_Node *node,
0094   void *visitor_arg
0095 )
0096 {
0097   rtems_rbheap_chunk *chunk = rtems_rbheap_chunk_of_node(node);
0098   chunk_visitor_context *context = visitor_arg;
0099   const chunk_descriptor *current = context->chunk_current;
0100 
0101   rtems_test_assert(current != context->chunk_end);
0102 
0103   rtems_test_assert(idx(chunk) == current->index);
0104   rtems_test_assert(rtems_rbheap_is_chunk_free(chunk) == current->free);
0105 
0106   context->chunk_current = current + 1;
0107 
0108   return false;
0109 }
0110 
0111 static void test_init_begin_greater_than_end(void)
0112 {
0113   rtems_status_code sc = RTEMS_SUCCESSFUL;
0114   rtems_rbheap_control control;
0115 
0116   sc = rtems_rbheap_initialize(
0117     &control,
0118     (void *) TEST_PAGE_SIZE,
0119     (uintptr_t) -TEST_PAGE_SIZE,
0120     TEST_PAGE_SIZE,
0121     extend_descriptors,
0122     NULL
0123   );
0124   rtems_test_assert(sc == RTEMS_INVALID_ADDRESS);
0125 }
0126 
0127 static void test_init_begin_greater_than_aligned_begin(void)
0128 {
0129   rtems_status_code sc = RTEMS_SUCCESSFUL;
0130   rtems_rbheap_control control;
0131 
0132   sc = rtems_rbheap_initialize(
0133     &control,
0134     (void *) -(TEST_PAGE_SIZE / 2),
0135     TEST_PAGE_SIZE,
0136     TEST_PAGE_SIZE,
0137     extend_descriptors,
0138     NULL
0139   );
0140   rtems_test_assert(sc == RTEMS_INVALID_ADDRESS);
0141 }
0142 
0143 static void test_init_aligned_begin_greater_than_aligned_end(void)
0144 {
0145   rtems_status_code sc = RTEMS_SUCCESSFUL;
0146   rtems_rbheap_control control;
0147 
0148   sc = rtems_rbheap_initialize(
0149     &control,
0150     (void *) TEST_PAGE_SIZE,
0151     TEST_PAGE_SIZE / 2,
0152     TEST_PAGE_SIZE,
0153     extend_descriptors,
0154     NULL
0155   );
0156   rtems_test_assert(sc == RTEMS_INVALID_ADDRESS);
0157 }
0158 
0159 static void test_init_empty_descriptors(void)
0160 {
0161   rtems_status_code sc = RTEMS_SUCCESSFUL;
0162   rtems_rbheap_control control;
0163 
0164   sc = rtems_rbheap_initialize(
0165     &control,
0166     (void *) TEST_PAGE_SIZE,
0167     TEST_PAGE_SIZE,
0168     TEST_PAGE_SIZE,
0169     rtems_rbheap_extend_descriptors_never,
0170     NULL
0171   );
0172   rtems_test_assert(sc == RTEMS_NO_MEMORY);
0173 }
0174 
0175 static void test_chunk_tree(
0176   const rtems_rbheap_control *control,
0177   const chunk_descriptor *chunk_begin,
0178   size_t chunk_count
0179 )
0180 {
0181   chunk_visitor_context context = {
0182     .chunk_current = chunk_begin,
0183     .chunk_end = chunk_begin + chunk_count
0184   };
0185 
0186   rtems_test_assert(
0187     rtems_chain_node_count_unprotected(&control->spare_descriptor_chain)
0188       == TEST_PAGE_COUNT - chunk_count
0189   );
0190 
0191   _RBTree_Iterate(
0192     &control->chunk_tree,
0193     chunk_visitor,
0194     &context
0195   );
0196 }
0197 
0198 #define TEST_PAGE_TREE(control, chunks) \
0199   test_chunk_tree( \
0200     control, \
0201     chunks, \
0202     RTEMS_ARRAY_SIZE(chunks) \
0203   )
0204 
0205 static void test_init_successful(rtems_rbheap_control *control)
0206 {
0207   static const chunk_descriptor chunks [] = {
0208     { 0, true }
0209   };
0210 
0211   rtems_status_code sc = RTEMS_SUCCESSFUL;
0212 
0213   sc = rtems_rbheap_initialize(
0214     control,
0215     area,
0216     sizeof(area),
0217     TEST_PAGE_SIZE,
0218     extend_descriptors,
0219     NULL
0220   );
0221   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0222 
0223   TEST_PAGE_TREE(control, chunks);
0224 }
0225 
0226 static void test_alloc_and_free_one(void)
0227 {
0228   static const chunk_descriptor chunks_0 [] = {
0229     { 0, true },
0230     { TEST_PAGE_COUNT - 1, false }
0231   };
0232   static const chunk_descriptor chunks_1 [] = {
0233     { 0, true }
0234   };
0235 
0236   rtems_status_code sc = RTEMS_SUCCESSFUL;
0237   rtems_rbheap_control control;
0238   void *ptr = NULL;
0239 
0240   test_init_successful(&control);
0241 
0242   ptr = rtems_rbheap_allocate(&control, TEST_PAGE_SIZE);
0243   rtems_test_assert(ptr != NULL);
0244 
0245   TEST_PAGE_TREE(&control, chunks_0);
0246 
0247   sc = rtems_rbheap_free(&control, ptr);
0248   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0249 
0250   TEST_PAGE_TREE(&control, chunks_1);
0251 }
0252 
0253 static void test_alloc_zero(void)
0254 {
0255   static const chunk_descriptor chunks [] = {
0256     { 0, true }
0257   };
0258 
0259   rtems_rbheap_control control;
0260   void *ptr = NULL;
0261 
0262   test_init_successful(&control);
0263 
0264   ptr = rtems_rbheap_allocate(&control, 0);
0265   rtems_test_assert(ptr == NULL);
0266 
0267   TEST_PAGE_TREE(&control, chunks);
0268 }
0269 
0270 static void test_alloc_huge_chunk(void)
0271 {
0272   static const chunk_descriptor chunks [] = {
0273     { 0, true }
0274   };
0275 
0276   rtems_rbheap_control control;
0277   void *ptr = NULL;
0278 
0279   test_init_successful(&control);
0280 
0281   ptr = rtems_rbheap_allocate(&control, (TEST_PAGE_COUNT + 1) * TEST_PAGE_SIZE);
0282   rtems_test_assert(ptr == NULL);
0283 
0284   TEST_PAGE_TREE(&control, chunks);
0285 }
0286 
0287 static void test_alloc_one_chunk(void)
0288 {
0289   static const chunk_descriptor chunks_0 [] = {
0290     { 0, false }
0291   };
0292   static const chunk_descriptor chunks_1 [] = {
0293     { 0, true },
0294   };
0295 
0296   rtems_status_code sc = RTEMS_SUCCESSFUL;
0297   rtems_rbheap_control control;
0298   void *ptr = NULL;
0299 
0300   test_init_successful(&control);
0301 
0302   ptr = rtems_rbheap_allocate(&control, TEST_PAGE_COUNT * TEST_PAGE_SIZE);
0303   rtems_test_assert(ptr != NULL);
0304 
0305   TEST_PAGE_TREE(&control, chunks_0);
0306 
0307   sc = rtems_rbheap_free(&control, ptr);
0308   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0309 
0310   TEST_PAGE_TREE(&control, chunks_1);
0311 }
0312 
0313 static void test_alloc_many_chunks(void)
0314 {
0315   static const chunk_descriptor chunks_0 [] = {
0316     { 0, false },
0317     { 1, false },
0318     { 2, false },
0319     { 3, false },
0320     { 4, false },
0321     { 5, false },
0322     { 6, false },
0323     { 7, false }
0324   };
0325   static const chunk_descriptor chunks_1 [] = {
0326     { 0, true }
0327   };
0328 
0329   rtems_status_code sc = RTEMS_SUCCESSFUL;
0330   rtems_rbheap_control control;
0331   void *ptr [TEST_PAGE_COUNT];
0332   void *null = NULL;
0333   int i = 0;
0334 
0335   test_init_successful(&control);
0336 
0337   for (i = 0; i < TEST_PAGE_COUNT; ++i) {
0338     ptr [i] = rtems_rbheap_allocate(&control, TEST_PAGE_SIZE);
0339     rtems_test_assert(ptr [i] != NULL);
0340   }
0341 
0342   TEST_PAGE_TREE(&control, chunks_0);
0343 
0344   null = rtems_rbheap_allocate(&control, TEST_PAGE_SIZE);
0345   rtems_test_assert(null == NULL);
0346 
0347   TEST_PAGE_TREE(&control, chunks_0);
0348 
0349   for (i = 0; i < TEST_PAGE_COUNT; ++i) {
0350     sc = rtems_rbheap_free(&control, ptr [i]);
0351     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0352   }
0353 
0354   TEST_PAGE_TREE(&control, chunks_1);
0355 }
0356 
0357 static void test_alloc_misaligned(void)
0358 {
0359   rtems_rbheap_control control;
0360   void *p;
0361 
0362   test_init_successful(&control);
0363 
0364   p = rtems_rbheap_allocate(&control, TEST_PAGE_SIZE - 1);
0365   rtems_test_assert(p != NULL);
0366 }
0367 
0368 static void test_alloc_with_malloc_extend(void)
0369 {
0370   rtems_status_code sc;
0371   rtems_rbheap_control control;
0372   void *p;
0373   void *opaque;
0374 
0375   sc = rtems_rbheap_initialize(
0376     &control,
0377     area,
0378     sizeof(area),
0379     TEST_PAGE_SIZE,
0380     rtems_rbheap_extend_descriptors_with_malloc,
0381     NULL
0382   );
0383   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0384 
0385   opaque = rtems_heap_greedy_allocate(NULL, 0);
0386 
0387   p = rtems_rbheap_allocate(&control, TEST_PAGE_SIZE);
0388   rtems_test_assert(p == NULL);
0389 
0390   rtems_heap_greedy_free(opaque);
0391 
0392   p = rtems_rbheap_allocate(&control, TEST_PAGE_SIZE);
0393   rtems_test_assert(p != NULL);
0394 }
0395 
0396 static void test_free_null(void)
0397 {
0398   rtems_status_code sc = RTEMS_SUCCESSFUL;
0399   rtems_rbheap_control control;
0400 
0401   test_init_successful(&control);
0402 
0403   sc = rtems_rbheap_free(&control, NULL);
0404   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0405 }
0406 
0407 static void test_free_invalid(void)
0408 {
0409   rtems_status_code sc = RTEMS_SUCCESSFUL;
0410   rtems_rbheap_control control;
0411 
0412   test_init_successful(&control);
0413 
0414   sc = rtems_rbheap_free(&control, (void *) 1);
0415   rtems_test_assert(sc == RTEMS_INVALID_ID);
0416 }
0417 
0418 static void test_free_double(void)
0419 {
0420   rtems_status_code sc = RTEMS_SUCCESSFUL;
0421   rtems_rbheap_control control;
0422   void *ptr = NULL;
0423 
0424   test_init_successful(&control);
0425 
0426   ptr = rtems_rbheap_allocate(&control, TEST_PAGE_COUNT * TEST_PAGE_SIZE);
0427   rtems_test_assert(ptr != NULL);
0428 
0429   sc = rtems_rbheap_free(&control, ptr);
0430   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0431 
0432   sc = rtems_rbheap_free(&control, ptr);
0433   rtems_test_assert(sc == RTEMS_INCORRECT_STATE);
0434 }
0435 
0436 enum {
0437   LOW,
0438   LEFT,
0439   MIDDLE,
0440   RIGHT,
0441   HIGH
0442 };
0443 
0444 static void test_free_merge_left_or_right(bool left)
0445 {
0446   static const chunk_descriptor chunks_0 [] = {
0447     { 0, true },
0448     { 3, false },
0449     { 4, false },
0450     { 5, false },
0451     { 6, false },
0452     { 7, false }
0453   };
0454   static const chunk_descriptor chunks_1_left [] = {
0455     { 0, true },
0456     { 3, false },
0457     { 4, true },
0458     { 5, false },
0459     { 6, false },
0460     { 7, false }
0461   };
0462   static const chunk_descriptor chunks_1_right [] = {
0463     { 0, true },
0464     { 3, false },
0465     { 4, false },
0466     { 5, false },
0467     { 6, true },
0468     { 7, false }
0469   };
0470   static const chunk_descriptor chunks_2_left [] = {
0471     { 0, true },
0472     { 3, false },
0473     { 4, true },
0474     { 6, false },
0475     { 7, false }
0476   };
0477   static const chunk_descriptor chunks_2_right [] = {
0478     { 0, true },
0479     { 3, false },
0480     { 4, false },
0481     { 5, true },
0482     { 7, false }
0483   };
0484 
0485   rtems_status_code sc = RTEMS_SUCCESSFUL;
0486   rtems_rbheap_control control;
0487   void *ptr [HIGH + 1];
0488   int dir = left ? LEFT : RIGHT;
0489   int i = 0;
0490 
0491   test_init_successful(&control);
0492 
0493   for (i = sizeof(ptr) / sizeof(ptr [0]) - 1; i >= 0; --i) {
0494     ptr [i] = rtems_rbheap_allocate(&control, TEST_PAGE_SIZE);
0495     rtems_test_assert(ptr [i] != NULL);
0496   }
0497 
0498   TEST_PAGE_TREE(&control, chunks_0);
0499 
0500   sc = rtems_rbheap_free(&control, ptr [dir]);
0501   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0502 
0503   if (left) {
0504     TEST_PAGE_TREE(&control, chunks_1_left);
0505   } else {
0506     TEST_PAGE_TREE(&control, chunks_1_right);
0507   }
0508 
0509   sc = rtems_rbheap_free(&control, ptr [MIDDLE]);
0510   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0511 
0512   if (left) {
0513     TEST_PAGE_TREE(&control, chunks_2_left);
0514   } else {
0515     TEST_PAGE_TREE(&control, chunks_2_right);
0516   }
0517 }
0518 
0519 static void Init(rtems_task_argument arg)
0520 {
0521   TEST_BEGIN();
0522 
0523   test_init_begin_greater_than_end();
0524   test_init_begin_greater_than_aligned_begin();
0525   test_init_aligned_begin_greater_than_aligned_end();
0526   test_init_empty_descriptors();
0527   test_alloc_and_free_one();
0528   test_alloc_zero();
0529   test_alloc_huge_chunk();
0530   test_alloc_one_chunk();
0531   test_alloc_many_chunks();
0532   test_alloc_misaligned();
0533   test_alloc_with_malloc_extend();
0534   test_free_null();
0535   test_free_invalid();
0536   test_free_double();
0537   test_free_merge_left_or_right(true);
0538   test_free_merge_left_or_right(false);
0539 
0540   TEST_END();
0541 
0542   rtems_test_exit(0);
0543 }
0544 
0545 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0546 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0547 
0548 #define CONFIGURE_MAXIMUM_TASKS 1
0549 
0550 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0551 
0552 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0553 
0554 #define CONFIGURE_INIT
0555 
0556 #include <rtems/confdefs.h>