Skip to content

Commit

Permalink
Making Os::Task::delay use the singleton pattern (#2954)
Browse files Browse the repository at this point in the history
* Making Os::Task::delay use the singleton pattern

* Add Os::Task::init call to Os::init

---------

Co-authored-by: thomas-bc <[email protected]>
  • Loading branch information
LeStarch and thomas-bc authored Oct 16, 2024
1 parent 9ed68fd commit c548b53
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 72 deletions.
2 changes: 2 additions & 0 deletions Os/Os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "Os/Cpu.hpp"
#include "Os/FileSystem.hpp"
#include "Os/Memory.hpp"
#include "Os/Task.hpp"

namespace Os {

Expand All @@ -17,6 +18,7 @@ void init() {
Os::FileSystem::init();
Os::Cpu::init();
Os::Memory::init();
Os::Task::init();
}

} // namespace Os
30 changes: 0 additions & 30 deletions Os/Posix/DefaultTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,11 @@
// \title Os/Posix/DefaultTask.cpp
// \brief sets default Os::Task to posix implementation via linker
// ======================================================================
#include <cerrno>
#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<TaskInterface, Os::Posix::Task::PosixTask>(aligned_new_memory);
Expand Down
33 changes: 33 additions & 0 deletions Os/Posix/Task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions Os/Posix/Task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 0 additions & 5 deletions Os/Stub/DefaultTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@
#include <sys/time.h>

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<TaskInterface, Os::Stub::Task::StubTask>(aligned_new_memory);
}
Expand Down
6 changes: 6 additions & 0 deletions Os/Stub/Task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}


}
}
}
9 changes: 9 additions & 0 deletions Os/Stub/Task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
24 changes: 0 additions & 24 deletions Os/Stub/test/DefaultTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,8 @@
#include "Os/Task.hpp"
#include "Os/Stub/test/Task.hpp"
#include "Os/Delegate.hpp"
#include <sys/time.h>

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<U64>::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<TaskInterface, Os::Stub::Task::Test::TestTask>(aligned_new_memory);
}
Expand Down
28 changes: 24 additions & 4 deletions Os/Stub/test/Task.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
//
// Created by Michael Starch on 4/12/24.
//

#include "Os/Stub/test/Task.hpp"
#include <sys/time.h>
namespace Os {
namespace Stub {
namespace Task {
Expand Down Expand Up @@ -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<U64>::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;
}
Expand Down
9 changes: 9 additions & 0 deletions Os/Stub/test/Task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
19 changes: 19 additions & 0 deletions Os/Task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<TaskInterface*>(&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;
}
Expand Down
43 changes: 34 additions & 9 deletions Os/Task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -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.
Expand Down

0 comments on commit c548b53

Please sign in to comment.