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