From 28f88b1ead21a8c34ed921247483fe2f95255098 Mon Sep 17 00:00:00 2001 From: dario Date: Thu, 18 Jan 2024 12:40:12 +0100 Subject: [PATCH 1/8] Added test case for thread killing --- include/sta/config.hpp | 2 + include/sta/tasty/config.hpp | 2 +- src/cases/case1.cpp | 3 ++ src/cases/case6.cpp | 85 ++++++++++++++++++++++++++++++++++++ src/tasks/supervisor.cpp | 4 +- src/tasks/toggle.cpp | 2 + 6 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 src/cases/case6.cpp diff --git a/include/sta/config.hpp b/include/sta/config.hpp index c05ab9f..e759d53 100644 --- a/include/sta/config.hpp +++ b/include/sta/config.hpp @@ -8,6 +8,8 @@ #ifndef STA_CONFIG_HPP #define STA_CONFIG_HPP +#define STA_STM32_SWD_USART_IDX 2 + #include // Doesn't really do too much right now. Has to be added for successful compilation. diff --git a/include/sta/tasty/config.hpp b/include/sta/tasty/config.hpp index 86882ee..6e9b4be 100644 --- a/include/sta/tasty/config.hpp +++ b/include/sta/tasty/config.hpp @@ -2,6 +2,6 @@ #ifndef STA_TASTY_CONFIG_HPP #define STA_TASTY_CONFIG_HPP -#define TASTY_CASE_5 +#define TASTY_CASE_6 #endif // STA_TASTY_CONFIG_HPP diff --git a/src/cases/case1.cpp b/src/cases/case1.cpp index 9edf0b2..829b375 100644 --- a/src/cases/case1.cpp +++ b/src/cases/case1.cpp @@ -41,6 +41,9 @@ namespace sta STA_TASTY_ASSERT(tacos::getState() == 1); STA_TASTY_TERMINATE(); + + + this->sleep(1000000); } }; diff --git a/src/cases/case6.cpp b/src/cases/case6.cpp new file mode 100644 index 0000000..744cfb9 --- /dev/null +++ b/src/cases/case6.cpp @@ -0,0 +1,85 @@ +/** + * Tests if killing tasks works correctly and the memory is correctly freed. + */ +#include +#ifdef TASTY_CASE_6 + +#include +#include +#include + +#include +#include + +namespace sta +{ + namespace tasty + { + static uint8_t victim_alive_flag; + + + class Victim : public tacos::TacosThread + { + public: + Victim() + : tacos::TacosThread{"Dummy", osPriorityNormal} + {} + + void func() override + { + victim_alive_flag = 1; + osThreadYield(); + } + }; + + + class ViciousMurderer : public tacos::TacosThread + { + public: + ViciousMurderer(std::shared_ptr victim_ptr) + : tacos::TacosThread{"Dummy", osPriorityNormal}, + victim_ptr_{victim_ptr} + {} + + void func() override + { + // Kill the thread and set it's heartbeat flag to 0. + victim_ptr_->kill(); + victim_alive_flag = 0; + + uint8_t frees = sta::rtos::getNumFrees(); + + // Skip a tick + osThreadYield(); + + // The killed threat shouldn't have set the heartbeat flag. + STA_TASTY_ASSERT(victim_alive_flag == 0); + + // Wait for 100 ticks. + this->sleep(100); + + // After waiting 100 ticks, the flag should still be 0 because the thread doesn't run. + STA_TASTY_ASSERT(victim_alive_flag == 0); + + // Also, there should be two more frees: + STA_TASTY_ASSERT(sta::rtos::getNumFrees() - frees == 2); + + STA_TASTY_TERMINATE(); + } + private: + std::shared_ptr victim_ptr_; + }; + + void onTastyInit() + { + std::shared_ptr victim_ptr = tacos::addThread({0}); + tacos::addThread({0}, victim_ptr); + } + } // namespace tasty +} // namespace sta + +#endif // TASTY_CASE_6/* + + + + diff --git a/src/tasks/supervisor.cpp b/src/tasks/supervisor.cpp index da6e6be..6ac0b4d 100644 --- a/src/tasks/supervisor.cpp +++ b/src/tasks/supervisor.cpp @@ -18,9 +18,9 @@ namespace sta { for (TastyCheck check : checks_) { - blocking( + /*blocking( check(); - ); + );*/ } } } // namespace tasty diff --git a/src/tasks/toggle.cpp b/src/tasks/toggle.cpp index 6ac2863..1e9d835 100644 --- a/src/tasks/toggle.cpp +++ b/src/tasks/toggle.cpp @@ -29,6 +29,7 @@ namespace sta void ToggleThread::func() { + /** blocking( this->sleep(ticks_); ) @@ -37,6 +38,7 @@ namespace sta uint16_t next = 1 - state; sta::tacos::setState(state, next, lockout_); + */ } } // namespace tasty } // namespace sta From 529e2f62244266d45b2d7d2fb6d32136d9d4ea94 Mon Sep 17 00:00:00 2001 From: dario Date: Wed, 24 Jan 2024 21:42:33 +0100 Subject: [PATCH 2/8] Added first test case for watchdog --- include/sta/tasty/config.hpp | 2 +- src/cases/case1.cpp | 3 -- src/cases/case7.cpp | 83 ++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 src/cases/case7.cpp diff --git a/include/sta/tasty/config.hpp b/include/sta/tasty/config.hpp index 6e9b4be..73432a9 100644 --- a/include/sta/tasty/config.hpp +++ b/include/sta/tasty/config.hpp @@ -2,6 +2,6 @@ #ifndef STA_TASTY_CONFIG_HPP #define STA_TASTY_CONFIG_HPP -#define TASTY_CASE_6 +#define TASTY_CASE_7 #endif // STA_TASTY_CONFIG_HPP diff --git a/src/cases/case1.cpp b/src/cases/case1.cpp index 829b375..9edf0b2 100644 --- a/src/cases/case1.cpp +++ b/src/cases/case1.cpp @@ -41,9 +41,6 @@ namespace sta STA_TASTY_ASSERT(tacos::getState() == 1); STA_TASTY_TERMINATE(); - - - this->sleep(1000000); } }; diff --git a/src/cases/case7.cpp b/src/cases/case7.cpp new file mode 100644 index 0000000..3afe246 --- /dev/null +++ b/src/cases/case7.cpp @@ -0,0 +1,83 @@ +/* + * case7.cpp + * + * Created on: Jan 24, 2024 + * Author: Dario + */ + +#include +#ifdef TASTY_CASE_7 + +#include +#include +#include + +namespace sta +{ + namespace tasty + { + static uint8_t alive_flag = 0; + + class Dummy : public tacos::TacosThread + { + public: + Dummy() + : tacos::TacosThread{"Dummy", osPriorityNormal} + { + + } + + void init() override + { + alive_flag = 1; + } + + void func() override + { + this->sleep(100); + + // Thread is stuck in infinite loop + while (true) + { + osThreadYield(); + } + } + }; + + class Observer : public tacos::TacosThread + { + public: + Observer() + : tacos::TacosThread{"Observer", osPriorityNormal} + { + + } + + void func() override + { + this->sleep(10); + STA_TASTY_ASSERT(alive_flag == 1); + + this->sleep(110); + alive_flag = 0; + + // After at most 1000 ticks, the watchdog should have revived the thread. + this->sleep(2000); + STA_TASTY_ASSERT(alive_flag == 1); + STA_TASTY_ASSERT(tacos::Watchdog::instance()->getNumRestarts() == 1); + + STA_TASTY_TERMINATE(); + } + }; + + void onTastyInit() + { + tacos::addThread({0}); + tacos::addThread({0}); + } + } // namespace tasty +} + +#endif // TASTY_CASE_7 + + From ccfc354c8f1d9f60d8b1b81780d90cc540cdb73a Mon Sep 17 00:00:00 2001 From: dario Date: Wed, 7 Feb 2024 17:03:45 +0100 Subject: [PATCH 3/8] Added new test case testing for memory leaks and correct thread starting --- include/sta/tasty/config.hpp | 2 +- src/cases/case5.cpp | 6 +- src/cases/case7.cpp | 3 + src/cases/case8.cpp | 97 +++++++++++++++++++++++++++++ src/cases/case9.cpp | 116 +++++++++++++++++++++++++++++++++++ src/utils.cpp | 2 + 6 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 src/cases/case8.cpp create mode 100644 src/cases/case9.cpp diff --git a/include/sta/tasty/config.hpp b/include/sta/tasty/config.hpp index 73432a9..9baa6f7 100644 --- a/include/sta/tasty/config.hpp +++ b/include/sta/tasty/config.hpp @@ -2,6 +2,6 @@ #ifndef STA_TASTY_CONFIG_HPP #define STA_TASTY_CONFIG_HPP -#define TASTY_CASE_7 +#define TASTY_CASE_9 #endif // STA_TASTY_CONFIG_HPP diff --git a/src/cases/case5.cpp b/src/cases/case5.cpp index 76e3793..1df1372 100644 --- a/src/cases/case5.cpp +++ b/src/cases/case5.cpp @@ -1,5 +1,7 @@ /** - * + * Timed state transitions can be overwritten by timed state transitions with later deadline. + * + * TODO: Implement the correct requirement. */ #include #ifdef TASTY_CASE_5 @@ -13,8 +15,6 @@ namespace sta { class DummyThread : public tacos::TacosThread { - private: - /* data */ public: DummyThread() : tacos::TacosThread{"Dummy", osPriorityNormal} diff --git a/src/cases/case7.cpp b/src/cases/case7.cpp index 3afe246..5f9b70e 100644 --- a/src/cases/case7.cpp +++ b/src/cases/case7.cpp @@ -5,6 +5,9 @@ * Author: Dario */ +/** + * A thread gets stuck in an infinite loop and the watchdog restarts it. + */ #include #ifdef TASTY_CASE_7 diff --git a/src/cases/case8.cpp b/src/cases/case8.cpp new file mode 100644 index 0000000..0127ffc --- /dev/null +++ b/src/cases/case8.cpp @@ -0,0 +1,97 @@ +/* + * case8.cpp + * + * Created on: Jan 24, 2024 + * Author: Dario + */ + +/** + * A thread gets stuck in an infinite loop and the watchdog restarts it. + */ +#include +#ifdef TASTY_CASE_8 + +#include +#include +#include +#include + +namespace sta +{ + namespace tasty + { + static RtosMutex * mutexA; + static RtosMutex * mutexB; + + class ThreadA : public tacos::TacosThread + { + public: + ThreadA() + : tacos::TacosThread{"A", osPriorityNormal} + { + + } + + void func() override + { + mutexA->acquire(); + + this->sleep(10); + + mutexB->acquire(); + } + }; + + class ThreadB : public tacos::TacosThread + { + public: + ThreadB() + : tacos::TacosThread{"B", osPriorityNormal} + { + + } + + void func() override + { + mutexB->acquire(); + + this->sleep(10); + + mutexA->acquire(); + } + }; + + class Observer : public tacos::TacosThread + { + public: + Observer() + : tacos::TacosThread{"Observer", osPriorityNormal} + { + + } + + void func() override + { + this->sleep(2000); + + STA_TASTY_ASSERT(tacos::Watchdog::instance()->getNumRestarts() == 2); + + STA_TASTY_TERMINATE(); + } + }; + + void onTastyInit() + { + mutexA = new RtosMutex("MutA"); + mutexB = new RtosMutex("MutB"); + + tacos::addThread({0}); + tacos::addThread({0}); + tacos::addThread({0}); + } + } // namespace tasty +} + +#endif // TASTY_CASE_8 + + diff --git a/src/cases/case9.cpp b/src/cases/case9.cpp new file mode 100644 index 0000000..88bd40e --- /dev/null +++ b/src/cases/case9.cpp @@ -0,0 +1,116 @@ +/* + * case8.cpp + * + * Created on: Jan 24, 2024 + * Author: Dario + */ + +/** + * Tests if threads are properly terminated and started because of state transitions. The thread status is updated accordingly and no memory leaks occur. + */ +#include +#ifdef TASTY_CASE_9 + +#include +#include +#include +#include +#include + +namespace sta +{ + namespace tasty + { + class ThreadA : public tacos::TacosThread + { + public: + ThreadA() + : tacos::TacosThread{"A", osPriorityNormal} + { + + } + + void func() override + { + osThreadYield(); + } + }; + + class ThreadB : public tacos::TacosThread + { + public: + ThreadB() + : tacos::TacosThread{"B", osPriorityNormal} + { + + } + + void func() override + { + osThreadYield(); + } + }; + + + std::shared_ptr thread_A; + std::shared_ptr thread_B; + + + class Observer : public tacos::TacosThread + { + public: + Observer() + : tacos::TacosThread{"Observer", osPriorityNormal} + { + + } + + void func() override + { + size_t mallocs = sta::rtos::getNumAllocs(); + + STA_TASTY_ASSERT(thread_A->isRunning()); + STA_TASTY_ASSERT(!thread_B->isRunning()); + STA_TASTY_ASSERT(thread_B->getStatus() == tacos::ThreadStatus::STOPPED); + + this->sleep(20); + + tacos::setState(0, 1); + + this->sleep(5); + + STA_TASTY_ASSERT(!thread_A->isRunning()); + STA_TASTY_ASSERT(thread_B->isRunning()); + STA_TASTY_ASSERT(thread_A->getStatus() == tacos::ThreadStatus::STOPPED); + STA_TASTY_ASSERT(sta::rtos::getNumAllocs() == mallocs + 2); + + tacos::setState(1, 0); + + this->sleep(5); + + STA_TASTY_ASSERT(thread_A->isRunning()); + STA_TASTY_ASSERT(!thread_B->isRunning()); + STA_TASTY_ASSERT(thread_B->getStatus() == tacos::ThreadStatus::STOPPED); + STA_TASTY_ASSERT(sta::rtos::getNumAllocs() == mallocs + 2); + + tacos::setState(0, 1); + + STA_TASTY_ASSERT(!thread_A->isRunning()); + STA_TASTY_ASSERT(thread_B->isRunning()); + STA_TASTY_ASSERT(thread_A->getStatus() == tacos::ThreadStatus::STOPPED); + STA_TASTY_ASSERT(sta::rtos::getNumAllocs() == mallocs + 2); + + STA_TASTY_TERMINATE(); + } + }; + + void onTastyInit() + { + thread_A = tacos::addThread({0}); + thread_B = tacos::addThread({1}); + tacos::addThread({0, 1}); + } + } // namespace tasty +} + +#endif // TASTY_CASE_9 diff --git a/src/utils.cpp b/src/utils.cpp index 6335b34..01010af 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -16,6 +16,8 @@ namespace sta void test_terminate() { STA_DEBUG_PRINTLN("[T]"); + + while (true) {} } } // namespace tasty } // namespace sta From 90cc3dba58599386b4ce651a9dd3763191d3dbb4 Mon Sep 17 00:00:00 2001 From: dario Date: Wed, 7 Feb 2024 18:51:08 +0100 Subject: [PATCH 4/8] Small fix for run.py --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index 5efa67e..d72bdf8 100644 --- a/run.py +++ b/run.py @@ -22,7 +22,7 @@ path = 'Tasty/src/cases/' for case in os.listdir(path): # Find the number of the test case. - match = re.match('case([0-9])+\.cpp', case) + match = re.match('case([0-9]+)\.cpp', case) number = match.group(1) with open('Tasty/include/sta/tasty/config.hpp', 'w') as f: From fadd08665d0b87aba54fa544799014017cb15a53 Mon Sep 17 00:00:00 2001 From: dario Date: Wed, 7 Feb 2024 18:51:25 +0100 Subject: [PATCH 5/8] Two more test cases for the watchdog --- src/cases/case10.cpp | 118 +++++++++++++++++++++++++++++++++++++++++++ src/cases/case11.cpp | 77 ++++++++++++++++++++++++++++ src/cases/case9.cpp | 2 - 3 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 src/cases/case10.cpp create mode 100644 src/cases/case11.cpp diff --git a/src/cases/case10.cpp b/src/cases/case10.cpp new file mode 100644 index 0000000..2fde2f4 --- /dev/null +++ b/src/cases/case10.cpp @@ -0,0 +1,118 @@ +/* + * case10.cpp + * + * Created on: Feb 7, 2024 + * Author: Dario + */ + +/** + * Tests if threads are properly terminated and started because of state transitions. The thread status is updated accordingly and no memory leaks occur. + */ +#include +#ifdef TASTY_CASE_10 + +#include +#include +#include +#include + +namespace sta +{ + namespace tasty + { + RtosSignal * signal; + + class ThreadA : public tacos::TacosThread + { + public: + ThreadA() + : tacos::TacosThread{"A", osPriorityNormal} + { + + } + + void pointless_expensive_computation() + { + uint32_t ticks = osKernelGetSysTimerCount(); + uint32_t freq = osKernelGetSysTimerCount(); + uint64_t dummyCounter = 0; + + while (osKernelGetSysTimerCount() <= ticks + 2 * freq) + { + dummyCounter++; + } + } + + void func() override + { + this->sleep(3000); + + signal->notify(); + + // This should notify the watchdog that this thread should be monitored. + blocking( + pointless_expensive_computation(); + ) + + signal->notify(); + + pointless_expensive_computation(); + + } + }; + + std::shared_ptr thread_A; + + class Observer : public tacos::TacosThread + { + public: + Observer() + : tacos::TacosThread{"Observer", osPriorityNormal} + { + + } + + + + void func() override + { + uint16_t restarts = tacos::Watchdog::instance()->getNumRestarts(); + + // Wait for thread A to finish sleeping. + blocking( + signal->wait(); + ) + + // Thread A shouldn't have been restarted because sleep() sets the thread's status to WAITING. + STA_TASTY_ASSERT(tacos::Watchdog::instance()->getNumRestarts() == restarts); + + blocking( + signal->wait(); + ) + + // Thread A shouldn't have been restarted because the computationally expensive computation was wrapped in blocking() + STA_TASTY_ASSERT(tacos::Watchdog::instance()->getNumRestarts() == restarts); + + this->sleep(2500); + + STA_TASTY_ASSERT(tacos::Watchdog::instance()->getNumRestarts() == restarts + 1); + + STA_TASTY_TERMINATE(); + } + }; + + void onTastyInit() + { + signal = new RtosSignal(2); + + thread_A = tacos::addThread({0}); + tacos::addThread({0, 1}); + } + } // namespace tasty +} + +#endif // TASTY_CASE_10 + + + + diff --git a/src/cases/case11.cpp b/src/cases/case11.cpp new file mode 100644 index 0000000..ef43b51 --- /dev/null +++ b/src/cases/case11.cpp @@ -0,0 +1,77 @@ +/* + * case10.cpp + * + * Created on: Feb 7, 2024 + * Author: Dario + */ + +/** + * Tests if threads are properly terminated and started because of state transitions. The thread status is updated accordingly and no memory leaks occur. + */ +#include +#ifdef TASTY_CASE_11 + +#include +#include +#include +#include + +namespace sta +{ + namespace tasty + { + class ThreadA : public tacos::TacosThread + { + public: + ThreadA() + : tacos::TacosThread{"A", osPriorityNormal} + { + + } + + void init() override + { + // Tells the watchdog to ignore this thread. + watchdogIgnore(); + } + + void func() override + { + // Thread is stuck in infinite loop + while (true) + { + osThreadYield(); + } + } + }; + + class Observer : public tacos::TacosThread + { + public: + Observer() + : tacos::TacosThread{"Observer", osPriorityNormal} + { + + } + + + void func() override + { + this->sleep(2000); + + // The watchdog shouldn't have restarted thread A. + STA_TASTY_ASSERT(tacos::Watchdog::instance()->getNumRestarts() == 0); + + STA_TASTY_TERMINATE(); + } + }; + + void onTastyInit() + { + tacos::addThread({0}); + tacos::addThread({0, 1}); + } + } // namespace tasty +} + +#endif // TASTY_CASE_11 diff --git a/src/cases/case9.cpp b/src/cases/case9.cpp index 88bd40e..6c23e87 100644 --- a/src/cases/case9.cpp +++ b/src/cases/case9.cpp @@ -13,8 +13,6 @@ #include #include -#include -#include #include namespace sta From 148a45c41e4911a852a1fecb328ecad59189bd72 Mon Sep 17 00:00:00 2001 From: dario Date: Wed, 7 Feb 2024 19:34:38 +0100 Subject: [PATCH 6/8] Updated description for case 8 --- src/cases/case8.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cases/case8.cpp b/src/cases/case8.cpp index 0127ffc..7c7e643 100644 --- a/src/cases/case8.cpp +++ b/src/cases/case8.cpp @@ -6,7 +6,7 @@ */ /** - * A thread gets stuck in an infinite loop and the watchdog restarts it. + * Two threads get stuck in a deadlock and are restarted. */ #include #ifdef TASTY_CASE_8 From 25b41578c458759666455aca3bed38b30e39d6b4 Mon Sep 17 00:00:00 2001 From: dario Date: Wed, 7 Feb 2024 19:39:10 +0100 Subject: [PATCH 7/8] Updated description for case 10 --- src/cases/case10.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cases/case10.cpp b/src/cases/case10.cpp index 2fde2f4..bb45076 100644 --- a/src/cases/case10.cpp +++ b/src/cases/case10.cpp @@ -6,7 +6,7 @@ */ /** - * Tests if threads are properly terminated and started because of state transitions. The thread status is updated accordingly and no memory leaks occur. + * A sleeping thread is not restarted by the watchdog. Additionally, using blocking() also prevents a restart. */ #include #ifdef TASTY_CASE_10 From 7dbccbbdf794a47e8744caf6097423528dbb63a1 Mon Sep 17 00:00:00 2001 From: dario Date: Wed, 14 Feb 2024 13:49:03 +0100 Subject: [PATCH 8/8] Updated test case descriptions --- src/cases/case10.cpp | 2 +- src/cases/case11.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cases/case10.cpp b/src/cases/case10.cpp index bb45076..3a60fbe 100644 --- a/src/cases/case10.cpp +++ b/src/cases/case10.cpp @@ -49,7 +49,7 @@ namespace sta signal->notify(); - // This should notify the watchdog that this thread should be monitored. + // This should notify the watchdog that this thread should not be monitored. blocking( pointless_expensive_computation(); ) diff --git a/src/cases/case11.cpp b/src/cases/case11.cpp index ef43b51..f8e27a9 100644 --- a/src/cases/case11.cpp +++ b/src/cases/case11.cpp @@ -1,12 +1,12 @@ /* - * case10.cpp + * case11.cpp * * Created on: Feb 7, 2024 * Author: Dario */ /** - * Tests if threads are properly terminated and started because of state transitions. The thread status is updated accordingly and no memory leaks occur. + * Tests if a thread with IGNORED status is properly ignored. */ #include #ifdef TASTY_CASE_11