mirror of
https://git.intern.spaceteamaachen.de/ALPAKA/Tasty.git
synced 2025-06-10 18:45:59 +00:00
Merge pull request 'watchdog-integration' (#2) from watchdog-integration into main
Reviewed-on: https://git.intern.spaceteamaachen.de/ALPAKA/Tasty/pulls/2
This commit is contained in:
commit
d44b87c987
@ -8,6 +8,8 @@
|
||||
#ifndef STA_CONFIG_HPP
|
||||
#define STA_CONFIG_HPP
|
||||
|
||||
#define STA_STM32_SWD_USART_IDX 2
|
||||
|
||||
#include <sta/devices/stm32/mcu/STM32F411xE.hpp>
|
||||
|
||||
// Doesn't really do too much right now. Has to be added for successful compilation.
|
||||
|
@ -2,6 +2,6 @@
|
||||
#ifndef STA_TASTY_CONFIG_HPP
|
||||
#define STA_TASTY_CONFIG_HPP
|
||||
|
||||
#define TASTY_CASE_5
|
||||
#define TASTY_CASE_9
|
||||
|
||||
#endif // STA_TASTY_CONFIG_HPP
|
||||
|
2
run.py
2
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:
|
||||
|
118
src/cases/case10.cpp
Normal file
118
src/cases/case10.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* case10.cpp
|
||||
*
|
||||
* Created on: Feb 7, 2024
|
||||
* Author: Dario
|
||||
*/
|
||||
|
||||
/**
|
||||
* A sleeping thread is not restarted by the watchdog. Additionally, using blocking() also prevents a restart.
|
||||
*/
|
||||
#include <sta/tasty/config.hpp>
|
||||
#ifdef TASTY_CASE_10
|
||||
|
||||
#include <sta/tacos.hpp>
|
||||
#include <sta/tasty/utils.hpp>
|
||||
#include <sta/tacos/watchdog.hpp>
|
||||
#include <sta/rtos/signal.hpp>
|
||||
|
||||
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 not be monitored.
|
||||
blocking(
|
||||
pointless_expensive_computation();
|
||||
)
|
||||
|
||||
signal->notify();
|
||||
|
||||
pointless_expensive_computation();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<ThreadA> 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<ThreadA>({0});
|
||||
tacos::addThread<Observer>({0, 1});
|
||||
}
|
||||
} // namespace tasty
|
||||
}
|
||||
|
||||
#endif // TASTY_CASE_10
|
||||
|
||||
|
||||
|
||||
|
77
src/cases/case11.cpp
Normal file
77
src/cases/case11.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* case11.cpp
|
||||
*
|
||||
* Created on: Feb 7, 2024
|
||||
* Author: Dario
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests if a thread with IGNORED status is properly ignored.
|
||||
*/
|
||||
#include <sta/tasty/config.hpp>
|
||||
#ifdef TASTY_CASE_11
|
||||
|
||||
#include <sta/tacos.hpp>
|
||||
#include <sta/tasty/utils.hpp>
|
||||
#include <sta/tacos/watchdog.hpp>
|
||||
#include <sta/rtos/signal.hpp>
|
||||
|
||||
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<ThreadA>({0});
|
||||
tacos::addThread<Observer>({0, 1});
|
||||
}
|
||||
} // namespace tasty
|
||||
}
|
||||
|
||||
#endif // TASTY_CASE_11
|
@ -1,5 +1,7 @@
|
||||
/**
|
||||
*
|
||||
* Timed state transitions can be overwritten by timed state transitions with later deadline.
|
||||
*
|
||||
* TODO: Implement the correct requirement.
|
||||
*/
|
||||
#include <sta/tasty/config.hpp>
|
||||
#ifdef TASTY_CASE_5
|
||||
@ -13,8 +15,6 @@ namespace sta
|
||||
{
|
||||
class DummyThread : public tacos::TacosThread
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
DummyThread()
|
||||
: tacos::TacosThread{"Dummy", osPriorityNormal}
|
||||
|
85
src/cases/case6.cpp
Normal file
85
src/cases/case6.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Tests if killing tasks works correctly and the memory is correctly freed.
|
||||
*/
|
||||
#include <sta/tasty/config.hpp>
|
||||
#ifdef TASTY_CASE_6
|
||||
|
||||
#include <memory>
|
||||
#include <sta/tacos.hpp>
|
||||
#include <sta/tasty/utils.hpp>
|
||||
|
||||
#include <sta/rtos/debug/heap_stats.hpp>
|
||||
#include <sta/rtos/signal.hpp>
|
||||
|
||||
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> 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> victim_ptr_;
|
||||
};
|
||||
|
||||
void onTastyInit()
|
||||
{
|
||||
std::shared_ptr<Victim> victim_ptr = tacos::addThread<Victim>({0});
|
||||
tacos::addThread<ViciousMurderer>({0}, victim_ptr);
|
||||
}
|
||||
} // namespace tasty
|
||||
} // namespace sta
|
||||
|
||||
#endif // TASTY_CASE_6/*
|
||||
|
||||
|
||||
|
||||
|
86
src/cases/case7.cpp
Normal file
86
src/cases/case7.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* case7.cpp
|
||||
*
|
||||
* Created on: Jan 24, 2024
|
||||
* Author: Dario
|
||||
*/
|
||||
|
||||
/**
|
||||
* A thread gets stuck in an infinite loop and the watchdog restarts it.
|
||||
*/
|
||||
#include <sta/tasty/config.hpp>
|
||||
#ifdef TASTY_CASE_7
|
||||
|
||||
#include <sta/tacos.hpp>
|
||||
#include <sta/tasty/utils.hpp>
|
||||
#include <sta/tacos/watchdog.hpp>
|
||||
|
||||
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<Dummy>({0});
|
||||
tacos::addThread<Observer>({0});
|
||||
}
|
||||
} // namespace tasty
|
||||
}
|
||||
|
||||
#endif // TASTY_CASE_7
|
||||
|
||||
|
97
src/cases/case8.cpp
Normal file
97
src/cases/case8.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* case8.cpp
|
||||
*
|
||||
* Created on: Jan 24, 2024
|
||||
* Author: Dario
|
||||
*/
|
||||
|
||||
/**
|
||||
* Two threads get stuck in a deadlock and are restarted.
|
||||
*/
|
||||
#include <sta/tasty/config.hpp>
|
||||
#ifdef TASTY_CASE_8
|
||||
|
||||
#include <sta/tacos.hpp>
|
||||
#include <sta/tasty/utils.hpp>
|
||||
#include <sta/tacos/watchdog.hpp>
|
||||
#include <sta/rtos/mutex.hpp>
|
||||
|
||||
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<ThreadA>({0});
|
||||
tacos::addThread<ThreadB>({0});
|
||||
tacos::addThread<Observer>({0});
|
||||
}
|
||||
} // namespace tasty
|
||||
}
|
||||
|
||||
#endif // TASTY_CASE_8
|
||||
|
||||
|
114
src/cases/case9.cpp
Normal file
114
src/cases/case9.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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 <sta/tasty/config.hpp>
|
||||
#ifdef TASTY_CASE_9
|
||||
|
||||
#include <sta/tacos.hpp>
|
||||
#include <sta/tasty/utils.hpp>
|
||||
#include <sta/rtos/debug/heap_stats.hpp>
|
||||
|
||||
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<ThreadA> thread_A;
|
||||
std::shared_ptr<ThreadB> 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<ThreadA>({0});
|
||||
thread_B = tacos::addThread<ThreadB>({1});
|
||||
tacos::addThread<Observer>({0, 1});
|
||||
}
|
||||
} // namespace tasty
|
||||
}
|
||||
|
||||
#endif // TASTY_CASE_9
|
@ -18,9 +18,9 @@ namespace sta
|
||||
{
|
||||
for (TastyCheck check : checks_)
|
||||
{
|
||||
blocking(
|
||||
/*blocking(
|
||||
check();
|
||||
);
|
||||
);*/
|
||||
}
|
||||
}
|
||||
} // namespace tasty
|
||||
|
@ -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
|
||||
|
@ -16,6 +16,8 @@ namespace sta
|
||||
void test_terminate()
|
||||
{
|
||||
STA_DEBUG_PRINTLN("[T]");
|
||||
|
||||
while (true) {}
|
||||
}
|
||||
} // namespace tasty
|
||||
} // namespace sta
|
||||
|
Loading…
x
Reference in New Issue
Block a user