3 * Copyright (C) Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * https://www.FreeRTOS.org
23 * https://github.com/FreeRTOS
27 #include "proof/queue.h"
29 /* Simplifying assumption: we do not verify queue initialisation in a
30 * concurrent environment. We assume the queue initialization (including reset)
31 * happens-before all concurrent send/receives. */
32 #ifdef VERIFAST /*< ***xQueueGenericReset happens-before concurrent behavior*** */
33 #define taskENTER_CRITICAL()
34 #define taskEXIT_CRITICAL()
37 /* The following intermediate queue predicates summarise states used by queue
38 * initialization but not used elsewhere so we confine them to these proofs
42 * predicate queue_init1(QueueHandle_t q;) =
43 * QUEUE_SHAPE(q, _, _, _, _) &*&
47 * predicate queue_init2(QueueHandle_t q, int8_t *Storage, size_t N, size_t M;) =
48 * QUEUE_SHAPE(q, Storage, N, M, _) &*&
51 * chars(Storage, (N*M), _) &*&
52 * malloc_block(Storage, N*M) &*&
53 * Storage + N * M <= (int8_t *)UINTPTR_MAX &*&
58 BaseType_t xQueueGenericReset( QueueHandle_t xQueue,
59 BaseType_t xNewQueue )
60 /*@requires queue_init2(xQueue, ?Storage, ?N, ?M);@*/
63 * ? freertos_mutex(xQueue, Storage, N, 0)
64 * : queue(xQueue, Storage, N, M, 0, (N-1), 0, false, nil) &*& queuelists(xQueue);@*/
66 #ifdef VERIFAST /*< const pointer declaration */
67 Queue_t * pxQueue = xQueue;
69 Queue_t * const pxQueue = xQueue;
72 configASSERT( pxQueue );
76 pxQueue->u.xQueue.pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize ); /*lint !e9016 Pointer arithmetic allowed on char types, especially when it assists conveying intent. */
77 pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
78 pxQueue->pcWriteTo = pxQueue->pcHead;
79 /*@mul_mono_l(0, N-1, M);@*/
80 pxQueue->u.xQueue.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - 1U ) * pxQueue->uxItemSize ); /*lint !e9016 Pointer arithmetic allowed on char types, especially when it assists conveying intent. */
81 pxQueue->cRxLock = queueUNLOCKED;
82 pxQueue->cTxLock = queueUNLOCKED;
84 if( xNewQueue == pdFALSE )
86 /* If there are tasks blocked waiting to read from the queue, then
87 * the tasks will remain blocked as after this function exits the queue
88 * will still be empty. If there are tasks blocked waiting to write to
89 * the queue, then one should be unblocked as after this function exits
90 * it will be possible to write to it. */
91 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
93 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
95 queueYIELD_IF_USING_PREEMPTION();
99 mtCOVERAGE_TEST_MARKER();
104 mtCOVERAGE_TEST_MARKER();
109 /* Ensure the event queues start in the correct state. */
110 vListInitialise( &( pxQueue->xTasksWaitingToSend ) );
111 vListInitialise( &( pxQueue->xTasksWaitingToReceive ) );
114 /*@if (M != 0) { buffer_from_chars(pxQueue->pcHead, N, M); }@*/
118 /* A value is returned for calling semantic consistency with previous
123 static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
124 const UBaseType_t uxItemSize,
125 uint8_t * pucQueueStorage,
126 const uint8_t ucQueueType,
127 Queue_t * pxNewQueue )
129 /*@requires queue_init1(pxNewQueue) &*&
130 * 0 < uxQueueLength &*& 0 < uxItemSize &*&
131 * malloc_block(pucQueueStorage, uxQueueLength * uxItemSize) &*&
132 * pucQueueStorage + uxQueueLength * uxItemSize <= (uint8_t *)UINTPTR_MAX &*&
133 * uchars(pucQueueStorage, uxQueueLength * uxItemSize,_);@*/
135 /*@ensures queue(pxNewQueue, ((int8_t *)(void *)pucQueueStorage), uxQueueLength, uxItemSize, 0, (uxQueueLength-1), 0, false, nil) &*&
136 * queuelists(pxNewQueue);@*/
138 #ifndef VERIFAST /*< void cast of unused var */
140 /* Remove compiler warnings about unused parameters should
141 * configUSE_TRACE_FACILITY not be set to 1. */
142 ( void ) ucQueueType;
145 if( uxItemSize == ( UBaseType_t ) 0 )
147 /* No RAM was allocated for the queue storage area, but PC head cannot
148 * be set to NULL because NULL is used as a key to say the queue is used as
149 * a mutex. Therefore just set pcHead to point to the queue as a benign
150 * value that is known to be within the memory map. */
151 #ifdef VERIFAST /*< stricter casting */
152 pxNewQueue->pcHead = ( int8_t * ) ( void * ) pxNewQueue;
154 pxNewQueue->pcHead = ( int8_t * ) pxNewQueue;
159 /* Set the head to the start of the queue storage area. */
160 #ifdef VERIFAST /*< stricter casting */
161 pxNewQueue->pcHead = ( int8_t * ) ( void * ) pucQueueStorage;
163 pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage;
167 /* Initialise the queue members as described where the queue type is
169 pxNewQueue->uxLength = uxQueueLength;
170 pxNewQueue->uxItemSize = uxItemSize;
171 /*@close queue_init2(pxNewQueue, _, uxQueueLength, uxItemSize);@*/
172 #ifdef VERIFAST /*< void cast of unused return value */
173 xQueueGenericReset( pxNewQueue, pdTRUE );
175 ( void ) xQueueGenericReset( pxNewQueue, pdTRUE );
178 #if ( configUSE_TRACE_FACILITY == 1 )
180 pxNewQueue->ucQueueType = ucQueueType;
182 #endif /* configUSE_TRACE_FACILITY */
184 #if ( configUSE_QUEUE_SETS == 1 )
186 pxNewQueue->pxQueueSetContainer = NULL;
188 #endif /* configUSE_QUEUE_SETS */
190 traceQUEUE_CREATE( pxNewQueue );
194 QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength,
195 const UBaseType_t uxItemSize,
196 const uint8_t ucQueueType )
198 /*@requires 0 < uxQueueLength &*&
200 * 0 < uxQueueLength * uxItemSize &*&
201 * uxQueueLength * uxItemSize <= UINT_MAX;@*/
203 /*@ensures result == NULL
205 * : queue(result, _, uxQueueLength, uxItemSize, 0, (uxQueueLength-1), 0, false, nil) &*&
206 * queuelists(result) &*&
207 * result->irqMask |-> _ &*&
208 * result->schedulerSuspend |-> _ &*&
209 * result->locked |-> _;@*/
211 Queue_t * pxNewQueue;
212 size_t xQueueSizeInBytes;
213 uint8_t * pucQueueStorage;
215 configASSERT( uxQueueLength > ( UBaseType_t ) 0 );
217 /* Allocate enough space to hold the maximum number of items that
218 * can be in the queue at any time. It is valid for uxItemSize to be
219 * zero in the case the queue is used as a semaphore. */
220 xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
222 /* Check for multiplication overflow. */
223 configASSERT( ( uxItemSize == 0 ) || ( uxQueueLength == ( xQueueSizeInBytes / uxItemSize ) ) );
225 /* Check for addition overflow. */
226 configASSERT( ( sizeof( Queue_t ) + xQueueSizeInBytes ) > xQueueSizeInBytes );
228 #ifdef VERIFAST /*< ***model single malloc of struct and buffer*** */
229 pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) );
232 /* Allocate the queue and storage area. Justification for MISRA
233 * deviation as follows: pvPortMalloc() always ensures returned memory
234 * blocks are aligned per the requirements of the MCU stack. In this case
235 * pvPortMalloc() must return a pointer that is guaranteed to meet the
236 * alignment requirements of the Queue_t structure - which in this case
237 * is an int8_t *. Therefore, whenever the stack alignment requirements
238 * are greater than or equal to the pointer to char requirements the cast
239 * is safe. In other cases alignment requirements are not strict (one or
241 pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); /*lint !e9087 !e9079 see comment above. */
244 if( pxNewQueue != NULL )
246 #ifdef VERIFAST /*< ***model single malloc of struct and buffer*** */
247 pucQueueStorage = ( uint8_t * ) pvPortMalloc( xQueueSizeInBytes );
249 if( pucQueueStorage == NULL )
251 vPortFree( pxNewQueue );
255 /*@malloc_block_limits(pucQueueStorage);@*/
258 /* Jump past the queue structure to find the location of the queue
260 pucQueueStorage = ( uint8_t * ) pxNewQueue;
261 pucQueueStorage += sizeof( Queue_t ); /*lint !e9016 Pointer arithmetic allowed on char types, especially when it assists conveying intent. */
262 #endif /* ifdef VERIFAST */
264 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
266 /* Queues can be created either statically or dynamically, so
267 * note this task was created dynamically in case it is later
269 pxNewQueue->ucStaticallyAllocated = pdFALSE;
271 #endif /* configSUPPORT_STATIC_ALLOCATION */
273 prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
277 traceQUEUE_CREATE_FAILED( ucQueueType );
278 mtCOVERAGE_TEST_MARKER();