Skip to content

Commit

Permalink
Merge pull request #10274 from kjbracey-arm/atomic_template
Browse files Browse the repository at this point in the history
Add Atomic<T> template
  • Loading branch information
kjbracey authored Jul 12, 2019
2 parents 0f39f01 + c9faf24 commit d53bd61
Show file tree
Hide file tree
Showing 8 changed files with 1,650 additions and 193 deletions.
222 changes: 157 additions & 65 deletions TESTS/mbed_platform/atomic/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,69 +26,84 @@

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
#define ADD_UNLOCKED_ITERATIONS (SystemCoreClock / 1000)
#define ADD_LOCKED_ITERATIONS (SystemCoreClock / 8000)

template <typename T>
void add_incrementer(T *ptr)
template <typename A>
static inline long add_iterations(A &a)
{
for (long i = ADD_ITERATIONS; i > 0; i--) {
core_util_atomic_fetch_add(ptr, T(1));
}
return a.is_lock_free() ? ADD_UNLOCKED_ITERATIONS : ADD_LOCKED_ITERATIONS;
}

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 A>
struct add_incrementer {
static void op(A *ptr)
{
for (long i = add_iterations(*ptr); i > 0; i--) {
++(*ptr);
}
}
}
};

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 A>
struct add_release_incrementer {
static void op(A *ptr)
{
for (long i = add_iterations(*ptr); i > 0; i--) {
ptr->fetch_add(1, mbed::memory_order_release);
}
}
}
};

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 A>
struct sub_incrementer {
static void op(A *ptr)
{
for (long i = add_iterations(*ptr); i > 0; i--) {
ptr->fetch_sub(-1);
}
}
}
};

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 A>
struct bitops_incrementer {
static void op(A *ptr)
{
for (long i = add_iterations(*ptr); i > 0; i--) {
(*ptr) += 1;
(*ptr) &= -1;
(*ptr) |= 0;
}
}
}
};

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)));
template <typename A>
struct weak_incrementer {
static void op(A *ptr)
{
for (long i = add_iterations(*ptr); i > 0; i--) {
typename A::value_type val = ptr->load();
do {
} while (!ptr->compare_exchange_weak(val, val + 1));
}
}
}
};

template <typename A>
struct strong_incrementer {
static void op(A *ptr)
{
for (long i = add_iterations(*ptr); i > 0; i--) {
typename A::value_type val = ptr->load();
do {
} while (!ptr->compare_exchange_strong(val, val + 1));
}
}
};



/*
Expand All @@ -100,32 +115,34 @@ void strong_incrementer(T *ptr)
* Using core_util_atomic_ templates, and exercising
* load and store briefly.
*/
template<typename T, void (*Fn)(T *)>
template<typename T, template<typename A> class Fn>
void test_atomic_add()
{
struct {
volatile T nonatomic1;
T atomic1;
T atomic2;
Atomic<T> atomic1;
volatile Atomic<T> atomic2; // use volatile just to exercise the templates' volatile methods
volatile T nonatomic2;
} data;
} data = { 0, { 0 }, { 1 }, 0 }; // test initialisation

TEST_ASSERT_EQUAL(sizeof(T), sizeof data.nonatomic1);
TEST_ASSERT_EQUAL(sizeof(T), sizeof data.atomic1);
TEST_ASSERT_EQUAL(4 * sizeof(T), sizeof data);

data.nonatomic1 = 0;
core_util_atomic_store(&data.atomic1, T(0));
core_util_atomic_store(&data.atomic2, T(0));
data.nonatomic2 = 0;
// test store
data.atomic2 = 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)));
TEST_ASSERT_EQUAL(osOK, t1.start(callback(Fn<decltype(data.atomic1)>::op, &data.atomic1)));
TEST_ASSERT_EQUAL(osOK, t2.start(callback(Fn<decltype(data.atomic1)>::op, &data.atomic1)));
TEST_ASSERT_EQUAL(osOK, t3.start(callback(Fn<decltype(data.atomic2)>::op, &data.atomic2)));
TEST_ASSERT_EQUAL(osOK, t4.start(callback(Fn<decltype(data.atomic2)>::op, &data.atomic2)));

for (long i = ADD_ITERATIONS; i > 0; i--) {
for (long i = ADD_UNLOCKED_ITERATIONS; i > 0; i--) {
data.nonatomic1++;
data.nonatomic2++;
}
Expand All @@ -135,10 +152,83 @@ void test_atomic_add()
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);
TEST_ASSERT_EQUAL(T(ADD_UNLOCKED_ITERATIONS), data.nonatomic1);
TEST_ASSERT_EQUAL(T(2 * add_iterations(data.atomic1)), data.atomic1);
TEST_ASSERT_EQUAL(T(2 * add_iterations(data.atomic2)), data.atomic2);
TEST_ASSERT_EQUAL(T(ADD_UNLOCKED_ITERATIONS), data.nonatomic2);
}

// This should fit into a uint32_t container, and there
// will be 1 byte of padding to ignore.
struct small {
uint8_t a;
uint8_t b;
uint8_t c;
};

// An 11-byte weird structure. Should work with critical sections.
struct large {
uint8_t a;
uint8_t b;
uint8_t c;
uint8_t dummy[8];
};

template<typename A>
void struct_incrementer_a(A *data)
{
for (long i = add_iterations(*data); i > 0; i--) {
typename A::value_type curval = *data, newval;
do {
newval = curval;
newval.a++;
} while (!data->compare_exchange_weak(curval, newval));
}
}

template<typename A>
void struct_incrementer_b(A *data)
{
for (long i = add_iterations(*data); i > 0; i--) {
typename A::value_type curval = *data, newval;
do {
newval = curval;
newval.b++;
} while (!data->compare_exchange_weak(curval, newval));
}
}

template<typename T, size_t N>
void test_atomic_struct()
{
TEST_ASSERT_EQUAL(N, sizeof(Atomic<T>));

// Small structures don't have value constructor implemented;
Atomic<T> data;
atomic_init(&data, T{0, 0, 0});

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

TEST_ASSERT_EQUAL(osOK, t1.start(callback(struct_incrementer_a<Atomic<T> >, &data)));
TEST_ASSERT_EQUAL(osOK, t2.start(callback(struct_incrementer_b<Atomic<T> >, &data)));

for (long i = add_iterations(data); i > 0; i--) {
T curval = data, newval;
do {
newval = curval;
newval.c++;
} while (!data.compare_exchange_weak(curval, newval));
}

t1.join();
t2.join();

T final_val = data;

TEST_ASSERT_EQUAL(uint8_t(add_iterations(data)), final_val.a);
TEST_ASSERT_EQUAL(uint8_t(add_iterations(data)), final_val.b);
TEST_ASSERT_EQUAL(uint8_t(add_iterations(data)), final_val.c);
}

} // namespace
Expand Down Expand Up @@ -174,7 +264,9 @@ Case cases[] = {
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>)
Case("Test atomic compare exchange strong 64-bit", test_atomic_add<uint64_t, strong_incrementer>),
Case("Test small atomic custom structure", test_atomic_struct<small, 4>),
Case("Test large atomic custom structure", test_atomic_struct<large, 11>)
};

utest::v1::Specification specification(test_setup, cases);
Expand Down
4 changes: 2 additions & 2 deletions UNITTESTS/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ project(${PROJECT_NAME})
macro(use_cxx14)
if (CMAKE_VERSION VERSION_LESS 3.1)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++98")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14")
endif()
else()
set(CMAKE_CXX_STANDARD 98)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
endmacro()
Expand Down
2 changes: 1 addition & 1 deletion UNITTESTS/stubs/ATHandler_stub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ int ATHandler_stub::int_count = kRead_int_table_size;
bool ATHandler_stub::process_oob_urc = false;

int ATHandler_stub::read_string_index = kRead_string_table_size;
const char *ATHandler_stub::read_string_table[kRead_string_table_size] = {'\0'};
const char *ATHandler_stub::read_string_table[kRead_string_table_size];
int ATHandler_stub::resp_stop_success_count = kResp_stop_count_default;

bool ATHandler_stub::get_debug_flag = false;
Expand Down
4 changes: 2 additions & 2 deletions features/cellular/framework/AT/AT_CellularSMS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const uint8_t SMS_MAX_GSM7_CONCATENATED_SINGLE_SMS_SIZE = 153;
#define NVAM '?' // Not Valid ascii, ISO-8859-1 mark

// mapping table from 7-bit GSM to ascii (ISO-8859-1)
static const char gsm_to_ascii[] = {
static const unsigned char gsm_to_ascii[] = {
64, // 0
163, // 1
36, // 2
Expand Down Expand Up @@ -1153,7 +1153,7 @@ uint16_t AT_CellularSMS::pack_7_bit_gsm_and_hex(const char *str, uint16_t len, c
char *gsm_str = new char[len];
for (uint16_t y = 0; y < len; y++) {
for (int x = 0; x < GSM_TO_ASCII_TABLE_SIZE; x++) {
if (gsm_to_ascii[x] == str[y]) {
if (gsm_to_ascii[x] == static_cast<unsigned char>(str[y])) {
gsm_str[y] = x;
}
}
Expand Down
2 changes: 1 addition & 1 deletion mbed.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
#include "drivers/InterruptIn.h"
#include "platform/mbed_wait_api.h"
#include "hal/sleep_api.h"
#include "platform/mbed_atomic.h"
#include "platform/Atomic.h"
#include "platform/mbed_power_mgmt.h"
#include "platform/mbed_rtc_time.h"
#include "platform/mbed_poll.h"
Expand Down
Loading

0 comments on commit d53bd61

Please sign in to comment.