mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			RTOS: Mutex: Rework tests
Add descriptions, fix small issues and timings.pull/4729/head
							parent
							
								
									aae62bd990
								
							
						
					
					
						commit
						01c0cfd4f8
					
				| 
						 | 
					@ -12,12 +12,8 @@ using namespace utest::v1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TEST_STACK_SIZE 512
 | 
					#define TEST_STACK_SIZE 512
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TEST_ONE_SEC_MS  (1000)
 | 
					#define TEST_LONG_DELAY 20
 | 
				
			||||||
#define TEST_HALF_SEC_MS (500)
 | 
					#define TEST_DELAY 10
 | 
				
			||||||
#define TEST_HALF_SEC_US (500000)
 | 
					 | 
				
			||||||
#define TEST_ONE_MS_US   (1000)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define THREAD_DELAY     50
 | 
					 | 
				
			||||||
#define SIGNALS_TO_EMIT 100
 | 
					#define SIGNALS_TO_EMIT 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Mutex stdio_mutex;
 | 
					Mutex stdio_mutex;
 | 
				
			||||||
| 
						 | 
					@ -26,11 +22,14 @@ volatile int change_counter = 0;
 | 
				
			||||||
volatile bool changing_counter = false;
 | 
					volatile bool changing_counter = false;
 | 
				
			||||||
volatile bool mutex_defect = false;
 | 
					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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    osStatus stat = stdio_mutex.lock();
 | 
					    osStatus stat = stdio_mutex.lock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    core_util_critical_section_enter();
 | 
				
			||||||
    if (changing_counter == true) {
 | 
					    if (changing_counter == true) {
 | 
				
			||||||
        result = false;
 | 
					        result = false;
 | 
				
			||||||
        mutex_defect = true;
 | 
					        mutex_defect = true;
 | 
				
			||||||
| 
						 | 
					@ -38,25 +37,37 @@ bool manipulate_protected_zone(const int thread_delay) {
 | 
				
			||||||
    changing_counter = true;
 | 
					    changing_counter = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    change_counter++;
 | 
					    change_counter++;
 | 
				
			||||||
 | 
					    core_util_critical_section_exit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Thread::wait(thread_delay);
 | 
					    Thread::wait(thread_delay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    core_util_critical_section_enter();
 | 
				
			||||||
    changing_counter = false;
 | 
					    changing_counter = false;
 | 
				
			||||||
 | 
					    core_util_critical_section_exit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = stdio_mutex.unlock();
 | 
					    stat = stdio_mutex.unlock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_thread(int const *thread_delay) {
 | 
					void test_thread(int const *thread_delay)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
    while (true) {
 | 
					    while (true) {
 | 
				
			||||||
        manipulate_protected_zone(*thread_delay);
 | 
					        manipulate_protected_zone(*thread_delay);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Test multiple thread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Given 3 threads started with different delays and a section protected with a mutex
 | 
				
			||||||
 | 
					    when each thread runs it tries to lock the mutex
 | 
				
			||||||
 | 
					    then no more than one thread should be able to access protected region
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
void test_multiple_threads(void)
 | 
					void test_multiple_threads(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const int t1_delay = THREAD_DELAY * 1;
 | 
					    const int t1_delay = TEST_DELAY * 1;
 | 
				
			||||||
    const int t2_delay = THREAD_DELAY * 2;
 | 
					    const int t2_delay = TEST_DELAY * 2;
 | 
				
			||||||
    const int t3_delay = THREAD_DELAY * 3;
 | 
					    const int t3_delay = TEST_DELAY * 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Thread t2(osPriorityNormal, TEST_STACK_SIZE);
 | 
					    Thread t2(osPriorityNormal, TEST_STACK_SIZE);
 | 
				
			||||||
    Thread t3(osPriorityNormal, TEST_STACK_SIZE);
 | 
					    Thread t3(osPriorityNormal, TEST_STACK_SIZE);
 | 
				
			||||||
| 
						 | 
					@ -69,34 +80,51 @@ void test_multiple_threads(void)
 | 
				
			||||||
        Thread::wait(t1_delay);
 | 
					        Thread::wait(t1_delay);
 | 
				
			||||||
        manipulate_protected_zone(t1_delay);
 | 
					        manipulate_protected_zone(t1_delay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        core_util_critical_section_enter();
 | 
				
			||||||
        if (change_counter >= SIGNALS_TO_EMIT or mutex_defect == true) {
 | 
					        if (change_counter >= SIGNALS_TO_EMIT or mutex_defect == true) {
 | 
				
			||||||
 | 
					            core_util_critical_section_exit();
 | 
				
			||||||
            t2.terminate();
 | 
					            t2.terminate();
 | 
				
			||||||
            t3.terminate();
 | 
					            t3.terminate();
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        core_util_critical_section_exit();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TEST_ASSERT_EQUAL(mutex_defect, false);
 | 
					    TEST_ASSERT_EQUAL(false, mutex_defect);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_dual_thread_nolock_lock_thread(Mutex *mutex)
 | 
					void test_dual_thread_nolock_lock_thread(Mutex *mutex)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    bool stat_b = mutex->trylock();
 | 
					    osStatus stat = mutex->lock(osWaitForever);
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat_b, true);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    osStatus stat = mutex->unlock();
 | 
					    stat = mutex->unlock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_dual_thread_nolock_trylock_thread(Mutex *mutex)
 | 
					void test_dual_thread_nolock_trylock_thread(Mutex *mutex)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    bool stat_b = mutex->trylock();
 | 
					    bool stat_b = mutex->trylock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat_b, true);
 | 
					    TEST_ASSERT_EQUAL(true, stat_b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    osStatus stat = mutex->unlock();
 | 
					    osStatus stat = mutex->unlock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Test dual thread no-lock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Test dual thread second thread lock
 | 
				
			||||||
 | 
					    Given two threads A & B and a mutex
 | 
				
			||||||
 | 
					    When thread A creates a mutex and starts thread B
 | 
				
			||||||
 | 
					        and thread B calls @a lock and @a unlock
 | 
				
			||||||
 | 
					    Then returned statuses are osOK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Test dual thread second thread trylock
 | 
				
			||||||
 | 
					    Given two threads A & B and a mutex
 | 
				
			||||||
 | 
					    When thread A creates a mutex and starts thread B
 | 
				
			||||||
 | 
					        and thread B calls @a trylock and @a unlock
 | 
				
			||||||
 | 
					    Then returned statuses are true and osOK
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
template <void (*F)(Mutex *)>
 | 
					template <void (*F)(Mutex *)>
 | 
				
			||||||
void test_dual_thread_nolock(void)
 | 
					void test_dual_thread_nolock(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -105,15 +133,24 @@ void test_dual_thread_nolock(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    thread.start(callback(F, &mutex));
 | 
					    thread.start(callback(F, &mutex));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wait_us(TEST_HALF_SEC_MS);
 | 
					    wait_ms(TEST_DELAY);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_dual_thread_lock_unlock_thread(Mutex *mutex)
 | 
					void test_dual_thread_lock_unlock_thread(Mutex *mutex)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    osStatus stat = mutex->lock(osWaitForever);
 | 
					    osStatus stat = mutex->lock(osWaitForever);
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Test dual thread lock unlock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Given two threads and a lock
 | 
				
			||||||
 | 
					    When thread A locks the lock and starts thread B
 | 
				
			||||||
 | 
					        and thread B calls @a lock on the mutex
 | 
				
			||||||
 | 
					    Then thread B waits for thread A to unlock the lock
 | 
				
			||||||
 | 
					    When thread A calls @a unlock on the mutex
 | 
				
			||||||
 | 
					    Then thread B acquires the lock
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
void test_dual_thread_lock_unlock(void)
 | 
					void test_dual_thread_lock_unlock(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Mutex mutex;
 | 
					    Mutex mutex;
 | 
				
			||||||
| 
						 | 
					@ -121,31 +158,45 @@ void test_dual_thread_lock_unlock(void)
 | 
				
			||||||
    Thread thread(osPriorityNormal, TEST_STACK_SIZE);
 | 
					    Thread thread(osPriorityNormal, TEST_STACK_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = mutex.lock();
 | 
					    stat = mutex.lock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    thread.start(callback(test_dual_thread_lock_unlock_thread, &mutex));
 | 
					    thread.start(callback(test_dual_thread_lock_unlock_thread, &mutex));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = mutex.unlock();
 | 
					    stat = mutex.unlock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wait_us(TEST_HALF_SEC_MS);
 | 
					    wait_ms(TEST_DELAY);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_dual_thread_lock_trylock_thread(Mutex *mutex)
 | 
					void test_dual_thread_lock_trylock_thread(Mutex *mutex)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    bool stat = mutex->trylock();
 | 
					    bool stat = mutex->trylock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, false);
 | 
					    TEST_ASSERT_EQUAL(false, stat);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_dual_thread_lock_lock_thread(Mutex *mutex)
 | 
					void test_dual_thread_lock_lock_thread(Mutex *mutex)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint32_t start = us_ticker_read();
 | 
					    uint32_t start = us_ticker_read();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    osStatus stat = mutex->lock(TEST_HALF_SEC_MS);
 | 
					    osStatus stat = mutex->lock(TEST_DELAY);
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osErrorTimeout);
 | 
					    TEST_ASSERT_EQUAL(osErrorTimeout, stat);
 | 
				
			||||||
    TEST_ASSERT_UINT32_WITHIN(TEST_ONE_MS_US, TEST_HALF_SEC_US, us_ticker_read() - start);
 | 
					    TEST_ASSERT_UINT32_WITHIN(5000, TEST_DELAY*1000, us_ticker_read() - start);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Test dual thread lock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Test dual thread lock locked
 | 
				
			||||||
 | 
					    Given a mutex and two threads A & B
 | 
				
			||||||
 | 
					    When thread A calls @a lock and starts thread B
 | 
				
			||||||
 | 
					        and thread B calls @a lock with 500ms timeout
 | 
				
			||||||
 | 
					    Then thread B waits 500ms and timeouts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Test dual thread trylock locked
 | 
				
			||||||
 | 
					    Given a mutex and two threads A & B
 | 
				
			||||||
 | 
					    When thread A calls @a lock and starts thread B
 | 
				
			||||||
 | 
					    Then thread B calls @a trylock
 | 
				
			||||||
 | 
					        and thread B fails to acquire the lock
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
template <void (*F)(Mutex *)>
 | 
					template <void (*F)(Mutex *)>
 | 
				
			||||||
void test_dual_thread_lock(void)
 | 
					void test_dual_thread_lock(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -154,59 +205,78 @@ void test_dual_thread_lock(void)
 | 
				
			||||||
    Thread thread(osPriorityNormal, TEST_STACK_SIZE);
 | 
					    Thread thread(osPriorityNormal, TEST_STACK_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = mutex.lock();
 | 
					    stat = mutex.lock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    thread.start(callback(F, &mutex));
 | 
					    thread.start(callback(F, &mutex));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wait_us(TEST_ONE_SEC_MS);
 | 
					    wait_ms(TEST_LONG_DELAY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = mutex.unlock();
 | 
					    stat = mutex.unlock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Test single thread lock recursive
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Given a mutex and a single running thread
 | 
				
			||||||
 | 
					    When thread calls @a lock twice and @a unlock twice on the mutex
 | 
				
			||||||
 | 
					    Then the returned statuses are osOK
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
void test_single_thread_lock_recursive(void)
 | 
					void test_single_thread_lock_recursive(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Mutex mutex;
 | 
					    Mutex mutex;
 | 
				
			||||||
    osStatus stat;
 | 
					    osStatus stat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = mutex.lock();
 | 
					    stat = mutex.lock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = mutex.lock();
 | 
					    stat = mutex.lock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = mutex.unlock();
 | 
					    stat = mutex.unlock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = mutex.unlock();
 | 
					    stat = mutex.unlock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Test single thread trylock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Given a mutex and a single running thread
 | 
				
			||||||
 | 
					    When thread calls @a trylock and @a unlock on the mutex
 | 
				
			||||||
 | 
					    Then the returned statuses are osOK
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
void test_single_thread_trylock(void)
 | 
					void test_single_thread_trylock(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Mutex mutex;
 | 
					    Mutex mutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool stat_b = mutex.trylock();
 | 
					    bool stat_b = mutex.trylock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat_b, true);
 | 
					    TEST_ASSERT_EQUAL(true, stat_b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    osStatus stat = mutex.unlock();
 | 
					    osStatus stat = mutex.unlock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Test single thread lock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Given a mutex and a single running thread
 | 
				
			||||||
 | 
					    When thread calls @a lock and @a unlock on the mutex
 | 
				
			||||||
 | 
					    Then the returned statuses are osOK
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
void test_single_thread_lock(void)
 | 
					void test_single_thread_lock(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Mutex mutex;
 | 
					    Mutex mutex;
 | 
				
			||||||
    osStatus stat;
 | 
					    osStatus stat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = mutex.lock();
 | 
					    stat = mutex.lock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stat = mutex.unlock();
 | 
					    stat = mutex.unlock();
 | 
				
			||||||
    TEST_ASSERT_EQUAL(stat, osOK);
 | 
					    TEST_ASSERT_EQUAL(osOK, stat);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
utest::v1::status_t test_setup(const size_t number_of_cases) {
 | 
					utest::v1::status_t test_setup(const size_t number_of_cases)
 | 
				
			||||||
    GREENTEA_SETUP(15, "default_auto");
 | 
					{
 | 
				
			||||||
 | 
					    GREENTEA_SETUP(10, "default_auto");
 | 
				
			||||||
    return verbose_test_setup_handler(number_of_cases);
 | 
					    return verbose_test_setup_handler(number_of_cases);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -224,6 +294,7 @@ Case cases[] = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Specification specification(test_setup, cases);
 | 
					Specification specification(test_setup, cases);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main() {
 | 
					int main()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
    return !Harness::run(specification);
 | 
					    return !Harness::run(specification);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue