Skip to content

Rework RTOS mutex tests #3786

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

Merged
merged 1 commit into from
Feb 21, 2017
Merged
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
220 changes: 171 additions & 49 deletions TESTS/mbedmicro-rtos-mbed/mutex/main.cpp
Original file line number Diff line number Diff line change
@@ -1,54 +1,31 @@
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "rtos.h"

#if defined(MBED_RTOS_SINGLE_THREAD)
#error [NOT_SUPPORTED] test not supported
#endif

#define THREAD_DELAY 50
#define SIGNALS_TO_EMIT 100
using namespace utest::v1;

/*
* The stack size is defined in cmsis_os.h mainly dependent on the underlying toolchain and
* the C standard library. For GCC, ARM_STD and IAR it is defined with a size of 2048 bytes
* and for ARM_MICRO 512. Because of reduce RAM size some targets need a reduced stacksize.
*/
#if defined(TARGET_STM32F334R8) && defined(TOOLCHAIN_IAR)
#define STACK_SIZE DEFAULT_STACK_SIZE/4
#elif defined(TARGET_STM32F070RB)
#define STACK_SIZE DEFAULT_STACK_SIZE/2
#elif defined(TARGET_STM32F072RB)
#define STACK_SIZE DEFAULT_STACK_SIZE/2
#elif defined(TARGET_STM32F302R8) && defined(TOOLCHAIN_IAR)
#define STACK_SIZE DEFAULT_STACK_SIZE/2
#elif defined(TARGET_STM32F303K8) && defined(TOOLCHAIN_IAR)
#define STACK_SIZE DEFAULT_STACK_SIZE/2
#elif defined(TARGET_STM32L073RZ)
#define STACK_SIZE DEFAULT_STACK_SIZE/2
#elif (defined(TARGET_EFM32HG_STK3400)) && !defined(TOOLCHAIN_ARM_MICRO)
#define STACK_SIZE 512
#elif (defined(TARGET_EFM32LG_STK3600) || defined(TARGET_EFM32WG_STK3800) || defined(TARGET_EFM32PG_STK3401)) && !defined(TOOLCHAIN_ARM_MICRO)
#define STACK_SIZE 768
#elif (defined(TARGET_EFM32GG_STK3700)) && !defined(TOOLCHAIN_ARM_MICRO)
#define STACK_SIZE 1536
#elif (defined(TARGET_EFR32)) && !defined(TOOLCHAIN_ARM_MICRO)
#define STACK_SIZE 768
#elif defined(TARGET_MCU_NRF51822) || defined(TARGET_MCU_NRF52832)
#define STACK_SIZE 1024
#elif defined(TARGET_XDOT_L151CC)
#define STACK_SIZE 1024
#else
#define STACK_SIZE DEFAULT_STACK_SIZE
#endif
#define TEST_STACK_SIZE 512

void print_char(char c = '*') {
printf("%c", c);
fflush(stdout);
}
#define TEST_ONE_SEC_MS (1000)
#define TEST_HALF_SEC_MS (500)
#define TEST_HALF_SEC_US (500000)
#define TEST_ONE_MS_US (1000)

#define THREAD_DELAY 50
#define SIGNALS_TO_EMIT 100

Mutex stdio_mutex;
DigitalOut led(LED1);

volatile int change_counter = 0;
volatile bool changing_counter = false;
Expand All @@ -57,23 +34,20 @@ volatile bool mutex_defect = false;
bool manipulate_protected_zone(const int thread_delay) {
bool result = true;

stdio_mutex.lock(); // LOCK
osStatus stat = stdio_mutex.lock();
TEST_ASSERT_EQUAL(stat, osOK);
if (changing_counter == true) {
// 'e' stands for error. If changing_counter is true access is not exclusively
print_char('e');
result = false;
mutex_defect = true;
}
changing_counter = true;

// Some action on protected
led = !led;
change_counter++;
print_char('.');
Thread::wait(thread_delay);

changing_counter = false;
stdio_mutex.unlock(); // UNLOCK
stat = stdio_mutex.unlock();
TEST_ASSERT_EQUAL(stat, osOK);
return result;
}

Expand All @@ -83,14 +57,14 @@ void test_thread(int const *thread_delay) {
}
}

int main() {
GREENTEA_SETUP(20, "default_auto");

void test_multiple_threads(void)
{
const int t1_delay = THREAD_DELAY * 1;
const int t2_delay = THREAD_DELAY * 2;
const int t3_delay = THREAD_DELAY * 3;
Thread t2(osPriorityNormal, STACK_SIZE);
Thread t3(osPriorityNormal, STACK_SIZE);

Thread t2(osPriorityNormal, TEST_STACK_SIZE);
Thread t3(osPriorityNormal, TEST_STACK_SIZE);

t2.start(callback(test_thread, &t2_delay));
t3.start(callback(test_thread, &t3_delay));
Expand All @@ -99,14 +73,162 @@ int main() {
// Thread 1 action
Thread::wait(t1_delay);
manipulate_protected_zone(t1_delay);

if (change_counter >= SIGNALS_TO_EMIT or mutex_defect == true) {
t2.terminate();
t3.terminate();
break;
}
}

fflush(stdout);
GREENTEA_TESTSUITE_RESULT(!mutex_defect);
return 0;
TEST_ASSERT_EQUAL(mutex_defect, false);
}

void test_dual_thread_nolock_lock_thread(Mutex *mutex)
{
bool stat_b = mutex->trylock();
TEST_ASSERT_EQUAL(stat_b, true);

osStatus stat = mutex->unlock();
TEST_ASSERT_EQUAL(stat, osOK);
}

void test_dual_thread_nolock_trylock_thread(Mutex *mutex)
{
bool stat_b = mutex->trylock();
TEST_ASSERT_EQUAL(stat_b, true);

osStatus stat = mutex->unlock();
TEST_ASSERT_EQUAL(stat, osOK);
}

template <void (*F)(Mutex *)>
void test_dual_thread_nolock(void)
{
Mutex mutex;
Thread thread;

thread.start(callback(F, &mutex));

wait_us(TEST_HALF_SEC_MS);
}

void test_dual_thread_lock_unlock_thread(Mutex *mutex)
{
osStatus stat = mutex->lock(osWaitForever);
TEST_ASSERT_EQUAL(stat, osOK);
}

void test_dual_thread_lock_unlock(void)
{
Mutex mutex;
osStatus stat;
Thread thread(osPriorityNormal, TEST_STACK_SIZE);

stat = mutex.lock();
TEST_ASSERT_EQUAL(stat, osOK);

thread.start(callback(test_dual_thread_lock_unlock_thread, &mutex));

stat = mutex.unlock();
TEST_ASSERT_EQUAL(stat, osOK);

wait_us(TEST_HALF_SEC_MS);
}

void test_dual_thread_lock_trylock_thread(Mutex *mutex)
{
bool stat = mutex->trylock();
TEST_ASSERT_EQUAL(stat, false);
}

void test_dual_thread_lock_lock_thread(Mutex *mutex)
{
uint32_t start = us_ticker_read();

osStatus stat = mutex->lock(TEST_HALF_SEC_MS);
TEST_ASSERT_EQUAL(stat, osEventTimeout);
TEST_ASSERT_UINT32_WITHIN(TEST_ONE_MS_US, TEST_HALF_SEC_US, us_ticker_read() - start);
}

template <void (*F)(Mutex *)>
void test_dual_thread_lock(void)
{
Mutex mutex;
osStatus stat;
Thread thread(osPriorityNormal, TEST_STACK_SIZE);

stat = mutex.lock();
TEST_ASSERT_EQUAL(stat, osOK);

thread.start(callback(F, &mutex));

wait_us(TEST_ONE_SEC_MS);

stat = mutex.unlock();
TEST_ASSERT_EQUAL(stat, osOK);
}

void test_single_thread_lock_recursive(void)
{
Mutex mutex;
osStatus stat;

stat = mutex.lock();
TEST_ASSERT_EQUAL(stat, osOK);

stat = mutex.lock();
TEST_ASSERT_EQUAL(stat, osOK);

stat = mutex.unlock();
TEST_ASSERT_EQUAL(stat, osOK);

stat = mutex.unlock();
TEST_ASSERT_EQUAL(stat, osOK);
}

void test_single_thread_trylock(void)
{
Mutex mutex;

bool stat_b = mutex.trylock();
TEST_ASSERT_EQUAL(stat_b, true);

osStatus stat = mutex.unlock();
TEST_ASSERT_EQUAL(stat, osOK);
}

void test_single_thread_lock(void)
{
Mutex mutex;
osStatus stat;

stat = mutex.lock();
TEST_ASSERT_EQUAL(stat, osOK);

stat = mutex.unlock();
TEST_ASSERT_EQUAL(stat, osOK);
}

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

Case cases[] = {
Case("Test single thread lock", test_single_thread_lock),
Case("Test single thread trylock", test_single_thread_trylock),
Case("Test single thread lock recursive", test_single_thread_lock_recursive),
Case("Test dual thread lock locked", test_dual_thread_lock<test_dual_thread_lock_lock_thread>),
Case("Test dual thread trylock locked", test_dual_thread_lock<test_dual_thread_lock_trylock_thread>),
Case("Test dual thread lock unlock", test_dual_thread_lock_unlock),
Case("Test dual thread second thread lock", test_dual_thread_nolock<test_dual_thread_nolock_lock_thread>),
Case("Test dual thread second thread trylock", test_dual_thread_nolock<test_dual_thread_nolock_trylock_thread>),
Case("Test multiple thread", test_multiple_threads),
};

Specification specification(test_setup, cases);

int main() {
return !Harness::run(specification);
}