diff --git a/TESTS/mbed_platform/critical_section/main.cpp b/TESTS/mbed_platform/critical_section/main.cpp new file mode 100644 index 00000000000..16054310b65 --- /dev/null +++ b/TESTS/mbed_platform/critical_section/main.cpp @@ -0,0 +1,230 @@ +/* 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/unity.h" +#include "utest/utest.h" + + +using utest::v1::Case; + + +volatile bool callback_called; + +void tiemout_callback(void) +{ + callback_called = true; +} + +template +void critical_section_raii_recursive(Timeout &timeout) +{ + static uint32_t depth = 0; + CriticalSectionLock cs; + + depth++; + TEST_ASSERT_TRUE(core_util_in_critical_section()); + + if(depth < N) { + critical_section_raii_recursive(timeout); + } else { + // max depth reached - do the test + const us_timestamp_t timeout_time_us = 1; + const int wait_time_us = timeout_time_us * 100; + + timeout.attach_us(callback(tiemout_callback), timeout_time_us); + wait_us(wait_time_us); + } + TEST_ASSERT_TRUE(core_util_in_critical_section()); + TEST_ASSERT_FALSE(callback_called); +} + + +/** Template for tests + + Test C API of critical section + Given a Timeout with callback attached + When before critical section + Then interrupts are enabled and timeout callback is fired + When inside critical section + Then interrupts are disabled and timeout callback is blocked + When after critical section + Then interrupts are enabled and timeout callback is fired + + Test C API of critical section - nested lock + Given a Timeout with callback attached + When before critical section + Then interrupts are enabled and timeout callback is fired + When inside nested critical section + Then interrupts are disabled and timeout callback is blocked + When after critical section + Then interrupts are enabled and timeout callback is fired + */ +template +void test_C_API(void) +{ + Timeout timeout; + const us_timestamp_t timeout_time_us = 1; + const int wait_time_us = timeout_time_us * 100; + + TEST_ASSERT_FALSE(core_util_in_critical_section()); + + callback_called = false; + timeout.attach_us(callback(tiemout_callback), timeout_time_us); + wait_us(wait_time_us); + TEST_ASSERT_TRUE(callback_called); + + for(int i = 0; i < N; i++) { + core_util_critical_section_enter(); + TEST_ASSERT_TRUE(core_util_in_critical_section()); + } + + callback_called = false; + timeout.attach_us(callback(tiemout_callback), timeout_time_us); + wait_us(wait_time_us); + TEST_ASSERT_FALSE(callback_called); + TEST_ASSERT_TRUE(core_util_in_critical_section()); + + for(int i = 0; i < N - 1; i++) { + core_util_critical_section_exit(); + TEST_ASSERT_TRUE(core_util_in_critical_section()); + TEST_ASSERT_FALSE(callback_called); + } + + core_util_critical_section_exit(); + TEST_ASSERT_FALSE(core_util_in_critical_section()); + TEST_ASSERT_TRUE(callback_called); +} + +/** Template for tests + + Test C++ API of critical section constructor/destructor + Given a Timeout with callback attached + When before critical section + Then interrupts are enabled and timeout callback is fired + When inside critical section + Then interrupts are disabled and timeout callback is blocked + When after critical section + Then interrupts are enabled and timeout callback is fired + + Test C++ API of critical section constructor/destructor - nested lock + Given a Timeout with callback attached + When before critical section + Then interrupts are enabled and timeout callback is fired + When inside nested critical section + Then interrupts are disabled and timeout callback is blocked + When after critical section + Then interrupts are enabled and timeout callback is fired + */ +template +void test_CPP_API_constructor_destructor(void) +{ + Timeout timeout; + const us_timestamp_t timeout_time_us = 1; + const int wait_time_us = timeout_time_us * 100; + + TEST_ASSERT_FALSE(core_util_in_critical_section()); + + callback_called = false; + timeout.attach_us(callback(tiemout_callback), timeout_time_us); + wait_us(wait_time_us); + TEST_ASSERT_TRUE(callback_called); + + callback_called = false; + critical_section_raii_recursive(timeout); + + TEST_ASSERT_FALSE(core_util_in_critical_section()); + TEST_ASSERT_TRUE(callback_called); +} + +/** Template for tests + + Test C++ API of critical section enable/disable + Given a Timeout with attached callback + When before critical section + Then interrupts are enabled and timeout callback is fired + When inside critical section + Then interrupts are disabled and timeout callback is blocked + When after critical section + Then interrupts are enabled and timeout callback is fired + + Test C++ API of critical section enable/disable - nested lock + Given a Timeout with attached callback + When before critical section + Then interrupts are enabled and timeout callback is fired + When inside nested critical section + Then interrupts are disabled and timeout callback is blocked + When after critical section + Then interrupts are enabled and timeout callback is fired + */ +template +void test_CPP_API_enable_disable(void) +{ + Timeout timeout; + const us_timestamp_t timeout_time_us = 1; + const int wait_time_us = timeout_time_us * 100; + + TEST_ASSERT_FALSE(core_util_in_critical_section()); + + callback_called = false; + timeout.attach_us(callback(tiemout_callback), timeout_time_us); + wait_us(wait_time_us); + TEST_ASSERT_TRUE(callback_called); + + for(int i = 0; i < N; i++) { + CriticalSectionLock::enable(); + TEST_ASSERT_TRUE(core_util_in_critical_section()); + } + + callback_called = false; + timeout.attach_us(callback(tiemout_callback), timeout_time_us); + wait_us(wait_time_us); + TEST_ASSERT_FALSE(callback_called); + TEST_ASSERT_TRUE(core_util_in_critical_section()); + + for(int i = 0; i < N - 1; i++) { + CriticalSectionLock::disable(); + TEST_ASSERT_TRUE(core_util_in_critical_section()); + TEST_ASSERT_FALSE(callback_called); + } + + CriticalSectionLock::disable(); + TEST_ASSERT_FALSE(core_util_in_critical_section()); + TEST_ASSERT_TRUE(callback_called); +} + + +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("Test critical section C API", test_C_API<1>), + Case("Test critical section C API nested lock", test_C_API<10>), + Case("Test critical section C++ API constructor/destructor", test_CPP_API_constructor_destructor<1>), + Case("Test critical section C++ API constructor/destructor nested lock", test_CPP_API_constructor_destructor<10>), + Case("Test critical section C++ API enable/disable", test_CPP_API_enable_disable<1>), + Case("Test critical section C++ API enable/disable nested lock", test_CPP_API_enable_disable<10>) +}; + +utest::v1::Specification specification(test_setup, cases); + +int main() +{ + return !utest::v1::Harness::run(specification); +}