Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002  * Copyright (c) 2013-2016, 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 #include "mbed.h"
00019 #include "greentea-client/test_env.h"
00020 #include "unity/unity.h"
00021 #include "utest/utest.h"
00022 #include "mbed_mem_trace.h"
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <stdarg.h>
00026 
00027 #ifndef MBED_MEM_TRACING_ENABLED
00028   #error [NOT_SUPPORTED] test not supported
00029 #endif
00030 
00031 using namespace utest::v1;
00032 
00033 /******************************************************************************/
00034 /* Helper functions and data structures                                       */
00035 /******************************************************************************/
00036 
00037 // This structure keeps data about the various memory allocation operations,
00038 // as traced by 'test_trace_cb' below.
00039 #define TEST_MAX_MEMORY_OPS             10
00040 // Trace results for all possible operations
00041 typedef struct {
00042     uint8_t op;
00043     void *res;
00044     union {
00045         struct {
00046             size_t arg_size;
00047         } malloc_info;
00048         struct {
00049             void *arg_ptr;
00050             size_t arg_size;
00051         } realloc_info;
00052         struct {
00053             size_t arg_nmemb;
00054             size_t arg_size;
00055         } calloc_info;
00056         struct {
00057             void *arg_ptr;
00058         } free_info;
00059     };
00060 } mem_trace_data_t;
00061 // Memory operation statistics
00062 typedef struct {
00063     mem_trace_data_t op_data[TEST_MAX_MEMORY_OPS];
00064     uint32_t total_ops;
00065     bool invalid_op, overflow;
00066 } stats_t;
00067 static stats_t stats;
00068 
00069 // Clear all the memory statistics
00070 static void test_clear_stats() {
00071     memset(&stats, 0, sizeof(stats));
00072 }
00073 
00074 // Memory tracer callback that records each operation in "stats" (above)
00075 extern "C" void test_trace_cb(uint8_t op, void *res, void *caller, ...) {
00076     va_list va;
00077     mem_trace_data_t *pmem = stats.op_data + stats.total_ops;
00078 
00079     if (stats.total_ops >= TEST_MAX_MEMORY_OPS) {
00080         stats.overflow = true;
00081         return;
00082     }
00083     va_start(va, caller);
00084     pmem->op = op;
00085     pmem->res = res;
00086     switch(op) {
00087         case MBED_MEM_TRACE_MALLOC:
00088             pmem->malloc_info.arg_size = va_arg(va, size_t);
00089             break;
00090 
00091         case MBED_MEM_TRACE_REALLOC:
00092             pmem->realloc_info.arg_ptr = va_arg(va, void *);
00093             pmem->realloc_info.arg_size = va_arg(va, size_t);
00094             break;
00095 
00096         case MBED_MEM_TRACE_CALLOC:
00097             pmem->calloc_info.arg_nmemb = va_arg(va, size_t);
00098             pmem->calloc_info.arg_size = va_arg(va, size_t);
00099             break;
00100 
00101         case MBED_MEM_TRACE_FREE:
00102             pmem->free_info.arg_ptr = va_arg(va, void *);
00103             break;
00104 
00105         default:
00106             stats.invalid_op = true;
00107     }
00108     stats.total_ops ++;
00109     va_end(va);
00110 }
00111 
00112 // Generic sanity checks for the tracer
00113 static void check_sanity(uint32_t expected_ops) {
00114     TEST_ASSERT_FALSE(stats.overflow);
00115     TEST_ASSERT_FALSE(stats.invalid_op);
00116     TEST_ASSERT_EQUAL_UINT32(stats.total_ops, expected_ops);
00117 }
00118 
00119 // Check a "malloc" operation
00120 static void check_malloc_op(const mem_trace_data_t *p, void *expected_res, size_t expected_arg_size) {
00121     TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_MALLOC);
00122     TEST_ASSERT_EQUAL_PTR(p->res, expected_res);
00123     TEST_ASSERT_EQUAL_UINT32(p->malloc_info.arg_size, expected_arg_size);
00124 }
00125 
00126 // Check a "free" operation
00127 static void check_free_op(const mem_trace_data_t *p, void *expected_arg_ptr) {
00128     TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_FREE);
00129     TEST_ASSERT_EQUAL_PTR(p->free_info.arg_ptr, expected_arg_ptr);
00130 }
00131 
00132 // Check a "realloc" operation
00133 static void check_realloc_op(const mem_trace_data_t *p, void *expected_res, void *expected_arg_ptr, size_t expected_arg_size) {
00134     TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_REALLOC);
00135     TEST_ASSERT_EQUAL_PTR(p->res, expected_res);
00136     TEST_ASSERT_EQUAL_UINT32(p->realloc_info.arg_ptr, expected_arg_ptr);
00137     TEST_ASSERT_EQUAL_UINT32(p->realloc_info.arg_size, expected_arg_size);
00138 }
00139 
00140 // Check a "calloc" operation
00141 static void check_calloc_op(const mem_trace_data_t *p, void *expected_res, size_t expected_arg_nmemb, size_t expected_arg_size) {
00142     TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_CALLOC);
00143     TEST_ASSERT_EQUAL_PTR(p->res, expected_res);
00144     TEST_ASSERT_EQUAL_UINT32(p->calloc_info.arg_nmemb, expected_arg_nmemb);
00145     TEST_ASSERT_EQUAL_UINT32(p->calloc_info.arg_size, expected_arg_size);
00146 }
00147 
00148 /******************************************************************************/
00149 /* Tests                                                                      */
00150 /******************************************************************************/
00151 
00152 // Allocate a single buffer, then free it. Check that tracing matches the operations.
00153 static void test_case_single_malloc_free() {
00154     const size_t block_size = 126;
00155     const mem_trace_data_t *pmem = stats.op_data;
00156 
00157     test_clear_stats();
00158     mbed_mem_trace_set_callback(test_trace_cb);
00159     // Allocate a single memory block
00160     void *p = malloc(block_size);
00161     TEST_ASSERT_NOT_EQUAL(p, NULL);
00162     // Free the memory block
00163     free(p);
00164     // Stop tracing
00165     mbed_mem_trace_set_callback(NULL);
00166     // Check tracer result
00167     check_sanity(2);
00168     check_malloc_op(pmem ++, p, block_size);
00169     check_free_op(pmem, p);
00170 }
00171 
00172 // Test all memory operations (malloc, realloc, free, calloc)
00173 static void test_case_all_memory_ops() {
00174     const size_t malloc_size = 40, realloc_size = 80, nmemb = 25, size = 10;
00175     const mem_trace_data_t *pmem = stats.op_data;
00176 
00177     test_clear_stats();
00178     mbed_mem_trace_set_callback(test_trace_cb);
00179     // Allocate a single memory block, the realloc it
00180     void *p_malloc = malloc(malloc_size);
00181     TEST_ASSERT_NOT_EQUAL(p_malloc, NULL);
00182     void *p_realloc = realloc(p_malloc, realloc_size);
00183     TEST_ASSERT_NOT_EQUAL(p_realloc, NULL);
00184     // Use calloc() now
00185     void *p_calloc = calloc(nmemb, size);
00186     //TEST_ASSERT_NOT_EQUAL(p_calloc, NULL);
00187     // Free the realloc() pointer first, then the calloc() one
00188     free(p_realloc);
00189     free(p_calloc);
00190     // Stop tracing
00191     mbed_mem_trace_set_callback(NULL);
00192     // Check tracer result
00193     check_sanity(6);
00194     check_malloc_op(pmem ++, p_malloc, malloc_size);
00195     check_realloc_op(pmem ++, p_realloc, p_malloc, realloc_size);
00196     // calloc() calls malloc() internally
00197     check_malloc_op(pmem ++, p_calloc, nmemb * size);
00198     check_calloc_op(pmem ++, p_calloc, nmemb, size);
00199     check_free_op(pmem ++, p_realloc);
00200     check_free_op(pmem, p_calloc);
00201 }
00202 
00203 // Test that tracing is off when using a NULL callback
00204 static void test_case_trace_off() {
00205     const size_t malloc_size = 10;
00206 
00207     test_clear_stats();
00208     // We don't want any tracing
00209     mbed_mem_trace_set_callback(NULL);
00210     // Allocate a buffer and free it
00211     void *p_malloc = malloc(malloc_size);
00212     TEST_ASSERT_NOT_EQUAL(p_malloc, NULL);
00213     free(p_malloc);
00214     // Check that we didn't trace anything
00215     check_sanity(0);
00216 }
00217 
00218 // Test partial tracing (start tracing, stop tracing, restart later)
00219 static void test_case_partial_trace() {
00220     const size_t malloc_size_1 = 20, malloc_size_2 = 30;
00221     const mem_trace_data_t *pmem = stats.op_data;
00222 
00223     test_clear_stats();
00224     // Start tracing
00225     mbed_mem_trace_set_callback(test_trace_cb);
00226     // Allocate a buffer
00227     void *p_malloc_1 = malloc(malloc_size_1);
00228     TEST_ASSERT_NOT_EQUAL(p_malloc_1, NULL);
00229     // Disable tracing before freeing the first buffer
00230     mbed_mem_trace_set_callback(NULL);
00231     free(p_malloc_1);
00232     // Allocate another buffer (still not traced)
00233     void *p_malloc_2 = malloc(malloc_size_2);
00234     TEST_ASSERT_NOT_EQUAL(p_malloc_2, NULL);
00235     // Re-enable tracing
00236     mbed_mem_trace_set_callback(test_trace_cb);
00237     // And free the second buffer (this operation should be tracer)
00238     free(p_malloc_2);
00239     // Stop tracing
00240     mbed_mem_trace_set_callback(NULL);
00241     // Check tracer result
00242     check_sanity(2);
00243     check_malloc_op(pmem ++, p_malloc_1, malloc_size_1);
00244     check_free_op(pmem, p_malloc_2);
00245 }
00246 
00247 // Test new/delete tracing
00248 static void test_case_new_delete() {
00249     const mem_trace_data_t *pmem = stats.op_data;
00250 
00251     test_clear_stats();
00252     // Start tracing
00253     mbed_mem_trace_set_callback(test_trace_cb);
00254     // Test new, new[], delete and delete[]
00255     int *p_int = new int;
00256     int *p_int_array = new int[10];
00257     delete p_int;
00258     delete[] p_int_array;
00259     // Stop tracing
00260     mbed_mem_trace_set_callback(NULL);
00261     // Check tracer result
00262     check_sanity(4);
00263     check_malloc_op(pmem ++, p_int, sizeof(int));
00264     check_malloc_op(pmem ++, p_int_array, 10 * sizeof(int));
00265     check_free_op(pmem ++, p_int);
00266     check_free_op(pmem ++, p_int_array);
00267 }
00268 
00269 static Case cases[] = {
00270     Case("single malloc/free", test_case_single_malloc_free),
00271     Case("all memory operations", test_case_all_memory_ops),
00272     Case("trace off", test_case_trace_off),
00273     Case("partial trace", test_case_partial_trace),
00274     Case("test new/delete", test_case_new_delete)
00275 };
00276 
00277 static status_t greentea_test_setup(const size_t number_of_cases) {
00278     GREENTEA_SETUP(20, "default_auto");
00279     return greentea_test_setup_handler(number_of_cases);
00280 }
00281 
00282 static Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
00283 
00284 int main() {
00285     // Disable stdout buffering to prevent any unwanted allocations
00286     setvbuf(stdout, NULL, _IONBF, 0);
00287     Harness::run(specification);
00288 }
00289