Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assembler atomics #10147

Merged
merged 4 commits into from
May 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions TESTS/mbed_platform/atomic/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest/utest.h"

#if !MBED_CONF_RTOS_PRESENT
#error [NOT_SUPPORTED] test not supported
#endif

#define THREAD_STACK 512

using utest::v1::Case;


namespace {

/* Lock-free operations will be much faster - keep runtime down */
#if MBED_ATOMIC_INT_LOCK_FREE
#define ADD_ITERATIONS (SystemCoreClock / 1000)
#else
#define ADD_ITERATIONS (SystemCoreClock / 8000)
#endif

template <typename T>
void add_incrementer(T *ptr)
{
for (long i = ADD_ITERATIONS; i > 0; i--) {
core_util_atomic_fetch_add(ptr, T(1));
}
}

template <typename T>
void add_release_incrementer(T *ptr)
{
for (long i = ADD_ITERATIONS; i > 0; i--) {
core_util_atomic_fetch_add_explicit(ptr, T(1), mbed_memory_order_release);
}
}

template <typename T>
void sub_incrementer(T *ptr)
{
for (long i = ADD_ITERATIONS; i > 0; i--) {
core_util_atomic_fetch_sub(ptr, T(-1));
}
}

template <typename T>
void bitops_incrementer(T *ptr)
{
for (long i = ADD_ITERATIONS; i > 0; i--) {
core_util_atomic_fetch_add(ptr, T(1));
core_util_atomic_fetch_and(ptr, T(-1));
core_util_atomic_fetch_or(ptr, T(0));
}
}

template <typename T>
void weak_incrementer(T *ptr)
{
for (long i = ADD_ITERATIONS; i > 0; i--) {
T val = core_util_atomic_load(ptr);
do {
} while (!core_util_atomic_compare_exchange_weak(ptr, &val, T(val + 1)));
}
}

template <typename T>
void strong_incrementer(T *ptr)
{
for (long i = ADD_ITERATIONS; i > 0; i--) {
T val = core_util_atomic_load(ptr);
do {
} while (!core_util_atomic_compare_exchange_strong(ptr, &val, T(val + 1)));
}
}


/*
* Run multiple threads incrementing each data item
* ADD_ITERATIONS times, and at the end, check that
* each item is <number of threads> * ADD_ITERATIONS.
* Items are adjacent to catch any interference.
*
* Using core_util_atomic_ templates, and exercising
* load and store briefly.
*/
template<typename T, void (*Fn)(T *)>
void test_atomic_add()
{
struct {
volatile T nonatomic1;
T atomic1;
T atomic2;
volatile T nonatomic2;
} data;

data.nonatomic1 = 0;
core_util_atomic_store(&data.atomic1, T(0));
core_util_atomic_store(&data.atomic2, T(0));
data.nonatomic2 = 0;

Thread t1(osPriorityNormal, THREAD_STACK);
Thread t2(osPriorityNormal, THREAD_STACK);
Thread t3(osPriorityNormal, THREAD_STACK);
Thread t4(osPriorityNormal, THREAD_STACK);

TEST_ASSERT_EQUAL(osOK, t1.start(callback(Fn, &data.atomic1)));
TEST_ASSERT_EQUAL(osOK, t2.start(callback(Fn, &data.atomic1)));
TEST_ASSERT_EQUAL(osOK, t3.start(callback(Fn, &data.atomic2)));
TEST_ASSERT_EQUAL(osOK, t4.start(callback(Fn, &data.atomic2)));

for (long i = ADD_ITERATIONS; i > 0; i--) {
data.nonatomic1++;
data.nonatomic2++;
}

t1.join();
t2.join();
t3.join();
t4.join();

TEST_ASSERT_EQUAL(T(ADD_ITERATIONS), data.nonatomic1);
TEST_ASSERT_EQUAL(T(2 * ADD_ITERATIONS), core_util_atomic_load(&data.atomic1));
TEST_ASSERT_EQUAL(T(2 * ADD_ITERATIONS), core_util_atomic_load(&data.atomic2));
TEST_ASSERT_EQUAL(T(ADD_ITERATIONS), data.nonatomic2);
}

} // namespace

utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(30, "default_auto");
return utest::v1::verbose_test_setup_handler(number_of_cases);
}

Case cases[] = {
Case("Test atomic add 8-bit", test_atomic_add<uint8_t, add_incrementer>),
Case("Test atomic add 16-bit", test_atomic_add<uint16_t, add_incrementer>),
Case("Test atomic add 32-bit", test_atomic_add<uint32_t, add_incrementer>),
Case("Test atomic add 64-bit", test_atomic_add<uint64_t, add_incrementer>),
Case("Test atomic add signed 8-bit", test_atomic_add<int8_t, add_incrementer>),
Case("Test atomic add signed 16-bit", test_atomic_add<int16_t, add_incrementer>),
Case("Test atomic add signed 32-bit", test_atomic_add<int32_t, add_incrementer>),
Case("Test atomic add signed 64-bit", test_atomic_add<int64_t, add_incrementer>),
Case("Test atomic add release 32-bit", test_atomic_add<uint32_t, add_release_incrementer>),
Case("Test atomic sub 8-bit", test_atomic_add<uint8_t, sub_incrementer>),
Case("Test atomic sub 16-bit", test_atomic_add<uint16_t, sub_incrementer>),
Case("Test atomic sub 32-bit", test_atomic_add<uint32_t, sub_incrementer>),
Case("Test atomic sub 64-bit", test_atomic_add<uint64_t, sub_incrementer>),
Case("Test atomic bitops 8-bit", test_atomic_add<uint8_t, bitops_incrementer>),
Case("Test atomic bitops 16-bit", test_atomic_add<uint16_t, bitops_incrementer>),
Case("Test atomic bitops 32-bit", test_atomic_add<uint32_t, bitops_incrementer>),
Case("Test atomic bitops 64-bit", test_atomic_add<uint64_t, bitops_incrementer>),
Case("Test atomic compare exchange weak 8-bit", test_atomic_add<uint8_t, weak_incrementer>),
Case("Test atomic compare exchange weak 16-bit", test_atomic_add<uint16_t, weak_incrementer>),
Case("Test atomic compare exchange weak 32-bit", test_atomic_add<uint32_t, weak_incrementer>),
Case("Test atomic compare exchange weak 64-bit", test_atomic_add<uint64_t, weak_incrementer>),
Case("Test atomic compare exchange strong 8-bit", test_atomic_add<uint8_t, strong_incrementer>),
Case("Test atomic compare exchange strong 16-bit", test_atomic_add<uint16_t, strong_incrementer>),
Case("Test atomic compare exchange strong 32-bit", test_atomic_add<uint32_t, strong_incrementer>),
Case("Test atomic compare exchange strong 64-bit", test_atomic_add<uint64_t, strong_incrementer>)
};

utest::v1::Specification specification(test_setup, cases);

int main()
{
return !utest::v1::Harness::run(specification);
}
35 changes: 16 additions & 19 deletions TESTS/mbed_platform/critical_section/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
using utest::v1::Case;


volatile bool callback_called;
bool callback_called;

void tiemout_callback(void)
{
callback_called = true;
core_util_atomic_store(&callback_called, true);
}

template<int N>
Expand All @@ -49,7 +49,7 @@ void critical_section_raii_recursive(Timeout &timeout)
wait_us(wait_time_us);
}
TEST_ASSERT_TRUE(core_util_in_critical_section());
TEST_ASSERT_FALSE(callback_called);
TEST_ASSERT_FALSE(core_util_atomic_load(&callback_called));
}


Expand Down Expand Up @@ -82,31 +82,30 @@ void test_C_API(void)

TEST_ASSERT_FALSE(core_util_in_critical_section());

callback_called = false;
core_util_atomic_store(&callback_called, false);
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
wait_us(wait_time_us);
TEST_ASSERT_TRUE(callback_called);
TEST_ASSERT_TRUE(core_util_atomic_exchange(&callback_called, false));

for (int i = 0; i < N; i++) {
core_util_critical_section_enter();
TEST_ASSERT_TRUE(core_util_in_critical_section());
}

callback_called = false;
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
wait_us(wait_time_us);
TEST_ASSERT_FALSE(callback_called);
TEST_ASSERT_FALSE(core_util_atomic_load(&callback_called));
TEST_ASSERT_TRUE(core_util_in_critical_section());

for (int i = 0; i < N - 1; i++) {
core_util_critical_section_exit();
TEST_ASSERT_TRUE(core_util_in_critical_section());
TEST_ASSERT_FALSE(callback_called);
TEST_ASSERT_FALSE(core_util_atomic_load(&callback_called));
}

core_util_critical_section_exit();
TEST_ASSERT_FALSE(core_util_in_critical_section());
TEST_ASSERT_TRUE(callback_called);
TEST_ASSERT_TRUE(core_util_atomic_load(&callback_called));
}

/** Template for tests
Expand Down Expand Up @@ -138,16 +137,15 @@ void test_CPP_API_constructor_destructor(void)

TEST_ASSERT_FALSE(core_util_in_critical_section());

callback_called = false;
core_util_atomic_store(&callback_called, false);
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
wait_us(wait_time_us);
TEST_ASSERT_TRUE(callback_called);
TEST_ASSERT_TRUE(core_util_atomic_exchange(&callback_called, false));

callback_called = false;
critical_section_raii_recursive<N>(timeout);

TEST_ASSERT_FALSE(core_util_in_critical_section());
TEST_ASSERT_TRUE(callback_called);
TEST_ASSERT_TRUE(core_util_atomic_load(&callback_called));
}

/** Template for tests
Expand Down Expand Up @@ -179,31 +177,30 @@ void test_CPP_API_enable_disable(void)

TEST_ASSERT_FALSE(core_util_in_critical_section());

callback_called = false;
core_util_atomic_store(&callback_called, false);
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
wait_us(wait_time_us);
TEST_ASSERT_TRUE(callback_called);
TEST_ASSERT_TRUE(core_util_atomic_exchange(&callback_called, false));

for (int i = 0; i < N; i++) {
CriticalSectionLock::enable();
TEST_ASSERT_TRUE(core_util_in_critical_section());
}

callback_called = false;
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
wait_us(wait_time_us);
TEST_ASSERT_FALSE(callback_called);
TEST_ASSERT_FALSE(core_util_atomic_load(&callback_called));
TEST_ASSERT_TRUE(core_util_in_critical_section());

for (int i = 0; i < N - 1; i++) {
CriticalSectionLock::disable();
TEST_ASSERT_TRUE(core_util_in_critical_section());
TEST_ASSERT_FALSE(callback_called);
TEST_ASSERT_FALSE(core_util_atomic_load(&callback_called));
}

CriticalSectionLock::disable();
TEST_ASSERT_FALSE(core_util_in_critical_section());
TEST_ASSERT_TRUE(callback_called);
TEST_ASSERT_TRUE(core_util_atomic_load(&callback_called));
}


Expand Down
2 changes: 1 addition & 1 deletion UNITTESTS/features/lorawan/lorawanstack/unittest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ set(unittest-test-sources
stubs/LoRaPHY_stub.cpp
stubs/LoRaMac_stub.cpp
stubs/mbed_assert_stub.c
stubs/mbed_critical_stub.c
stubs/mbed_atomic_stub.c
stubs/LoRaMacCrypto_stub.cpp
stubs/LoRaMacChannelPlan_stub.cpp
stubs/LoRaWANTimer_stub.cpp
Expand Down
1 change: 1 addition & 0 deletions UNITTESTS/features/netsocket/DTLSSocket/unittest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ set(unittest-test-sources
features/netsocket/DTLSSocket/test_DTLSSocket.cpp
stubs/Mutex_stub.cpp
stubs/mbed_assert_stub.c
stubs/mbed_atomic_stub.c
stubs/mbed_critical_stub.c
stubs/equeue_stub.c
../features/nanostack/coap-service/test/coap-service/unittest/stub/mbedtls_stub.c
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ set(unittest-test-sources
features/netsocket/DTLSSocketWrapper/test_DTLSSocketWrapper.cpp
stubs/Mutex_stub.cpp
stubs/mbed_assert_stub.c
stubs/mbed_atomic_stub.c
stubs/mbed_critical_stub.c
stubs/equeue_stub.c
../features/nanostack/coap-service/test/coap-service/unittest/stub/mbedtls_stub.c
Expand Down
1 change: 1 addition & 0 deletions UNITTESTS/features/netsocket/InternetSocket/unittest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ set(unittest-test-sources
features/netsocket/InternetSocket/test_InternetSocket.cpp
stubs/Mutex_stub.cpp
stubs/mbed_assert_stub.c
stubs/mbed_atomic_stub.c
stubs/mbed_critical_stub.c
stubs/equeue_stub.c
stubs/EventQueue_stub.cpp
Expand Down
1 change: 1 addition & 0 deletions UNITTESTS/features/netsocket/TCPServer/unittest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ set(unittest-sources
set(unittest-test-sources
stubs/Mutex_stub.cpp
stubs/mbed_assert_stub.c
stubs/mbed_atomic_stub.c
stubs/mbed_critical_stub.c
stubs/equeue_stub.c
stubs/EventQueue_stub.cpp
Expand Down
1 change: 1 addition & 0 deletions UNITTESTS/features/netsocket/TCPSocket/unittest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ set(unittest-test-sources
features/netsocket/TCPSocket/test_TCPSocket.cpp
stubs/Mutex_stub.cpp
stubs/mbed_assert_stub.c
stubs/mbed_atomic_stub.c
stubs/mbed_critical_stub.c
stubs/equeue_stub.c
stubs/EventQueue_stub.cpp
Expand Down
1 change: 1 addition & 0 deletions UNITTESTS/features/netsocket/TLSSocket/unittest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ set(unittest-test-sources
features/netsocket/TLSSocket/test_TLSSocket.cpp
stubs/Mutex_stub.cpp
stubs/mbed_assert_stub.c
stubs/mbed_atomic_stub.c
stubs/mbed_critical_stub.c
stubs/equeue_stub.c
../features/nanostack/coap-service/test/coap-service/unittest/stub/mbedtls_stub.c
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ set(unittest-test-sources
features/netsocket/TLSSocketWrapper/test_TLSSocketWrapper.cpp
stubs/Mutex_stub.cpp
stubs/mbed_assert_stub.c
stubs/mbed_atomic_stub.c
stubs/mbed_critical_stub.c
stubs/equeue_stub.c
../features/nanostack/coap-service/test/coap-service/unittest/stub/mbedtls_stub.c
Expand Down
1 change: 1 addition & 0 deletions UNITTESTS/features/netsocket/UDPSocket/unittest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ set(unittest-test-sources
features/netsocket/UDPSocket/test_UDPSocket.cpp
stubs/Mutex_stub.cpp
stubs/mbed_assert_stub.c
stubs/mbed_atomic_stub.c
stubs/mbed_critical_stub.c
stubs/equeue_stub.c
stubs/EventQueue_stub.cpp
Expand Down
Loading