implemented deadlien missed print for host

This commit is contained in:
Robin Müller 2021-03-21 16:20:13 +01:00
parent 078116c7be
commit e3c44fd27f
8 changed files with 236 additions and 41 deletions

View File

@ -10,6 +10,7 @@
#if defined(WIN32) #if defined(WIN32)
#include <processthreadsapi.h> #include <processthreadsapi.h>
#include <fsfw/osal/windows/winTaskHelpers.h>
#elif defined(LINUX) #elif defined(LINUX)
#include <pthread.h> #include <pthread.h>
#endif #endif
@ -22,33 +23,11 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
// It is propably possible to set task priorities by using the native // It is propably possible to set task priorities by using the native
// task handles for Windows / Linux // task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
#if defined(WIN32) #if defined(_WIN32)
/* List of possible priority classes: tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ tasks::insertTaskName(mainThread.get_id(), taskName);
* nf-processthreadsapi-setpriorityclass #elif defined(__unix__)
* And respective thread priority numbers: // TODO: We could reuse existing code here.
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
#endif
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
#endif
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#endif #endif
} }

View File

@ -1,14 +1,20 @@
#include "../../tasks/TaskFactory.h"
#include "../../osal/host/FixedTimeslotTask.h" #include "../../osal/host/FixedTimeslotTask.h"
#include "../../osal/host/PeriodicTask.h" #include "../../osal/host/PeriodicTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/PeriodicTaskIF.h" #include "../../tasks/PeriodicTaskIF.h"
#ifdef _WIN32
#include "../windows/winTaskHelpers.h"
#endif
#include <chrono> #include <chrono>
TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
// Will propably not be used for hosted implementation // Not used for the host implementation for now because C++ thread abstraction is used
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
TaskFactory::TaskFactory() { TaskFactory::TaskFactory() {
@ -49,8 +55,33 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
} }
void TaskFactory::printMissedDeadline() { void TaskFactory::printMissedDeadline() {
/* TODO: Implement */ #ifdef __unix__
return; char name[20] = {0};
int status = pthread_getname_np(pthread_self(), name, sizeof(name));
#if FSFW_CPP_OSTREAM_ENABLED == 1
if(status == 0) {
sif::warning << "TaskFactory::printMissedDeadline: " << name << "" << std::endl;
}
else {
sif::warning << "TaskFactory::printMissedDeadline: Unknown task name" << status <<
std::endl;
}
#else
if(status == 0) {
sif::printWarning("TaskFactory::printMissedDeadline: %s\n", name);
}
else {
sif::printWarning("TaskFactory::printMissedDeadline: Unknown task name\n", name);
}
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#elif defined(_WIN32)
std::string name = tasks::getTaskName(std::this_thread::get_id());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TaskFactory::printMissedDeadline: " << name << std::endl;
#else
sif::printWarning("TaskFactory::printMissedDeadline: %s\n", name);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* defined(_WIN32) */
} }

View File

@ -6,7 +6,7 @@
#include <errno.h> #include <errno.h>
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_): PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_):
thread(0),priority(priority_),stackSize(stackSize_) { thread(0), priority(priority_), stackSize(stackSize_) {
name[0] = '\0'; name[0] = '\0';
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1); std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
} }
@ -75,18 +75,18 @@ bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms,
if (currentTime_ms < *prevoiusWakeTime_ms) { if (currentTime_ms < *prevoiusWakeTime_ms) {
/* The tick count has overflowed since this function was /* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed, actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */ is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
&& (nextTimeToWake_ms > currentTime_ms)) { && (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true; shouldDelay = true;
} }
} else { } else {
/* The tick time has not overflowed. In this case we will /* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */ tick time is less than the wake time. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
|| (nextTimeToWake_ms > currentTime_ms)) { || (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true; shouldDelay = true;

View File

@ -1,3 +1,4 @@
target_sources(${LIB_FSFW_NAME} PRIVATE target_sources(${LIB_FSFW_NAME} PRIVATE
tcpipHelpers.cpp tcpipHelpers.cpp
winTaskHelpers.cpp
) )

View File

@ -0,0 +1,130 @@
#include <fsfw/osal/windows/winTaskHelpers.h>
#include <mutex>
std::mutex nameMapLock;
std::map<std::thread::id, std::string> taskNameMap;
TaskPriority tasks::makeWinPriority(PriorityClass prioClass, PriorityNumber prioNumber) {
return (static_cast<uint16_t>(prioClass) << 16) | static_cast<uint16_t> (prioNumber);
}
void tasks::getWinPriorityParameters(TaskPriority priority,
DWORD& priorityClass, int& priorityNumber) {
PriorityClass classInternal = static_cast<PriorityClass>(priority >> 16 & 0xff);
PriorityNumber numberInternal = static_cast<PriorityNumber>(priority & 0xff);
switch(classInternal) {
case(CLASS_IDLE): {
priorityClass = IDLE_PRIORITY_CLASS;
break;
}
case(CLASS_BELOW_NORMAL): {
priorityClass = BELOW_NORMAL_PRIORITY_CLASS;
break;
}
case(CLASS_NORMAL): {
priorityClass = NORMAL_PRIORITY_CLASS;
break;
}
case(CLASS_ABOVE_NORMAL): {
priorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
break;
}
case(CLASS_HIGH): {
priorityClass = HIGH_PRIORITY_CLASS;
break;
}
case(CLASS_REALTIME): {
priorityClass = REALTIME_PRIORITY_CLASS;
break;
}
default: {
priorityClass = NORMAL_PRIORITY_CLASS;
}
}
switch(numberInternal) {
case(IDLE): {
priorityNumber = THREAD_PRIORITY_IDLE;
break;
}
case(LOWEST): {
priorityNumber = THREAD_PRIORITY_LOWEST;
break;
}
case(BELOW_NORMAL): {
priorityNumber = THREAD_PRIORITY_BELOW_NORMAL;
break;
}
case(NORMAL): {
priorityNumber = THREAD_PRIORITY_NORMAL;
break;
}
case(ABOVE_NORMAL): {
priorityNumber = THREAD_PRIORITY_ABOVE_NORMAL;
break;
}
case(HIGHEST): {
priorityNumber = THREAD_PRIORITY_HIGHEST;
break;
}
case(CRITICAL): {
priorityNumber = THREAD_PRIORITY_TIME_CRITICAL;
break;
}
default: {
priorityNumber = THREAD_PRIORITY_NORMAL;
}
}
}
ReturnValue_t tasks::setTaskPriority(HANDLE nativeHandle, TaskPriority priority) {
/* List of possible priority classes:
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setpriorityclass
And respective thread priority numbers:
https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
*/
DWORD dwPriorityClass = 0;
int nPriorityNumber = 0;
tasks::getWinPriorityParameters(priority, dwPriorityClass, nPriorityNumber);
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(nativeHandle),
dwPriorityClass);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
#endif
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(nativeHandle),
nPriorityNumber);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
#endif
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t tasks::insertTaskName(std::thread::id threadId, std::string taskName) {
std::lock_guard<std::mutex> lg(nameMapLock);
auto returnPair = taskNameMap.emplace(threadId, taskName);
if(not returnPair.second) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
std::string tasks::getTaskName(std::thread::id threadId) {
std::lock_guard<std::mutex> lg(nameMapLock);
auto resultIter = taskNameMap.find(threadId);
if(resultIter != taskNameMap.end()) {
return resultIter->second;
}
else {
return "Unknown task";
}
}

View File

@ -0,0 +1,40 @@
#include "../../tasks/TaskFactory.h"
#include <thread>
#include <map>
#ifdef _WIN32
namespace tasks {
enum PriorityClass: uint16_t {
CLASS_IDLE,
CLASS_BELOW_NORMAL,
CLASS_NORMAL,
CLASS_ABOVE_NORMAL,
CLASS_HIGH,
CLASS_REALTIME
};
enum PriorityNumber: uint16_t {
IDLE,
LOWEST,
BELOW_NORMAL,
NORMAL,
ABOVE_NORMAL,
HIGHEST,
CRITICAL
};
TaskPriority makeWinPriority(PriorityClass prioClass = PriorityClass::CLASS_NORMAL,
PriorityNumber prioNumber = PriorityNumber::NORMAL);
void getWinPriorityParameters(TaskPriority priority, DWORD& priorityClass,
int& priorityNumber);
ReturnValue_t setTaskPriority(HANDLE nativeHandle, TaskPriority priority);
ReturnValue_t insertTaskName(std::thread::id threadId, std::string taskName);
std::string getTaskName(std::thread::id threadId);
}
#endif

View File

@ -22,9 +22,23 @@ public:
/** /**
* Creates a new periodic task and returns the interface pointer. * Creates a new periodic task and returns the interface pointer.
* @param name_ Name of the task * @param name_ Name of the task
* @param taskPriority_ Priority of the task * @param taskPriority_
* Priority of the task. This value might have different ranges for the various OSALs.
* Linux: Value ranging from 0 to 99 with 99 being the highest value.
* Host: Value can be retrieved by using the #tasks::makeWinPriority function.
* FreeRTOS: Value depends on the FreeRTOS configuration, higher number means higher priority
* RTEMS: Values ranging from 0 to 99 with 99 being the highest value.
*
* @param stackSize_ Stack Size of the task * @param stackSize_ Stack Size of the task
* This value might have different recommended ranges for the various OSALs.
* Linux: Lowest limit is the PeriodicTaskIF::MINIMUM_STACK_SIZE value
* Host: Value is ignored for now because the C++ threading abstraction layer is used.
* FreeRTOS: Stack size in bytes. It is recommended to specify at least 1kB of stack for
* FSFW tasks, but the lowest possible size is specified in the FreeRTOSConfig.h file.
* RTEMS: Lowest limit is the PeriodicTaskIF::MINIMUM_STACK_SIZE value.
*
* @param period_ Period of the task * @param period_ Period of the task
*
* @param deadLineMissedFunction_ Function to be called if a deadline was missed * @param deadLineMissedFunction_ Function to be called if a deadline was missed
* @return PeriodicTaskIF* Pointer to the newly created Task * @return PeriodicTaskIF* Pointer to the newly created Task
*/ */

View File

@ -2,7 +2,7 @@
#define FRAMEWORK_TASKS_TYPEDEF_H_ #define FRAMEWORK_TASKS_TYPEDEF_H_
typedef const char* TaskName; typedef const char* TaskName;
typedef uint8_t TaskPriority; typedef uint32_t TaskPriority;
typedef size_t TaskStackSize; typedef size_t TaskStackSize;
typedef double TaskPeriod; typedef double TaskPeriod;
typedef void (*TaskDeadlineMissedFunction)(); typedef void (*TaskDeadlineMissedFunction)();