diff --git a/osal/host/PeriodicTask.cpp b/osal/host/PeriodicTask.cpp index 7663d522..4c0bf338 100644 --- a/osal/host/PeriodicTask.cpp +++ b/osal/host/PeriodicTask.cpp @@ -10,6 +10,7 @@ #if defined(WIN32) #include +#include #elif defined(LINUX) #include #endif @@ -22,33 +23,11 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, // It is propably possible to set task priorities by using the native // task handles for Windows / Linux mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); -#if defined(WIN32) - /* 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 */ - int result = SetPriorityClass( - reinterpret_cast(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(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. +#if defined(_WIN32) + tasks::setTaskPriority(reinterpret_cast(mainThread.native_handle()), setPriority); + tasks::insertTaskName(mainThread.get_id(), taskName); +#elif defined(__unix__) + // TODO: We could reuse existing code here. #endif } diff --git a/osal/host/TaskFactory.cpp b/osal/host/TaskFactory.cpp index 4fafd349..4ac44364 100644 --- a/osal/host/TaskFactory.cpp +++ b/osal/host/TaskFactory.cpp @@ -1,14 +1,20 @@ +#include "../../tasks/TaskFactory.h" #include "../../osal/host/FixedTimeslotTask.h" #include "../../osal/host/PeriodicTask.h" -#include "../../tasks/TaskFactory.h" #include "../../returnvalues/HasReturnvaluesIF.h" #include "../../tasks/PeriodicTaskIF.h" +#ifdef _WIN32 + +#include "../windows/winTaskHelpers.h" + +#endif + #include 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; TaskFactory::TaskFactory() { @@ -49,8 +55,33 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ } void TaskFactory::printMissedDeadline() { - /* TODO: Implement */ - return; +#ifdef __unix__ + 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) */ } diff --git a/osal/linux/PosixThread.cpp b/osal/linux/PosixThread.cpp index bd8e7258..5296dfb5 100644 --- a/osal/linux/PosixThread.cpp +++ b/osal/linux/PosixThread.cpp @@ -6,7 +6,7 @@ #include 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'; 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) { /* The tick count has overflowed since this function was - lasted called. In this case the only time we should ever - actually delay is if the wake time has also overflowed, - and the wake time is greater than the tick time. When this - is the case it is as if neither time had overflowed. */ + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) && (nextTimeToWake_ms > currentTime_ms)) { shouldDelay = true; } } else { - /* The tick time has not overflowed. In this case we will - delay if either the wake time has overflowed, and/or the - tick time is less than the wake time. */ + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) || (nextTimeToWake_ms > currentTime_ms)) { shouldDelay = true; diff --git a/osal/windows/CMakeLists.txt b/osal/windows/CMakeLists.txt index 1bb39b37..36a54765 100644 --- a/osal/windows/CMakeLists.txt +++ b/osal/windows/CMakeLists.txt @@ -1,3 +1,4 @@ target_sources(${LIB_FSFW_NAME} PRIVATE tcpipHelpers.cpp + winTaskHelpers.cpp ) diff --git a/osal/windows/winTaskHelpers.cpp b/osal/windows/winTaskHelpers.cpp new file mode 100644 index 00000000..e96cd70e --- /dev/null +++ b/osal/windows/winTaskHelpers.cpp @@ -0,0 +1,130 @@ +#include +#include + +std::mutex nameMapLock; +std::map taskNameMap; + +TaskPriority tasks::makeWinPriority(PriorityClass prioClass, PriorityNumber prioNumber) { + return (static_cast(prioClass) << 16) | static_cast (prioNumber); +} + +void tasks::getWinPriorityParameters(TaskPriority priority, + DWORD& priorityClass, int& priorityNumber) { + PriorityClass classInternal = static_cast(priority >> 16 & 0xff); + PriorityNumber numberInternal = static_cast(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(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(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 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 lg(nameMapLock); + auto resultIter = taskNameMap.find(threadId); + if(resultIter != taskNameMap.end()) { + return resultIter->second; + } + else { + return "Unknown task"; + } +} diff --git a/osal/windows/winTaskHelpers.h b/osal/windows/winTaskHelpers.h new file mode 100644 index 00000000..d17b611a --- /dev/null +++ b/osal/windows/winTaskHelpers.h @@ -0,0 +1,40 @@ +#include "../../tasks/TaskFactory.h" + +#include +#include + +#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 + diff --git a/tasks/TaskFactory.h b/tasks/TaskFactory.h index 03b5163c..4fba345f 100644 --- a/tasks/TaskFactory.h +++ b/tasks/TaskFactory.h @@ -22,9 +22,23 @@ public: /** * Creates a new periodic task and returns the interface pointer. * @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 + * 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 deadLineMissedFunction_ Function to be called if a deadline was missed * @return PeriodicTaskIF* Pointer to the newly created Task */ diff --git a/tasks/Typedef.h b/tasks/Typedef.h index 07d96b00..55f6bda2 100644 --- a/tasks/Typedef.h +++ b/tasks/Typedef.h @@ -2,7 +2,7 @@ #define FRAMEWORK_TASKS_TYPEDEF_H_ typedef const char* TaskName; -typedef uint8_t TaskPriority; +typedef uint32_t TaskPriority; typedef size_t TaskStackSize; typedef double TaskPeriod; typedef void (*TaskDeadlineMissedFunction)();