Skip to content

Commit 1618fd2

Browse files
committed
Add some atomic tests
These are platform tests, but rely on the RTOS to run multiple threads to exercise it. (The atomics are still useful in non-RTOS, to protect against interrupt handlers, but testing versus other threads is easier. The implementation is the same either way, so doesn't seem worth testing non-RTOS specifically).
1 parent ccdcb4e commit 1618fd2

File tree

1 file changed

+185
-0
lines changed

1 file changed

+185
-0
lines changed

TESTS/mbed_platform/atomic/main.cpp

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include "mbed.h"
17+
#include "greentea-client/test_env.h"
18+
#include "unity/unity.h"
19+
#include "utest/utest.h"
20+
21+
#if !MBED_CONF_RTOS_PRESENT
22+
#error [NOT_SUPPORTED] test not supported
23+
#endif
24+
25+
#define THREAD_STACK 512
26+
27+
using utest::v1::Case;
28+
29+
30+
namespace {
31+
32+
/* Lock-free operations will be much faster - keep runtime down */
33+
#if MBED_ATOMIC_INT_LOCK_FREE
34+
#define ADD_ITERATIONS (SystemCoreClock / 1000)
35+
#else
36+
#define ADD_ITERATIONS (SystemCoreClock / 8000)
37+
#endif
38+
39+
template <typename T>
40+
void add_incrementer(T *ptr)
41+
{
42+
for (long i = ADD_ITERATIONS; i > 0; i--) {
43+
core_util_atomic_fetch_add(ptr, T(1));
44+
}
45+
}
46+
47+
template <typename T>
48+
void add_release_incrementer(T *ptr)
49+
{
50+
for (long i = ADD_ITERATIONS; i > 0; i--) {
51+
core_util_atomic_fetch_add_explicit(ptr, T(1), mbed_memory_order_release);
52+
}
53+
}
54+
55+
template <typename T>
56+
void sub_incrementer(T *ptr)
57+
{
58+
for (long i = ADD_ITERATIONS; i > 0; i--) {
59+
core_util_atomic_fetch_sub(ptr, T(-1));
60+
}
61+
}
62+
63+
template <typename T>
64+
void bitops_incrementer(T *ptr)
65+
{
66+
for (long i = ADD_ITERATIONS; i > 0; i--) {
67+
core_util_atomic_fetch_add(ptr, T(1));
68+
core_util_atomic_fetch_and(ptr, T(-1));
69+
core_util_atomic_fetch_or(ptr, T(0));
70+
}
71+
}
72+
73+
template <typename T>
74+
void weak_incrementer(T *ptr)
75+
{
76+
for (long i = ADD_ITERATIONS; i > 0; i--) {
77+
T val = core_util_atomic_load(ptr);
78+
do {
79+
} while (!core_util_atomic_compare_exchange_weak(ptr, &val, T(val + 1)));
80+
}
81+
}
82+
83+
template <typename T>
84+
void strong_incrementer(T *ptr)
85+
{
86+
for (long i = ADD_ITERATIONS; i > 0; i--) {
87+
T val = core_util_atomic_load(ptr);
88+
do {
89+
} while (!core_util_atomic_compare_exchange_strong(ptr, &val, T(val + 1)));
90+
}
91+
}
92+
93+
94+
/*
95+
* Run multiple threads incrementing each data item
96+
* ADD_ITERATIONS times, and at the end, check that
97+
* each item is <number of threads> * ADD_ITERATIONS.
98+
* Items are adjacent to catch any interference.
99+
*
100+
* Using core_util_atomic_ templates, and exercising
101+
* load and store briefly.
102+
*/
103+
template<typename T, void (*Fn)(T *)>
104+
void test_atomic_add()
105+
{
106+
struct {
107+
volatile T nonatomic1;
108+
T atomic1;
109+
T atomic2;
110+
volatile T nonatomic2;
111+
} data;
112+
113+
data.nonatomic1 = 0;
114+
core_util_atomic_store(&data.atomic1, T(0));
115+
core_util_atomic_store(&data.atomic2, T(0));
116+
data.nonatomic2 = 0;
117+
118+
Thread t1(osPriorityNormal, THREAD_STACK);
119+
Thread t2(osPriorityNormal, THREAD_STACK);
120+
Thread t3(osPriorityNormal, THREAD_STACK);
121+
Thread t4(osPriorityNormal, THREAD_STACK);
122+
123+
TEST_ASSERT_EQUAL(osOK, t1.start(callback(Fn, &data.atomic1)));
124+
TEST_ASSERT_EQUAL(osOK, t2.start(callback(Fn, &data.atomic1)));
125+
TEST_ASSERT_EQUAL(osOK, t3.start(callback(Fn, &data.atomic2)));
126+
TEST_ASSERT_EQUAL(osOK, t4.start(callback(Fn, &data.atomic2)));
127+
128+
for (long i = ADD_ITERATIONS; i > 0; i--) {
129+
data.nonatomic1++;
130+
data.nonatomic2++;
131+
}
132+
133+
t1.join();
134+
t2.join();
135+
t3.join();
136+
t4.join();
137+
138+
TEST_ASSERT_EQUAL(T(ADD_ITERATIONS), data.nonatomic1);
139+
TEST_ASSERT_EQUAL(T(2 * ADD_ITERATIONS), core_util_atomic_load(&data.atomic1));
140+
TEST_ASSERT_EQUAL(T(2 * ADD_ITERATIONS), core_util_atomic_load(&data.atomic2));
141+
TEST_ASSERT_EQUAL(T(ADD_ITERATIONS), data.nonatomic2);
142+
}
143+
144+
} // namespace
145+
146+
utest::v1::status_t test_setup(const size_t number_of_cases)
147+
{
148+
GREENTEA_SETUP(30, "default_auto");
149+
return utest::v1::verbose_test_setup_handler(number_of_cases);
150+
}
151+
152+
Case cases[] = {
153+
Case("Test atomic add 8-bit", test_atomic_add<uint8_t, add_incrementer>),
154+
Case("Test atomic add 16-bit", test_atomic_add<uint16_t, add_incrementer>),
155+
Case("Test atomic add 32-bit", test_atomic_add<uint32_t, add_incrementer>),
156+
Case("Test atomic add 64-bit", test_atomic_add<uint64_t, add_incrementer>),
157+
Case("Test atomic add signed 8-bit", test_atomic_add<int8_t, add_incrementer>),
158+
Case("Test atomic add signed 16-bit", test_atomic_add<int16_t, add_incrementer>),
159+
Case("Test atomic add signed 32-bit", test_atomic_add<int32_t, add_incrementer>),
160+
Case("Test atomic add signed 64-bit", test_atomic_add<int64_t, add_incrementer>),
161+
Case("Test atomic add release 32-bit", test_atomic_add<uint32_t, add_release_incrementer>),
162+
Case("Test atomic sub 8-bit", test_atomic_add<uint8_t, sub_incrementer>),
163+
Case("Test atomic sub 16-bit", test_atomic_add<uint16_t, sub_incrementer>),
164+
Case("Test atomic sub 32-bit", test_atomic_add<uint32_t, sub_incrementer>),
165+
Case("Test atomic sub 64-bit", test_atomic_add<uint64_t, sub_incrementer>),
166+
Case("Test atomic bitops 8-bit", test_atomic_add<uint8_t, bitops_incrementer>),
167+
Case("Test atomic bitops 16-bit", test_atomic_add<uint16_t, bitops_incrementer>),
168+
Case("Test atomic bitops 32-bit", test_atomic_add<uint32_t, bitops_incrementer>),
169+
Case("Test atomic bitops 64-bit", test_atomic_add<uint64_t, bitops_incrementer>),
170+
Case("Test atomic compare exchange weak 8-bit", test_atomic_add<uint8_t, weak_incrementer>),
171+
Case("Test atomic compare exchange weak 16-bit", test_atomic_add<uint16_t, weak_incrementer>),
172+
Case("Test atomic compare exchange weak 32-bit", test_atomic_add<uint32_t, weak_incrementer>),
173+
Case("Test atomic compare exchange weak 64-bit", test_atomic_add<uint64_t, weak_incrementer>),
174+
Case("Test atomic compare exchange strong 8-bit", test_atomic_add<uint8_t, strong_incrementer>),
175+
Case("Test atomic compare exchange strong 16-bit", test_atomic_add<uint16_t, strong_incrementer>),
176+
Case("Test atomic compare exchange strong 32-bit", test_atomic_add<uint32_t, strong_incrementer>),
177+
Case("Test atomic compare exchange strong 64-bit", test_atomic_add<uint64_t, strong_incrementer>)
178+
};
179+
180+
utest::v1::Specification specification(test_setup, cases);
181+
182+
int main()
183+
{
184+
return !utest::v1::Harness::run(specification);
185+
}

0 commit comments

Comments
 (0)