Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers emac_TestMemoryManager.cpp Source File

emac_TestMemoryManager.cpp

00001 /*
00002  * Copyright (c) 2018, 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 MBED_CONF_APP_TEST_WIFI || MBED_CONF_APP_TEST_ETHERNET
00019 
00020 #include <stdio.h>
00021 #include <stdarg.h>
00022 #include <string.h>
00023 #include <list>
00024 #include <stdlib.h>
00025 
00026 #include "unity.h"
00027 
00028 #include "rtos/Mutex.h"
00029 
00030 extern "C" {
00031 #include "arm_hal_interrupt_private.h"
00032 }
00033 #include "nsdynmemLIB.h"
00034 
00035 #include "EMACMemoryManager.h"
00036 #include "emac_TestMemoryManager.h"
00037 
00038 #define BUF_HEAD        "headheadheadhead"
00039 #define BUF_HEAD_SIZE   16
00040 #define BUF_TAIL        "tailtailtailtail"
00041 #define BUF_TAIL_SIZE   16
00042 
00043 #define CHECK_ASSERT(value, fmt, ...) check_value(value, fmt, ##__VA_ARGS__)
00044 
00045 #define BUF_POOL_SIZE   (14 + 40 + 20 + 536) /* Ethernet + IP + TCP + payload */
00046 
00047 #define MEM_MNGR_TRACE "test mem mngr: "
00048 
00049 char s_trace_buffer[100] = MEM_MNGR_TRACE;
00050 
00051 /* For LPC boards define the heap memory bank ourselves to give us section placement
00052    control */
00053 #ifndef ETHMEM_SECTION
00054 #if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
00055 #  if defined (__ICCARM__)
00056 #     define ETHMEM_SECTION
00057 #  elif defined(TOOLCHAIN_GCC_CR)
00058 #     define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32")))
00059 #  else
00060 #     define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
00061 #  endif
00062 #elif defined(TARGET_LPC1768) || defined(TARGET_LPC1769)
00063 #  if defined (__ICCARM__)
00064 #     define ETHMEM_SECTION
00065 #  elif defined(TOOLCHAIN_GCC_CR)
00066 #     define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32")))
00067 #  else
00068 #     define ETHMEM_SECTION __attribute__((section("AHBSRAM0"),aligned))
00069 #  endif
00070 #endif
00071 #endif
00072 
00073 #ifdef ETHMEM_SECTION
00074 // Use nanostack libservice dynamic memory library
00075 #define EMAC_HEAP_SIZE 16300
00076 
00077 #if defined (__ICCARM__)
00078 #pragma location = ".ethusbram"
00079 #endif
00080 ETHMEM_SECTION static unsigned char ns_heap[EMAC_HEAP_SIZE];
00081 
00082 void emac_heap_error_handler(heap_fail_t event)
00083 {
00084     MBED_ASSERT(0);
00085 }
00086 #endif
00087 
00088 EmacTestMemoryManager::EmacTestMemoryManager()
00089     : m_mem_mutex(),
00090       m_mem_buffers(),
00091       m_alloc_unit(BUF_POOL_SIZE),
00092       m_memory_available(true)
00093 {
00094 #ifdef ETHMEM_SECTION
00095     static bool ns_heap_init = false;
00096     if (!ns_heap_init) {
00097         platform_critical_init(); // Create mutex for dynamic memory library
00098         ns_dyn_mem_init(ns_heap, EMAC_HEAP_SIZE, emac_heap_error_handler, NULL);
00099         ns_heap_init = true;
00100     }
00101 #endif
00102 }
00103 
00104 emac_mem_buf_t *EmacTestMemoryManager::alloc_heap(uint32_t size, uint32_t align)
00105 {
00106     return alloc_heap(size, align, MEM_CHECK);
00107 }
00108 
00109 emac_mem_buf_t *EmacTestMemoryManager::alloc_heap(uint32_t size, uint32_t align, uint8_t opt)
00110 {
00111     validate_list();
00112 
00113     CHECK_ASSERT(size, "alloc_heap() invalid parameter size");
00114 
00115     check_align(align);
00116 
00117     if ((opt & MEM_CHECK) && !m_memory_available) {
00118         return NULL;
00119     }
00120 
00121     m_mem_mutex.lock();
00122 
00123     emac_memory_t *buf = new emac_memory_t;
00124 
00125     CHECK_ASSERT(buf, "alloc_heap() no memory");
00126 
00127 #ifdef ETHMEM_SECTION
00128     buf->buffer = ns_dyn_mem_alloc(BUF_HEAD_SIZE + size + align + BUF_TAIL_SIZE);
00129 #else
00130     buf->buffer = std::malloc(BUF_HEAD_SIZE + size + align + BUF_TAIL_SIZE);
00131 #endif
00132 
00133     CHECK_ASSERT(buf->buffer, "alloc_heap() no memory");
00134 
00135     buf->next = 0;
00136     buf->ptr = static_cast<char *>(buf->buffer) + BUF_HEAD_SIZE;
00137     buf->orig_len = size;
00138     buf->len = size;
00139     buf->first = true;
00140 
00141     if (opt & MEM_NO_ALIGN) {
00142         if (reinterpret_cast<uint32_t>(buf->ptr) % sizeof(uint16_t) == 0) {
00143             buf->ptr = static_cast<char *>(buf->ptr) + 1;
00144         }
00145     } else if (align) {
00146         uint32_t remainder = reinterpret_cast<uint32_t>(buf->ptr) % align;
00147         if (remainder) {
00148             uint32_t offset = align - remainder;
00149             if (offset >= align) {
00150                 offset = align;
00151             }
00152             buf->ptr = static_cast<char *>(buf->ptr) + offset;
00153         }
00154     }
00155 
00156     char *buffer_head = static_cast<char *>(buf->ptr) - BUF_HEAD_SIZE;
00157     memcpy(buffer_head, BUF_HEAD, BUF_HEAD_SIZE);
00158 
00159     char *buffer_tail = static_cast<char *>(buf->ptr) + buf->len;
00160     memcpy(buffer_tail, BUF_TAIL, BUF_TAIL_SIZE);
00161 
00162     m_mem_buffers.push_front(buf);
00163 
00164     m_mem_mutex.unlock();
00165 
00166     return buf;
00167 }
00168 
00169 emac_mem_buf_t *EmacTestMemoryManager::alloc_pool(uint32_t size, uint32_t align)
00170 {
00171     return alloc_pool(size, align, MEM_CHECK);
00172 }
00173 
00174 emac_mem_buf_t *EmacTestMemoryManager::alloc_pool(uint32_t size, uint32_t align, uint8_t opt)
00175 {
00176     validate_list();
00177 
00178     CHECK_ASSERT(size, "alloc_pool() invalid parameter size");
00179 
00180     check_align(align);
00181 
00182     if ((opt & MEM_CHECK) && !m_memory_available) {
00183         return NULL;
00184     }
00185 
00186     // Contiguous allocation
00187     if (size + align <= m_alloc_unit) {
00188         return alloc_heap(size, align, opt);
00189     }
00190 
00191     unsigned int pool_buffer_max_size = m_alloc_unit - align;
00192 
00193     CHECK_ASSERT(pool_buffer_max_size > 0, "alloc_pool() invalid align");
00194 
00195     emac_memory_t *first_buf = 0;
00196     emac_memory_t *prev_buf = 0;
00197     unsigned int size_left = size;
00198 
00199     while (size_left != 0) {
00200         unsigned int alloc_size;
00201 
00202         // New alloc size buffer needed
00203         if (size_left > pool_buffer_max_size) {
00204             size_left = size_left - pool_buffer_max_size;
00205             alloc_size = pool_buffer_max_size;
00206         // New smaller than alloc size buffer needed
00207         } else {
00208             alloc_size = size_left;
00209             size_left = 0;
00210         }
00211 
00212         emac_memory_t *new_buf = static_cast<emac_memory_t *>(alloc_heap(alloc_size, align, opt));
00213 
00214         if (prev_buf) {
00215             new_buf->first = false;
00216             prev_buf->next = new_buf;
00217         } else {
00218             first_buf = new_buf;
00219         }
00220         prev_buf = new_buf;
00221     }
00222 
00223     return first_buf;
00224 }
00225 
00226 uint32_t EmacTestMemoryManager::get_pool_alloc_unit(uint32_t align) const
00227 {
00228     validate_list();
00229 
00230     check_align(align);
00231 
00232     return m_alloc_unit - align;
00233 }
00234 
00235 void EmacTestMemoryManager::free(emac_mem_buf_t *buf)
00236 {
00237     validate_list();
00238 
00239     CHECK_ASSERT(buf, "free(): buffer parameter is null");
00240 
00241     emac_memory_t *mem_buf = static_cast<emac_memory_t *>(buf);
00242 
00243     CHECK_ASSERT(mem_buf->first, "free() not first in chain");
00244 
00245     std::list<emac_memory_t *>::iterator mem_buf_entry;
00246 
00247     m_mem_mutex.lock();
00248 
00249     while (mem_buf) {
00250         for (mem_buf_entry = m_mem_buffers.begin(); mem_buf_entry != m_mem_buffers.end(); ++mem_buf_entry) {
00251             if (*mem_buf_entry == mem_buf) {
00252                 break;
00253             }
00254         }
00255 
00256         if (mem_buf_entry == m_mem_buffers.end()) {
00257             CHECK_ASSERT(0, "free(): %p buffer already freed", mem_buf);
00258             m_mem_mutex.unlock();
00259             return;
00260         }
00261 
00262         char *buffer_head = static_cast<char *>(mem_buf->ptr) - BUF_HEAD_SIZE;
00263         if (memcmp(buffer_head, BUF_HEAD, BUF_HEAD_SIZE) != 0) {
00264             CHECK_ASSERT(0, "free(): %p head overwrite", mem_buf);
00265         }
00266 
00267         char *buffer_tail = static_cast<char *>(mem_buf->ptr) + mem_buf->orig_len;
00268         if (memcmp(buffer_tail, BUF_TAIL, BUF_TAIL_SIZE) != 0) {
00269             CHECK_ASSERT(0, "free(): %p tail overwrite", mem_buf);
00270         }
00271 
00272         emac_memory_t *next = mem_buf->next;
00273 
00274         m_mem_buffers.erase(mem_buf_entry);
00275 
00276 #ifdef ETHMEM_SECTION
00277         ns_dyn_mem_free(mem_buf->buffer);
00278 #else
00279         std::free(mem_buf->buffer);
00280 #endif
00281         delete mem_buf;
00282 
00283         mem_buf = next;
00284     }
00285 
00286     m_mem_mutex.unlock();
00287 }
00288 
00289 uint32_t EmacTestMemoryManager::get_total_len(const emac_mem_buf_t *buf) const
00290 {
00291     validate_list();
00292 
00293     if (!validate_ptr(buf)) {
00294         CHECK_ASSERT(0, "get_total_len(): %p invalid buffer", buf);
00295         return 0;
00296     }
00297 
00298     uint32_t total_len = 0;
00299 
00300     for (emac_memory_t *mem_buf = (emac_memory_t *) buf; mem_buf != NULL; mem_buf = mem_buf->next) {
00301         total_len += mem_buf->len;
00302     }
00303 
00304     return total_len;
00305 }
00306 
00307 void EmacTestMemoryManager::copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_buf)
00308 {
00309     validate_list();
00310 
00311     if (!validate_ptr(to_buf)) {
00312         CHECK_ASSERT(0, "copy(): %p invalid to buffer", to_buf);
00313         return;
00314     }
00315 
00316     if (!validate_ptr(from_buf)) {
00317         CHECK_ASSERT(0, "copy(): %p invalid from buffer", from_buf);
00318         return;
00319     }
00320 
00321     if (get_total_len(to_buf) != get_total_len(from_buf)) {
00322         CHECK_ASSERT(0, "copy(): %p to and %p from buffer total lengths not same", to_buf, from_buf);
00323         return;
00324     }
00325 
00326     unsigned int to_buf_offset = 0;
00327     unsigned int from_buf_offset = 0;
00328 
00329     emac_memory_t *to_mem_buf = static_cast<emac_memory_t *>(to_buf);
00330     const emac_memory_t *from_mem_buf = static_cast<const emac_memory_t *>(from_buf);
00331 
00332     while (to_mem_buf && from_mem_buf) {
00333         unsigned int buf_copy_len;
00334 
00335         // Is there data in from buffer
00336         buf_copy_len = from_mem_buf->len - from_buf_offset;
00337         if (buf_copy_len == 0) {
00338             from_mem_buf = from_mem_buf->next;
00339             from_buf_offset = 0;
00340             continue;
00341         }
00342 
00343         // Is there space left in to buffer
00344         if (buf_copy_len > to_mem_buf->len - to_buf_offset) {
00345             buf_copy_len = to_mem_buf->len - to_buf_offset;
00346         }
00347         if (buf_copy_len == 0) {
00348             to_mem_buf = to_mem_buf->next;
00349             to_buf_offset = 0;
00350             continue;
00351         }
00352 
00353         // Copy data
00354         memcpy(static_cast<char *>(to_mem_buf->ptr) + to_buf_offset, static_cast<const char *>(from_mem_buf->ptr) + from_buf_offset, buf_copy_len);
00355         from_buf_offset += buf_copy_len;
00356         to_buf_offset += buf_copy_len;
00357     }
00358 }
00359 
00360 void EmacTestMemoryManager::cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf)
00361 {
00362     validate_list();
00363 
00364     if (!validate_ptr(to_buf)) {
00365         CHECK_ASSERT(0, "cat(): %p invalid to buffer", to_buf);
00366         return;
00367     }
00368 
00369     if (!validate_ptr(cat_buf)) {
00370         CHECK_ASSERT(0, "cat(): %p invalid cat buffer", cat_buf);
00371         return;
00372     }
00373 
00374     emac_memory_t *cat_mem_buf = static_cast<emac_memory_t *>(cat_buf);
00375 
00376     if (!cat_mem_buf->first) {
00377         CHECK_ASSERT(0, "cat(): %p cat buffer does not point to head of chain", cat_buf);
00378         return;
00379     }
00380 
00381     emac_memory_t *to_mem_buf = static_cast<emac_memory_t *>(to_buf);
00382 
00383     while (to_mem_buf->next != 0) {
00384         to_mem_buf = to_mem_buf->next;
00385     }
00386 
00387     to_mem_buf->next = cat_mem_buf;
00388     cat_mem_buf->first = false;
00389 }
00390 
00391 emac_mem_buf_t *EmacTestMemoryManager::get_next(const emac_mem_buf_t *buf) const
00392 {
00393     validate_list();
00394 
00395     if (!validate_ptr(buf)) {
00396         CHECK_ASSERT(0, "get_next(): %p invalid buffer", buf);
00397         return NULL;
00398     }
00399 
00400     const emac_memory_t *mem_buf = static_cast<const emac_memory_t *>(buf);
00401     return mem_buf->next;
00402 }
00403 
00404 void *EmacTestMemoryManager::get_ptr(const emac_mem_buf_t *buf) const
00405 {
00406     validate_list();
00407 
00408     if (!validate_ptr(buf)) {
00409         CHECK_ASSERT(0, "get_ptr(): %p invalid buffer", buf);
00410         return NULL;
00411     }
00412 
00413     const emac_memory_t *mem_buf = static_cast<const emac_memory_t *>(buf);
00414     return mem_buf->ptr;
00415 }
00416 
00417 uint32_t EmacTestMemoryManager::get_len(const emac_mem_buf_t *buf) const
00418 {
00419     validate_list();
00420 
00421     if (!validate_ptr(buf)) {
00422         CHECK_ASSERT(0, "get_len(): %p invalid buffer", buf);
00423         return 0;
00424     }
00425 
00426     const emac_memory_t *mem_buf = static_cast<const emac_memory_t *>(buf);
00427     return mem_buf->len;
00428 }
00429 
00430 void EmacTestMemoryManager::set_len(emac_mem_buf_t *buf, uint32_t len)
00431 {
00432     validate_list();
00433 
00434     if (!validate_ptr(buf)) {
00435         CHECK_ASSERT(0, "set_len(): %p invalid buffer", buf);
00436         return;
00437     }
00438 
00439     emac_memory_t *mem_buf = static_cast<emac_memory_t *>(buf);
00440 
00441     if (len > mem_buf->orig_len) {
00442         CHECK_ASSERT(0, "set_len(): %p new length %i must be less or equal allocated size %i", buf, len, mem_buf->orig_len);
00443         return;
00444     }
00445 
00446     if (!mem_buf->first) {
00447         CHECK_ASSERT(0, "set_len(): %p buffer does not point to head of chain", buf);
00448         return;
00449     }
00450 
00451     mem_buf->len = len;
00452 }
00453 
00454 void EmacTestMemoryManager::set_alloc_unit(uint32_t alloc_unit)
00455 {
00456     validate_list();
00457 
00458     m_alloc_unit = alloc_unit;
00459 }
00460 
00461 void EmacTestMemoryManager::set_memory_available(bool memory)
00462 {
00463     m_memory_available = memory;
00464 }
00465 
00466 void EmacTestMemoryManager::get_memory_statistics(int *buffers, int *memory)
00467 {
00468     if (!buffers || !memory) {
00469         return;
00470     }
00471 
00472     *buffers = 0;
00473     *memory = 0;
00474 
00475     m_mem_mutex.lock();
00476 
00477     const emac_memory_t *mem_buf;
00478 
00479     for (std::list<emac_memory_t *>::const_iterator it = m_mem_buffers.begin(); it != m_mem_buffers.end(); ++it) {
00480         mem_buf = static_cast<const emac_memory_t *>(*it);
00481         ++(*buffers);
00482         *memory += mem_buf->orig_len;
00483     }
00484 
00485     m_mem_mutex.unlock();
00486 }
00487 
00488 template <typename TYPE> void EmacTestMemoryManager::check_value(TYPE value, const char *fmt, ...) const
00489 {
00490     if (!value) {
00491         va_list ap;
00492         va_start(ap, fmt);
00493         snprintf(s_trace_buffer + sizeof(MEM_MNGR_TRACE) - 1, sizeof(s_trace_buffer) - sizeof(MEM_MNGR_TRACE) - 1, fmt, ap);
00494         va_end(ap);
00495         TEST_ASSERT_MESSAGE(0, s_trace_buffer);
00496     }
00497 }
00498 
00499 bool EmacTestMemoryManager::validate_ptr(const emac_mem_buf_t *buf) const
00500 {
00501     if (!buf) {
00502         return false;
00503     }
00504 
00505     m_mem_mutex.lock();
00506 
00507     const emac_memory_t *mem_buf = static_cast<const emac_memory_t *>(buf);
00508 
00509     for (std::list<emac_memory_t *>::const_iterator it = m_mem_buffers.begin(); it != m_mem_buffers.end(); ++it) {
00510         emac_memory_t *list_buf = static_cast<emac_memory_t *>(*it);
00511         if (list_buf == mem_buf) {
00512             m_mem_mutex.unlock();
00513             return true;
00514         }
00515     }
00516 
00517     m_mem_mutex.unlock();
00518 
00519     return false;
00520 }
00521 
00522 void EmacTestMemoryManager::check_align(uint32_t align) const
00523 {
00524     if (align > 64) {
00525         CHECK_ASSERT(0, "check_align(): invalid alignment value");
00526     }
00527 }
00528 
00529 void EmacTestMemoryManager::validate_list() const
00530 {
00531     m_mem_mutex.lock();
00532 
00533     const emac_memory_t *mem_buf;
00534 
00535     for (std::list<emac_memory_t *>::const_iterator it = m_mem_buffers.begin(); it != m_mem_buffers.end(); ++it) {
00536         mem_buf = static_cast<const emac_memory_t *>(*it);
00537 
00538         char *buffer_head = static_cast<char *>(mem_buf->ptr) - BUF_HEAD_SIZE;
00539         if (memcmp(buffer_head, BUF_HEAD, BUF_HEAD_SIZE) != 0) {
00540             CHECK_ASSERT(0, "validate_list(): %p head overwrite", mem_buf);
00541         }
00542 
00543         char *buffer_tail = static_cast<char *>(mem_buf->ptr) + mem_buf->orig_len;
00544         if (memcmp(buffer_tail, BUF_TAIL, BUF_TAIL_SIZE) != 0) {
00545             CHECK_ASSERT(0, "validate_list(): %p tail overwrite", mem_buf);
00546 
00547         }
00548     }
00549 
00550     m_mem_mutex.unlock();
00551 }
00552 
00553 EmacTestMemoryManager &EmacTestMemoryManager::get_instance() {
00554     static EmacTestMemoryManager test_memory_manager;
00555     return test_memory_manager;
00556 }
00557 
00558 #endif