Marco Zecchini
/
Example_RTOS
Rtos API example
Diff: mbed-os/TESTS/mbedmicro-rtos-mbed/signals/main.cpp
- Revision:
- 0:9fca2b23d0ba
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os/TESTS/mbedmicro-rtos-mbed/signals/main.cpp Sat Feb 23 12:13:36 2019 +0000 @@ -0,0 +1,408 @@ +/* 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 "utest/utest.h" +#include "unity/unity.h" + +using utest::v1::Case; + + +#if defined(MBED_RTOS_SINGLE_THREAD) + #error [NOT_SUPPORTED] test not supported +#endif + +#define TEST_STACK_SIZE 512 +#define MAX_FLAG_POS 30 + +#define ALL_SIGNALS 0x7fffffff +#define NO_SIGNALS 0x0 +#define PROHIBITED_SIGNAL 0x80000000 +#define SIGNAL1 0x1 +#define SIGNAL2 0x2 +#define SIGNAL3 0x4 + +struct Sync { + Sync(Semaphore &parent, Semaphore &child): sem_parent(parent), sem_child(child) + {} + + Semaphore &sem_parent; + Semaphore &sem_child; +}; + + +/* In order to successfully run this test suite when compiled with --profile=debug + * error() has to be redefined as noop. + * + * ThreadFlags calls RTX API which uses Event Recorder functionality. When compiled + * with MBED_TRAP_ERRORS_ENABLED=1 (set in debug profile) EvrRtxEventFlagsError() calls error() + * which aborts test program. + */ +#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED +void error(const char* format, ...) { + (void) format; +} +#endif + + +template <int32_t signals, uint32_t timeout, int32_t test_val> +void run_signal_wait(void) +{ + osEvent ev = Thread::signal_wait(signals, timeout); + TEST_ASSERT_EQUAL(test_val, ev.status); +} + +template <int32_t signals, uint32_t timeout, int32_t test_val> +void run_release_signal_wait(Semaphore *sem) +{ + sem->release(); + osEvent ev = Thread::signal_wait(signals, timeout); + TEST_ASSERT_EQUAL(test_val, ev.status); +} + +template <int32_t signals, uint32_t timeout, int32_t test_val> +void run_release_wait_signal_wait(Sync *sync) +{ + sync->sem_parent.release(); + sync->sem_child.wait(); + osEvent ev = Thread::signal_wait(signals, timeout); + TEST_ASSERT_EQUAL(test_val, ev.status); +} + +template <int32_t signals, int32_t test_val> +void run_clear(void) +{ + int32_t ret = Thread::signal_clr(signals); + TEST_ASSERT_EQUAL(test_val, ret); +} + +template <int32_t signals, int32_t test_val> +void run_wait_clear(Sync *sync) +{ + sync->sem_parent.release(); + sync->sem_child.wait(); + int32_t ret = Thread::signal_clr(signals); + TEST_ASSERT_EQUAL(test_val, ret); +} + +template <int32_t signals1, int32_t signals2, int32_t test_val1, int32_t test_val2> +void run_double_wait_clear(Sync *sync) +{ + int32_t ret; + + sync->sem_parent.release(); + sync->sem_child.wait(); + ret = Thread::signal_clr(signals1); + TEST_ASSERT_EQUAL(test_val1, ret); + + ret = Thread::signal_clr(signals2); + TEST_ASSERT_EQUAL(test_val2, ret); +} + +void run_loop_wait_clear(Sync *sync) +{ + int32_t signals = NO_SIGNALS; + for (int i = 0; i <= MAX_FLAG_POS; i++) { + int32_t signal = 1 << i; + signals |= signal; + sync->sem_child.wait(); + int32_t ret = Thread::signal_clr(NO_SIGNALS); + TEST_ASSERT_EQUAL(signals, ret); + sync->sem_parent.release(); + } +} + + +/** Validate that call signal_clr(NO_SIGNALS) doesn't change thread signals and return actual signals + + Given two threads A & B are started, B with all signals already set + When thread B calls @a signal_clr(NO_SIGNALS) + Then thread B @a signal_clr status should be ALL_SIGNALS indicating that thread B state is unchanged + */ +void test_clear_no_signals(void) +{ + Semaphore sem_parent(0, 1); + Semaphore sem_child(0, 1); + Sync sync(sem_parent, sem_child); + + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_double_wait_clear<NO_SIGNALS, NO_SIGNALS, ALL_SIGNALS, ALL_SIGNALS>, &sync)); + sem_parent.wait(); + t.signal_set(ALL_SIGNALS); + sem_child.release(); + t.join(); +} + +/** Validate if any signals are set on just created thread + + Given the thread is running + When thread execute @a signal_clr(NO_SIGNALS) + Then thread @a signal_clr return status should be NO_SIGNALS(0) indicating no signals set + */ +void test_init_state(void) +{ + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_clear<NO_SIGNALS, NO_SIGNALS>)); + t.join(); +} + +/** Validate all signals set in one shot + + Given two threads A & B are started + When thread A call @a signal_set(ALL_SIGNALS) with all possible signals + Then thread B @a signal_clr(NO_SIGNALS) status should be ALL_SIGNALS indicating all signals set correctly + */ +void test_set_all(void) +{ + int32_t ret; + Semaphore sem_parent(0, 1); + Semaphore sem_child(0, 1); + Sync sync(sem_parent, sem_child); + + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_wait_clear<NO_SIGNALS, ALL_SIGNALS>, &sync)); + + sem_parent.wait(); + ret = t.signal_set(ALL_SIGNALS); + TEST_ASSERT_EQUAL(ALL_SIGNALS, ret); + + sem_child.release(); + t.join(); +} + +/** Validate that call signal_set with prohibited signal doesn't change thread signals + + Given two threads A & B are started, B with all signals set + When thread A executes @a signal_set(PROHIBITED_SIGNAL) with prohibited signal + Then thread B @a signal_clr(NO_SIGNALS) status should be ALL_SIGNALS indicating that thread B signals are unchanged + + @note Each signal has up to 31 event flags 0x1, 0x2, 0x4, 0x8, ..., 0x40000000 + Most significant bit is reserved and thereby flag 0x80000000 is prohibited + */ +void test_set_prohibited(void) +{ + int32_t ret; + Semaphore sem_parent(0, 1); + Semaphore sem_child(0, 1); + Sync sync(sem_parent, sem_child); + + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_wait_clear<NO_SIGNALS, ALL_SIGNALS>, &sync)); + + sem_parent.wait(); + t.signal_set(ALL_SIGNALS); + + ret = t.signal_set(PROHIBITED_SIGNAL); + TEST_ASSERT_EQUAL(osErrorParameter, ret); + + sem_child.release(); + t.join(); +} + +/** Validate all signals clear in one shot + + Given two threads A & B are started, B with all signals set + When thread B execute @a signal_clr(ALL_SIGNALS) with all possible signals + Then thread B @a signal_clr(NO_SIGNALS) status should be NO_SIGNALS(0) indicating all signals cleared correctly + */ +void test_clear_all(void) +{ + Semaphore sem_parent(0, 1); + Semaphore sem_child(0, 1); + Sync sync(sem_parent, sem_child); + + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_double_wait_clear<ALL_SIGNALS, NO_SIGNALS, ALL_SIGNALS, NO_SIGNALS>, &sync)); + sem_parent.wait(); + t.signal_set(ALL_SIGNALS); + sem_child.release(); + t.join(); +} + +/** Validate all signals set one by one in loop + + Given two threads A & B are started + When thread A executes @a signal_set(signal) in loop with all possible signals + */ +void test_set_all_loop(void) +{ + int32_t ret; + Semaphore sem_parent(0, 1); + Semaphore sem_child(0, 1); + Sync sync(sem_parent, sem_child); + + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_loop_wait_clear, &sync)); + + int32_t signals = 0; + for (int i = 0; i <= MAX_FLAG_POS; i++) { + int32_t signal = 1 << i; + + ret = t.signal_set(signal); + signals |= signal; + TEST_ASSERT_EQUAL(signals, ret); + sem_child.release(); + sem_parent.wait(); + } + t.join(); +} + +/** Validate signal_wait return status if timeout specified + + Given the thread is running + When thread executes @a signal_wait(signals, timeout) with specified signals and timeout + Then thread @a signal_wait status should be osEventTimeout indicating a timeout + thread @a signal_wait status should be osOK indicating 0[ms] timeout set + */ +template <int32_t signals, uint32_t timeout, int32_t status> +void test_wait_timeout(void) +{ + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_signal_wait<signals, timeout, status>)); + t.join(); +} + +/** Validate that call of signal_wait return correctly when thread has all signals already set + + Given two threads A & B are started, B with all signals already set + When thread B executes @a signal_wait(ALL_SIGNALS, osWaitForever), + Then thread B @a signal_wait return immediately with status osEventSignal indicating all wait signals was already set + */ +void test_wait_all_already_set(void) +{ + Semaphore sem_parent(0, 1); + Semaphore sem_child(0, 1); + Sync sync(sem_parent, sem_child); + + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_release_wait_signal_wait<ALL_SIGNALS, osWaitForever, osEventSignal>, &sync)); + + sem_parent.wait(); + TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state()); + t.signal_set(ALL_SIGNALS); + sem_child.release(); + t.join(); +} + +/** Validate if signal_wait return correctly when all signals set + + Given two threads A & B are started and B waiting for a thread flag to be set + When thread A executes @a signal_set(ALL_SIGNALS) with all possible signals + Then thread B @a signal_wait status is osEventSignal indicating all wait signals was set + */ +void test_wait_all(void) +{ + Semaphore sem(0, 1); + + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_release_signal_wait<ALL_SIGNALS, osWaitForever, osEventSignal>, &sem)); + + sem.wait(); + TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, t.get_state()); + + t.signal_set(ALL_SIGNALS); + t.join(); +} + +/** Validate if signal_wait accumulate signals and return correctly when all signals set + + Given two threads A & B are started and B waiting for a thread signals to be set + When thread A executes @a signal_set setting all signals in loop + Then thread B @a signal_wait status is osEventSignal indicating that all wait signals was set + */ +void test_wait_all_loop(void) +{ + int32_t ret; + Semaphore sem(0, 1); + + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_release_signal_wait<ALL_SIGNALS, osWaitForever, osEventSignal>, &sem)); + + sem.wait(); + TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, t.get_state()); + + for (int i = 0; i < MAX_FLAG_POS; i++) { + int32_t signal = 1 << i; + ret = t.signal_set(signal); + } + ret = t.signal_set(1 << MAX_FLAG_POS); + TEST_ASSERT_EQUAL(NO_SIGNALS, ret); + t.join(); +} + +/** Validate if setting same signal twice cause any unwanted behaviour + + Given two threads A & B are started and B waiting for a thread signals to be set + When thread A executes @a signal_set twice for the same signal + Then thread A @a signal_set status is current signal set + thread B @a signal_wait status is osEventSignal indicating that all wait signals was set + */ +void test_set_double(void) +{ + int32_t ret; + Semaphore sem(0, 1); + + Thread t(osPriorityNormal, TEST_STACK_SIZE); + t.start(callback(run_release_signal_wait<SIGNAL1|SIGNAL2|SIGNAL3, osWaitForever, osEventSignal>, &sem)); + + sem.wait(); + TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, t.get_state()); + + ret = t.signal_set(SIGNAL1); + TEST_ASSERT_EQUAL(SIGNAL1, ret); + + ret = t.signal_set(SIGNAL2); + TEST_ASSERT_EQUAL(SIGNAL1 | SIGNAL2, ret); + + ret = t.signal_set(SIGNAL2); + TEST_ASSERT_EQUAL(SIGNAL1 | SIGNAL2, ret); + TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, t.get_state()); + + ret = t.signal_set(SIGNAL3); + TEST_ASSERT_EQUAL(NO_SIGNALS, ret); + t.join(); +} + + +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(10, "default_auto"); + return utest::v1::verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Validate that call signal_clr(NO_SIGNALS) doesn't change thread signals and return actual signals", test_clear_no_signals), + Case("Validate if any signals are set on just created thread", test_init_state), + Case("Validate all signals set in one shot", test_set_all), + Case("Validate that call signal_set with prohibited signal doesn't change thread signals", test_set_prohibited), + Case("Validate all signals clear in one shot", test_clear_all), + Case("Validate all signals set one by one in loop", test_set_all_loop), + Case("Validate signal_wait return status if timeout specified: 0[ms] no signals", test_wait_timeout<0, 0, osOK>), + Case("Validate signal_wait return status if timeout specified: 0[ms] all signals", test_wait_timeout<ALL_SIGNALS, 0, osOK>), + Case("Validate signal_wait return status if timeout specified: 1[ms] no signals", test_wait_timeout<0, 1, osEventTimeout>), + Case("Validate signal_wait return status if timeout specified: 1[ms] all signals", test_wait_timeout<ALL_SIGNALS, 1, osEventTimeout>), + Case("Validate that call of signal_wait return correctly when thread has all signals already set", test_wait_all_already_set), + Case("Validate if signal_wait return correctly when all signals set", test_wait_all), + Case("Validate if signal_wait accumulate signals and return correctly when all signals set", test_wait_all_loop), + Case("Validate if setting same signal twice cause any unwanted behaviour", test_set_double) +}; + +utest::v1::Specification specification(test_setup, cases); + +int main() +{ + return !utest::v1::Harness::run(specification); +}