3 * Copyright (C) 2020 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
26 /*! @file recursive_mutex_utest.c */
28 #include "../queue_utest_common.h"
32 #include "FreeRTOSConfig.h"
34 #include "mock_fake_port.h"
36 /* ============================ GLOBAL VARIABLES =========================== */
38 /* ========================== CALLBACK FUNCTIONS =========================== */
40 /* ============================= Unity Fixtures ============================= */
45 xTaskPriorityDisinherit_IgnoreAndReturn( pdFALSE );
58 int suiteTearDown( int numFailures )
60 return commonSuiteTearDown( numFailures );
63 /* ========================== Helper functions =========================== */
65 /* ============================= Test Cases ============================== */
68 * @brief Test xSemaphoreCreateRecursiveMutex where the call to malloc fails
69 * @coverage xQueueCreateMutex
71 void test_macro_xSemaphoreCreateRecursiveMutex_malloc_fail( void )
73 UnityMalloc_MakeMallocFailAfterCount( 0 );
75 SemaphoreHandle_t xSemaphore = INVALID_PTR;
77 xSemaphore = xSemaphoreCreateRecursiveMutex();
79 /* validate returned semaphore handle */
80 TEST_ASSERT_EQUAL( NULL, xSemaphore );
84 * @brief Test xSemaphoreCreateRecursiveMutex
85 * @details Create a mutex using xSemaphoreCreateRecursiveMutex
86 * @coverage xQueueCreateMutex
88 void test_macro_xSemaphoreCreateRecursiveMutex_success( void )
90 SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
92 /* validate returned semaphore handle */
93 TEST_ASSERT_NOT_EQUAL( NULL, xSemaphore );
95 TEST_ASSERT_EQUAL( QUEUE_T_SIZE, getLastMallocSize() );
97 TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
99 vSemaphoreDelete( xSemaphore );
103 * @brief Test xSemaphoreCreateRecursiveMutexStatic with a null buffer
104 * @coverage xQueueCreateMutexStatic
106 void test_macro_xSemaphoreCreateRecursiveMutexStatic_nullptr( void )
108 SemaphoreHandle_t xSemaphore = INVALID_PTR;
110 /* Expect that xQueueCreate will assert due to the NULL buffer */
111 fakeAssertExpectFail();
113 xSemaphore = xSemaphoreCreateRecursiveMutexStatic( NULL );
115 /* Check that configASSERT was called twice */
116 fakeAssertVerifyNumAssertsAndClear( 2 );
118 TEST_ASSERT_EQUAL( NULL, xSemaphore );
119 TEST_ASSERT_EQUAL( 0, getLastMallocSize() );
123 * @brief Verify that calling xSemaphoreTakeRecursive with a NULL mutex handle causes a configASSERT failure.
124 * @coverage xQueueTakeMutexRecursive
126 void test_macro_xSemaphoreTakeRecursive_null_handle( void )
128 EXPECT_ASSERT_BREAK( xSemaphoreTakeRecursive( NULL, 0 ) );
132 * @brief Test xSemaphoreTakeRecursive with a mutex that is not owned by any task.
133 * @coverage xQueueTakeMutexRecursive
135 void test_macro_xSemaphoreTakeRecursive_not_owned_once( void )
137 TaskHandle_t xMutexHolder = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
139 SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
141 TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
143 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
144 pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder );
146 TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreTakeRecursive( xSemaphore, 0 ) );
148 TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
150 vSemaphoreDelete( xSemaphore );
154 * @brief Test xSemaphoreTakeRecursive with a mutex that is already owned by the current task
155 * @coverage xQueueTakeMutexRecursive
157 void test_macro_xSemaphoreTakeRecursive_self_owned_twice( void )
159 TaskHandle_t xMutexHolder = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
161 SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
163 TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
165 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
166 pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder );
168 TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreTakeRecursive( xSemaphore, 0 ) );
170 TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
172 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
174 TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreTakeRecursive( xSemaphore, 0 ) );
176 TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
178 vSemaphoreDelete( xSemaphore );
182 * @brief Test xSemaphoreTakeRecursive on a mutex that is already owned by a different task
183 * @coverage xQueueTakeMutexRecursive
185 void test_macro_xSemaphoreTakeRecursive_owned_other_task( void )
187 TaskHandle_t xMutexHolder1 = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
188 TaskHandle_t xMutexHolder2 = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
190 SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
192 /* Take the recursive mutex with task handle == xMutexHolder1 */
193 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder1 );
194 pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder1 );
195 TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreTakeRecursive( xSemaphore, 0 ) );
197 /* Attempt to take the recursive mutex with task handle == xMutexHolder2 */
198 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder2 );
199 TEST_ASSERT_EQUAL( pdFALSE, xSemaphoreTakeRecursive( xSemaphore, 0 ) );
201 vSemaphoreDelete( xSemaphore );
205 * @brief Verify that calling xSemaphoreGiveRecursive with a NULL mutex handle causes a configASSERT failure.
206 * @coverage xQueueGiveMutexRecursive
208 void test_macro_xSemaphoreGiveRecursive_null_handle( void )
210 EXPECT_ASSERT_BREAK( xSemaphoreGiveRecursive( NULL ) );
214 * @brief Test xSemaphoreGiveRecursive with a mutex that is not already owned by any task.
215 * @coverage xQueueGiveMutexRecursive
217 void test_macro_xSemaphoreGiveRecursive_unowned( void )
219 TaskHandle_t xMutexHolder = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
221 SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
223 TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
225 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
227 TEST_ASSERT_EQUAL( pdFALSE, xSemaphoreGiveRecursive( xSemaphore ) );
229 TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
231 vSemaphoreDelete( xSemaphore );
235 * @brief Test xSemaphoreGiveRecursive with a mutex that is not owned by any task with a NULL TaskHandle returned by calls to xTaskGetCurrentTaskHandle.
236 * @coverage xQueueGiveMutexRecursive
238 void test_macro_xSemaphoreGiveRecursive_unowned_null_taskhandle( void )
240 SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
242 TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
244 xTaskGetCurrentTaskHandle_ExpectAndReturn( NULL );
246 TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreGiveRecursive( xSemaphore ) );
248 TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
250 vSemaphoreDelete( xSemaphore );
254 * @brief Test xSemaphoreGiveRecursive with a mutex that is already owned by the current task
255 * @coverage xQueueGiveMutexRecursive
257 void test_macro_xSemaphoreGiveRecursive_self_owned( void )
259 TaskHandle_t xMutexHolder = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
261 SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
263 /* Take the Recursive Mutex from taskHandle == xMutexHolder */
264 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
265 pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder );
267 xSemaphoreTakeRecursive( xSemaphore, 0 );
269 /* Verify that the Recursive Mutex is in the taken state */
270 TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
272 /* call xSemaphoreGiveRecursive to release the Recursive Mutex */
273 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
275 TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreGiveRecursive( xSemaphore ) );
277 /* Verify that the Recursive Mutex is now in the available state */
278 TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
280 vSemaphoreDelete( xSemaphore );
284 * @brief Test xSemaphoreGiveRecursive on a mutex that is already owned by a different task
285 * @coverage xQueueGiveMutexRecursive
287 void test_macro_xSemaphoreGiveRecursive_owned_other_task( void )
289 TaskHandle_t xMutexHolder1 = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
290 TaskHandle_t xMutexHolder2 = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
292 SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
294 /* Take the Recursive Mutex from taskHandle == xMutexHolder */
295 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder1 );
296 pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder1 );
298 xSemaphoreTakeRecursive( xSemaphore, 0 );
300 /* Verify that the Recursive Mutex is in the taken state */
301 TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
303 /* call xSemaphoreGiveRecursive to release the Recursive Mutex */
304 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder2 );
306 TEST_ASSERT_EQUAL( pdFALSE, xSemaphoreGiveRecursive( xSemaphore ) );
308 /* Verify that the Recursive Mutex remains in the taken state */
309 TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
311 vSemaphoreDelete( xSemaphore );
316 * @brief Call xSemaphoreTakeRecursive and xSemaphoreGiveRecursive each multiple times
317 * @coverage xQueueTakeMutexRecursive xQueueGiveMutexRecursive
319 void test_macro_xSemaphoreTakeRecursive_xSemaphoreGiveRecursive_recursive( void )
321 TaskHandle_t xMutexHolder = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
323 SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
325 /* Take the Recursive Mutex */
326 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
327 pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder );
328 xSemaphoreTakeRecursive( xSemaphore, 0 );
330 /* Verify that the Recursive Mutex is in the taken state */
331 TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
333 /* Take the Recursive Mutex a second time */
334 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
335 xSemaphoreTakeRecursive( xSemaphore, 0 );
337 /* Verify that the Recursive Mutex remains in the taken state */
338 TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
340 /* call xSemaphoreGiveRecursive to release the Recursive Mutex (first time) */
341 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
342 TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreGiveRecursive( xSemaphore ) );
344 /* Verify that the Recursive Mutex remains in the taken state */
345 TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
347 /* call xSemaphoreGiveRecursive to release the Recursive Mutex (second time) */
348 xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
349 TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreGiveRecursive( xSemaphore ) );
351 /* Verify that the Recursive Mutex is now in the available state */
352 TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
354 vSemaphoreDelete( xSemaphore );