]> begriffs open source - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c
Added +TCP code to main repo.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / BufferManagement / BufferAllocation_1.c
1 /*\r
2  * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.\r
3  * Authors include Hein Tibosch and Richard Barry\r
4  *\r
5  *******************************************************************************\r
6  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
7  ***                                                                         ***\r
8  ***                                                                         ***\r
9  ***   FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP     ***\r
10  ***   demos have a dependency on FreeRTOS+FAT, which is only in the Labs    ***\r
11  ***   download):                                                            ***\r
12  ***                                                                         ***\r
13  ***   FreeRTOS+TCP is functional and has been used in commercial products   ***\r
14  ***   for some time.  Be aware however that we are still refining its       ***\r
15  ***   design, the source code does not yet quite conform to the strict      ***\r
16  ***   coding and style standards mandated by Real Time Engineers ltd., and  ***\r
17  ***   the documentation and testing is not necessarily complete.            ***\r
18  ***                                                                         ***\r
19  ***   PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE    ***\r
20  ***   URL: http://www.FreeRTOS.org/contact  Active early adopters may, at   ***\r
21  ***   the sole discretion of Real Time Engineers Ltd., be offered versions  ***\r
22  ***   under a license other than that described below.                      ***\r
23  ***                                                                         ***\r
24  ***                                                                         ***\r
25  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
26  *******************************************************************************\r
27  *\r
28  * FreeRTOS+TCP can be used under two different free open source licenses.  The\r
29  * license that applies is dependent on the processor on which FreeRTOS+TCP is\r
30  * executed, as follows:\r
31  *\r
32  * If FreeRTOS+TCP is executed on one of the processors listed under the Special\r
33  * License Arrangements heading of the FreeRTOS+TCP license information web\r
34  * page, then it can be used under the terms of the FreeRTOS Open Source\r
35  * License.  If FreeRTOS+TCP is used on any other processor, then it can be used\r
36  * under the terms of the GNU General Public License V2.  Links to the relevant\r
37  * licenses follow:\r
38  *\r
39  * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license\r
40  * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license\r
41  * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt\r
42  *\r
43  * FreeRTOS+TCP is distributed in the hope that it will be useful.  You cannot\r
44  * use FreeRTOS+TCP unless you agree that you use the software 'as is'.\r
45  * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied\r
46  * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR\r
47  * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they\r
48  * implied, expressed, or statutory.\r
49  *\r
50  * 1 tab == 4 spaces!\r
51  *\r
52  * http://www.FreeRTOS.org\r
53  * http://www.FreeRTOS.org/plus\r
54  * http://www.FreeRTOS.org/labs\r
55  *\r
56  */\r
57 \r
58 /******************************************************************************\r
59  *\r
60  * See the following web page for essential buffer allocation scheme usage and\r
61  * configuration details:\r
62  * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html\r
63  *\r
64  ******************************************************************************/\r
65 \r
66 /* Standard includes. */\r
67 #include <stdint.h>\r
68 \r
69 /* FreeRTOS includes. */\r
70 #include "FreeRTOS.h"\r
71 #include "task.h"\r
72 #include "queue.h"\r
73 #include "semphr.h"\r
74 \r
75 /* FreeRTOS+TCP includes. */\r
76 #include "FreeRTOS_IP.h"\r
77 #include "FreeRTOS_IP_Private.h"\r
78 #include "NetworkInterface.h"\r
79 #include "NetworkBufferManagement.h"\r
80 \r
81 /* For an Ethernet interrupt to be able to obtain a network buffer there must\r
82 be at least this number of buffers available. */\r
83 #define baINTERRUPT_BUFFER_GET_THRESHOLD        ( 3 )\r
84 \r
85 /* A list of free (available) NetworkBufferDescriptor_t structures. */\r
86 static List_t xFreeBuffersList;\r
87 \r
88 /* Some statistics about the use of buffers. */\r
89 static UBaseType_t uxMinimumFreeNetworkBuffers = 0u;\r
90 \r
91 /* Declares the pool of NetworkBufferDescriptor_t structures that are available\r
92 to the system.  All the network buffers referenced from xFreeBuffersList exist\r
93 in this array.  The array is not accessed directly except during initialisation,\r
94 when the xFreeBuffersList is filled (as all the buffers are free when the system\r
95 is booted). */\r
96 static NetworkBufferDescriptor_t xNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];\r
97 \r
98 /* This constant is defined as true to let FreeRTOS_TCP_IP.c know that the\r
99 network buffers have constant size, large enough to hold the biggest Ethernet\r
100 packet. No resizing will be done. */\r
101 const BaseType_t xBufferAllocFixedSize = pdTRUE;\r
102 \r
103 /* The semaphore used to obtain network buffers. */\r
104 static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;\r
105 \r
106 #if( ipconfigTCP_IP_SANITY != 0 )\r
107         static char cIsLow = pdFALSE;\r
108         UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );\r
109 #else\r
110         static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );\r
111 #endif /* ipconfigTCP_IP_SANITY */\r
112 \r
113 static void prvShowWarnings( void );\r
114 \r
115 /* The user can define their own ipconfigBUFFER_ALLOC_LOCK() and\r
116 ipconfigBUFFER_ALLOC_UNLOCK() macros, especially for use form an ISR.  If these\r
117 are not defined then default them to call the normal enter/exit critical\r
118 section macros. */\r
119 #if !defined( ipconfigBUFFER_ALLOC_LOCK )\r
120 \r
121         #define ipconfigBUFFER_ALLOC_INIT( ) do {} while (0)\r
122         #define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR()            \\r
123                 UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \\r
124                 {\r
125 \r
126         #define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR()          \\r
127                         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \\r
128                 }\r
129 \r
130         #define ipconfigBUFFER_ALLOC_LOCK()                                     taskENTER_CRITICAL()\r
131         #define ipconfigBUFFER_ALLOC_UNLOCK()                           taskEXIT_CRITICAL()\r
132 \r
133 #endif /* ipconfigBUFFER_ALLOC_LOCK */\r
134 \r
135 /*-----------------------------------------------------------*/\r
136 \r
137 #if( ipconfigTCP_IP_SANITY != 0 )\r
138 \r
139         /* HT: SANITY code will be removed as soon as the library is stable\r
140          * and and ready to become public\r
141          * Function below gives information about the use of buffers */\r
142         #define WARN_LOW                ( 2 )\r
143         #define WARN_HIGH               ( ( 5 * ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) / 10 )\r
144 \r
145 #endif /* ipconfigTCP_IP_SANITY */\r
146 \r
147 /*-----------------------------------------------------------*/\r
148 \r
149 #if( ipconfigTCP_IP_SANITY != 0 )\r
150 \r
151         BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr )\r
152         {\r
153                 return ( bIsValidNetworkDescriptor( pxDescr ) != 0 ) &&\r
154                         ( listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxDescr->xBufferListItem ) ) != 0 );\r
155         }\r
156         /*-----------------------------------------------------------*/\r
157 \r
158         static void prvShowWarnings( void )\r
159         {\r
160                 UBaseType_t uxCount = uxGetNumberOfFreeNetworkBuffers( );\r
161                 if( ( ( cIsLow == 0 ) && ( uxCount <= WARN_LOW ) ) || ( ( cIsLow != 0 ) && ( uxCount >= WARN_HIGH ) ) )\r
162                 {\r
163                         cIsLow = !cIsLow;\r
164                         FreeRTOS_debug_printf( ( "*** Warning *** %s %lu buffers left\n", cIsLow ? "only" : "now", uxCount ) );\r
165                 }\r
166         }\r
167         /*-----------------------------------------------------------*/\r
168 \r
169         UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc )\r
170         {\r
171                 uint32_t offset = ( uint32_t ) ( ((const char *)pxDesc) - ((const char *)xNetworkBuffers) );\r
172                 if( ( offset >= sizeof( xNetworkBuffers ) ) ||\r
173                         ( ( offset % sizeof( xNetworkBuffers[0] ) ) != 0 ) )\r
174                         return pdFALSE;\r
175                 return (UBaseType_t) (pxDesc - xNetworkBuffers) + 1;\r
176         }\r
177         /*-----------------------------------------------------------*/\r
178 \r
179 #else\r
180         static UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc)\r
181         {\r
182                 ( void ) pxDesc;\r
183                 return ( UBaseType_t ) pdTRUE;\r
184         }\r
185         /*-----------------------------------------------------------*/\r
186 \r
187         static void prvShowWarnings( void )\r
188         {\r
189         }\r
190         /*-----------------------------------------------------------*/\r
191 \r
192 #endif /* ipconfigTCP_IP_SANITY */\r
193 \r
194 BaseType_t xNetworkBuffersInitialise( void )\r
195 {\r
196 BaseType_t xReturn, x;\r
197 \r
198         /* Only initialise the buffers and their associated kernel objects if they\r
199         have not been initialised before. */\r
200         if( xNetworkBufferSemaphore == NULL )\r
201         {\r
202                 /* In case alternative locking is used, the mutexes can be initialised\r
203                 here */\r
204                 ipconfigBUFFER_ALLOC_INIT();\r
205 \r
206                 xNetworkBufferSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );\r
207                 configASSERT( xNetworkBufferSemaphore );\r
208 \r
209                 if( xNetworkBufferSemaphore != NULL )\r
210                 {\r
211                         vListInitialise( &xFreeBuffersList );\r
212 \r
213                         /* Initialise all the network buffers.  The buffer storage comes\r
214                         from the network interface, and different hardware has different\r
215                         requirements. */\r
216                         vNetworkInterfaceAllocateRAMToBuffers( xNetworkBuffers );\r
217                         for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )\r
218                         {\r
219                                 /* Initialise and set the owner of the buffer list items. */\r
220                                 vListInitialiseItem( &( xNetworkBuffers[ x ].xBufferListItem ) );\r
221                                 listSET_LIST_ITEM_OWNER( &( xNetworkBuffers[ x ].xBufferListItem ), &xNetworkBuffers[ x ] );\r
222 \r
223                                 /* Currently, all buffers are available for use. */\r
224                                 vListInsert( &xFreeBuffersList, &( xNetworkBuffers[ x ].xBufferListItem ) );\r
225                         }\r
226 \r
227                         uxMinimumFreeNetworkBuffers = ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;\r
228                 }\r
229         }\r
230 \r
231         if( xNetworkBufferSemaphore == NULL )\r
232         {\r
233                 xReturn = pdFAIL;\r
234         }\r
235         else\r
236         {\r
237                 xReturn = pdPASS;\r
238         }\r
239 \r
240         return xReturn;\r
241 }\r
242 /*-----------------------------------------------------------*/\r
243 \r
244 NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )\r
245 {\r
246 NetworkBufferDescriptor_t *pxReturn = NULL;\r
247 BaseType_t xInvalid = pdFALSE;\r
248 UBaseType_t uxCount;\r
249 \r
250         /* The current implementation only has a single size memory block, so\r
251         the requested size parameter is not used (yet). */\r
252         ( void ) xRequestedSizeBytes;\r
253 \r
254         if( xNetworkBufferSemaphore != NULL )\r
255         {\r
256                 /* If there is a semaphore available, there is a network buffer\r
257                 available. */\r
258                 if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )\r
259                 {\r
260                         /* Protect the structure as it is accessed from tasks and\r
261                         interrupts. */\r
262                         ipconfigBUFFER_ALLOC_LOCK();\r
263                         {\r
264                                 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );\r
265 \r
266                                 if( ( bIsValidNetworkDescriptor( pxReturn ) != pdFALSE_UNSIGNED ) &&\r
267                                         listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxReturn->xBufferListItem ) ) )\r
268                                 {\r
269                                         uxListRemove( &( pxReturn->xBufferListItem ) );\r
270                                 }\r
271                                 else\r
272                                 {\r
273                                         xInvalid = pdTRUE;\r
274                                 }\r
275                         }\r
276                         ipconfigBUFFER_ALLOC_UNLOCK();\r
277 \r
278                         if( xInvalid == pdTRUE )\r
279                         {\r
280                                 /* _RB_ Can printf() be called from an interrupt?  (comment\r
281                                 above says this can be called from an interrupt too) */\r
282                                 /* _HT_ The function shall not be called from an ISR. Comment\r
283                                 was indeed misleading. Hopefully clear now?\r
284                                 So the printf()is OK here. */\r
285                                 FreeRTOS_debug_printf( ( "pxGetNetworkBufferWithDescriptor: INVALID BUFFER: %p (valid %lu)\n",\r
286                                         pxReturn, bIsValidNetworkDescriptor( pxReturn ) ) );\r
287                                 pxReturn = NULL;\r
288                         }\r
289                         else\r
290                         {\r
291                                 /* Reading UBaseType_t, no critical section needed. */\r
292                                 uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );\r
293 \r
294                                 /* For stats, latch the lowest number of network buffers since\r
295                                 booting. */\r
296                                 if( uxMinimumFreeNetworkBuffers > uxCount )\r
297                                 {\r
298                                         uxMinimumFreeNetworkBuffers = uxCount;\r
299                                 }\r
300 \r
301                                 pxReturn->xDataLength = xRequestedSizeBytes;\r
302 \r
303                                 #if( ipconfigTCP_IP_SANITY != 0 )\r
304                                 {\r
305                                         prvShowWarnings();\r
306                                 }\r
307                                 #endif /* ipconfigTCP_IP_SANITY */\r
308 \r
309                                 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
310                                 {\r
311                                         /* make sure the buffer is not linked */\r
312                                         pxReturn->pxNextBuffer = NULL;\r
313                                 }\r
314                                 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */\r
315 \r
316                                 if( xTCPWindowLoggingLevel > 3 )\r
317                                 {\r
318                                         FreeRTOS_debug_printf( ( "BUF_GET[%ld]: %p (%p)\n",\r
319                                                 bIsValidNetworkDescriptor( pxReturn ),\r
320                                                 pxReturn, pxReturn->pucEthernetBuffer ) );\r
321                                 }\r
322                         }\r
323                         iptraceNETWORK_BUFFER_OBTAINED( pxReturn );\r
324                 }\r
325                 else\r
326                 {\r
327                         iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();\r
328                 }\r
329         }\r
330 \r
331         return pxReturn;\r
332 }\r
333 /*-----------------------------------------------------------*/\r
334 \r
335 NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes )\r
336 {\r
337 NetworkBufferDescriptor_t *pxReturn = NULL;\r
338 \r
339         /* The current implementation only has a single size memory block, so\r
340         the requested size parameter is not used (yet). */\r
341         ( void ) xRequestedSizeBytes;\r
342 \r
343         /* If there is a semaphore available then there is a buffer available, but,\r
344         as this is called from an interrupt, only take a buffer if there are at\r
345         least baINTERRUPT_BUFFER_GET_THRESHOLD buffers remaining.  This prevents,\r
346         to a certain degree at least, a rapidly executing interrupt exhausting\r
347         buffer and in so doing preventing tasks from continuing. */\r
348         if( uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) xNetworkBufferSemaphore ) > ( UBaseType_t ) baINTERRUPT_BUFFER_GET_THRESHOLD )\r
349         {\r
350                 if( xSemaphoreTakeFromISR( xNetworkBufferSemaphore, NULL ) == pdPASS )\r
351                 {\r
352                         /* Protect the structure as it is accessed from tasks and interrupts. */\r
353                         ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();\r
354                         {\r
355                                 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );\r
356                                 uxListRemove( &( pxReturn->xBufferListItem ) );\r
357                         }\r
358                         ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();\r
359 \r
360                         iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxReturn );\r
361                 }\r
362         }\r
363 \r
364         if( pxReturn == NULL )\r
365         {\r
366                 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR();\r
367         }\r
368 \r
369         return pxReturn;\r
370 }\r
371 /*-----------------------------------------------------------*/\r
372 \r
373 BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
374 {\r
375 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
376 \r
377         /* Ensure the buffer is returned to the list of free buffers before the\r
378         counting semaphore is 'given' to say a buffer is available. */\r
379         ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();\r
380         {\r
381                 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );\r
382         }\r
383         ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();\r
384 \r
385         xSemaphoreGiveFromISR( xNetworkBufferSemaphore, &xHigherPriorityTaskWoken );\r
386         iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );\r
387 \r
388         return xHigherPriorityTaskWoken;\r
389 }\r
390 /*-----------------------------------------------------------*/\r
391 \r
392 void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
393 {\r
394 BaseType_t xListItemAlreadyInFreeList;\r
395 \r
396         if( bIsValidNetworkDescriptor( pxNetworkBuffer ) == pdFALSE_UNSIGNED )\r
397         {\r
398                 FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: Invalid buffer %p\n", pxNetworkBuffer ) );\r
399                 return ;\r
400         }\r
401         /* Ensure the buffer is returned to the list of free buffers before the\r
402         counting semaphore is 'given' to say a buffer is available. */\r
403         ipconfigBUFFER_ALLOC_LOCK();\r
404         {\r
405                 {\r
406                         xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );\r
407 \r
408                         if( xListItemAlreadyInFreeList == pdFALSE )\r
409                         {\r
410                                 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );\r
411                         }\r
412                 }\r
413         }\r
414         ipconfigBUFFER_ALLOC_UNLOCK();\r
415 \r
416         if( xListItemAlreadyInFreeList )\r
417         {\r
418                 FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: %p ALREADY RELEASED (now %lu)\n",\r
419                         pxNetworkBuffer, uxGetNumberOfFreeNetworkBuffers( ) ) );\r
420         }\r
421         if( xListItemAlreadyInFreeList == pdFALSE )\r
422         {\r
423                 xSemaphoreGive( xNetworkBufferSemaphore );\r
424                 prvShowWarnings();\r
425                 if( xTCPWindowLoggingLevel > 3 )\r
426                         FreeRTOS_debug_printf( ( "BUF_PUT[%ld]: %p (%p) (now %lu)\n",\r
427                                 bIsValidNetworkDescriptor( pxNetworkBuffer ),\r
428                                 pxNetworkBuffer, pxNetworkBuffer->pucEthernetBuffer,\r
429                                 uxGetNumberOfFreeNetworkBuffers( ) ) );\r
430         }\r
431         iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );\r
432 }\r
433 /*-----------------------------------------------------------*/\r
434 \r
435 UBaseType_t uxGetMinimumFreeNetworkBuffers( void )\r
436 {\r
437         return uxMinimumFreeNetworkBuffers;\r
438 }\r
439 /*-----------------------------------------------------------*/\r
440 \r
441 UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )\r
442 {\r
443         return listCURRENT_LIST_LENGTH( &xFreeBuffersList );\r
444 }\r
445 \r
446 NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )\r
447 {\r
448         /* In BufferAllocation_1.c all network buffer are allocated with a\r
449         maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the\r
450         network buffer. */\r
451         ( void ) xNewSizeBytes;\r
452         return pxNetworkBuffer;\r
453 }\r
454 \r
455 /*#endif */ /* ipconfigINCLUDE_TEST_CODE */\r