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