GCC Code Coverage Report


Directory: ./
File: Task.cpp
Date: 2026-09-23 22:12:21
Exec Total Coverage
Lines: 97 137 70.8%
Functions: 17 26 65.4%
Branches: 25 44 56.8%

Line Branch Exec Source
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
10 23 TaskInterface::Arguments::Arguments(const Fw::ConstStringBase& name,
11 const Os::TaskInterface::taskRoutine routine,
12 void* const routine_argument,
13 const FwTaskPriorityType priority,
14 const FwSizeType stackSize,
15 const FwSizeType cpuAffinity,
16 23 const FwTaskIdType identifier)
17 23 : m_name(name),
18 23 m_routine(routine),
19 23 m_routine_argument(routine_argument),
20 23 m_priority(priority),
21 23 m_stackSize(stackSize),
22 23 m_cpuAffinity(cpuAffinity),
23 23 m_identifier(identifier) {
24 23 FW_ASSERT(routine != nullptr);
25 23 }
26
27 24 Task::TaskRoutineWrapper::TaskRoutineWrapper(Task& self) : m_task(self) {}
28
29 23 void Task::TaskRoutineWrapper::run(void* wrapper_pointer) {
30 23 FW_ASSERT(wrapper_pointer != nullptr);
31 23 TaskRoutineWrapper& wrapper = *reinterpret_cast<TaskRoutineWrapper*>(wrapper_pointer);
32 23 FW_ASSERT(wrapper.m_user_function != nullptr);
33
34 23 wrapper.m_task.m_lock.lock();
35 23 Task::State state = wrapper.m_task.m_state;
36 23 wrapper.m_task.m_lock.unlock();
37 23 FW_ASSERT(state != Task::State::NOT_STARTED);
38 // Run once start code
39
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (state == Task::State::STARTING) {
40 23 wrapper.m_task.m_lock.lock();
41 23 wrapper.m_task.m_state = Task::State::RUNNING;
42 23 wrapper.m_task.m_lock.unlock();
43 23 wrapper.m_task.onStart();
44 }
45
46 // Call user function supplying the user argument
47 23 wrapper.m_user_function(wrapper.m_user_argument);
48 23 }
49
50 ✗ void Task::TaskRoutineWrapper::invoke() {
51 ✗ TaskRoutineWrapper::run(this);
52 ✗ }
53
54 TaskRegistry* Task::s_taskRegistry = nullptr;
55 FwSizeType Task::s_numTasks = 0;
56 Mutex Task::s_taskMutex;
57
58 6687 bool TaskInterface::isCooperative() {
59 6687 return false;
60 }
61
62
5/5
✓ Branch 2 taken 24 times.
✓ Branch 5 taken 24 times.
✓ Branch 8 taken 960 times.
✓ Branch 9 taken 24 times.
✓ Branch 11 taken 24 times.
984 Task::Task() : m_wrapper(*this), m_handle_storage(), m_delegate(*TaskInterface::getDelegate(m_handle_storage)) {}
63
64 48 Task::~Task() {
65 // If a registry has been registered and the task has been started then remove task from the registry
66
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
48 if ((Task::s_taskRegistry != nullptr) && this->m_registered) {
67 ✗ Task::s_taskRegistry->removeTask(this);
68 }
69 48 m_delegate.~TaskInterface();
70 48 }
71
72 ✗ void Task::suspend() {
73 ✗ this->suspend(Task::SuspensionType::UNINTENTIONAL);
74 ✗ }
75
76 25 Task::State Task::getState() const {
77 Task::State state;
78 25 this->m_lock.lock();
79 25 state = this->m_state;
80 25 this->m_lock.unlock();
81 25 return state;
82 }
83
84 ✗ Task::Status Task::start(const Fw::ConstStringBase& name,
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 23 Task::Status Task::start(const Task::Arguments& arguments) {
97
1/1
✓ Branch 1 taken 23 times.
23 Task::init();
98 // init call above is to ensure singleton is initialized in a thread-safe
99 // manner and such that the address sanitizer does not inadvertently
100 // result in a stack overflow when multiple calls to getSingleton are made
101 // simultaneously from different threads. (As was observed in UT runs.)
102 23 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
103 23 FW_ASSERT(arguments.m_routine != nullptr);
104
1/1
✓ Branch 1 taken 23 times.
23 this->m_name = arguments.m_name;
105 23 this->m_state = State::STARTING;
106
107
1/1
✓ Branch 1 taken 23 times.
23 Arguments wrapped_arguments = arguments;
108 // Intercept routine and argument with the local wrapper
109 23 this->m_wrapper.m_user_function = arguments.m_routine;
110 23 this->m_wrapper.m_user_argument = arguments.m_routine_argument;
111 23 wrapped_arguments.m_routine = Task::TaskRoutineWrapper::run;
112 23 wrapped_arguments.m_routine_argument = &this->m_wrapper;
113
114
1/1
✓ Branch 1 taken 23 times.
23 Task::Status status = this->m_delegate.start(wrapped_arguments);
115
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (status == Task::Status::OP_OK) {
116
1/1
✓ Branch 1 taken 23 times.
23 Task::m_lock.lock();
117 23 this->m_priority = wrapped_arguments.m_priority;
118
1/1
✓ Branch 1 taken 23 times.
23 Task::m_lock.unlock();
119
1/1
✓ Branch 1 taken 23 times.
23 Task::s_taskMutex.lock();
120 23 Task::s_numTasks++;
121
1/1
✓ Branch 1 taken 23 times.
23 Task::s_taskMutex.unlock();
122
123 // If a registry has been registered, register task to it
124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (Task::s_taskRegistry) {
125 ✗ Task::s_taskRegistry->addTask(this);
126 ✗ this->m_registered = true;
127 }
128 }
129 23 return status;
130 23 }
131
132 23 void Task::onStart() {
133 23 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
134 23 this->m_delegate.onStart();
135 23 }
136
137 ✗ void Task::invokeRoutine() {
138 ✗ this->m_wrapper.invoke();
139 ✗ }
140
141 23 Task::Status Task::join() {
142 23 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
143 23 Task::Status status = Task::Status::INVALID_STATE;
144 23 Task::State state = this->getState();
145
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
23 if (state == Task::RUNNING || state == STARTING) {
146 23 status = this->m_delegate.join();
147 23 this->m_lock.lock();
148
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (status == Task::Status::OP_OK) {
149 23 this->m_state = Task::State::EXITED;
150 } else {
151 ✗ this->m_state = Task::State::UNKNOWN;
152 }
153 23 this->m_lock.unlock();
154 }
155 23 return status;
156 }
157
158 ✗ void Task::suspend(Task::SuspensionType suspensionType) {
159 ✗ FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
160 ✗ this->m_delegate.suspend(suspensionType);
161 ✗ this->m_lock.lock();
162 ✗ this->m_state = (suspensionType == Task::SuspensionType::INTENTIONAL) ? State::SUSPENDED_INTENTIONALLY
163 : State::SUSPENDED_UNINTENTIONALLY;
164 ✗ this->m_lock.unlock();
165 ✗ }
166
167 ✗ void Task::resume() {
168 ✗ FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
169 ✗ this->m_delegate.resume();
170 ✗ }
171
172 6687 bool Task::isCooperative() {
173 6687 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
174 6687 return this->m_delegate.isCooperative();
175 }
176
177 2 TaskString Task::getName() {
178
1/1
✓ Branch 1 taken 2 times.
2 Os::ScopeLock lock(this->m_lock);
179
1/1
✓ Branch 1 taken 2 times.
4 return this->m_name;
180 2 }
181
182 ✗ FwTaskPriorityType Task::getPriority() {
183 ✗ Os::ScopeLock lock(this->m_lock);
184 ✗ return this->m_priority;
185 ✗ }
186
187 23 TaskHandle* Task::getHandle() {
188 23 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
189 23 return this->m_delegate.getHandle();
190 }
191
192 ✗ FwSizeType Task::getNumTasks() {
193 ✗ Task::s_taskMutex.lock();
194 ✗ FwSizeType num_tasks = Task::s_numTasks;
195 ✗ Task::s_taskMutex.unlock();
196 ✗ return num_tasks;
197 }
198
199 4916 Os::TaskInterface::Status Task::_delay(const Fw::TimeInterval& interval) {
200 4916 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
201 4916 return this->m_delegate._delay(interval);
202 }
203
204 4916 Os::TaskInterface::Status Task::delay(const Fw::TimeInterval& interval) {
205 4916 return Task::getSingleton()._delay(interval);
206 }
207
208 24 void Task::init() {
209 // Force trigger on the fly singleton setup
210 24 (void)Task::getSingleton();
211 24 }
212
213 4940 Task& Task::getSingleton() {
214
4/7
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4939 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4940 static Task s_singleton;
215 4940 return s_singleton;
216 }
217
218 ✗ void Task::registerTaskRegistry(TaskRegistry* registry) {
219 ✗ Task::s_taskRegistry = registry;
220 ✗ }
221 } // namespace Os
222