diff --git a/TESTS/mbedmicro-rtos-mbed/mutex/main.cpp b/TESTS/mbedmicro-rtos-mbed/mutex/main.cpp index 5026f0534b6..6fa2efaec36 100644 --- a/TESTS/mbedmicro-rtos-mbed/mutex/main.cpp +++ b/TESTS/mbedmicro-rtos-mbed/mutex/main.cpp @@ -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; @@ -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; } @@ -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)); @@ -99,6 +73,7 @@ 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(); @@ -106,7 +81,154 @@ int main() { } } - 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 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 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), + Case("Test dual thread trylock locked", test_dual_thread_lock), + Case("Test dual thread lock unlock", test_dual_thread_lock_unlock), + Case("Test dual thread second thread lock", test_dual_thread_nolock), + Case("Test dual thread second thread trylock", test_dual_thread_nolock), + Case("Test multiple thread", test_multiple_threads), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); }