]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / BufferManagement / BufferAllocation_1.c
1 /*\r
2  * FreeRTOS+TCP V2.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /******************************************************************************\r
30  *\r
31  * See the following web page for essential buffer allocation scheme usage and\r
32  * configuration details:\r
33  * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html\r
34  *\r
35  ******************************************************************************/\r
36 \r
37 /* Standard includes. */\r
38 #include <stdint.h>\r
39 \r
40 /* FreeRTOS includes. */\r
41 #include "FreeRTOS.h"\r
42 #include "task.h"\r
43 #include "queue.h"\r
44 #include "semphr.h"\r
45 \r
46 /* FreeRTOS+TCP includes. */\r
47 #include "FreeRTOS_IP.h"\r
48 #include "FreeRTOS_IP_Private.h"\r
49 #include "NetworkInterface.h"\r
50 #include "NetworkBufferManagement.h"\r
51 \r
52 /* For an Ethernet interrupt to be able to obtain a network buffer there must\r
53 be at least this number of buffers available. */\r
54 #define baINTERRUPT_BUFFER_GET_THRESHOLD        ( 3 )\r
55 \r
56 /* A list of free (available) NetworkBufferDescriptor_t structures. */\r
57 static List_t xFreeBuffersList;\r
58 \r
59 /* Some statistics about the use of buffers. */\r
60 static UBaseType_t uxMinimumFreeNetworkBuffers = 0u;\r
61 \r
62 /* Declares the pool of NetworkBufferDescriptor_t structures that are available\r
63 to the system.  All the network buffers referenced from xFreeBuffersList exist\r
64 in this array.  The array is not accessed directly except during initialisation,\r
65 when the xFreeBuffersList is filled (as all the buffers are free when the system\r
66 is booted). */\r
67 static NetworkBufferDescriptor_t xNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];\r
68 \r
69 /* This constant is defined as true to let FreeRTOS_TCP_IP.c know that the\r
70 network buffers have constant size, large enough to hold the biggest Ethernet\r
71 packet. No resizing will be done. */\r
72 const BaseType_t xBufferAllocFixedSize = pdTRUE;\r
73 \r
74 /* The semaphore used to obtain network buffers. */\r
75 static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;\r
76 \r
77 #if( ipconfigTCP_IP_SANITY != 0 )\r
78         static char cIsLow = pdFALSE;\r
79         UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );\r
80 #else\r
81         static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );\r
82 #endif /* ipconfigTCP_IP_SANITY */\r
83 \r
84 static void prvShowWarnings( void );\r
85 \r
86 /* The user can define their own ipconfigBUFFER_ALLOC_LOCK() and\r
87 ipconfigBUFFER_ALLOC_UNLOCK() macros, especially for use form an ISR.  If these\r
88 are not defined then default them to call the normal enter/exit critical\r
89 section macros. */\r
90 #if !defined( ipconfigBUFFER_ALLOC_LOCK )\r
91 \r
92         #define ipconfigBUFFER_ALLOC_INIT( ) do {} while (0)\r
93         #define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR()            \\r
94                 UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \\r
95                 {\r
96 \r
97         #define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR()          \\r
98                         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \\r
99                 }\r
100 \r
101         #define ipconfigBUFFER_ALLOC_LOCK()                                     taskENTER_CRITICAL()\r
102         #define ipconfigBUFFER_ALLOC_UNLOCK()                           taskEXIT_CRITICAL()\r
103 \r
104 #endif /* ipconfigBUFFER_ALLOC_LOCK */\r
105 \r
106 /*-----------------------------------------------------------*/\r
107 \r
108 #if( ipconfigTCP_IP_SANITY != 0 )\r
109 \r
110         /* HT: SANITY code will be removed as soon as the library is stable\r
111          * and and ready to become public\r
112          * Function below gives information about the use of buffers */\r
113         #define WARN_LOW                ( 2 )\r
114         #define WARN_HIGH               ( ( 5 * ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) / 10 )\r
115 \r
116 #endif /* ipconfigTCP_IP_SANITY */\r
117 \r
118 /*-----------------------------------------------------------*/\r
119 \r
120 #if( ipconfigTCP_IP_SANITY != 0 )\r
121 \r
122         BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr )\r
123         {\r
124                 return ( bIsValidNetworkDescriptor( pxDescr ) != 0 ) &&\r
125                         ( listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxDescr->xBufferListItem ) ) != 0 );\r
126         }\r
127         /*-----------------------------------------------------------*/\r
128 \r
129         static void prvShowWarnings( void )\r
130         {\r
131                 UBaseType_t uxCount = uxGetNumberOfFreeNetworkBuffers( );\r
132                 if( ( ( cIsLow == 0 ) && ( uxCount <= WARN_LOW ) ) || ( ( cIsLow != 0 ) && ( uxCount >= WARN_HIGH ) ) )\r
133                 {\r
134                         cIsLow = !cIsLow;\r
135                         FreeRTOS_debug_printf( ( "*** Warning *** %s %lu buffers left\n", cIsLow ? "only" : "now", uxCount ) );\r
136                 }\r
137         }\r
138         /*-----------------------------------------------------------*/\r
139 \r
140         UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc )\r
141         {\r
142                 uint32_t offset = ( uint32_t ) ( ((const char *)pxDesc) - ((const char *)xNetworkBuffers) );\r
143                 if( ( offset >= sizeof( xNetworkBuffers ) ) ||\r
144                         ( ( offset % sizeof( xNetworkBuffers[0] ) ) != 0 ) )\r
145                         return pdFALSE;\r
146                 return (UBaseType_t) (pxDesc - xNetworkBuffers) + 1;\r
147         }\r
148         /*-----------------------------------------------------------*/\r
149 \r
150 #else\r
151         static UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc)\r
152         {\r
153                 ( void ) pxDesc;\r
154                 return ( UBaseType_t ) pdTRUE;\r
155         }\r
156         /*-----------------------------------------------------------*/\r
157 \r
158         static void prvShowWarnings( void )\r
159         {\r
160         }\r
161         /*-----------------------------------------------------------*/\r
162 \r
163 #endif /* ipconfigTCP_IP_SANITY */\r
164 \r
165 BaseType_t xNetworkBuffersInitialise( void )\r
166 {\r
167 BaseType_t xReturn, x;\r
168 \r
169         /* Only initialise the buffers and their associated kernel objects if they\r
170         have not been initialised before. */\r
171         if( xNetworkBufferSemaphore == NULL )\r
172         {\r
173                 /* In case alternative locking is used, the mutexes can be initialised\r
174                 here */\r
175                 ipconfigBUFFER_ALLOC_INIT();\r
176 \r
177                 xNetworkBufferSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );\r
178                 configASSERT( xNetworkBufferSemaphore );\r
179 \r
180                 if( xNetworkBufferSemaphore != NULL )\r
181                 {\r
182                         vListInitialise( &xFreeBuffersList );\r
183 \r
184                         /* Initialise all the network buffers.  The buffer storage comes\r
185                         from the network interface, and different hardware has different\r
186                         requirements. */\r
187                         vNetworkInterfaceAllocateRAMToBuffers( xNetworkBuffers );\r
188                         for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )\r
189                         {\r
190                                 /* Initialise and set the owner of the buffer list items. */\r
191                                 vListInitialiseItem( &( xNetworkBuffers[ x ].xBufferListItem ) );\r
192                                 listSET_LIST_ITEM_OWNER( &( xNetworkBuffers[ x ].xBufferListItem ), &xNetworkBuffers[ x ] );\r
193 \r
194                                 /* Currently, all buffers are available for use. */\r
195                                 vListInsert( &xFreeBuffersList, &( xNetworkBuffers[ x ].xBufferListItem ) );\r
196                         }\r
197 \r
198                         uxMinimumFreeNetworkBuffers = ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;\r
199                 }\r
200         }\r
201 \r
202         if( xNetworkBufferSemaphore == NULL )\r
203         {\r
204                 xReturn = pdFAIL;\r
205         }\r
206         else\r
207         {\r
208                 xReturn = pdPASS;\r
209         }\r
210 \r
211         return xReturn;\r
212 }\r
213 /*-----------------------------------------------------------*/\r
214 \r
215 NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )\r
216 {\r
217 NetworkBufferDescriptor_t *pxReturn = NULL;\r
218 BaseType_t xInvalid = pdFALSE;\r
219 UBaseType_t uxCount;\r
220 \r
221         /* The current implementation only has a single size memory block, so\r
222         the requested size parameter is not used (yet). */\r
223         ( void ) xRequestedSizeBytes;\r
224 \r
225         if( xNetworkBufferSemaphore != NULL )\r
226         {\r
227                 /* If there is a semaphore available, there is a network buffer\r
228                 available. */\r
229                 if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )\r
230                 {\r
231                         /* Protect the structure as it is accessed from tasks and\r
232                         interrupts. */\r
233                         ipconfigBUFFER_ALLOC_LOCK();\r
234                         {\r
235                                 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );\r
236 \r
237                                 if( ( bIsValidNetworkDescriptor( pxReturn ) != pdFALSE_UNSIGNED ) &&\r
238                                         listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxReturn->xBufferListItem ) ) )\r
239                                 {\r
240                                         uxListRemove( &( pxReturn->xBufferListItem ) );\r
241                                 }\r
242                                 else\r
243                                 {\r
244                                         xInvalid = pdTRUE;\r
245                                 }\r
246                         }\r
247                         ipconfigBUFFER_ALLOC_UNLOCK();\r
248 \r
249                         if( xInvalid == pdTRUE )\r
250                         {\r
251                                 /* _RB_ Can printf() be called from an interrupt?  (comment\r
252                                 above says this can be called from an interrupt too) */\r
253                                 /* _HT_ The function shall not be called from an ISR. Comment\r
254                                 was indeed misleading. Hopefully clear now?\r
255                                 So the printf()is OK here. */\r
256                                 FreeRTOS_debug_printf( ( "pxGetNetworkBufferWithDescriptor: INVALID BUFFER: %p (valid %lu)\n",\r
257                                         pxReturn, bIsValidNetworkDescriptor( pxReturn ) ) );\r
258                                 pxReturn = NULL;\r
259                         }\r
260                         else\r
261                         {\r
262                                 /* Reading UBaseType_t, no critical section needed. */\r
263                                 uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );\r
264 \r
265                                 /* For stats, latch the lowest number of network buffers since\r
266                                 booting. */\r
267                                 if( uxMinimumFreeNetworkBuffers > uxCount )\r
268                                 {\r
269                                         uxMinimumFreeNetworkBuffers = uxCount;\r
270                                 }\r
271 \r
272                                 pxReturn->xDataLength = xRequestedSizeBytes;\r
273 \r
274                                 #if( ipconfigTCP_IP_SANITY != 0 )\r
275                                 {\r
276                                         prvShowWarnings();\r
277                                 }\r
278                                 #endif /* ipconfigTCP_IP_SANITY */\r
279 \r
280                                 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
281                                 {\r
282                                         /* make sure the buffer is not linked */\r
283                                         pxReturn->pxNextBuffer = NULL;\r
284                                 }\r
285                                 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */\r
286 \r
287                                 if( xTCPWindowLoggingLevel > 3 )\r
288                                 {\r
289                                         FreeRTOS_debug_printf( ( "BUF_GET[%ld]: %p (%p)\n",\r
290                                                 bIsValidNetworkDescriptor( pxReturn ),\r
291                                                 pxReturn, pxReturn->pucEthernetBuffer ) );\r
292                                 }\r
293                         }\r
294                         iptraceNETWORK_BUFFER_OBTAINED( pxReturn );\r
295                 }\r
296                 else\r
297                 {\r
298                         iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();\r
299                 }\r
300         }\r
301 \r
302         return pxReturn;\r
303 }\r
304 /*-----------------------------------------------------------*/\r
305 \r
306 NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes )\r
307 {\r
308 NetworkBufferDescriptor_t *pxReturn = NULL;\r
309 \r
310         /* The current implementation only has a single size memory block, so\r
311         the requested size parameter is not used (yet). */\r
312         ( void ) xRequestedSizeBytes;\r
313 \r
314         /* If there is a semaphore available then there is a buffer available, but,\r
315         as this is called from an interrupt, only take a buffer if there are at\r
316         least baINTERRUPT_BUFFER_GET_THRESHOLD buffers remaining.  This prevents,\r
317         to a certain degree at least, a rapidly executing interrupt exhausting\r
318         buffer and in so doing preventing tasks from continuing. */\r
319         if( uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) xNetworkBufferSemaphore ) > ( UBaseType_t ) baINTERRUPT_BUFFER_GET_THRESHOLD )\r
320         {\r
321                 if( xSemaphoreTakeFromISR( xNetworkBufferSemaphore, NULL ) == pdPASS )\r
322                 {\r
323                         /* Protect the structure as it is accessed from tasks and interrupts. */\r
324                         ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();\r
325                         {\r
326                                 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );\r
327                                 uxListRemove( &( pxReturn->xBufferListItem ) );\r
328                         }\r
329                         ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();\r
330 \r
331                         iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxReturn );\r
332                 }\r
333         }\r
334 \r
335         if( pxReturn == NULL )\r
336         {\r
337                 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR();\r
338         }\r
339 \r
340         return pxReturn;\r
341 }\r
342 /*-----------------------------------------------------------*/\r
343 \r
344 BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
345 {\r
346 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
347 \r
348         /* Ensure the buffer is returned to the list of free buffers before the\r
349         counting semaphore is 'given' to say a buffer is available. */\r
350         ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();\r
351         {\r
352                 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );\r
353         }\r
354         ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();\r
355 \r
356         xSemaphoreGiveFromISR( xNetworkBufferSemaphore, &xHigherPriorityTaskWoken );\r
357         iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );\r
358 \r
359         return xHigherPriorityTaskWoken;\r
360 }\r
361 /*-----------------------------------------------------------*/\r
362 \r
363 void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
364 {\r
365 BaseType_t xListItemAlreadyInFreeList;\r
366 \r
367         if( bIsValidNetworkDescriptor( pxNetworkBuffer ) == pdFALSE_UNSIGNED )\r
368         {\r
369                 FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: Invalid buffer %p\n", pxNetworkBuffer ) );\r
370                 return ;\r
371         }\r
372         /* Ensure the buffer is returned to the list of free buffers before the\r
373         counting semaphore is 'given' to say a buffer is available. */\r
374         ipconfigBUFFER_ALLOC_LOCK();\r
375         {\r
376                 {\r
377                         xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );\r
378 \r
379                         if( xListItemAlreadyInFreeList == pdFALSE )\r
380                         {\r
381                                 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );\r
382                         }\r
383                 }\r
384         }\r
385         ipconfigBUFFER_ALLOC_UNLOCK();\r
386 \r
387         if( xListItemAlreadyInFreeList )\r
388         {\r
389                 FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: %p ALREADY RELEASED (now %lu)\n",\r
390                         pxNetworkBuffer, uxGetNumberOfFreeNetworkBuffers( ) ) );\r
391         }\r
392         if( xListItemAlreadyInFreeList == pdFALSE )\r
393         {\r
394                 xSemaphoreGive( xNetworkBufferSemaphore );\r
395                 prvShowWarnings();\r
396                 if( xTCPWindowLoggingLevel > 3 )\r
397                         FreeRTOS_debug_printf( ( "BUF_PUT[%ld]: %p (%p) (now %lu)\n",\r
398                                 bIsValidNetworkDescriptor( pxNetworkBuffer ),\r
399                                 pxNetworkBuffer, pxNetworkBuffer->pucEthernetBuffer,\r
400                                 uxGetNumberOfFreeNetworkBuffers( ) ) );\r
401         }\r
402         iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );\r
403 }\r
404 /*-----------------------------------------------------------*/\r
405 \r
406 UBaseType_t uxGetMinimumFreeNetworkBuffers( void )\r
407 {\r
408         return uxMinimumFreeNetworkBuffers;\r
409 }\r
410 /*-----------------------------------------------------------*/\r
411 \r
412 UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )\r
413 {\r
414         return listCURRENT_LIST_LENGTH( &xFreeBuffersList );\r
415 }\r
416 \r
417 NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )\r
418 {\r
419         /* In BufferAllocation_1.c all network buffer are allocated with a\r
420         maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the\r
421         network buffer. */\r
422         ( void ) xNewSizeBytes;\r
423         return pxNetworkBuffer;\r
424 }\r
425 \r
426 /*#endif */ /* ipconfigINCLUDE_TEST_CODE */\r