1 /*
2  * Copyright (c) 2015 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <ztest.h>
8 #include <sys/atomic.h>
9 
10 /* an example of the number of atomic bit in an array */
11 #define NUM_FLAG_BITS 100
12 
13 /* set test_cycle 1000us * 20 = 20ms */
14 #define TEST_CYCLE 20
15 
16 #define THREADS_NUM 2
17 
18 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACKSIZE)
19 
20 static K_THREAD_STACK_ARRAY_DEFINE(stack, THREADS_NUM, STACK_SIZE);
21 
22 static struct k_thread thread[THREADS_NUM];
23 
24 atomic_t total_atomic;
25 
26 /**
27  * @addtogroup kernel_common_tests
28  * @{
29  */
30 
31 /**
32  * @brief Verify atomic functionalities
33  * @details
34  * Test Objective:
35  * - Test the function of the atomic operation API is correct.
36  *
37  * Test techniques:
38  * - Dynamic analysis and testing
39  * - Functional and black box testing
40  * - Interface testing
41  *
42  * Prerequisite Conditions:
43  * - N/A
44  *
45  * Input Specifications:
46  * - N/A
47  *
48  * Test Procedure:
49  * -# Call the API interface of the following atomic operations in turn,
50  * judge the change of function return value and target operands.
51  * - atomic_cas()
52  * - atomic_ptr_cas()
53  * - atomic_add()
54  * - atomic_sub()
55  * - atomic_inc()
56  * - atomic_dec()
57  * - atomic_get()
58  * - atomic_ptr_get()
59  * - atomic_set()
60  * - atomic_ptr_set()
61  * - atomic_clear()
62  * - atomic_ptr_clear()
63  * - atomic_or()
64  * - atomic_xor()
65  * - atomic_and()
66  * - atomic_nand()
67  * - atomic_test_bit()
68  * - atomic_test_and_clear_bit()
69  * - atomic_test_and_set_bit()
70  * - atomic_clear_bit()
71  * - atomic_set_bit()
72  * - atomic_set_bit_to()
73  * - ATOMIC_DEFINE
74  *
75  * Expected Test Result:
76  * - The change of function return value and target operands is correct.
77  *
78  * Pass/Fail Criteria:
79  * - Successful if check points in test procedure are all passed, otherwise failure.
80  *
81  * Assumptions and Constraints:
82  * - N/A
83  *
84  * @see atomic_cas(), atomic_add(), atomic_sub(),
85  * atomic_inc(), atomic_dec(), atomic_get(), atomic_set(),
86  * atomic_clear(), atomic_or(), atomic_and(), atomic_xor(),
87  * atomic_nand(), atomic_test_bit(), atomic_test_and_clear_bit(),
88  * atomic_test_and_set_bit(), atomic_clear_bit(), atomic_set_bit(),
89  * ATOMIC_DEFINE
90  *
91  * @ingroup kernel_common_tests
92  */
test_atomic(void)93 void test_atomic(void)
94 {
95 	int i;
96 
97 	atomic_t target, orig;
98 	atomic_ptr_t ptr_target;
99 	atomic_val_t value;
100 	atomic_val_t oldvalue;
101 	void *ptr_value, *old_ptr_value;
102 
103 	ATOMIC_DEFINE(flag_bits, NUM_FLAG_BITS) = {0};
104 
105 	target = 4;
106 	value = 5;
107 	oldvalue = 6;
108 
109 	/* atomic_cas() */
110 	zassert_false(atomic_cas(&target, oldvalue, value), "atomic_cas");
111 	target = 6;
112 	zassert_true(atomic_cas(&target, oldvalue, value), "atomic_cas");
113 	zassert_true((target == value), "atomic_cas");
114 
115 	/* atomic_ptr_cas() */
116 	ptr_target = ATOMIC_PTR_INIT((void *)4);
117 	ptr_value = (atomic_ptr_val_t)5;
118 	old_ptr_value = (atomic_ptr_val_t)6;
119 	zassert_false(atomic_ptr_cas(&ptr_target, old_ptr_value, ptr_value),
120 		      "atomic_ptr_cas");
121 	ptr_target = (atomic_ptr_val_t)6;
122 	zassert_true(atomic_ptr_cas(&ptr_target, old_ptr_value, ptr_value),
123 		     "atomic_ptr_cas");
124 	zassert_true((ptr_target == ptr_value), "atomic_ptr_cas");
125 
126 	/* atomic_add() */
127 	target = 1;
128 	value = 2;
129 	zassert_true((atomic_add(&target, value) == 1), "atomic_add");
130 	zassert_true((target == 3), "atomic_add");
131 	/* Test the atomic_add() function parameters can be negative */
132 	target = 2;
133 	value = -4;
134 	zassert_true((atomic_add(&target, value) == 2), "atomic_add");
135 	zassert_true((target == -2), "atomic_add");
136 
137 	/* atomic_sub() */
138 	target = 10;
139 	value = 2;
140 	zassert_true((atomic_sub(&target, value) == 10), "atomic_sub");
141 	zassert_true((target == 8), "atomic_sub");
142 	/* Test the atomic_sub() function parameters can be negative */
143 	target = 5;
144 	value = -4;
145 	zassert_true((atomic_sub(&target, value) == 5), "atomic_sub");
146 	zassert_true((target == 9), "atomic_sub");
147 
148 	/* atomic_inc() */
149 	target = 5;
150 	zassert_true((atomic_inc(&target) == 5), "atomic_inc");
151 	zassert_true((target == 6), "atomic_inc");
152 
153 	/* atomic_dec() */
154 	target = 2;
155 	zassert_true((atomic_dec(&target) == 2), "atomic_dec");
156 	zassert_true((target == 1), "atomic_dec");
157 
158 	/* atomic_get() */
159 	target = 50;
160 	zassert_true((atomic_get(&target) == 50), "atomic_get");
161 
162 	/* atomic_ptr_get() */
163 	ptr_target = ATOMIC_PTR_INIT((void *)50);
164 	zassert_true((atomic_ptr_get(&ptr_target) == (atomic_ptr_val_t)50),
165 		     "atomic_ptr_get");
166 
167 	/* atomic_set() */
168 	target = 42;
169 	value = 77;
170 	zassert_true((atomic_set(&target, value) == 42), "atomic_set");
171 	zassert_true((target == value), "atomic_set");
172 
173 	/* atomic_ptr_set() */
174 	ptr_target = ATOMIC_PTR_INIT((void *)42);
175 	ptr_value = (atomic_ptr_val_t)77;
176 	zassert_true((atomic_ptr_set(&ptr_target, ptr_value) == (atomic_ptr_val_t)42),
177 		     "atomic_ptr_set");
178 	zassert_true((ptr_target == ptr_value), "atomic_ptr_set");
179 
180 	/* atomic_clear() */
181 	target = 100;
182 	zassert_true((atomic_clear(&target) == 100), "atomic_clear");
183 	zassert_true((target == 0), "atomic_clear");
184 
185 	/* atomic_ptr_clear() */
186 	ptr_target = ATOMIC_PTR_INIT((void *)100);
187 	zassert_true((atomic_ptr_clear(&ptr_target) == (atomic_ptr_val_t)100),
188 		     "atomic_ptr_clear");
189 	zassert_true((ptr_target == NULL), "atomic_ptr_clear");
190 
191 	/* atomic_or() */
192 	target = 0xFF00;
193 	value  = 0x0F0F;
194 	zassert_true((atomic_or(&target, value) == 0xFF00), "atomic_or");
195 	zassert_true((target == 0xFF0F), "atomic_or");
196 
197 	/* atomic_xor() */
198 	target = 0xFF00;
199 	value  = 0x0F0F;
200 	zassert_true((atomic_xor(&target, value) == 0xFF00), "atomic_xor");
201 	zassert_true((target == 0xF00F), "atomic_xor");
202 
203 	/* atomic_and() */
204 	target = 0xFF00;
205 	value  = 0x0F0F;
206 	zassert_true((atomic_and(&target, value) == 0xFF00), "atomic_and");
207 	zassert_true((target == 0x0F00), "atomic_and");
208 
209 
210 	/* atomic_nand() */
211 	target = 0xFF00;
212 	value  = 0x0F0F;
213 	zassert_true((atomic_nand(&target, value) == 0xFF00), "atomic_nand");
214 	zassert_true((target == 0xFFFFF0FF), "atomic_nand");
215 
216 	/* atomic_test_bit() */
217 	for (i = 0; i < 32; i++) {
218 		target = 0x0F0F0F0F;
219 		zassert_true(!!(atomic_test_bit(&target, i) == !!(target & (1 << i))),
220 			     "atomic_test_bit");
221 	}
222 
223 	/* atomic_test_and_clear_bit() */
224 	for (i = 0; i < 32; i++) {
225 		orig = 0x0F0F0F0F;
226 		target = orig;
227 		zassert_true(!!(atomic_test_and_clear_bit(&target, i)) == !!(orig & (1 << i)),
228 			     "atomic_test_and_clear_bit");
229 		zassert_true(target == (orig & ~(1 << i)), "atomic_test_and_clear_bit");
230 	}
231 
232 	/* atomic_test_and_set_bit() */
233 	for (i = 0; i < 32; i++) {
234 		orig = 0x0F0F0F0F;
235 		target = orig;
236 		zassert_true(!!(atomic_test_and_set_bit(&target, i)) == !!(orig & (1 << i)),
237 			     "atomic_test_and_set_bit");
238 		zassert_true(target == (orig | (1 << i)), "atomic_test_and_set_bit");
239 	}
240 
241 	/* atomic_clear_bit() */
242 	for (i = 0; i < 32; i++) {
243 		orig = 0x0F0F0F0F;
244 		target = orig;
245 		atomic_clear_bit(&target, i);
246 		zassert_true(target == (orig & ~(1 << i)), "atomic_clear_bit");
247 	}
248 
249 	/* atomic_set_bit() */
250 	for (i = 0; i < 32; i++) {
251 		orig = 0x0F0F0F0F;
252 		target = orig;
253 		atomic_set_bit(&target, i);
254 		zassert_true(target == (orig | (1 << i)), "atomic_set_bit");
255 	}
256 
257 	/* atomic_set_bit_to(&target, i, false) */
258 	for (i = 0; i < 32; i++) {
259 		orig = 0x0F0F0F0F;
260 		target = orig;
261 		atomic_set_bit_to(&target, i, false);
262 		zassert_true(target == (orig & ~(1 << i)), "atomic_set_bit_to");
263 	}
264 
265 	/* atomic_set_bit_to(&target, i, true) */
266 	for (i = 0; i < 32; i++) {
267 		orig = 0x0F0F0F0F;
268 		target = orig;
269 		atomic_set_bit_to(&target, i, true);
270 		zassert_true(target == (orig | (1 << i)), "atomic_set_bit_to");
271 	}
272 
273 	/* ATOMIC_DEFINE */
274 	for (i = 0; i < NUM_FLAG_BITS; i++) {
275 		atomic_set_bit(flag_bits, i);
276 		zassert_true(!!atomic_test_bit(flag_bits, i) == !!(1),
277 			"Failed to set a single bit in an array of atomic variables");
278 		atomic_clear_bit(flag_bits, i);
279 		zassert_true(!!atomic_test_bit(flag_bits, i) == !!(0),
280 			"Failed to clear a single bit in an array of atomic variables");
281 	}
282 }
283 
284 /* This helper function will run more the one slice */
atomic_handler(void * p1,void * p2,void * p3)285 void atomic_handler(void *p1, void *p2, void *p3)
286 {
287 	ARG_UNUSED(p1);
288 	ARG_UNUSED(p2);
289 	ARG_UNUSED(p3);
290 
291 	for (int i = 0; i < TEST_CYCLE; i++) {
292 		atomic_inc(&total_atomic);
293 		/* Do 1000us busywait to longer the handler execute time */
294 		k_busy_wait(1000);
295 	}
296 }
297 
298 /**
299  * @brief Verify atomic operation with threads
300  *
301  * @details Creat two preempt threads with equal priority to
302  * atomiclly access the same atomic value. Because these preempt
303  * threads are of equal priority, so enable time slice to make
304  * them scheduled. The thread will execute for some time.
305  * In this time, the two sub threads will be scheduled separately
306  * according to the time slice.
307  *
308  * @ingroup kernel_common_tests
309  */
test_threads_access_atomic(void)310 void test_threads_access_atomic(void)
311 {
312 	k_tid_t tid[THREADS_NUM];
313 
314 	/* enable time slice 1ms at priority 10 */
315 	k_sched_time_slice_set(1, K_PRIO_PREEMPT(10));
316 
317 	for (int i = 0; i < THREADS_NUM; i++) {
318 		tid[i] = k_thread_create(&thread[i], stack[i], STACK_SIZE,
319 				atomic_handler, NULL, NULL, NULL,
320 				K_PRIO_PREEMPT(10), 0, K_NO_WAIT);
321 	}
322 
323 	for (int i = 0; i < THREADS_NUM; i++) {
324 		k_thread_join(tid[i], K_FOREVER);
325 	}
326 
327 	/* disable time slice */
328 	k_sched_time_slice_set(0, K_PRIO_PREEMPT(10));
329 
330 	zassert_true(total_atomic == (TEST_CYCLE * THREADS_NUM),
331 		"atomic counting failure");
332 }
333 /**
334  * @}
335  */
336