]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c
Sync FreeRTOS-Labs -CLI -TCP -Trace with the version in FreeRTOS-Plus.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-Plus-TCP / portable / BufferManagement / BufferAllocation_2.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://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 /* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR\r
37 THAT WILL FRAGMENT THE HEAP MEMORY.  For example, heap_2 must not be used,\r
38 heap_4 can be used. */\r
39 \r
40 \r
41 /* Standard includes. */\r
42 #include <stdint.h>\r
43 \r
44 /* FreeRTOS includes. */\r
45 #include "FreeRTOS.h"\r
46 #include "task.h"\r
47 #include "semphr.h"\r
48 \r
49 /* FreeRTOS+TCP includes. */\r
50 #include "FreeRTOS_IP.h"\r
51 #include "FreeRTOS_UDP_IP.h"\r
52 #include "FreeRTOS_IP_Private.h"\r
53 #include "NetworkInterface.h"\r
54 #include "NetworkBufferManagement.h"\r
55 \r
56 /* The obtained network buffer must be large enough to hold a packet that might\r
57 replace the packet that was requested to be sent. */\r
58 #if ipconfigUSE_TCP == 1\r
59         #define baMINIMAL_BUFFER_SIZE           sizeof( TCPPacket_t )\r
60 #else\r
61         #define baMINIMAL_BUFFER_SIZE           sizeof( ARPPacket_t )\r
62 #endif /* ipconfigUSE_TCP == 1 */\r
63 \r
64 /*_RB_ This is too complex not to have an explanation. */\r
65 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
66         #define ASSERT_CONCAT_(a, b) a##b\r
67         #define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)\r
68         #define STATIC_ASSERT(e) \\r
69                 ;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }\r
70 \r
71         STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE );\r
72 #endif\r
73 \r
74 /* A list of free (available) NetworkBufferDescriptor_t structures. */\r
75 static List_t xFreeBuffersList;\r
76 \r
77 /* Some statistics about the use of buffers. */\r
78 static size_t uxMinimumFreeNetworkBuffers;\r
79 \r
80 /* Declares the pool of NetworkBufferDescriptor_t structures that are available\r
81 to the system.  All the network buffers referenced from xFreeBuffersList exist\r
82 in this array.  The array is not accessed directly except during initialisation,\r
83 when the xFreeBuffersList is filled (as all the buffers are free when the system\r
84 is booted). */\r
85 static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];\r
86 \r
87 /* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the\r
88 network buffers have a variable size: resizing may be necessary */\r
89 const BaseType_t xBufferAllocFixedSize = pdFALSE;\r
90 \r
91 /* The semaphore used to obtain network buffers. */\r
92 static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;\r
93 \r
94 /*-----------------------------------------------------------*/\r
95 \r
96 BaseType_t xNetworkBuffersInitialise( void )\r
97 {\r
98 BaseType_t xReturn, x;\r
99 \r
100         /* Only initialise the buffers and their associated kernel objects if they\r
101         have not been initialised before. */\r
102         if( xNetworkBufferSemaphore == NULL )\r
103         {\r
104                 xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );\r
105                 configASSERT( xNetworkBufferSemaphore );\r
106 \r
107                 if( xNetworkBufferSemaphore != NULL )\r
108                 {\r
109                         #if ( configQUEUE_REGISTRY_SIZE > 0 )\r
110                         {\r
111                                 vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" );\r
112                         }\r
113                         #endif /* configQUEUE_REGISTRY_SIZE */\r
114 \r
115                         /* If the trace recorder code is included name the semaphore for viewing\r
116                         in FreeRTOS+Trace.  */\r
117                         #if( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 )\r
118                         {\r
119                                 extern QueueHandle_t xNetworkEventQueue;\r
120                                 vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" );\r
121                                 vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" );\r
122                         }\r
123                         #endif /*  ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */\r
124 \r
125                         vListInitialise( &xFreeBuffersList );\r
126 \r
127                         /* Initialise all the network buffers.  No storage is allocated to\r
128                         the buffers yet. */\r
129                         for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )\r
130                         {\r
131                                 /* Initialise and set the owner of the buffer list items. */\r
132                                 xNetworkBufferDescriptors[ x ].pucEthernetBuffer = NULL;\r
133                                 vListInitialiseItem( &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );\r
134                                 listSET_LIST_ITEM_OWNER( &( xNetworkBufferDescriptors[ x ].xBufferListItem ), &xNetworkBufferDescriptors[ x ] );\r
135 \r
136                                 /* Currently, all buffers are available for use. */\r
137                                 vListInsert( &xFreeBuffersList, &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );\r
138                         }\r
139 \r
140                         uxMinimumFreeNetworkBuffers = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;\r
141                 }\r
142         }\r
143 \r
144         if( xNetworkBufferSemaphore == NULL )\r
145         {\r
146                 xReturn = pdFAIL;\r
147         }\r
148         else\r
149         {\r
150                 xReturn = pdPASS;\r
151         }\r
152 \r
153         return xReturn;\r
154 }\r
155 /*-----------------------------------------------------------*/\r
156 \r
157 uint8_t *pucGetNetworkBuffer( size_t *pxRequestedSizeBytes )\r
158 {\r
159 uint8_t *pucEthernetBuffer;\r
160 size_t xSize = *pxRequestedSizeBytes;\r
161 \r
162         if( xSize < baMINIMAL_BUFFER_SIZE )\r
163         {\r
164                 /* Buffers must be at least large enough to hold a TCP-packet with\r
165                 headers, or an ARP packet, in case TCP is not included. */\r
166                 xSize = baMINIMAL_BUFFER_SIZE;\r
167         }\r
168 \r
169         /* Round up xSize to the nearest multiple of N bytes,\r
170         where N equals 'sizeof( size_t )'. */\r
171         if( ( xSize & ( sizeof( size_t ) - 1u ) ) != 0u )\r
172         {\r
173                 xSize = ( xSize | ( sizeof( size_t ) - 1u ) ) + 1u;\r
174         }\r
175         *pxRequestedSizeBytes = xSize;\r
176 \r
177         /* Allocate a buffer large enough to store the requested Ethernet frame size\r
178         and a pointer to a network buffer structure (hence the addition of\r
179         ipBUFFER_PADDING bytes). */\r
180         pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING );\r
181         configASSERT( pucEthernetBuffer );\r
182 \r
183         if( pucEthernetBuffer != NULL )\r
184         {\r
185                 /* Enough space is left at the start of the buffer to place a pointer to\r
186                 the network buffer structure that references this Ethernet buffer.\r
187                 Return a pointer to the start of the Ethernet buffer itself. */\r
188                 pucEthernetBuffer += ipBUFFER_PADDING;\r
189         }\r
190 \r
191         return pucEthernetBuffer;\r
192 }\r
193 /*-----------------------------------------------------------*/\r
194 \r
195 void vReleaseNetworkBuffer( uint8_t *pucEthernetBuffer )\r
196 {\r
197         /* There is space before the Ethernet buffer in which a pointer to the\r
198         network buffer that references this Ethernet buffer is stored.  Remove the\r
199         space before freeing the buffer. */\r
200         if( pucEthernetBuffer != NULL )\r
201         {\r
202                 pucEthernetBuffer -= ipBUFFER_PADDING;\r
203                 vPortFree( ( void * ) pucEthernetBuffer );\r
204         }\r
205 }\r
206 /*-----------------------------------------------------------*/\r
207 \r
208 NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )\r
209 {\r
210 NetworkBufferDescriptor_t *pxReturn = NULL;\r
211 size_t uxCount;\r
212 \r
213         if( xNetworkBufferSemaphore != NULL )\r
214         {\r
215                 if( ( xRequestedSizeBytes != 0u ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) )\r
216                 {\r
217                         /* ARP packets can replace application packets, so the storage must be\r
218                         at least large enough to hold an ARP. */\r
219                         xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE;\r
220                 }\r
221 \r
222                 /* Add 2 bytes to xRequestedSizeBytes and round up xRequestedSizeBytes\r
223                 to the nearest multiple of N bytes, where N equals 'sizeof( size_t )'. */\r
224                 xRequestedSizeBytes += 2u;\r
225                 if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1u ) ) != 0u )\r
226                 {\r
227                         xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1u ) ) + 1u;\r
228                 }\r
229 \r
230                 /* If there is a semaphore available, there is a network buffer available. */\r
231                 if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )\r
232                 {\r
233                         /* Protect the structure as it is accessed from tasks and interrupts. */\r
234                         taskENTER_CRITICAL();\r
235                         {\r
236                                 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );\r
237                                 uxListRemove( &( pxReturn->xBufferListItem ) );\r
238                         }\r
239                         taskEXIT_CRITICAL();\r
240 \r
241                         /* Reading UBaseType_t, no critical section needed. */\r
242                         uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );\r
243 \r
244                         if( uxMinimumFreeNetworkBuffers > uxCount )\r
245                         {\r
246                                 uxMinimumFreeNetworkBuffers = uxCount;\r
247                         }\r
248 \r
249                         /* Allocate storage of exactly the requested size to the buffer. */\r
250                         configASSERT( pxReturn->pucEthernetBuffer == NULL );\r
251                         if( xRequestedSizeBytes > 0 )\r
252                         {\r
253                                 /* Extra space is obtained so a pointer to the network buffer can\r
254                                 be stored at the beginning of the buffer. */\r
255                                 pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING );\r
256 \r
257                                 if( pxReturn->pucEthernetBuffer == NULL )\r
258                                 {\r
259                                         /* The attempt to allocate storage for the buffer payload failed,\r
260                                         so the network buffer structure cannot be used and must be\r
261                                         released. */\r
262                                         vReleaseNetworkBufferAndDescriptor( pxReturn );\r
263                                         pxReturn = NULL;\r
264                                 }\r
265                                 else\r
266                                 {\r
267                                         /* Store a pointer to the network buffer structure in the\r
268                                         buffer storage area, then move the buffer pointer on past the\r
269                                         stored pointer so the pointer value is not overwritten by the\r
270                                         application when the buffer is used. */\r
271                                         *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn;\r
272                                         pxReturn->pucEthernetBuffer += ipBUFFER_PADDING;\r
273 \r
274                                         /* Store the actual size of the allocated buffer, which may be\r
275                                         greater than the original requested size. */\r
276                                         pxReturn->xDataLength = xRequestedSizeBytes;\r
277 \r
278                                         #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
279                                         {\r
280                                                 /* make sure the buffer is not linked */\r
281                                                 pxReturn->pxNextBuffer = NULL;\r
282                                         }\r
283                                         #endif /* ipconfigUSE_LINKED_RX_MESSAGES */\r
284                                 }\r
285                         }\r
286                         else\r
287                         {\r
288                                 /* A descriptor is being returned without an associated buffer being\r
289                                 allocated. */\r
290                         }\r
291                 }\r
292         }\r
293 \r
294         if( pxReturn == NULL )\r
295         {\r
296                 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();\r
297         }\r
298         else\r
299         {\r
300                 iptraceNETWORK_BUFFER_OBTAINED( pxReturn );\r
301         }\r
302 \r
303         return pxReturn;\r
304 }\r
305 /*-----------------------------------------------------------*/\r
306 \r
307 void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
308 {\r
309 BaseType_t xListItemAlreadyInFreeList;\r
310 \r
311         /* Ensure the buffer is returned to the list of free buffers before the\r
312         counting semaphore is 'given' to say a buffer is available.  Release the\r
313         storage allocated to the buffer payload.  THIS FILE SHOULD NOT BE USED\r
314         IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP\r
315         MEMORY.  For example, heap_2 must not be used, heap_4 can be used. */\r
316         vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );\r
317         pxNetworkBuffer->pucEthernetBuffer = NULL;\r
318 \r
319         taskENTER_CRITICAL();\r
320         {\r
321                 xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );\r
322 \r
323                 if( xListItemAlreadyInFreeList == pdFALSE )\r
324                 {\r
325                         vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );\r
326                 }\r
327         }\r
328         taskEXIT_CRITICAL();\r
329 \r
330         /*\r
331          * Update the network state machine, unless the program fails to release its 'xNetworkBufferSemaphore'.\r
332          * The program should only try to release its semaphore if 'xListItemAlreadyInFreeList' is false.\r
333          */\r
334         if( xListItemAlreadyInFreeList == pdFALSE )\r
335         {\r
336                 if ( xSemaphoreGive( xNetworkBufferSemaphore ) == pdTRUE )\r
337                 {\r
338                         iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );\r
339                 }\r
340         }\r
341         else\r
342         {\r
343                 iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );\r
344         }\r
345 }\r
346 /*-----------------------------------------------------------*/\r
347 \r
348 /*\r
349  * Returns the number of free network buffers\r
350  */\r
351 UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )\r
352 {\r
353         return listCURRENT_LIST_LENGTH( &xFreeBuffersList );\r
354 }\r
355 /*-----------------------------------------------------------*/\r
356 \r
357 UBaseType_t uxGetMinimumFreeNetworkBuffers( void )\r
358 {\r
359         return uxMinimumFreeNetworkBuffers;\r
360 }\r
361 /*-----------------------------------------------------------*/\r
362 \r
363 NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )\r
364 {\r
365 size_t xOriginalLength;\r
366 uint8_t *pucBuffer;\r
367 \r
368         xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING;\r
369         xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING;\r
370 \r
371         pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) );\r
372 \r
373         if( pucBuffer == NULL )\r
374         {\r
375                 /* In case the allocation fails, return NULL. */\r
376                 pxNetworkBuffer = NULL;\r
377         }\r
378         else\r
379         {\r
380                 pxNetworkBuffer->xDataLength = xNewSizeBytes;\r
381                 if( xNewSizeBytes > xOriginalLength )\r
382                 {\r
383                         xNewSizeBytes = xOriginalLength;\r
384                 }\r
385 \r
386                 memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes );\r
387                 vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );\r
388                 pxNetworkBuffer->pucEthernetBuffer = pucBuffer;\r
389         }\r
390 \r
391         return pxNetworkBuffer;\r
392 }\r
393 \r