F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
Task.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title Os/Task.cpp
3 // \brief common function implementation for Os::Task
4 // ======================================================================
5 #include <Os/Task.hpp>
6 #include <Fw/Types/Assert.hpp>
7 
8 namespace Os {
9 
11  void * const routine_argument, const FwSizeType priority,
12  const FwSizeType stackSize, const FwSizeType cpuAffinity,
13  const PlatformUIntType identifier) :
14  m_name(name),
15  m_routine(routine),
16  m_routine_argument(routine_argument),
17  m_priority(priority),
18  m_stackSize(stackSize),
19  m_cpuAffinity(cpuAffinity),
20  m_identifier(identifier)
21 {
22  FW_ASSERT(routine != nullptr);
23 }
24 
26 
27 void Task::TaskRoutineWrapper::run(void* wrapper_pointer) {
28  FW_ASSERT(wrapper_pointer != nullptr);
29  TaskRoutineWrapper& wrapper = *reinterpret_cast<TaskRoutineWrapper*>(wrapper_pointer);
30  FW_ASSERT(wrapper.m_user_function != nullptr);
31 
32  wrapper.m_task.m_lock.lock();
33  Task::State state = wrapper.m_task.m_state;
34  wrapper.m_task.m_lock.unlock();
35  FW_ASSERT(state != Task::State::NOT_STARTED);
36  // Run once start code
37  if (state == Task::State::STARTING) {
38  wrapper.m_task.m_lock.lock();
39  wrapper.m_task.m_state = Task::State::RUNNING;
40  wrapper.m_task.m_lock.unlock();
41  wrapper.m_task.onStart();
42  }
43 
44  // Call user function supplying the user argument
45  wrapper.m_user_function(wrapper.m_user_argument);
46 }
47 
50 }
51 
52 TaskRegistry* Task::s_taskRegistry = nullptr;
53 FwSizeType Task::s_numTasks = 0;
54 Mutex Task::s_taskMutex;
55 
57  return false;
58 }
59 
60 Task::Task() : m_wrapper(*this), m_handle_storage(), m_delegate(*TaskInterface::getDelegate(m_handle_storage)) {}
61 
63  // If a registry has been registered and the task has been started then remove task from the registry
64  if ((Task::s_taskRegistry != nullptr) && this->m_registered) {
65  Task::s_taskRegistry->removeTask(this);
66  }
67  m_delegate.~TaskInterface();
68 }
69 
70 void Task::suspend() {
71  this->suspend(Task::SuspensionType::UNINTENTIONAL);
72 }
73 
75  Task::State state;
76  this->m_lock.lock();
77  state = this->m_state;
78  this->m_lock.unlock();
79  return state;
80 }
81 
82 Task::Status Task::start(const Fw::StringBase &name, const taskRoutine routine, void* const arg,
83  const ParamType priority, const ParamType stackSize, const ParamType cpuAffinity,
84  const ParamType identifier) {
85  FW_ASSERT(routine != nullptr);
86  return this->start(Task::Arguments(name, routine, arg,
87  priority,
88  stackSize,
89  cpuAffinity,
90  static_cast<PlatformUIntType>(identifier)));
91 }
92 
93 
94 Task::Status Task::start(const Task::Arguments& arguments) {
95  FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
96  FW_ASSERT(arguments.m_routine != nullptr);
97  this->m_name = arguments.m_name;
98  this->m_state = State::STARTING;
99 
100  Arguments wrapped_arguments = arguments;
101  // Intercept routine and argument with the local wrapper
102  this->m_wrapper.m_user_function = arguments.m_routine;
103  this->m_wrapper.m_user_argument = arguments.m_routine_argument;
104  wrapped_arguments.m_routine = Task::TaskRoutineWrapper::run;
105  wrapped_arguments.m_routine_argument = &this->m_wrapper;
106 
107  Task::Status status = this->m_delegate.start(wrapped_arguments);
108  if (status == Task::Status::OP_OK) {
109  Task::m_lock.lock();
110  this->m_priority = wrapped_arguments.m_priority;
111  Task::m_lock.unlock();
112  Task::s_taskMutex.lock();
113  Task::s_numTasks++;
114  Task::s_taskMutex.unlock();
115 
116  // If a registry has been registered, register task to it
117  if (Task::s_taskRegistry) {
118  Task::s_taskRegistry->addTask(this);
119  this->m_registered = true;
120  }
121  }
122  return status;
123 }
124 
126  FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
127  this->m_delegate.onStart();
128 }
129 
131  this->m_wrapper.invoke();
132 }
133 
135  FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
136  Task::Status status = Task::Status::INVALID_STATE;
137  Task::State state = this->getState();
138  if (state == Task::RUNNING || state == STARTING) {
139  status = this->m_delegate.join();
140  this->m_lock.lock();
141  if (status == Task::Status::OP_OK) {
142  this->m_state = Task::State::EXITED;
143  } else {
144  this->m_state = Task::State::UNKNOWN;
145  }
146  this->m_lock.unlock();
147  }
148  return status;
149 }
150 
151 void Task::suspend(Task::SuspensionType suspensionType) {
152  FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
153  this->m_delegate.suspend(suspensionType);
154  this->m_lock.lock();
155  this->m_state = (suspensionType == Task::SuspensionType::INTENTIONAL) ? State::SUSPENDED_INTENTIONALLY : State::SUSPENDED_UNINTENTIONALLY;
156  this->m_lock.unlock();
157 }
158 
159 void Task::resume() {
160  FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
161  this->m_delegate.resume();
162 }
163 
165  FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
166  return this->m_delegate.isCooperative();
167 }
168 
170  Os::ScopeLock lock(this->m_lock);
171  return this->m_priority;
172 }
173 
175  FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
176  return this->m_delegate.getHandle();
177 }
178 
180  Task::s_taskMutex.lock();
181  FwSizeType num_tasks = Task::s_numTasks;
182  Task::s_taskMutex.unlock();
183  return num_tasks;
184 }
185 
187  FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
188  return this->m_delegate._delay(interval);
189 }
190 
192  return Task::getSingleton()._delay(interval);
193 }
194 
195 void Task::init() {
196  // Force trigger on the fly singleton setup
197  (void) Task::getSingleton();
198 }
199 
201  static Task s_singleton;
202  return s_singleton;
203 }
204 
206  Task::s_taskRegistry = registry;
207 }
208 }
#define FW_ASSERT(...)
Definition: Assert.hpp:14
unsigned int PlatformUIntType
PlatformSizeType FwSizeType
Definition: FpConfig.h:35
void unlock()
alias for unLock to meet BasicLockable requirements
Definition: Mutex.hpp:63
void lock()
lock the mutex and assert success
Definition: Mutex.cpp:34
locks a mutex within the current scope
Definition: Mutex.hpp:79
Wrapper for task routine that ensures onStart() is called once the task actually begins.
Definition: Task.hpp:199
void invoke()
invoke the run method with "self" as argument
Definition: Task.cpp:48
static void run(void *task_pointer)
run the task routine wrapper
Definition: Task.cpp:27
void * m_user_argument
Argument to user function.
Definition: Task.hpp:215
TaskRoutineWrapper(Task &self)
Definition: Task.cpp:25
Task & m_task
Reference to owning task.
Definition: Task.hpp:213
taskRoutine m_user_function
User function to run once started.
Definition: Task.hpp:214
Task handle representation.
Definition: Task.hpp:24
static FwSizeType getNumTasks()
get the current number of tasks
Definition: Task.cpp:179
bool isCooperative() override
determine if the task is cooperative multitasking (implementation specific)
Definition: Task.cpp:164
static Status delay(Fw::TimeInterval interval)
delay the current task
Definition: Task.cpp:191
Task()
default constructor
Definition: Task.cpp:60
TaskHandle * getHandle() override
return the underlying task handle (implementation specific)
Definition: Task.cpp:174
State getState()
get the task's state
Definition: Task.cpp:74
FwSizeType getPriority()
get the task priority
Definition: Task.cpp:169
FwSizeType ParamType
backwards-compatible parameter type
Definition: Task.hpp:219
static Task & getSingleton()
get a reference to singleton
Definition: Task.cpp:200
static void init()
initialize singleton
Definition: Task.cpp:195
void resume() override
resume a suspended task
Definition: Task.cpp:159
void onStart() override
perform delegate's required task start actions
Definition: Task.cpp:125
Status _delay(Fw::TimeInterval interval) override
delay the current task
Definition: Task.cpp:186
void invokeRoutine()
invoke the task's routine
Definition: Task.cpp:130
void suspend()
suspend the current task
Definition: Task.cpp:70
static void registerTaskRegistry(TaskRegistry *registry)
register a task registry to track Threads
Definition: Task.cpp:205
Status start(const Arguments &arguments) override
start the task
Definition: Task.cpp:82
~Task() final
default virtual destructor
Definition: Task.cpp:62
Status join() override
block until the task has ended
Definition: Task.cpp:134
Arguments(const Fw::StringBase &name, const taskRoutine routine, void *const routine_argument=nullptr, const FwSizeType priority=TASK_DEFAULT, const FwSizeType stackSize=TASK_DEFAULT, const FwSizeType cpuAffinity=TASK_DEFAULT, const PlatformUIntType identifier=static_cast< PlatformUIntType >(TASK_DEFAULT))
construct a set of arguments to start a task
Definition: Task.cpp:10
const Os::TaskString m_name
Definition: Task.hpp:83
virtual TaskHandle * getHandle()=0
return the underlying task handle (implementation specific)
virtual Status start(const Arguments &arguments)=0
start the task
virtual void suspend(SuspensionType suspensionType)=0
suspend the task given the suspension type
virtual Status join()=0
block until the task has ended
virtual void resume()=0
resume a suspended task
virtual Status _delay(Fw::TimeInterval interval)=0
delay the currently scheduled task using the given architecture
static TaskInterface * getDelegate(TaskHandleStorage &aligned_placement_new_memory)
provide a pointer to a task delegate object
Definition: DefaultTask.cpp:11
virtual ~TaskInterface()=default
default virtual destructor
void(* taskRoutine)(void *ptr)
Prototype for task routine started in task context.
Definition: Task.hpp:59
virtual void onStart()=0
perform required task start actions
virtual bool isCooperative()
determine if the task requires cooperative multitasking
Definition: Task.cpp:56
virtual void addTask(Task *task)=0
add supplied task to the registry
virtual void removeTask(Task *task)=0
remove supplied task to the registry
@ OP_OK
Operation succeeded.
Definition: Os.hpp:26