Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers net_mem.c Source File

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