X-Git-Url: https://git.sur5r.net/?p=freertos;a=blobdiff_plain;f=FreeRTOS-Plus%2FSource%2FFreeRTOS-Plus-TCP%2Fportable%2FBufferManagement%2FBufferAllocation_1.c;fp=FreeRTOS-Plus%2FSource%2FFreeRTOS-Plus-TCP%2Fportable%2FBufferManagement%2FBufferAllocation_1.c;h=e70eb80ebdb9314984236aed66c99e8f3dd13c7d;hp=fa3f4333f3270f3fe14eae46cca5c3164bd3df99;hb=b15dfacb6026af3b0ba697e5753844923b468d2b;hpb=4334233a064299a09d167a497889d3860932a587 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c index fa3f4333f..e70eb80eb 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c @@ -1,411 +1,411 @@ -/* -FreeRTOS+TCP V2.0.11 -Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - http://aws.amazon.com/freertos - http://www.FreeRTOS.org -*/ - -/****************************************************************************** - * - * See the following web page for essential buffer allocation scheme usage and - * configuration details: - * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html - * - ******************************************************************************/ - -/* Standard includes. */ -#include - -/* FreeRTOS includes. */ -#include "FreeRTOS.h" -#include "task.h" -#include "queue.h" -#include "semphr.h" - -/* FreeRTOS+TCP includes. */ -#include "FreeRTOS_IP.h" -#include "FreeRTOS_IP_Private.h" -#include "NetworkInterface.h" -#include "NetworkBufferManagement.h" - -/* For an Ethernet interrupt to be able to obtain a network buffer there must -be at least this number of buffers available. */ -#define baINTERRUPT_BUFFER_GET_THRESHOLD ( 3 ) - -/* A list of free (available) NetworkBufferDescriptor_t structures. */ -static List_t xFreeBuffersList; - -/* Some statistics about the use of buffers. */ -static UBaseType_t uxMinimumFreeNetworkBuffers = 0u; - -/* Declares the pool of NetworkBufferDescriptor_t structures that are available -to the system. All the network buffers referenced from xFreeBuffersList exist -in this array. The array is not accessed directly except during initialisation, -when the xFreeBuffersList is filled (as all the buffers are free when the system -is booted). */ -static NetworkBufferDescriptor_t xNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ]; - -/* This constant is defined as true to let FreeRTOS_TCP_IP.c know that the -network buffers have constant size, large enough to hold the biggest Ethernet -packet. No resizing will be done. */ -const BaseType_t xBufferAllocFixedSize = pdTRUE; - -/* The semaphore used to obtain network buffers. */ -static SemaphoreHandle_t xNetworkBufferSemaphore = NULL; - -#if( ipconfigTCP_IP_SANITY != 0 ) - static char cIsLow = pdFALSE; - UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc ); -#else - static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc ); -#endif /* ipconfigTCP_IP_SANITY */ - -static void prvShowWarnings( void ); - -/* The user can define their own ipconfigBUFFER_ALLOC_LOCK() and -ipconfigBUFFER_ALLOC_UNLOCK() macros, especially for use form an ISR. If these -are not defined then default them to call the normal enter/exit critical -section macros. */ -#if !defined( ipconfigBUFFER_ALLOC_LOCK ) - - #define ipconfigBUFFER_ALLOC_INIT( ) do {} while (0) - #define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR() \ - UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \ - { - - #define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR() \ - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ - } - - #define ipconfigBUFFER_ALLOC_LOCK() taskENTER_CRITICAL() - #define ipconfigBUFFER_ALLOC_UNLOCK() taskEXIT_CRITICAL() - -#endif /* ipconfigBUFFER_ALLOC_LOCK */ - -/*-----------------------------------------------------------*/ - -#if( ipconfigTCP_IP_SANITY != 0 ) - - /* HT: SANITY code will be removed as soon as the library is stable - * and and ready to become public - * Function below gives information about the use of buffers */ - #define WARN_LOW ( 2 ) - #define WARN_HIGH ( ( 5 * ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) / 10 ) - -#endif /* ipconfigTCP_IP_SANITY */ - -/*-----------------------------------------------------------*/ - -#if( ipconfigTCP_IP_SANITY != 0 ) - - BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr ) - { - return ( bIsValidNetworkDescriptor( pxDescr ) != 0 ) && - ( listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxDescr->xBufferListItem ) ) != 0 ); - } - /*-----------------------------------------------------------*/ - - static void prvShowWarnings( void ) - { - UBaseType_t uxCount = uxGetNumberOfFreeNetworkBuffers( ); - if( ( ( cIsLow == 0 ) && ( uxCount <= WARN_LOW ) ) || ( ( cIsLow != 0 ) && ( uxCount >= WARN_HIGH ) ) ) - { - cIsLow = !cIsLow; - FreeRTOS_debug_printf( ( "*** Warning *** %s %lu buffers left\n", cIsLow ? "only" : "now", uxCount ) ); - } - } - /*-----------------------------------------------------------*/ - - UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc ) - { - uint32_t offset = ( uint32_t ) ( ((const char *)pxDesc) - ((const char *)xNetworkBuffers) ); - if( ( offset >= sizeof( xNetworkBuffers ) ) || - ( ( offset % sizeof( xNetworkBuffers[0] ) ) != 0 ) ) - return pdFALSE; - return (UBaseType_t) (pxDesc - xNetworkBuffers) + 1; - } - /*-----------------------------------------------------------*/ - -#else - static UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc) - { - ( void ) pxDesc; - return ( UBaseType_t ) pdTRUE; - } - /*-----------------------------------------------------------*/ - - static void prvShowWarnings( void ) - { - } - /*-----------------------------------------------------------*/ - -#endif /* ipconfigTCP_IP_SANITY */ - -BaseType_t xNetworkBuffersInitialise( void ) -{ -BaseType_t xReturn, x; - - /* Only initialise the buffers and their associated kernel objects if they - have not been initialised before. */ - if( xNetworkBufferSemaphore == NULL ) - { - /* In case alternative locking is used, the mutexes can be initialised - here */ - ipconfigBUFFER_ALLOC_INIT(); - - xNetworkBufferSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ); - configASSERT( xNetworkBufferSemaphore ); - - if( xNetworkBufferSemaphore != NULL ) - { - vListInitialise( &xFreeBuffersList ); - - /* Initialise all the network buffers. The buffer storage comes - from the network interface, and different hardware has different - requirements. */ - vNetworkInterfaceAllocateRAMToBuffers( xNetworkBuffers ); - for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ ) - { - /* Initialise and set the owner of the buffer list items. */ - vListInitialiseItem( &( xNetworkBuffers[ x ].xBufferListItem ) ); - listSET_LIST_ITEM_OWNER( &( xNetworkBuffers[ x ].xBufferListItem ), &xNetworkBuffers[ x ] ); - - /* Currently, all buffers are available for use. */ - vListInsert( &xFreeBuffersList, &( xNetworkBuffers[ x ].xBufferListItem ) ); - } - - uxMinimumFreeNetworkBuffers = ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; - } - } - - if( xNetworkBufferSemaphore == NULL ) - { - xReturn = pdFAIL; - } - else - { - xReturn = pdPASS; - } - - return xReturn; -} -/*-----------------------------------------------------------*/ - -NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks ) -{ -NetworkBufferDescriptor_t *pxReturn = NULL; -BaseType_t xInvalid = pdFALSE; -UBaseType_t uxCount; - - /* The current implementation only has a single size memory block, so - the requested size parameter is not used (yet). */ - ( void ) xRequestedSizeBytes; - - if( xNetworkBufferSemaphore != NULL ) - { - /* If there is a semaphore available, there is a network buffer - available. */ - if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS ) - { - /* Protect the structure as they are accessed from tasks and - interrupts. */ - ipconfigBUFFER_ALLOC_LOCK(); - { - pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList ); - - if( ( bIsValidNetworkDescriptor( pxReturn ) != pdFALSE_UNSIGNED ) && - listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxReturn->xBufferListItem ) ) ) - { - uxListRemove( &( pxReturn->xBufferListItem ) ); - } - else - { - xInvalid = pdTRUE; - } - } - ipconfigBUFFER_ALLOC_UNLOCK(); - - if( xInvalid == pdTRUE ) - { - /* _RB_ Can printf() be called from an interrupt? (comment - above says this can be called from an interrupt too) */ - /* _HT_ The function shall not be called from an ISR. Comment - was indeed misleading. Hopefully clear now? - So the printf()is OK here. */ - FreeRTOS_debug_printf( ( "pxGetNetworkBufferWithDescriptor: INVALID BUFFER: %p (valid %lu)\n", - pxReturn, bIsValidNetworkDescriptor( pxReturn ) ) ); - pxReturn = NULL; - } - else - { - /* Reading UBaseType_t, no critical section needed. */ - uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList ); - - /* For stats, latch the lowest number of network buffers since - booting. */ - if( uxMinimumFreeNetworkBuffers > uxCount ) - { - uxMinimumFreeNetworkBuffers = uxCount; - } - - pxReturn->xDataLength = xRequestedSizeBytes; - - #if( ipconfigTCP_IP_SANITY != 0 ) - { - prvShowWarnings(); - } - #endif /* ipconfigTCP_IP_SANITY */ - - #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) - { - /* make sure the buffer is not linked */ - pxReturn->pxNextBuffer = NULL; - } - #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ - } - iptraceNETWORK_BUFFER_OBTAINED( pxReturn ); - } - else - { - iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER(); - } - } - - return pxReturn; -} -/*-----------------------------------------------------------*/ - -NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes ) -{ -NetworkBufferDescriptor_t *pxReturn = NULL; - - /* The current implementation only has a single size memory block, so - the requested size parameter is not used (yet). */ - ( void ) xRequestedSizeBytes; - - /* If there is a semaphore available then there is a buffer available, but, - as this is called from an interrupt, only take a buffer if there are at - least baINTERRUPT_BUFFER_GET_THRESHOLD buffers remaining. This prevents, - to a certain degree at least, a rapidly executing interrupt exhausting - buffer and in so doing preventing tasks from continuing. */ - if( uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) xNetworkBufferSemaphore ) > ( UBaseType_t ) baINTERRUPT_BUFFER_GET_THRESHOLD ) - { - if( xSemaphoreTakeFromISR( xNetworkBufferSemaphore, NULL ) == pdPASS ) - { - /* Protect the structure as it is accessed from tasks and interrupts. */ - ipconfigBUFFER_ALLOC_LOCK_FROM_ISR(); - { - pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList ); - uxListRemove( &( pxReturn->xBufferListItem ) ); - } - ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR(); - - iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxReturn ); - } - } - - if( pxReturn == NULL ) - { - iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR(); - } - - return pxReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer ) -{ -BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - /* Ensure the buffer is returned to the list of free buffers before the - counting semaphore is 'given' to say a buffer is available. */ - ipconfigBUFFER_ALLOC_LOCK_FROM_ISR(); - { - vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); - } - ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR(); - - xSemaphoreGiveFromISR( xNetworkBufferSemaphore, &xHigherPriorityTaskWoken ); - iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); - - return xHigherPriorityTaskWoken; -} -/*-----------------------------------------------------------*/ - -void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer ) -{ -BaseType_t xListItemAlreadyInFreeList; - - if( bIsValidNetworkDescriptor( pxNetworkBuffer ) == pdFALSE_UNSIGNED ) - { - FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: Invalid buffer %p\n", pxNetworkBuffer ) ); - return ; - } - /* Ensure the buffer is returned to the list of free buffers before the - counting semaphore is 'given' to say a buffer is available. */ - ipconfigBUFFER_ALLOC_LOCK(); - { - { - xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); - - if( xListItemAlreadyInFreeList == pdFALSE ) - { - vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); - } - } - } - ipconfigBUFFER_ALLOC_UNLOCK(); - - if( xListItemAlreadyInFreeList ) - { - FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: %p ALREADY RELEASED (now %lu)\n", - pxNetworkBuffer, uxGetNumberOfFreeNetworkBuffers( ) ) ); - } - if( xListItemAlreadyInFreeList == pdFALSE ) - { - xSemaphoreGive( xNetworkBufferSemaphore ); - prvShowWarnings(); - } - iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); -} -/*-----------------------------------------------------------*/ - -UBaseType_t uxGetMinimumFreeNetworkBuffers( void ) -{ - return uxMinimumFreeNetworkBuffers; -} -/*-----------------------------------------------------------*/ - -UBaseType_t uxGetNumberOfFreeNetworkBuffers( void ) -{ - return listCURRENT_LIST_LENGTH( &xFreeBuffersList ); -} - -NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes ) -{ - /* In BufferAllocation_1.c all network buffer are allocated with a - maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the - network buffer. */ - ( void ) xNewSizeBytes; - return pxNetworkBuffer; -} - -/*#endif */ /* ipconfigINCLUDE_TEST_CODE */ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/****************************************************************************** + * + * See the following web page for essential buffer allocation scheme usage and + * configuration details: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html + * + ******************************************************************************/ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" + +/* For an Ethernet interrupt to be able to obtain a network buffer there must +be at least this number of buffers available. */ +#define baINTERRUPT_BUFFER_GET_THRESHOLD ( 3 ) + +/* A list of free (available) NetworkBufferDescriptor_t structures. */ +static List_t xFreeBuffersList; + +/* Some statistics about the use of buffers. */ +static UBaseType_t uxMinimumFreeNetworkBuffers = 0u; + +/* Declares the pool of NetworkBufferDescriptor_t structures that are available +to the system. All the network buffers referenced from xFreeBuffersList exist +in this array. The array is not accessed directly except during initialisation, +when the xFreeBuffersList is filled (as all the buffers are free when the system +is booted). */ +static NetworkBufferDescriptor_t xNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ]; + +/* This constant is defined as true to let FreeRTOS_TCP_IP.c know that the +network buffers have constant size, large enough to hold the biggest Ethernet +packet. No resizing will be done. */ +const BaseType_t xBufferAllocFixedSize = pdTRUE; + +/* The semaphore used to obtain network buffers. */ +static SemaphoreHandle_t xNetworkBufferSemaphore = NULL; + +#if( ipconfigTCP_IP_SANITY != 0 ) + static char cIsLow = pdFALSE; + UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc ); +#else + static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc ); +#endif /* ipconfigTCP_IP_SANITY */ + +static void prvShowWarnings( void ); + +/* The user can define their own ipconfigBUFFER_ALLOC_LOCK() and +ipconfigBUFFER_ALLOC_UNLOCK() macros, especially for use form an ISR. If these +are not defined then default them to call the normal enter/exit critical +section macros. */ +#if !defined( ipconfigBUFFER_ALLOC_LOCK ) + + #define ipconfigBUFFER_ALLOC_INIT( ) do {} while (0) + #define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR() \ + UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \ + { + + #define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR() \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ + } + + #define ipconfigBUFFER_ALLOC_LOCK() taskENTER_CRITICAL() + #define ipconfigBUFFER_ALLOC_UNLOCK() taskEXIT_CRITICAL() + +#endif /* ipconfigBUFFER_ALLOC_LOCK */ + +/*-----------------------------------------------------------*/ + +#if( ipconfigTCP_IP_SANITY != 0 ) + + /* HT: SANITY code will be removed as soon as the library is stable + * and and ready to become public + * Function below gives information about the use of buffers */ + #define WARN_LOW ( 2 ) + #define WARN_HIGH ( ( 5 * ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) / 10 ) + +#endif /* ipconfigTCP_IP_SANITY */ + +/*-----------------------------------------------------------*/ + +#if( ipconfigTCP_IP_SANITY != 0 ) + + BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr ) + { + return ( bIsValidNetworkDescriptor( pxDescr ) != 0 ) && + ( listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxDescr->xBufferListItem ) ) != 0 ); + } + /*-----------------------------------------------------------*/ + + static void prvShowWarnings( void ) + { + UBaseType_t uxCount = uxGetNumberOfFreeNetworkBuffers( ); + if( ( ( cIsLow == 0 ) && ( uxCount <= WARN_LOW ) ) || ( ( cIsLow != 0 ) && ( uxCount >= WARN_HIGH ) ) ) + { + cIsLow = !cIsLow; + FreeRTOS_debug_printf( ( "*** Warning *** %s %lu buffers left\n", cIsLow ? "only" : "now", uxCount ) ); + } + } + /*-----------------------------------------------------------*/ + + UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc ) + { + uint32_t offset = ( uint32_t ) ( ((const char *)pxDesc) - ((const char *)xNetworkBuffers) ); + if( ( offset >= sizeof( xNetworkBuffers ) ) || + ( ( offset % sizeof( xNetworkBuffers[0] ) ) != 0 ) ) + return pdFALSE; + return (UBaseType_t) (pxDesc - xNetworkBuffers) + 1; + } + /*-----------------------------------------------------------*/ + +#else + static UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc) + { + ( void ) pxDesc; + return ( UBaseType_t ) pdTRUE; + } + /*-----------------------------------------------------------*/ + + static void prvShowWarnings( void ) + { + } + /*-----------------------------------------------------------*/ + +#endif /* ipconfigTCP_IP_SANITY */ + +BaseType_t xNetworkBuffersInitialise( void ) +{ +BaseType_t xReturn, x; + + /* Only initialise the buffers and their associated kernel objects if they + have not been initialised before. */ + if( xNetworkBufferSemaphore == NULL ) + { + /* In case alternative locking is used, the mutexes can be initialised + here */ + ipconfigBUFFER_ALLOC_INIT(); + + xNetworkBufferSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ); + configASSERT( xNetworkBufferSemaphore ); + + if( xNetworkBufferSemaphore != NULL ) + { + vListInitialise( &xFreeBuffersList ); + + /* Initialise all the network buffers. The buffer storage comes + from the network interface, and different hardware has different + requirements. */ + vNetworkInterfaceAllocateRAMToBuffers( xNetworkBuffers ); + for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ ) + { + /* Initialise and set the owner of the buffer list items. */ + vListInitialiseItem( &( xNetworkBuffers[ x ].xBufferListItem ) ); + listSET_LIST_ITEM_OWNER( &( xNetworkBuffers[ x ].xBufferListItem ), &xNetworkBuffers[ x ] ); + + /* Currently, all buffers are available for use. */ + vListInsert( &xFreeBuffersList, &( xNetworkBuffers[ x ].xBufferListItem ) ); + } + + uxMinimumFreeNetworkBuffers = ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; + } + } + + if( xNetworkBufferSemaphore == NULL ) + { + xReturn = pdFAIL; + } + else + { + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks ) +{ +NetworkBufferDescriptor_t *pxReturn = NULL; +BaseType_t xInvalid = pdFALSE; +UBaseType_t uxCount; + + /* The current implementation only has a single size memory block, so + the requested size parameter is not used (yet). */ + ( void ) xRequestedSizeBytes; + + if( xNetworkBufferSemaphore != NULL ) + { + /* If there is a semaphore available, there is a network buffer + available. */ + if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS ) + { + /* Protect the structure as they are accessed from tasks and + interrupts. */ + ipconfigBUFFER_ALLOC_LOCK(); + { + pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList ); + + if( ( bIsValidNetworkDescriptor( pxReturn ) != pdFALSE_UNSIGNED ) && + listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxReturn->xBufferListItem ) ) ) + { + uxListRemove( &( pxReturn->xBufferListItem ) ); + } + else + { + xInvalid = pdTRUE; + } + } + ipconfigBUFFER_ALLOC_UNLOCK(); + + if( xInvalid == pdTRUE ) + { + /* _RB_ Can printf() be called from an interrupt? (comment + above says this can be called from an interrupt too) */ + /* _HT_ The function shall not be called from an ISR. Comment + was indeed misleading. Hopefully clear now? + So the printf()is OK here. */ + FreeRTOS_debug_printf( ( "pxGetNetworkBufferWithDescriptor: INVALID BUFFER: %p (valid %lu)\n", + pxReturn, bIsValidNetworkDescriptor( pxReturn ) ) ); + pxReturn = NULL; + } + else + { + /* Reading UBaseType_t, no critical section needed. */ + uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList ); + + /* For stats, latch the lowest number of network buffers since + booting. */ + if( uxMinimumFreeNetworkBuffers > uxCount ) + { + uxMinimumFreeNetworkBuffers = uxCount; + } + + pxReturn->xDataLength = xRequestedSizeBytes; + + #if( ipconfigTCP_IP_SANITY != 0 ) + { + prvShowWarnings(); + } + #endif /* ipconfigTCP_IP_SANITY */ + + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + /* make sure the buffer is not linked */ + pxReturn->pxNextBuffer = NULL; + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + } + iptraceNETWORK_BUFFER_OBTAINED( pxReturn ); + } + else + { + iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER(); + } + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes ) +{ +NetworkBufferDescriptor_t *pxReturn = NULL; + + /* The current implementation only has a single size memory block, so + the requested size parameter is not used (yet). */ + ( void ) xRequestedSizeBytes; + + /* If there is a semaphore available then there is a buffer available, but, + as this is called from an interrupt, only take a buffer if there are at + least baINTERRUPT_BUFFER_GET_THRESHOLD buffers remaining. This prevents, + to a certain degree at least, a rapidly executing interrupt exhausting + buffer and in so doing preventing tasks from continuing. */ + if( uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) xNetworkBufferSemaphore ) > ( UBaseType_t ) baINTERRUPT_BUFFER_GET_THRESHOLD ) + { + if( xSemaphoreTakeFromISR( xNetworkBufferSemaphore, NULL ) == pdPASS ) + { + /* Protect the structure as it is accessed from tasks and interrupts. */ + ipconfigBUFFER_ALLOC_LOCK_FROM_ISR(); + { + pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList ); + uxListRemove( &( pxReturn->xBufferListItem ) ); + } + ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR(); + + iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxReturn ); + } + } + + if( pxReturn == NULL ) + { + iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR(); + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + /* Ensure the buffer is returned to the list of free buffers before the + counting semaphore is 'given' to say a buffer is available. */ + ipconfigBUFFER_ALLOC_LOCK_FROM_ISR(); + { + vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + } + ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR(); + + xSemaphoreGiveFromISR( xNetworkBufferSemaphore, &xHigherPriorityTaskWoken ); + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); + + return xHigherPriorityTaskWoken; +} +/*-----------------------------------------------------------*/ + +void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +BaseType_t xListItemAlreadyInFreeList; + + if( bIsValidNetworkDescriptor( pxNetworkBuffer ) == pdFALSE_UNSIGNED ) + { + FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: Invalid buffer %p\n", pxNetworkBuffer ) ); + return ; + } + /* Ensure the buffer is returned to the list of free buffers before the + counting semaphore is 'given' to say a buffer is available. */ + ipconfigBUFFER_ALLOC_LOCK(); + { + { + xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + + if( xListItemAlreadyInFreeList == pdFALSE ) + { + vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + } + } + } + ipconfigBUFFER_ALLOC_UNLOCK(); + + if( xListItemAlreadyInFreeList ) + { + FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: %p ALREADY RELEASED (now %lu)\n", + pxNetworkBuffer, uxGetNumberOfFreeNetworkBuffers( ) ) ); + } + if( xListItemAlreadyInFreeList == pdFALSE ) + { + xSemaphoreGive( xNetworkBufferSemaphore ); + prvShowWarnings(); + } + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxGetMinimumFreeNetworkBuffers( void ) +{ + return uxMinimumFreeNetworkBuffers; +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxGetNumberOfFreeNetworkBuffers( void ) +{ + return listCURRENT_LIST_LENGTH( &xFreeBuffersList ); +} + +NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes ) +{ + /* In BufferAllocation_1.c all network buffer are allocated with a + maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the + network buffer. */ + ( void ) xNewSizeBytes; + return pxNetworkBuffer; +} + +/*#endif */ /* ipconfigINCLUDE_TEST_CODE */