1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2022-07-27     flybreak     the first version
9  * 2023-03-21     WangShun     add atomic test
10  * 2023-09-15     xqyjlj       change stack size in cpu64
11  */
12 
13 #include <rtthread.h>
14 #include "utest.h"
15 #include "rtatomic.h"
16 #include <rthw.h>
17 
18 #define THREAD_PRIORITY         25
19 #define THREAD_TIMESLICE        1
20 #define THREAD_STACKSIZE        UTEST_THR_STACK_SIZE
21 
22 /* convenience macro - return either 64-bit or 32-bit value */
23 #define ATOMIC_WORD(val_if_64, val_if_32)                                           \
24     ((rt_atomic_t)((sizeof(void *) == sizeof(uint64_t)) ? (val_if_64) : (val_if_32)))
25 
26 static rt_atomic_t count = 0;
27 static rt_sem_t sem_t;
28 
test_atomic_api(void)29 static void test_atomic_api(void)
30 {
31     rt_atomic_t base;
32     rt_atomic_t oldval;
33     rt_atomic_t result;
34 
35     /* rt_atomic_t */
36     uassert_true(sizeof(rt_atomic_t) == ATOMIC_WORD(sizeof(uint64_t), sizeof(uint32_t)));
37 
38     /* rt_atomic_add */
39     base = 0;
40     result = rt_atomic_add(&base, 10);
41     uassert_true(base == 10);
42     uassert_true(result == 0);
43     /* rt_atomic_add negative */
44     base = 2;
45     result = rt_atomic_add(&base, -4);
46     uassert_true(base == -2);
47     uassert_true(result == 2);
48 
49     /* rt_atomic_sub */
50     base = 11;
51     result = rt_atomic_sub(&base, 10);
52     uassert_true(base == 1);
53     uassert_true(result == 11);
54     /* rt_atomic_sub negative */
55     base = 2;
56     result = rt_atomic_sub(&base, -5);
57     uassert_true(base == 7);
58     uassert_true(result == 2);
59 
60     /* rt_atomic_or */
61     base = 0xFF00;
62     result = rt_atomic_or(&base, 0x0F0F);
63     uassert_true(base == 0xFF0F);
64     uassert_true(result == 0xFF00);
65 
66     /* rt_atomic_xor */
67     base = 0xFF00;
68     result = rt_atomic_xor(&base, 0x0F0F);
69     uassert_true(base == 0xF00F);
70     uassert_true(result == 0xFF00);
71 
72     /* rt_atomic_and */
73     base = 0xFF00;
74     result = rt_atomic_and(&base, 0x0F0F);
75     uassert_true(base == 0x0F00);
76     uassert_true(result == 0xFF00);
77 
78     /* rt_atomic_exchange */
79     base = 0xFF00;
80     result = rt_atomic_exchange(&base, 0x0F0F);
81     uassert_true(base == 0x0F0F);
82     uassert_true(result == 0xFF00);
83 
84     /* rt_atomic_flag_test_and_set (Flag 0) */
85     base = 0x0;
86     result = rt_atomic_flag_test_and_set(&base);
87     uassert_true(base == 0x1);
88     uassert_true(result == 0x0);
89     /* rt_atomic_flag_test_and_set (Flag 1) */
90     base = 0x1;
91     result = rt_atomic_flag_test_and_set(&base);
92     uassert_true(base == 0x1);
93     uassert_true(result == 0x1);
94 
95     /* rt_atomic_flag_clear */
96     base = 0x1;
97     rt_atomic_flag_clear(&base);
98     uassert_true(base == 0x0);
99 
100     /* rt_atomic_load */
101     base = 0xFF00;
102     result = rt_atomic_load(&base);
103     uassert_true(base == 0xFF00);
104     uassert_true(result == 0xFF00);
105 
106     /* rt_atomic_store */
107     base = 0xFF00;
108     rt_atomic_store(&base, 0x0F0F);
109     uassert_true(base == 0x0F0F);
110 
111     /* rt_atomic_compare_exchange_strong (equal) */
112     base = 10;
113     oldval = 10;
114     result = rt_atomic_compare_exchange_strong(&base, &oldval, 11);
115     uassert_true(base == 11);
116     uassert_true(result == 0x1);
117     /* rt_atomic_compare_exchange_strong (not equal) */
118     base = 10;
119     oldval = 5;
120     result = rt_atomic_compare_exchange_strong(&base, &oldval, 11);
121     uassert_true(base == 10);
122     uassert_true(result == 0x0);
123 }
124 
ture_entry(void * parameter)125 static void ture_entry(void *parameter)
126 {
127     int i;
128     for (i = 0; i < 1000000; i++)
129     {
130         rt_atomic_add(&count, 1);
131     }
132     rt_sem_release(sem_t);
133 }
134 
test_atomic_add(void)135 static void test_atomic_add(void)
136 {
137     rt_thread_t thread;
138     size_t i;
139     sem_t = rt_sem_create("atomic_sem", 0, RT_IPC_FLAG_PRIO);
140 
141     rt_atomic_store(&count, 0);
142 
143     thread = rt_thread_create("t1", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
144     rt_thread_startup(thread);
145     thread = rt_thread_create("t2", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
146     rt_thread_startup(thread);
147     thread = rt_thread_create("t3", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
148     rt_thread_startup(thread);
149 
150     for (i = 0; i < 3; i++)
151     {
152         rt_sem_take(sem_t, RT_WAITING_FOREVER);
153     }
154     i = rt_atomic_load(&count);
155     uassert_true(i == 3000000);
156 }
157 
utest_tc_init(void)158 static rt_err_t utest_tc_init(void)
159 {
160     return RT_EOK;
161 }
162 
utest_tc_cleanup(void)163 static rt_err_t utest_tc_cleanup(void)
164 {
165     return RT_EOK;
166 }
167 
testcase(void)168 static void testcase(void)
169 {
170     UTEST_UNIT_RUN(test_atomic_api);
171     UTEST_UNIT_RUN(test_atomic_add);
172 }
173 UTEST_TC_EXPORT(testcase, "testcases.kernel.atomic_tc", utest_tc_init, utest_tc_cleanup, 10);
174