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