Skip to content

Commit 4144d43

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 2e088b2 commit 4144d43

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

TESTS/mbed_platform/atomic/main.cpp

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
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+
#define ADD_ITERATIONS (SystemCoreClock / 1000)
33+
34+
template <typename T>
35+
void add_incrementer(T *ptr)
36+
{
37+
for (long long i = ADD_ITERATIONS; i > 0; i--) {
38+
core_util_atomic_fetch_add(ptr, (T)1);
39+
}
40+
}
41+
42+
template <typename T>
43+
void sub_incrementer(T *ptr)
44+
{
45+
for (long long i = ADD_ITERATIONS; i > 0; i--) {
46+
core_util_atomic_fetch_sub(ptr, (T) -1);
47+
}
48+
}
49+
50+
template <typename T>
51+
void bitops_incrementer(T *ptr)
52+
{
53+
for (long long i = ADD_ITERATIONS; i > 0; i--) {
54+
core_util_atomic_fetch_add(ptr, (T)1);
55+
core_util_atomic_fetch_and(ptr, (T)-1);
56+
core_util_atomic_fetch_or(ptr, (T)-20);
57+
}
58+
}
59+
60+
template <typename T>
61+
void weak_incrementer(T *ptr)
62+
{
63+
for (long long i = ADD_ITERATIONS; i > 0; i--) {
64+
T val = -1;//core_util_atomic_load(ptr);
65+
do {
66+
} while (!core_util_atomic_compare_exchange_weak(ptr, &val, T(val + 1)));
67+
}
68+
}
69+
70+
template <typename T>
71+
void strong_incrementer(T *ptr)
72+
{
73+
for (long long i = ADD_ITERATIONS; i > 0; i--) {
74+
T val = core_util_atomic_load(ptr);
75+
do {
76+
} while (!core_util_atomic_compare_exchange_strong(ptr, &val, T(val + 1)));
77+
}
78+
}
79+
/*
80+
* Run multiple threads incrementing each data item
81+
* ADD_ITERATIONS times, and at the end, check that
82+
* each item is <number of threads> * ADD_ITERATIONS.
83+
* Items are adjacent to catch any interference.
84+
*
85+
* Using core_util_atomic_ templates, and exercising
86+
* load and store briefly.
87+
*/
88+
template<typename T, void (*Fn)(T *)>
89+
void test_atomic_add()
90+
{
91+
struct {
92+
volatile T nonatomic1;
93+
T atomic1;
94+
T atomic2;
95+
volatile T nonatomic2;
96+
} data;
97+
98+
data.nonatomic1 = 0;
99+
core_util_atomic_store(&data.atomic1, (T)0);
100+
core_util_atomic_store(&data.atomic2, (T)0);
101+
data.nonatomic2 = 0;
102+
103+
Thread t1(osPriorityNormal, THREAD_STACK);
104+
Thread t2(osPriorityNormal, THREAD_STACK);
105+
Thread t3(osPriorityNormal, THREAD_STACK);
106+
Thread t4(osPriorityNormal, THREAD_STACK);
107+
108+
TEST_ASSERT_EQUAL(osOK, t1.start(callback(Fn, &data.atomic1)));
109+
TEST_ASSERT_EQUAL(osOK, t2.start(callback(Fn, &data.atomic1)));
110+
TEST_ASSERT_EQUAL(osOK, t3.start(callback(Fn, &data.atomic2)));
111+
TEST_ASSERT_EQUAL(osOK, t4.start(callback(Fn, &data.atomic2)));
112+
113+
for (long long i = ADD_ITERATIONS; i > 0; i--) {
114+
data.nonatomic1++;
115+
data.nonatomic2++;
116+
}
117+
118+
t1.join();
119+
t2.join();
120+
t3.join();
121+
t4.join();
122+
123+
TEST_ASSERT_EQUAL((T)ADD_ITERATIONS, data.nonatomic1);
124+
TEST_ASSERT_EQUAL((T)(2 * ADD_ITERATIONS), core_util_atomic_load(&data.atomic1));
125+
TEST_ASSERT_EQUAL((T)(2 * ADD_ITERATIONS), core_util_atomic_load(&data.atomic2));
126+
TEST_ASSERT_EQUAL((T)ADD_ITERATIONS, data.nonatomic2);
127+
}
128+
129+
} // namespace
130+
131+
utest::v1::status_t test_setup(const size_t number_of_cases)
132+
{
133+
GREENTEA_SETUP(30, "default_auto");
134+
return utest::v1::verbose_test_setup_handler(number_of_cases);
135+
}
136+
137+
Case cases[] = {
138+
Case("Test atomic add 8-bit", test_atomic_add<uint8_t, add_incrementer>),
139+
Case("Test atomic add 16-bit", test_atomic_add<uint16_t, add_incrementer>),
140+
Case("Test atomic add 32-bit", test_atomic_add<uint32_t, add_incrementer>),
141+
Case("Test atomic add 64-bit", test_atomic_add<uint64_t, add_incrementer>),
142+
Case("Test atomic add signed 8-bit", test_atomic_add<int8_t, add_incrementer>),
143+
Case("Test atomic add signed 16-bit", test_atomic_add<int16_t, add_incrementer>),
144+
Case("Test atomic add signed 32-bit", test_atomic_add<int32_t, add_incrementer>),
145+
Case("Test atomic add signed 64-bit", test_atomic_add<int64_t, add_incrementer>),
146+
Case("Test atomic sub 8-bit", test_atomic_add<uint8_t, sub_incrementer>),
147+
Case("Test atomic sub 16-bit", test_atomic_add<uint16_t, sub_incrementer>),
148+
Case("Test atomic sub 32-bit", test_atomic_add<uint32_t, sub_incrementer>),
149+
Case("Test atomic sub 64-bit", test_atomic_add<uint64_t, sub_incrementer>),
150+
Case("Test atomic bitops 8-bit", test_atomic_add<uint8_t, bitops_incrementer>),
151+
Case("Test atomic bitops 16-bit", test_atomic_add<uint16_t, bitops_incrementer>),
152+
Case("Test atomic bitops 32-bit", test_atomic_add<uint32_t, bitops_incrementer>),
153+
Case("Test atomic bitops 64-bit", test_atomic_add<uint64_t, bitops_incrementer>),
154+
Case("Test atomic compare exchange weak 8-bit", test_atomic_add<uint8_t, weak_incrementer>),
155+
Case("Test atomic compare exchange weak 16-bit", test_atomic_add<uint16_t, weak_incrementer>),
156+
Case("Test atomic compare exchange weak 32-bit", test_atomic_add<uint32_t, weak_incrementer>),
157+
Case("Test atomic compare exchange weak 64-bit", test_atomic_add<uint64_t, weak_incrementer>),
158+
Case("Test atomic compare exchange strong 8-bit", test_atomic_add<uint8_t, strong_incrementer>),
159+
Case("Test atomic compare exchange strong 16-bit", test_atomic_add<uint16_t, strong_incrementer>),
160+
Case("Test atomic compare exchange strong 32-bit", test_atomic_add<uint32_t, strong_incrementer>),
161+
Case("Test atomic compare exchange strong 64-bit", test_atomic_add<uint64_t, strong_incrementer>)
162+
};
163+
164+
utest::v1::Specification specification(test_setup, cases);
165+
166+
int main()
167+
{
168+
return !utest::v1::Harness::run(specification);
169+
}

0 commit comments

Comments
 (0)