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