Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002  * Copyright (c) 2016-2017, ARM Limited, All Rights Reserved
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00006  * not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #if defined(TARGET_CORTEX_A)
00019    #error [NOT_SUPPORTED] This function not supported for this target
00020 #endif
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 
00026 #include "mbed.h"
00027 #include "cmsis.h"
00028 #include "greentea-client/test_env.h"
00029 #include "utest/utest.h"
00030 #include "unity/unity.h"
00031 
00032 using utest::v1::Case;
00033 
00034 static const int test_timeout = 30;
00035 
00036 
00037 // Amount to malloc for each iteration
00038 #define MALLOC_TEST_SIZE            256
00039 // Malloc fill pattern
00040 #define MALLOC_FILL                 0x55
00041 
00042 extern uint32_t mbed_heap_start;
00043 extern uint32_t mbed_heap_size;
00044 extern uint32_t mbed_stack_isr_start;
00045 extern uint32_t mbed_stack_isr_size;
00046 
00047 
00048 struct linked_list {
00049     linked_list * next;
00050     uint8_t data[MALLOC_TEST_SIZE];
00051 };
00052 
00053 
00054 
00055 /* TODO: add memory layout test.
00056  *
00057  * The test was skipped for now since not all devices seems to comply with Mbed OS memory.
00058  *
00059  * @note Mbed OS memory model: https://os.mbed.com/docs/latest/reference/memory.html
00060  *
00061  */
00062 
00063 
00064 /*
00065  * Return true if addr is in range [start:start+size)
00066  */
00067 static bool inrange(uint32_t addr, uint32_t start, uint32_t size)
00068 {
00069     return (addr >= start) && (addr < (start + size));
00070 }
00071 
00072 /*
00073  * Return true if [addr:addr+size] is inside [start:start+len]
00074  */
00075 static bool rangeinrange(uint32_t addr, uint32_t size, uint32_t start, uint32_t len)
00076 {
00077     if ((addr + size) > (start + len)) {
00078         return false;
00079     }
00080     if (addr < start) {
00081         return false;
00082     }
00083     return true;
00084 }
00085 
00086 /*
00087  * Return true if the region is filled only with the specified value
00088  */
00089 static bool valid_fill(uint8_t * data, uint32_t size, uint8_t fill)
00090 {
00091     for (uint32_t i = 0; i < size; i++) {
00092         if (data[i] != fill) {
00093             return false;
00094         }
00095     }
00096     return true;
00097 }
00098 
00099 static void allocate_and_fill_heap(linked_list *&head)
00100 {
00101     linked_list *current;
00102 
00103     current = (linked_list*) malloc(sizeof(linked_list));
00104     TEST_ASSERT_NOT_NULL(current);
00105 
00106     current->next = NULL;
00107     memset((void*) current->data, MALLOC_FILL, sizeof(current->data));
00108 
00109     // Allocate until malloc returns NULL
00110     head = current;
00111     while (true) {
00112 
00113         // Allocate
00114         linked_list *temp = (linked_list*) malloc(sizeof(linked_list));
00115 
00116         if (NULL == temp) {
00117             break;
00118         }
00119         bool result = rangeinrange((uint32_t) temp, sizeof(linked_list), mbed_heap_start, mbed_heap_size);
00120 
00121         TEST_ASSERT_TRUE_MESSAGE(result, "Memory allocation out of range");
00122 
00123         // Init
00124         temp->next = NULL;
00125         memset((void*) temp->data, MALLOC_FILL, sizeof(current->data));
00126 
00127         // Add to list
00128         current->next = temp;
00129         current = temp;
00130     }
00131 }
00132 
00133 static void check_and_free_heap(linked_list *head, uint32_t &max_allocation_size)
00134 {
00135     uint32_t total_size = 0;
00136     linked_list * current = head;
00137 
00138     while (current != NULL) {
00139         total_size += sizeof(linked_list);
00140         bool result = valid_fill(current->data, sizeof(current->data), MALLOC_FILL);
00141 
00142         TEST_ASSERT_TRUE_MESSAGE(result, "Memory fill check failed");
00143 
00144         linked_list * next = current->next;
00145         free(current);
00146         current = next;
00147     }
00148 
00149     max_allocation_size = total_size;
00150 }
00151 
00152 /** Test heap allocation
00153 
00154     Given a heap
00155     When memory is allocated from heap
00156     Then the memory is within heap boundary
00157 
00158  */
00159 void test_heap_in_range(void)
00160 {
00161     char *initial_heap;
00162 
00163     // Sanity check malloc
00164     initial_heap = (char*) malloc(1);
00165     TEST_ASSERT_NOT_NULL(initial_heap);
00166 
00167     bool result = inrange((uint32_t) initial_heap, mbed_heap_start, mbed_heap_size);
00168 
00169     TEST_ASSERT_TRUE_MESSAGE(result, "Heap in wrong location");
00170     free(initial_heap);
00171 }
00172 
00173 /** Test for Main thread stack
00174 
00175     Given a Main thread and its stack
00176     When check Main thread stack pointer
00177     Then the SP is within Main stack boundary
00178  */
00179 void test_main_stack_in_range(void)
00180 {
00181     os_thread_t *thread = (os_thread_t*) osThreadGetId();
00182 
00183     uint32_t psp = __get_PSP();
00184     uint8_t *stack_mem = (uint8_t*) thread->stack_mem;
00185     uint32_t stack_size = thread->stack_size;
00186 
00187     // PSP stack should be somewhere in the middle
00188     bool result = inrange(psp, (uint32_t) stack_mem, stack_size);
00189 
00190     TEST_ASSERT_TRUE_MESSAGE(result, "Main stack in wrong location");
00191 }
00192 
00193 /** Test for Scheduler/ISR thread stack
00194 
00195     Given a Scheduler/ISR thread and its stack
00196     When check Scheduler/ISR thread stack pointer
00197     Then the SP is within Scheduler/ISR stack boundary
00198  */
00199 void test_isr_stack_in_range(void)
00200 {
00201     // MSP stack should be very near end (test using within 128 bytes)
00202     uint32_t msp = __get_MSP();
00203     bool result = inrange(msp, mbed_stack_isr_start + mbed_stack_isr_size - 128, 128);
00204 
00205     TEST_ASSERT_TRUE_MESSAGE(result, "Interrupt stack in wrong location");
00206 }
00207 
00208 /** Test full heap allocation
00209 
00210     Given a heap and linked_list data structure
00211     When linked_list is filled till run out of heap memory
00212     Then the memory is properly initialised and freed
00213  */
00214 void test_heap_allocation_free(void)
00215 {
00216     linked_list *head = NULL;
00217     uint32_t max_allocation_size = 0;
00218 
00219     // Fully allocate the heap and stack
00220     allocate_and_fill_heap(head);
00221 
00222     check_and_free_heap(head, max_allocation_size);
00223 
00224     // Force a task switch so a stack check is performed
00225     Thread::wait(10);
00226 
00227     printf("Total size dynamically allocated: %luB\n", max_allocation_size);
00228 }
00229 
00230 
00231 // Test cases
00232 Case cases[] = {
00233     Case("Test heap in range", test_heap_in_range),
00234     Case("Test main stack in range", test_main_stack_in_range),
00235     Case("Test isr stack in range", test_isr_stack_in_range),
00236     Case("Test heap allocation and free", test_heap_allocation_free)
00237 };
00238 
00239 utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
00240 {
00241     GREENTEA_SETUP(test_timeout, "default_auto");
00242     return utest::v1::greentea_test_setup_handler(number_of_cases);
00243 }
00244 
00245 utest::v1::Specification specification(greentea_test_setup, cases);
00246 
00247 int main()
00248 {
00249     return !utest::v1::Harness::run(specification);
00250 }