Rework RTOS mutex tests

pull/3786/head
Bartek Szatkowski 2017-02-15 19:59:26 +00:00
parent 21b91c794e
commit 9377fa97c9
1 changed files with 171 additions and 49 deletions
TESTS/mbedmicro-rtos-mbed/mutex

View File

@ -1,54 +1,31 @@
#include "mbed.h" #include "mbed.h"
#include "greentea-client/test_env.h" #include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "rtos.h" #include "rtos.h"
#if defined(MBED_RTOS_SINGLE_THREAD) #if defined(MBED_RTOS_SINGLE_THREAD)
#error [NOT_SUPPORTED] test not supported #error [NOT_SUPPORTED] test not supported
#endif #endif
#define THREAD_DELAY 50 using namespace utest::v1;
#define SIGNALS_TO_EMIT 100
/* /*
* The stack size is defined in cmsis_os.h mainly dependent on the underlying toolchain and * 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 * 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. * and for ARM_MICRO 512. Because of reduce RAM size some targets need a reduced stacksize.
*/ */
#if defined(TARGET_STM32F334R8) && defined(TOOLCHAIN_IAR) #define TEST_STACK_SIZE 512
#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
void print_char(char c = '*') { #define TEST_ONE_SEC_MS (1000)
printf("%c", c); #define TEST_HALF_SEC_MS (500)
fflush(stdout); #define TEST_HALF_SEC_US (500000)
} #define TEST_ONE_MS_US (1000)
#define THREAD_DELAY 50
#define SIGNALS_TO_EMIT 100
Mutex stdio_mutex; Mutex stdio_mutex;
DigitalOut led(LED1);
volatile int change_counter = 0; volatile int change_counter = 0;
volatile bool changing_counter = false; volatile bool changing_counter = false;
@ -57,23 +34,20 @@ volatile bool mutex_defect = false;
bool manipulate_protected_zone(const int thread_delay) { bool manipulate_protected_zone(const int thread_delay) {
bool result = true; bool result = true;
stdio_mutex.lock(); // LOCK osStatus stat = stdio_mutex.lock();
TEST_ASSERT_EQUAL(stat, osOK);
if (changing_counter == true) { if (changing_counter == true) {
// 'e' stands for error. If changing_counter is true access is not exclusively
print_char('e');
result = false; result = false;
mutex_defect = true; mutex_defect = true;
} }
changing_counter = true; changing_counter = true;
// Some action on protected
led = !led;
change_counter++; change_counter++;
print_char('.');
Thread::wait(thread_delay); Thread::wait(thread_delay);
changing_counter = false; changing_counter = false;
stdio_mutex.unlock(); // UNLOCK stat = stdio_mutex.unlock();
TEST_ASSERT_EQUAL(stat, osOK);
return result; return result;
} }
@ -83,14 +57,14 @@ void test_thread(int const *thread_delay) {
} }
} }
int main() { void test_multiple_threads(void)
GREENTEA_SETUP(20, "default_auto"); {
const int t1_delay = THREAD_DELAY * 1; const int t1_delay = THREAD_DELAY * 1;
const int t2_delay = THREAD_DELAY * 2; const int t2_delay = THREAD_DELAY * 2;
const int t3_delay = THREAD_DELAY * 3; 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)); t2.start(callback(test_thread, &t2_delay));
t3.start(callback(test_thread, &t3_delay)); t3.start(callback(test_thread, &t3_delay));
@ -99,6 +73,7 @@ int main() {
// Thread 1 action // Thread 1 action
Thread::wait(t1_delay); Thread::wait(t1_delay);
manipulate_protected_zone(t1_delay); manipulate_protected_zone(t1_delay);
if (change_counter >= SIGNALS_TO_EMIT or mutex_defect == true) { if (change_counter >= SIGNALS_TO_EMIT or mutex_defect == true) {
t2.terminate(); t2.terminate();
t3.terminate(); t3.terminate();
@ -106,7 +81,154 @@ int main() {
} }
} }
fflush(stdout); TEST_ASSERT_EQUAL(mutex_defect, false);
GREENTEA_TESTSUITE_RESULT(!mutex_defect); }
return 0;
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);
} }