1 /*
2  * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Unlicense OR CC0-1.0
5  */
6 #include <stdio.h>
7 #include <stdbool.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/lock.h>
11 #include "unity.h"
12 #include "test_utils.h"
13 #include "sdkconfig.h"
14 #include "freertos/FreeRTOS.h"
15 #include "freertos/semphr.h"
16 
17 #if defined(_RETARGETABLE_LOCKING)
18 
locking_task(void * arg)19 static void locking_task(void* arg)
20 {
21     _LOCK_T lock = (_LOCK_T) arg;
22     __lock_acquire(lock);
23     __lock_release(lock);
24     vTaskSuspend(NULL);
25 }
26 
recursive_locking_task(void * arg)27 static void recursive_locking_task(void* arg)
28 {
29     _LOCK_T lock = (_LOCK_T) arg;
30     __lock_acquire_recursive(lock);
31     __lock_release_recursive(lock);
32     vTaskSuspend(NULL);
33 }
34 
test_inner_normal(_LOCK_T lock)35 static void test_inner_normal(_LOCK_T lock)
36 {
37     /* Acquire the lock */
38     __lock_acquire(lock);
39 
40     /* Create another task to try acquire same lock */
41     TaskHandle_t task_hdl;
42     TEST_ASSERT(xTaskCreate(&locking_task, "locking_task", 2048, lock, UNITY_FREERTOS_PRIORITY, &task_hdl));
43     vTaskDelay(2);
44     /* It should get blocked */
45     TEST_ASSERT_EQUAL(eBlocked, eTaskGetState(task_hdl));
46 
47     /* Once we release the lock, the task should succeed and suspend itself */
48     __lock_release(lock);
49     vTaskDelay(2);
50     TEST_ASSERT_EQUAL(eSuspended, eTaskGetState(task_hdl));
51     vTaskDelete(task_hdl);
52 
53     /* Can not recursively acquire the lock from same task */
54     TEST_ASSERT_EQUAL(0, __lock_try_acquire(lock));
55     TEST_ASSERT_EQUAL(-1, __lock_try_acquire(lock));
56     __lock_release(lock);
57 }
58 
test_inner_recursive(_LOCK_T lock)59 static void test_inner_recursive(_LOCK_T lock)
60 {
61     /* Acquire the lock */
62     __lock_acquire_recursive(lock);
63 
64     /* Create another task to try acquire same lock */
65     TaskHandle_t task_hdl;
66     TEST_ASSERT(xTaskCreate(&recursive_locking_task, "locking_task", 2048, lock, UNITY_FREERTOS_PRIORITY, &task_hdl));
67     vTaskDelay(2);
68     /* It should get blocked */
69     TEST_ASSERT_EQUAL(eBlocked, eTaskGetState(task_hdl));
70 
71     /* Once we release the lock, the task should succeed and suspend itself */
72     __lock_release_recursive(lock);
73     vTaskDelay(2);
74     TEST_ASSERT_EQUAL(eSuspended, eTaskGetState(task_hdl));
75     vTaskDelete(task_hdl);
76 
77     /* Try recursively acquiring the lock */
78     TEST_ASSERT_EQUAL(0, __lock_try_acquire_recursive(lock));
79     TEST_ASSERT_EQUAL(0, __lock_try_acquire_recursive(lock));
80     __lock_release_recursive(lock);
81     __lock_release_recursive(lock);
82 }
83 
84 TEST_CASE("Retargetable static locks", "[newlib_locks]")
85 {
86     StaticSemaphore_t semaphore;
87     _LOCK_T lock = (_LOCK_T) xSemaphoreCreateMutexStatic(&semaphore);
88     test_inner_normal(lock);
89 }
90 
91 TEST_CASE("Retargetable static recursive locks", "[newlib_locks]")
92 {
93     StaticSemaphore_t semaphore;
94     _LOCK_T lock = (_LOCK_T) xSemaphoreCreateRecursiveMutexStatic(&semaphore);
95     test_inner_recursive(lock);
96 }
97 
98 TEST_CASE("Retargetable dynamic locks", "[newlib_locks]")
99 {
100     _LOCK_T lock;
101     __lock_init(lock);
102     test_inner_normal(lock);
103     __lock_close(lock);
104 }
105 
106 TEST_CASE("Retargetable dynamic recursive locks", "[newlib_locks]")
107 {
108     _LOCK_T lock;
109     __lock_init_recursive(lock);
110     test_inner_recursive(lock);
111     __lock_close_recursive(lock);
112 }
113 
114 #endif // _RETARGETABLE_LOCKING
115