Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
net_mem.c
Go to the documentation of this file.
00001 /** 00002 * @file net_mem.c 00003 * @brief Memory management 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL MEM_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include "core/net.h" 00034 #include "core/net_mem.h" 00035 #include "debug.h" 00036 00037 //Maximum number of chunks for dynamically allocated buffers 00038 #if (IPV4_SUPPORT == ENABLED && IPV6_SUPPORT == ENABLED) 00039 #define MAX_CHUNK_COUNT (N(MAX(IPV4_MAX_FRAG_DATAGRAM_SIZE, IPV6_MAX_FRAG_DATAGRAM_SIZE)) + 3) 00040 #elif (IPV4_SUPPORT == ENABLED) 00041 #define MAX_CHUNK_COUNT (N(IPV4_MAX_FRAG_DATAGRAM_SIZE) + 3) 00042 #elif (IPV6_SUPPORT == ENABLED) 00043 #define MAX_CHUNK_COUNT (N(IPV6_MAX_FRAG_DATAGRAM_SIZE) + 3) 00044 #endif 00045 00046 //Use fixed-size blocks allocation? 00047 #if (NET_MEM_POOL_SUPPORT == ENABLED) 00048 00049 //Mutex preventing simultaneous access to the memory pool 00050 static OsMutex memPoolMutex; 00051 //Memory pool 00052 static uint8_t memPool[NET_MEM_POOL_BUFFER_COUNT][NET_MEM_POOL_BUFFER_SIZE]; 00053 //Allocation table 00054 static bool_t memPoolAllocTable[NET_MEM_POOL_BUFFER_COUNT]; 00055 //Number of buffers currently allocated 00056 uint_t memPoolCurrentUsage; 00057 //Maximum number of buffers that have been allocated so far 00058 uint_t memPoolMaxUsage; 00059 00060 #endif 00061 00062 00063 /** 00064 * @brief Memory pool initialization 00065 * @return Error code 00066 **/ 00067 00068 error_t memPoolInit(void) 00069 { 00070 //Use fixed-size blocks allocation? 00071 #if (NET_MEM_POOL_SUPPORT == ENABLED) 00072 //Create a mutex to prevent simultaneous access to the memory pool 00073 if(!osCreateMutex(&memPoolMutex)) 00074 { 00075 //Failed to create mutex 00076 return ERROR_OUT_OF_RESOURCES; 00077 } 00078 00079 //Clear allocation table 00080 memset(memPoolAllocTable, 0, sizeof(memPoolAllocTable)); 00081 00082 //Clear statistics 00083 memPoolCurrentUsage = 0; 00084 memPoolMaxUsage = 0; 00085 #endif 00086 00087 //Successful initialization 00088 return NO_ERROR; 00089 } 00090 00091 00092 /** 00093 * @brief Allocate a memory block 00094 * @param[in] size Bytes to allocate 00095 * @return Pointer to the allocated space or NULL if there is insufficient memory available 00096 **/ 00097 00098 void *memPoolAlloc(size_t size) 00099 { 00100 #if (NET_MEM_POOL_SUPPORT == ENABLED) 00101 uint_t i; 00102 #endif 00103 00104 //Pointer to the allocated memory block 00105 void *p = NULL; 00106 00107 //Debug message 00108 TRACE_DEBUG("Allocating %" PRIuSIZE " bytes...\r\n", size); 00109 00110 //Use fixed-size blocks allocation? 00111 #if (NET_MEM_POOL_SUPPORT == ENABLED) 00112 //Acquire exclusive access to the memory pool 00113 osAcquireMutex(&memPoolMutex); 00114 00115 //Enforce block size 00116 if(size <= NET_MEM_POOL_BUFFER_SIZE) 00117 { 00118 //Loop through allocation table 00119 for(i = 0; i < NET_MEM_POOL_BUFFER_COUNT; i++) 00120 { 00121 //Check whether the current block is free 00122 if(!memPoolAllocTable[i]) 00123 { 00124 //Mark the current entry as used 00125 memPoolAllocTable[i] = TRUE; 00126 //Point to the corresponding memory block 00127 p = memPool[i]; 00128 00129 //Update statistics 00130 memPoolCurrentUsage++; 00131 //Maximum number of buffers that have been allocated so far 00132 memPoolMaxUsage = MAX(memPoolCurrentUsage, memPoolMaxUsage); 00133 00134 //Exit immediately 00135 break; 00136 } 00137 } 00138 } 00139 00140 //Release exclusive access to the memory pool 00141 osReleaseMutex(&memPoolMutex); 00142 #else 00143 //Allocate a memory block 00144 p = osAllocMem(size); 00145 #endif 00146 00147 //Failed to allocate memory? 00148 if(!p) 00149 { 00150 //Debug message 00151 TRACE_WARNING("Memory allocation failed!\r\n"); 00152 } 00153 00154 //Return a pointer to the allocated memory block 00155 return p; 00156 } 00157 00158 00159 /** 00160 * @brief Release a memory block 00161 * @param[in] p Previously allocated memory block to be freed 00162 **/ 00163 00164 void memPoolFree(void *p) 00165 { 00166 //Use fixed-size blocks allocation? 00167 #if (NET_MEM_POOL_SUPPORT == ENABLED) 00168 uint_t i; 00169 00170 //Acquire exclusive access to the memory pool 00171 osAcquireMutex(&memPoolMutex); 00172 00173 //Loop through allocation table 00174 for(i = 0; i < NET_MEM_POOL_BUFFER_COUNT; i++) 00175 { 00176 if(memPool[i] == p) 00177 { 00178 //Mark the current block as free 00179 memPoolAllocTable[i] = FALSE; 00180 00181 //Update statistics 00182 memPoolCurrentUsage--; 00183 00184 //Exit immediately 00185 break; 00186 } 00187 } 00188 00189 //Release exclusive access to the memory pool 00190 osReleaseMutex(&memPoolMutex); 00191 #else 00192 //Release memory block 00193 osFreeMem(p); 00194 #endif 00195 } 00196 00197 00198 /** 00199 * @brief Get memory pool usage 00200 * @param[out] currentUsage Number of buffers currently allocated 00201 * @param[out] maxUsage Maximum number of buffers that have been allocated so far 00202 * @param[out] size Total number of buffers in the memory pool 00203 **/ 00204 00205 void memPoolGetStats(uint_t *currentUsage, uint_t *maxUsage, uint_t *size) 00206 { 00207 //Use fixed-size blocks allocation? 00208 #if (NET_MEM_POOL_SUPPORT == ENABLED) 00209 //Number of buffers currently allocated 00210 if(currentUsage != NULL) 00211 *currentUsage = memPoolCurrentUsage; 00212 00213 //Maximum number of buffers that have been allocated so far 00214 if(maxUsage != NULL) 00215 *maxUsage = memPoolMaxUsage; 00216 00217 //Total number of buffers in the memory pool 00218 if(size != NULL) 00219 *size = NET_MEM_POOL_BUFFER_COUNT; 00220 #else 00221 //Memory pool is not used... 00222 if(currentUsage != NULL) 00223 *currentUsage = 0; 00224 00225 if(maxUsage != NULL) 00226 *maxUsage = 0; 00227 00228 if(size != NULL) 00229 *size = 0; 00230 #endif 00231 } 00232 00233 00234 /** 00235 * @brief Allocate a multi-part buffer 00236 * @param[in] length Desired length 00237 * @return Pointer to the allocated buffer or NULL if there is 00238 * insufficient memory available 00239 **/ 00240 00241 NetBuffer *netBufferAlloc(size_t length) 00242 { 00243 error_t error; 00244 NetBuffer *buffer; 00245 00246 //Allocate memory to hold the multi-part buffer 00247 buffer = memPoolAlloc(NET_MEM_POOL_BUFFER_SIZE); 00248 //Failed to allocate memory? 00249 if(buffer == NULL) 00250 return NULL; 00251 00252 //The multi-part buffer consists of a single chunk 00253 buffer->chunkCount = 1; 00254 buffer->maxChunkCount = MAX_CHUNK_COUNT; 00255 buffer->chunk[0].address = (uint8_t *) buffer + CHUNKED_BUFFER_HEADER_SIZE; 00256 buffer->chunk[0].length = NET_MEM_POOL_BUFFER_SIZE - CHUNKED_BUFFER_HEADER_SIZE; 00257 buffer->chunk[0].size = 0; 00258 00259 //Adjust the length of the buffer 00260 error = netBufferSetLength(buffer, length); 00261 //Any error to report? 00262 if(error) 00263 { 00264 //Clean up side effects 00265 netBufferFree(buffer); 00266 //Report an failure 00267 return NULL; 00268 } 00269 00270 //Successful memory allocation 00271 return buffer; 00272 } 00273 00274 00275 /** 00276 * @brief Dispose a multi-part buffer 00277 * @param[in] buffer Pointer to the multi-part buffer to be released 00278 **/ 00279 00280 void netBufferFree(NetBuffer *buffer) 00281 { 00282 //Properly dispose data chunks 00283 netBufferSetLength(buffer, 0); 00284 //Release multi-part buffer 00285 memPoolFree(buffer); 00286 } 00287 00288 00289 /** 00290 * @brief Get the actual length of a multi-part buffer 00291 * @param[in] buffer Pointer to a multi-part buffer 00292 * @return Actual length in bytes 00293 **/ 00294 00295 size_t netBufferGetLength(const NetBuffer *buffer) 00296 { 00297 uint_t i; 00298 00299 //Total length 00300 size_t length = 0; 00301 00302 //Loop through data chunks 00303 for(i = 0; i < buffer->chunkCount; i++) 00304 length += buffer->chunk[i].length; 00305 00306 //Return total length 00307 return length; 00308 } 00309 00310 00311 /** 00312 * @brief Adjust the length of a multi-part buffer 00313 * @param[in] buffer Pointer to the multi-part buffer whose length is to be changed 00314 * @param[in] length Desired length 00315 * @return Error code 00316 **/ 00317 00318 error_t netBufferSetLength(NetBuffer *buffer, size_t length) 00319 { 00320 uint_t i; 00321 uint_t chunkCount; 00322 ChunkDesc *chunk; 00323 00324 //Get the actual number of chunks 00325 chunkCount = buffer->chunkCount; 00326 00327 //Loop through data chunks 00328 for(i = 0; i < chunkCount && length > 0; i++) 00329 { 00330 //Point to the chunk descriptor; 00331 chunk = &buffer->chunk[i]; 00332 00333 //Adjust the length of the current chunk when possible 00334 if(length <= chunk->length) 00335 { 00336 chunk->length = length; 00337 } 00338 else if(chunk->size > 0 && i == (chunkCount - 1)) 00339 { 00340 chunk->length = MIN(length, chunk->size); 00341 } 00342 00343 //Prepare to process next chunk 00344 length -= chunk->length; 00345 } 00346 00347 //The size of the buffer should be decreased? 00348 if(!length) 00349 { 00350 //Adjust the number of chunks 00351 buffer->chunkCount = i; 00352 00353 //Delete unnecessary data chunks 00354 while(i < chunkCount) 00355 { 00356 //Point to the chunk descriptor; 00357 chunk = &buffer->chunk[i]; 00358 00359 //Release previously allocated memory 00360 if(chunk->size > 0) 00361 memPoolFree(chunk->address); 00362 00363 //Mark the current chunk as free 00364 chunk->address = NULL; 00365 chunk->length = 0; 00366 chunk->size = 0; 00367 00368 //Next chunk 00369 i++; 00370 } 00371 } 00372 //The size of the buffer should be increased? 00373 else 00374 { 00375 //Add as many chunks as necessary 00376 while(i < buffer->maxChunkCount && length > 0) 00377 { 00378 //Point to the chunk descriptor; 00379 chunk = &buffer->chunk[i]; 00380 00381 //Allocate memory to hold a new chunk 00382 chunk->address = memPoolAlloc(NET_MEM_POOL_BUFFER_SIZE); 00383 //Failed to allocate memory? 00384 if(!chunk->address) 00385 return ERROR_OUT_OF_MEMORY; 00386 00387 //Allocated memory 00388 chunk->size = NET_MEM_POOL_BUFFER_SIZE; 00389 //Actual length of the data chunk 00390 chunk->length = MIN(length, NET_MEM_POOL_BUFFER_SIZE); 00391 00392 //Prepare to process next chunk 00393 length -= chunk->length; 00394 buffer->chunkCount++; 00395 i++; 00396 } 00397 } 00398 00399 //Return status code 00400 return (length > 0) ? ERROR_OUT_OF_RESOURCES : NO_ERROR; 00401 } 00402 00403 00404 /** 00405 * @brief Returns a pointer to the data at the specified position 00406 * @param[in] buffer Pointer to a multi-part buffer 00407 * @param[in] offset Offset from the beginning of the buffer 00408 * @return Pointer the data at the specified position 00409 **/ 00410 00411 void *netBufferAt(const NetBuffer *buffer, size_t offset) 00412 { 00413 uint_t i; 00414 00415 //Loop through data chunks 00416 for(i = 0; i < buffer->chunkCount; i++) 00417 { 00418 //The data at the specified offset resides in the current chunk? 00419 if(offset < buffer->chunk[i].length) 00420 return (uint8_t *) buffer->chunk[i].address + offset; 00421 00422 //Jump to the next chunk 00423 offset -= buffer->chunk[i].length; 00424 } 00425 00426 //Invalid offset... 00427 return NULL; 00428 } 00429 00430 00431 /** 00432 * @brief Concatenate two multi-part buffers 00433 * @param[out] dest Pointer to the destination buffer 00434 * @param[in] src Pointer to the source buffer 00435 * @param[in] srcOffset Read offset 00436 * @param[in] length Number of bytes to read from the source buffer 00437 * @return Error code 00438 **/ 00439 00440 error_t netBufferConcat(NetBuffer *dest, 00441 const NetBuffer *src, size_t srcOffset, size_t length) 00442 { 00443 uint_t i; 00444 uint_t j; 00445 00446 //Skip the beginning of the source data 00447 for(j = 0; j < src->chunkCount; j++) 00448 { 00449 //The data at the specified offset resides in the current chunk? 00450 if(srcOffset < src->chunk[j].length) 00451 break; 00452 00453 //Jump to the next chunk 00454 srcOffset -= src->chunk[j].length; 00455 } 00456 00457 //Invalid offset? 00458 if(j >= src->chunkCount) 00459 return ERROR_INVALID_PARAMETER; 00460 00461 //Position to the end of the destination data 00462 i = dest->chunkCount; 00463 00464 //Copy data blocks 00465 while(length > 0 && i < dest->maxChunkCount && j < src->chunkCount) 00466 { 00467 //Copy current block 00468 dest->chunk[i].address = (uint8_t *) src->chunk[j].address + srcOffset; 00469 dest->chunk[i].length = src->chunk[j].length - srcOffset; 00470 dest->chunk[i].size = 0; 00471 00472 //Limit the number of bytes to copy 00473 if(length < dest->chunk[i].length) 00474 dest->chunk[i].length = length; 00475 00476 //Decrement the number of remaining bytes 00477 length -= dest->chunk[i].length; 00478 //Increment the number of chunks 00479 dest->chunkCount++; 00480 00481 //Adjust variables 00482 srcOffset = 0; 00483 i++; 00484 j++; 00485 } 00486 00487 //Return status code 00488 return (length > 0) ? ERROR_FAILURE : NO_ERROR; 00489 } 00490 00491 00492 /** 00493 * @brief Copy data between multi-part buffers 00494 * @param[out] dest Pointer to the destination buffer 00495 * @param[in] destOffset Write offset 00496 * @param[in] src Pointer to the source buffer 00497 * @param[in] srcOffset Read offset 00498 * @param[in] length Number of bytes to be copied 00499 * @return Error code 00500 **/ 00501 00502 error_t netBufferCopy(NetBuffer *dest, size_t destOffset, 00503 const NetBuffer *src, size_t srcOffset, size_t length) 00504 { 00505 uint_t i; 00506 uint_t j; 00507 uint_t n; 00508 uint8_t *p; 00509 uint8_t *q; 00510 00511 //Skip the beginning of the source data 00512 for(i = 0; i < dest->chunkCount; i++) 00513 { 00514 //The data at the specified offset resides in the current chunk? 00515 if(destOffset < dest->chunk[i].length) 00516 break; 00517 00518 //Jump to the next chunk 00519 destOffset -= dest->chunk[i].length; 00520 } 00521 00522 //Invalid offset? 00523 if(i >= dest->chunkCount) 00524 return ERROR_INVALID_PARAMETER; 00525 00526 //Skip the beginning of the source data 00527 for(j = 0; j < src->chunkCount; j++) 00528 { 00529 //The data at the specified offset resides in the current chunk? 00530 if(srcOffset < src->chunk[j].length) 00531 break; 00532 00533 //Jump to the next chunk 00534 srcOffset -= src->chunk[j].length; 00535 } 00536 00537 //Invalid offset? 00538 if(j >= src->chunkCount) 00539 return ERROR_INVALID_PARAMETER; 00540 00541 while(length > 0 && i < dest->chunkCount && j < src->chunkCount) 00542 { 00543 //Point to the first data byte 00544 p = (uint8_t *) dest->chunk[i].address + destOffset; 00545 q = (uint8_t *) src->chunk[j].address + srcOffset; 00546 00547 //Compute the number of bytes to copy 00548 n = MIN(length, dest->chunk[i].length - destOffset); 00549 n = MIN(n, src->chunk[j].length - srcOffset); 00550 00551 //Copy data 00552 memcpy(p, q, n); 00553 00554 destOffset += n; 00555 srcOffset += n; 00556 length -= n; 00557 00558 if(destOffset >= dest->chunk[i].length) 00559 { 00560 destOffset = 0; 00561 i++; 00562 } 00563 00564 if(srcOffset >= src->chunk[j].length) 00565 { 00566 srcOffset = 0; 00567 j++; 00568 } 00569 } 00570 00571 //Return status code 00572 return (length > 0) ? ERROR_FAILURE : NO_ERROR; 00573 } 00574 00575 00576 /** 00577 * @brief Append data a multi-part buffer 00578 * @param[out] dest Pointer to a multi-part buffer 00579 * @param[in] src User buffer containing the data to be appended 00580 * @param[in] length Number of bytes in the user buffer 00581 * @return Error code 00582 **/ 00583 00584 error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length) 00585 { 00586 uint_t i; 00587 00588 //Make sure there is enough space to add an extra chunk 00589 if(dest->chunkCount >= dest->maxChunkCount) 00590 return ERROR_FAILURE; 00591 00592 //Position to the end of the buffer 00593 i = dest->chunkCount; 00594 00595 //Insert a new chunk at the end of the list 00596 dest->chunk[i].address = (void *) src; 00597 dest->chunk[i].length = length; 00598 dest->chunk[i].size = 0; 00599 00600 //Increment the number of chunks 00601 dest->chunkCount++; 00602 00603 //Successful processing 00604 return NO_ERROR; 00605 } 00606 00607 00608 /** 00609 * @brief Write data to a multi-part buffer 00610 * @param[out] dest Pointer to a multi-part buffer 00611 * @param[in] destOffset Offset from the beginning of the multi-part buffer 00612 * @param[in] src User buffer containing the data to be written 00613 * @param[in] length Number of bytes to copy 00614 * @return Actual number of bytes copied 00615 **/ 00616 00617 size_t netBufferWrite(NetBuffer *dest, 00618 size_t destOffset, const void *src, size_t length) 00619 { 00620 uint_t i; 00621 uint_t n; 00622 size_t totalLength; 00623 uint8_t *p; 00624 00625 //Total number of bytes written 00626 totalLength = 0; 00627 00628 //Loop through data chunks 00629 for(i = 0; i < dest->chunkCount && totalLength < length; i++) 00630 { 00631 //Is there any data to copy in the current chunk? 00632 if(destOffset < dest->chunk[i].length) 00633 { 00634 //Point to the first byte to be written 00635 p = (uint8_t *) dest->chunk[i].address + destOffset; 00636 //Compute the number of bytes to copy at a time 00637 n = MIN(length - totalLength, dest->chunk[i].length - destOffset); 00638 00639 //Copy data 00640 memcpy(p, src, n); 00641 00642 //Advance read pointer 00643 src = (uint8_t *) src + n; 00644 //Total number of bytes written 00645 totalLength += n; 00646 //Process the next block from the start 00647 destOffset = 0; 00648 } 00649 else 00650 { 00651 //Skip the current chunk 00652 destOffset -= dest->chunk[i].length; 00653 } 00654 } 00655 00656 //Return the actual number of bytes written 00657 return totalLength; 00658 } 00659 00660 00661 /** 00662 * @brief Read data from a multi-part buffer 00663 * @param[out] dest Pointer to the buffer where to return the data 00664 * @param[in] src Pointer to a multi-part buffer 00665 * @param[in] srcOffset Offset from the beginning of the multi-part buffer 00666 * @param[in] length Number of bytes to copy 00667 * @return Actual number of bytes copied 00668 **/ 00669 00670 size_t netBufferRead(void *dest, const NetBuffer *src, 00671 size_t srcOffset, size_t length) 00672 { 00673 uint_t i; 00674 uint_t n; 00675 size_t totalLength; 00676 uint8_t *p; 00677 00678 //Total number of bytes copied 00679 totalLength = 0; 00680 00681 //Loop through data chunks 00682 for(i = 0; i < src->chunkCount && totalLength < length; i++) 00683 { 00684 //Is there any data to copy from the current chunk? 00685 if(srcOffset < src->chunk[i].length) 00686 { 00687 //Point to the first byte to be read 00688 p = (uint8_t *) src->chunk[i].address + srcOffset; 00689 //Compute the number of bytes to copy at a time 00690 n = MIN(length - totalLength, src->chunk[i].length - srcOffset); 00691 00692 //Copy data 00693 memcpy(dest, p, n); 00694 00695 //Advance write pointer 00696 dest = (uint8_t *) dest + n; 00697 //Total number of bytes copied 00698 totalLength += n; 00699 //Process the next block from the start 00700 srcOffset = 0; 00701 } 00702 else 00703 { 00704 //Skip the current chunk 00705 srcOffset -= src->chunk[i].length; 00706 } 00707 } 00708 00709 //Return the actual number of bytes copied 00710 return totalLength; 00711 } 00712
Generated on Tue Jul 12 2022 17:10:15 by
