Marco Zecchini
/
Example_RTOS
Rtos API example
mbed-os/TESTS/mbedmicro-rtos-mbed/mutex/main.cpp
- Committer:
- marcozecchini
- Date:
- 2019-02-23
- Revision:
- 0:9fca2b23d0ba
File content as of revision 0:9fca2b23d0ba:
/* mbed Microcontroller Library * Copyright (c) 2017 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #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 using namespace utest::v1; #define TEST_STACK_SIZE 512 #define TEST_LONG_DELAY 20 #define TEST_DELAY 10 #define SIGNALS_TO_EMIT 100 Mutex stdio_mutex; volatile int change_counter = 0; volatile bool changing_counter = false; volatile bool mutex_defect = false; bool manipulate_protected_zone(const int thread_delay) { bool result = true; osStatus stat = stdio_mutex.lock(); TEST_ASSERT_EQUAL(osOK, stat); core_util_critical_section_enter(); if (changing_counter == true) { result = false; mutex_defect = true; } changing_counter = true; change_counter++; core_util_critical_section_exit(); Thread::wait(thread_delay); core_util_critical_section_enter(); changing_counter = false; core_util_critical_section_exit(); stat = stdio_mutex.unlock(); TEST_ASSERT_EQUAL(osOK, stat); return result; } void test_thread(int const *thread_delay) { while (true) { 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) { const int t1_delay = TEST_DELAY * 1; const int t2_delay = TEST_DELAY * 2; const int t3_delay = TEST_DELAY * 3; 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)); while (true) { // Thread 1 action Thread::wait(t1_delay); manipulate_protected_zone(t1_delay); core_util_critical_section_enter(); if (change_counter >= SIGNALS_TO_EMIT or mutex_defect == true) { core_util_critical_section_exit(); t2.terminate(); t3.terminate(); break; } core_util_critical_section_exit(); } TEST_ASSERT_EQUAL(false, mutex_defect); } void test_dual_thread_nolock_lock_thread(Mutex *mutex) { osStatus stat = mutex->lock(osWaitForever); TEST_ASSERT_EQUAL(osOK, stat); stat = mutex->unlock(); TEST_ASSERT_EQUAL(osOK, stat); } void test_dual_thread_nolock_trylock_thread(Mutex *mutex) { bool stat_b = mutex->trylock(); TEST_ASSERT_EQUAL(true, stat_b); osStatus stat = mutex->unlock(); 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 *)> void test_dual_thread_nolock(void) { Mutex mutex; Thread thread(osPriorityNormal, TEST_STACK_SIZE); thread.start(callback(F, &mutex)); wait_ms(TEST_DELAY); } void test_dual_thread_lock_unlock_thread(Mutex *mutex) { osStatus stat = mutex->lock(osWaitForever); 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) { Mutex mutex; osStatus stat; Thread thread(osPriorityNormal, TEST_STACK_SIZE); stat = mutex.lock(); TEST_ASSERT_EQUAL(osOK, stat); thread.start(callback(test_dual_thread_lock_unlock_thread, &mutex)); stat = mutex.unlock(); TEST_ASSERT_EQUAL(osOK, stat); wait_ms(TEST_DELAY); } void test_dual_thread_lock_trylock_thread(Mutex *mutex) { bool stat = mutex->trylock(); TEST_ASSERT_EQUAL(false, stat); } void test_dual_thread_lock_lock_thread(Mutex *mutex) { Timer timer; timer.start(); osStatus stat = mutex->lock(TEST_DELAY); TEST_ASSERT_EQUAL(osErrorTimeout, stat); TEST_ASSERT_UINT32_WITHIN(5000, TEST_DELAY*1000, timer.read_us()); } /** 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 *)> void test_dual_thread_lock(void) { Mutex mutex; osStatus stat; Thread thread(osPriorityNormal, TEST_STACK_SIZE); stat = mutex.lock(); TEST_ASSERT_EQUAL(osOK, stat); thread.start(callback(F, &mutex)); wait_ms(TEST_LONG_DELAY); stat = mutex.unlock(); 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) { Mutex mutex; osStatus stat; stat = mutex.lock(); TEST_ASSERT_EQUAL(osOK, stat); stat = mutex.lock(); TEST_ASSERT_EQUAL(osOK, stat); stat = mutex.unlock(); TEST_ASSERT_EQUAL(osOK, stat); stat = mutex.unlock(); 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) { Mutex mutex; bool stat_b = mutex.trylock(); TEST_ASSERT_EQUAL(true, stat_b); osStatus stat = mutex.unlock(); 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) { Mutex mutex; osStatus stat; stat = mutex.lock(); TEST_ASSERT_EQUAL(osOK, stat); stat = mutex.unlock(); TEST_ASSERT_EQUAL(osOK, stat); } utest::v1::status_t test_setup(const size_t number_of_cases) { GREENTEA_SETUP(10, "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); }