Skip to content

Commit

Permalink
Merge pull request #10147 from kjbracey-arm/atomic_bitwise
Browse files Browse the repository at this point in the history
Assembler atomics
  • Loading branch information
0xc0170 authored May 13, 2019
2 parents 1aa95c0 + 2bb4045 commit 3ea1c56
Show file tree
Hide file tree
Showing 48 changed files with 2,924 additions and 1,241 deletions.
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

0 comments on commit 3ea1c56

Please sign in to comment.