1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/portability/cmsis_os2.h>
10 #include <zephyr/portability/cmsis_types.h>
11 
12 #define WAIT_TICKS    5
13 #define TIMEOUT_TICKS (10 + WAIT_TICKS)
14 #define STACKSZ       CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE
15 
16 int max_mtx_cnt = CONFIG_CMSIS_V2_MUTEX_MAX_COUNT;
17 const osMutexAttr_t mutex_attr = {"myMutex", osMutexRecursive | osMutexPrioInherit, NULL, 0U};
18 
cleanup_max_mutex(osMutexId_t * mutex_ids)19 void cleanup_max_mutex(osMutexId_t *mutex_ids)
20 {
21 	int mutex_count = 0;
22 	osStatus_t status;
23 
24 	for (mutex_count = 0; mutex_count < max_mtx_cnt; mutex_count++) {
25 		status = osMutexDelete(mutex_ids[mutex_count]);
26 		zassert_true(status == osOK, "Mutex delete fail");
27 	}
28 }
29 
test_max_mutex(void)30 void test_max_mutex(void)
31 {
32 	osMutexId_t mutex_ids[CONFIG_CMSIS_V2_MUTEX_MAX_COUNT + 1];
33 	int mtx_cnt = 0;
34 
35 	/* Try mutex creation for more than maximum count */
36 	for (mtx_cnt = 0; mtx_cnt < max_mtx_cnt + 1; mtx_cnt++) {
37 		mutex_ids[mtx_cnt] = osMutexNew(&mutex_attr);
38 		if (mtx_cnt == max_mtx_cnt) {
39 			zassert_true(mutex_ids[mtx_cnt] == NULL,
40 				     "Mutex creation pass unexpectedly after max count");
41 			cleanup_max_mutex(mutex_ids);
42 		} else {
43 			zassert_true(mutex_ids[mtx_cnt] != NULL,
44 				     "Multiple mutex creation failed before max count");
45 		}
46 	}
47 }
48 
ZTEST(cmsis_mutex,test_mutex)49 ZTEST(cmsis_mutex, test_mutex)
50 {
51 	osMutexId_t mutex_id = 0;
52 	osThreadId_t id;
53 	osStatus_t status;
54 	const char *name;
55 
56 	/* Try deleting invalid mutex object */
57 	status = osMutexDelete(mutex_id);
58 	zassert_true(status == osErrorParameter, "Invalid Mutex deleted unexpectedly!");
59 
60 	mutex_id = osMutexNew(&mutex_attr);
61 	zassert_true(mutex_id != NULL, "Mutex1 creation failed");
62 
63 	name = osMutexGetName(mutex_id);
64 	zassert_str_equal(mutex_attr.name, name, "Error getting Mutex name");
65 
66 	/* Try to release mutex without obtaining it */
67 	status = osMutexRelease(mutex_id);
68 	zassert_true(status == osErrorResource, "Mutex released unexpectedly!");
69 
70 	/* Try figuring out the owner for a Mutex which has not been
71 	 * acquired by any thread yet.
72 	 */
73 	id = osMutexGetOwner(mutex_id);
74 	zassert_true(id == NULL, "Something wrong with MutexGetOwner!");
75 
76 	status = osMutexAcquire(mutex_id, 0);
77 	zassert_true(status == osOK, "Mutex wait failure");
78 
79 	id = osMutexGetOwner(mutex_id);
80 	zassert_equal(id, osThreadGetId(), "Current thread is not the owner!");
81 
82 	/* Try to acquire an already acquired mutex */
83 	status = osMutexAcquire(mutex_id, 0);
84 	zassert_true(status == osOK, "Mutex wait failure");
85 
86 	status = osMutexRelease(mutex_id);
87 	zassert_true(status == osOK, "Mutex release failure");
88 
89 	/* Release mutex again as it was acquired twice */
90 	status = osMutexRelease(mutex_id);
91 	zassert_true(status == osOK, "Mutex release failure");
92 
93 	/* Try to release mutex that was already released */
94 	status = osMutexRelease(mutex_id);
95 	zassert_true(status == osErrorResource, "Mutex released unexpectedly!");
96 
97 	status = osMutexDelete(mutex_id);
98 	zassert_true(status == osOK, "Mutex delete failure");
99 
100 	/* Try mutex creation for more than maximum allowed count */
101 	test_max_mutex();
102 }
103 
tThread_entry_lock_timeout(void * arg)104 void tThread_entry_lock_timeout(void *arg)
105 {
106 	osStatus_t status;
107 	osThreadId_t id;
108 
109 	/* Mutex cannot be acquired/released here as it is still held
110 	 * by the other thread. Try with and without timeout.
111 	 */
112 	status = osMutexAcquire((osMutexId_t)arg, 0);
113 	zassert_true(status == osErrorResource);
114 
115 	status = osMutexAcquire((osMutexId_t)arg, WAIT_TICKS);
116 	zassert_true(status == osErrorTimeout);
117 
118 	status = osMutexRelease((osMutexId_t)arg);
119 	zassert_true(status == osErrorResource, "Mutex unexpectedly released");
120 
121 	id = osMutexGetOwner((osMutexId_t)arg);
122 	zassert_not_equal(id, osThreadGetId(), "Unexpectedly, current thread is the mutex owner!");
123 
124 	/* This delay ensures that the mutex gets released by the other
125 	 * thread in the meantime
126 	 */
127 	osDelay(TIMEOUT_TICKS);
128 
129 	/* Now that the mutex is free, it should be possible to acquire
130 	 * and release it.
131 	 */
132 	status = osMutexAcquire((osMutexId_t)arg, TIMEOUT_TICKS);
133 	zassert_true(status == osOK);
134 	osMutexRelease((osMutexId_t)arg);
135 }
136 
137 static K_THREAD_STACK_DEFINE(test_stack, STACKSZ);
138 static osThreadAttr_t thread_attr = {.name = "Mutex_check",
139 				     .attr_bits = osThreadDetached,
140 				     .cb_mem = NULL,
141 				     .cb_size = 0,
142 				     .stack_mem = &test_stack,
143 				     .stack_size = STACKSZ,
144 				     .priority = osPriorityNormal,
145 				     .tz_module = 0,
146 				     .reserved = 0};
147 
ZTEST(cmsis_mutex,test_mutex_lock_timeout)148 ZTEST(cmsis_mutex, test_mutex_lock_timeout)
149 {
150 	osThreadId_t id;
151 	osMutexId_t mutex_id;
152 	osStatus_t status;
153 
154 	mutex_id = osMutexNew(&mutex_attr);
155 	zassert_true(mutex_id != NULL, "Mutex2 creation failed");
156 
157 	id = osThreadNew(tThread_entry_lock_timeout, mutex_id, &thread_attr);
158 	zassert_true(id != NULL, "Thread creation failed");
159 
160 	status = osMutexAcquire(mutex_id, osWaitForever);
161 	zassert_true(status == osOK, "Mutex wait failure");
162 
163 	/* wait for spawn thread to take action */
164 	osDelay(TIMEOUT_TICKS);
165 
166 	/* Release the mutex to be used by the other thread */
167 	osMutexRelease(mutex_id);
168 	osDelay(TIMEOUT_TICKS);
169 
170 	osMutexDelete(mutex_id);
171 }
172 
173 static struct cmsis_rtos_mutex_cb mutex_cb2;
174 static const osMutexAttr_t mutex_attrs2 = {
175 	.name = "Mutex2",
176 	.attr_bits = osMutexPrioInherit,
177 	.cb_mem = &mutex_cb2,
178 	.cb_size = sizeof(mutex_cb2),
179 };
ZTEST(cmsis_mutex,test_mutex_static_allocation)180 ZTEST(cmsis_mutex, test_mutex_static_allocation)
181 {
182 	osMutexId_t id;
183 
184 	id = osMutexNew(&mutex_attrs2);
185 	zassert_not_null(id, "Failed creating mutex using static cb");
186 
187 	zassert_true(osMutexDelete(id) == osOK, "osMutexDelete failed");
188 }
189 
ZTEST(cmsis_mutex,test_mutex_static_multiple_new)190 ZTEST(cmsis_mutex, test_mutex_static_multiple_new)
191 {
192 	osMutexId_t id;
193 
194 	for (int i = 0; i < 100; ++i) {
195 		id = osMutexNew(&mutex_attrs2);
196 		zassert_not_null(id, "Failed creating mutex using static cb");
197 
198 		zassert_true(osMutexDelete(id) == osOK, "osMutexDelete failed");
199 	}
200 }
201 ZTEST_SUITE(cmsis_mutex, NULL, NULL, NULL, NULL, NULL);
202