diff --git a/Os/Posix/DefaultTask.cpp b/Os/Posix/DefaultTask.cpp index 986714198b..6066ea3b48 100644 --- a/Os/Posix/DefaultTask.cpp +++ b/Os/Posix/DefaultTask.cpp @@ -2,41 +2,11 @@ // \title Os/Posix/DefaultTask.cpp // \brief sets default Os::Task to posix implementation via linker // ====================================================================== -#include #include "Os/Task.hpp" #include "Os/Posix/Task.hpp" #include "Os/Delegate.hpp" namespace Os { - Os::Task::Status TaskInterface::delay(Fw::TimeInterval interval) { - Os::Task::Status task_status = Os::Task::OP_OK; - timespec sleep_interval; - sleep_interval.tv_sec = interval.getSeconds(); - sleep_interval.tv_nsec = interval.getUSeconds() * 1000; - - timespec remaining_interval; - remaining_interval.tv_sec = 0; - remaining_interval.tv_nsec = 0; - - while (true) { - PlatformIntType status = nanosleep(&sleep_interval, &remaining_interval); - // Success, return ok - if (0 == status) { - break; - } - // Interrupted, reset sleep and iterate - else if (EINTR == errno) { - sleep_interval = remaining_interval; - continue; - } - // Anything else is an error - else { - task_status = Os::Task::Status::DELAY_ERROR; - break; - } - } - return task_status; - } TaskInterface* TaskInterface::getDelegate(TaskHandleStorage& aligned_new_memory) { return Os::Delegate::makeDelegate(aligned_new_memory); diff --git a/Os/Posix/Task.cpp b/Os/Posix/Task.cpp index b7e007f33b..f26796beb5 100644 --- a/Os/Posix/Task.cpp +++ b/Os/Posix/Task.cpp @@ -209,6 +209,39 @@ namespace Task { void PosixTask::resume() { FW_ASSERT(0); } + + + Os::Task::Status PosixTask::_delay(Fw::TimeInterval interval) { + Os::Task::Status task_status = Os::Task::OP_OK; + timespec sleep_interval; + sleep_interval.tv_sec = interval.getSeconds(); + sleep_interval.tv_nsec = interval.getUSeconds() * 1000; + + timespec remaining_interval; + remaining_interval.tv_sec = 0; + remaining_interval.tv_nsec = 0; + + while (true) { + PlatformIntType status = nanosleep(&sleep_interval, &remaining_interval); + // Success, return ok + if (0 == status) { + break; + } + // Interrupted, reset sleep and iterate + else if (EINTR == errno) { + sleep_interval = remaining_interval; + continue; + } + // Anything else is an error + else { + task_status = Os::Task::Status::DELAY_ERROR; + break; + } + } + return task_status; + } + + } // end namespace Task } // end namespace Posix } // end namespace Os diff --git a/Os/Posix/Task.hpp b/Os/Posix/Task.hpp index f040233574..26c062455c 100644 --- a/Os/Posix/Task.hpp +++ b/Os/Posix/Task.hpp @@ -91,6 +91,15 @@ namespace Task { //! void resume() override; + //! \brief delay the current task + //! + //! Delays, or sleeps, the current task by the supplied time interval. In non-preempting os implementations + //! the task will resume no earlier than expected but an exact wake-up time is not guaranteed. + //! + //! \param interval: delay time + //! \return status of the delay + Status _delay(Fw::TimeInterval interval) override; + //! \brief return the underlying task handle (implementation specific) //! \return internal task handle representation TaskHandle* getHandle() override; diff --git a/Os/Stub/DefaultTask.cpp b/Os/Stub/DefaultTask.cpp index 31c0922228..e6b34e006b 100644 --- a/Os/Stub/DefaultTask.cpp +++ b/Os/Stub/DefaultTask.cpp @@ -9,11 +9,6 @@ #include namespace Os { - Os::Task::Status TaskInterface::delay(Fw::TimeInterval interval) { - FW_ASSERT(0); - return Os::Task::Status::UNKNOWN_ERROR; - } - TaskInterface* TaskInterface::getDelegate(TaskHandleStorage& aligned_new_memory) { return Os::Delegate::makeDelegate(aligned_new_memory); } diff --git a/Os/Stub/Task.cpp b/Os/Stub/Task.cpp index 29b404095a..2d781e1c14 100644 --- a/Os/Stub/Task.cpp +++ b/Os/Stub/Task.cpp @@ -31,6 +31,12 @@ bool StubTask::isCooperative() { return true; } +Os::Task::Status StubTask::_delay(Fw::TimeInterval interval) { + FW_ASSERT(0); + return Os::Task::Status::UNKNOWN_ERROR; +} + + } } } diff --git a/Os/Stub/Task.hpp b/Os/Stub/Task.hpp index daffabec19..a42727b1b5 100644 --- a/Os/Stub/Task.hpp +++ b/Os/Stub/Task.hpp @@ -48,6 +48,15 @@ class StubTask : public TaskInterface { //! void resume() override; + //! \brief delay the current task + //! + //! Delays, or sleeps, the current task by the supplied time interval. In non-preempting os implementations + //! the task will resume no earlier than expected but an exact wake-up time is not guaranteed. + //! + //! \param interval: delay time + //! \return status of the delay + Status _delay(Fw::TimeInterval interval) override; + //! \brief return the underlying task handle (implementation specific) //! \return internal task handle representation TaskHandle* getHandle() override; diff --git a/Os/Stub/test/DefaultTask.cpp b/Os/Stub/test/DefaultTask.cpp index 86e5628c4c..c665b1a102 100644 --- a/Os/Stub/test/DefaultTask.cpp +++ b/Os/Stub/test/DefaultTask.cpp @@ -6,32 +6,8 @@ #include "Os/Task.hpp" #include "Os/Stub/test/Task.hpp" #include "Os/Delegate.hpp" -#include namespace Os { - Os::Task::Status TaskInterface::delay(Fw::TimeInterval interval) { - Os::Stub::Task::Test::StaticData::data.lastCalled = Os::Stub::Task::Test::StaticData::LastFn::DELAY_FN; - Os::Stub::Task::Test::StaticData::data.delay = interval; - - // For testing stub, the default implementation of delay for a "task" is a busy wait. This acts as a synthetic - // albeit inefficient implementation. - timeval start; - timeval end; - if (gettimeofday(&start, nullptr) == 0) { - end.tv_usec = (start.tv_usec + interval.getUSeconds()) % 1000000; - end.tv_sec = start.tv_sec + interval.getSeconds() + (start.tv_usec + interval.getUSeconds())/1000000; - // Bounded busy wait - for (U64 wait = 0; wait < std::numeric_limits::max(); wait++) { - gettimeofday(&start, nullptr); - if (((start.tv_sec >= end.tv_sec) && (start.tv_usec >= end.tv_usec)) || - (start.tv_sec > end.tv_sec)) { - break; - } - } - } - return Os::Stub::Task::Test::StaticData::data.delayStatus; - } - TaskInterface* TaskInterface::getDelegate(TaskHandleStorage& aligned_new_memory) { return Os::Delegate::makeDelegate(aligned_new_memory); } diff --git a/Os/Stub/test/Task.cpp b/Os/Stub/test/Task.cpp index 40e3cd5ba2..37efeb686d 100644 --- a/Os/Stub/test/Task.cpp +++ b/Os/Stub/test/Task.cpp @@ -1,8 +1,5 @@ -// -// Created by Michael Starch on 4/12/24. -// - #include "Os/Stub/test/Task.hpp" +#include namespace Os { namespace Stub { namespace Task { @@ -46,6 +43,29 @@ Os::TaskInterface::Status TestTask::start(const Os::TaskInterface::Arguments &ar return StaticData::data.startStatus; } +Os::Task::Status TestTask::_delay(Fw::TimeInterval interval) { + Os::Stub::Task::Test::StaticData::data.lastCalled = Os::Stub::Task::Test::StaticData::LastFn::DELAY_FN; + Os::Stub::Task::Test::StaticData::data.delay = interval; + + // For testing stub, the default implementation of delay for a "task" is a busy wait. This acts as a synthetic + // albeit inefficient implementation. + timeval start; + timeval end; + if (gettimeofday(&start, nullptr) == 0) { + end.tv_usec = (start.tv_usec + interval.getUSeconds()) % 1000000; + end.tv_sec = start.tv_sec + interval.getSeconds() + (start.tv_usec + interval.getUSeconds())/1000000; + // Bounded busy wait + for (U64 wait = 0; wait < std::numeric_limits::max(); wait++) { + gettimeofday(&start, nullptr); + if (((start.tv_sec >= end.tv_sec) && (start.tv_usec >= end.tv_usec)) || + (start.tv_sec > end.tv_sec)) { + break; + } + } + } + return Os::Stub::Task::Test::StaticData::data.delayStatus; +} + bool TestTask::isCooperative() { return true; } diff --git a/Os/Stub/test/Task.hpp b/Os/Stub/test/Task.hpp index f3b2d1d64b..ce84437f22 100644 --- a/Os/Stub/test/Task.hpp +++ b/Os/Stub/test/Task.hpp @@ -77,6 +77,15 @@ class TestTask : public TaskInterface { //! void resume() override; + //! \brief delay the current task + //! + //! Delays, or sleeps, the current task by the supplied time interval. In non-preempting os implementations + //! the task will resume no earlier than expected but an exact wake-up time is not guaranteed. + //! + //! \param interval: delay time + //! \return status of the delay + Status _delay(Fw::TimeInterval interval) override; + //! \brief return the underlying task handle (implementation specific) //! \return internal task handle representation TaskHandle* getHandle() override; diff --git a/Os/Task.cpp b/Os/Task.cpp index 497ccfdd0b..f70382bde3 100644 --- a/Os/Task.cpp +++ b/Os/Task.cpp @@ -175,6 +175,25 @@ FwSizeType Task::getNumTasks() { return num_tasks; } +Os::TaskInterface::Status Task::_delay(Fw::TimeInterval interval) { + FW_ASSERT(&this->m_delegate == reinterpret_cast(&this->m_handle_storage[0])); + return this->m_delegate._delay(interval); +} + +Os::TaskInterface::Status Task::delay(Fw::TimeInterval interval) { + return Task::getSingleton()._delay(interval); +} + +void Task::init() { + // Force trigger on the fly singleton setup + (void) Task::getSingleton(); +} + +Task& Task::getSingleton() { + static Task s_singleton; + return s_singleton; +} + void Task::registerTaskRegistry(TaskRegistry* registry) { Task::s_taskRegistry = registry; } diff --git a/Os/Task.hpp b/Os/Task.hpp index 03a2b4bb56..269228c4c5 100644 --- a/Os/Task.hpp +++ b/Os/Task.hpp @@ -105,15 +105,6 @@ namespace Os { // Implementation functions (static) to be supplied by the linker // ================= - //! \brief delay the current task - //! - //! Delays, or sleeps, the current task by the supplied time interval. In non-preempting os implementations - //! the task will resume no earlier than expected but an exact wake-up time is not guaranteed. - //! - //! \param interval: delay time - //! \return status of the delay - static Status delay(Fw::TimeInterval interval); - //! \brief provide a pointer to a task delegate object //! //! This function must return a pointer to a `TaskInterface` object that contains the real implementation of the file @@ -165,6 +156,15 @@ namespace Os { //! virtual void resume() = 0; + //! \brief delay the currently scheduled task using the given architecture + //! + //! Delays, or sleeps, the current task by the supplied time interval. In non-preempting os implementations + //! the task will resume no earlier than expected but an exact wake-up time is not guaranteed. + //! + //! \param interval: delay time + //! \return status of the delay + virtual Status _delay(Fw::TimeInterval interval) = 0; + //! \brief determine if the task requires cooperative multitasking //! //! Some task implementations require cooperative multitasking where the task execution is run by a user @@ -317,6 +317,15 @@ namespace Os { //! void resume() override; + //! \brief delay the current task + //! + //! Delays, or sleeps, the current task by the supplied time interval. In non-preempting os implementations + //! the task will resume no earlier than expected but an exact wake-up time is not guaranteed. + //! + //! \param interval: delay time + //! \return status of the delay + Status _delay(Fw::TimeInterval interval) override; + //! \brief determine if the task is cooperative multitasking (implementation specific) //! \return true if cooperative, false otherwise bool isCooperative() override; @@ -325,6 +334,9 @@ namespace Os { //! \return internal task handle representation TaskHandle* getHandle() override; + //! \brief initialize singleton + static void init(); + //! \brief get the current number of tasks //! \return current number of tasks static FwSizeType getNumTasks(); @@ -333,6 +345,19 @@ namespace Os { //! static void registerTaskRegistry(TaskRegistry* registry); + //! \brief get a reference to singleton + //! \return reference to singleton + static Task& getSingleton(); + + //! \brief delay the current task + //! + //! Delays, or sleeps, the current task by the supplied time interval. In non-preempting os implementations + //! the task will resume no earlier than expected but an exact wake-up time is not guaranteed. + //! + //! \param interval: delay time + //! \return status of the delay + static Status delay(Fw::TimeInterval interval); + PRIVATE: static TaskRegistry* s_taskRegistry; //!< Pointer to registered task registry static FwSizeType s_numTasks; //!< Stores the number of tasks created.