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

Add Atomic<T> template #10274

Merged
merged 7 commits into from
Jul 12, 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
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