GCC Code Coverage Report


Directory: ./
File: Os/Task.cpp
Date: 2026-09-23 21:11:01
Exec Total Coverage
Lines: 133 137 97.1%
Functions: 25 26 96.2%
Branches: 42 50 84.0%

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 1867 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 1867 const FwTaskIdType identifier)
17 1867 : m_name(name),
18 1867 m_routine(routine),
19 1867 m_routine_argument(routine_argument),
20 1867 m_priority(priority),
21 1867 m_stackSize(stackSize),
22 1867 m_cpuAffinity(cpuAffinity),
23 1867 m_identifier(identifier) {
24 1867 FW_ASSERT(routine != nullptr);
25 1867 }
26
27 3942 Task::TaskRoutineWrapper::TaskRoutineWrapper(Task& self) : m_task(self) {}
28
29 8265 void Task::TaskRoutineWrapper::run(void* wrapper_pointer) {
30 8265 FW_ASSERT(wrapper_pointer != nullptr);
31 8265 TaskRoutineWrapper& wrapper = *reinterpret_cast<TaskRoutineWrapper*>(wrapper_pointer);
32 8265 FW_ASSERT(wrapper.m_user_function != nullptr);
33
34 8265 wrapper.m_task.m_lock.lock();
35
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 8265 times.
8265 Task::State state = wrapper.m_task.m_state;
36 8265 wrapper.m_task.m_lock.unlock();
37 8264 FW_ASSERT(state != Task::State::NOT_STARTED);
38 // Run once start code
39
2/2
✓ Branch 0 taken 1861 times.
✓ Branch 1 taken 6403 times.
8264 if (state == Task::State::STARTING) {
40 1861 wrapper.m_task.m_lock.lock();
41 1863 wrapper.m_task.m_state = Task::State::RUNNING;
42 1863 wrapper.m_task.m_lock.unlock();
43 1863 wrapper.m_task.onStart();
44 }
45
46 // Call user function supplying the user argument
47 8266 wrapper.m_user_function(wrapper.m_user_argument);
48 8265 }
49
50 6818 void Task::TaskRoutineWrapper::invoke() {
51 6818 TaskRoutineWrapper::run(this);
52 6818 }
53
54 TaskRegistry* Task::s_taskRegistry = nullptr;
55 FwSizeType Task::s_numTasks = 0;
56 Mutex Task::s_taskMutex;
57
58 2711775 bool TaskInterface::isCooperative() {
59 2711775 return false;
60 }
61
62
5/5
✓ Branch 10 taken 3942 times.
✓ Branch 20 taken 3942 times.
✓ Branch 39 taken 157680 times.
✓ Branch 40 taken 3942 times.
✓ Branch 46 taken 3942 times.
161622 Task::Task() : m_wrapper(*this), m_handle_storage(), m_delegate(*TaskInterface::getDelegate(m_handle_storage)) {}
63
64 23656 Task::~Task() {
65 // If a registry has been registered and the task has been started then remove task from the registry
66
5/6
✓ Branch 0 taken 1275 times.
✓ Branch 1 taken 2667 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1275 times.
✓ Branch 7 taken 798 times.
✓ Branch 8 taken 477 times.
7884 if ((Task::s_taskRegistry != nullptr) && this->m_registered) {
67 1596 Task::s_taskRegistry->removeTask(this);
68 }
69 7884 m_delegate.~TaskInterface();
70 15772 }
71
72 1 void Task::suspend() {
73 1 this->suspend(Task::SuspensionType::UNINTENTIONAL);
74 1 }
75
76 3105 Task::State Task::getState() const {
77 Task::State state;
78 3105 this->m_lock.lock();
79
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 3105 times.
3105 state = this->m_state;
80 3105 this->m_lock.unlock();
81 3105 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 1867 Task::Status Task::start(const Task::Arguments& arguments) {
97
1/1
✓ Branch 1 taken 1867 times.
1867 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 1867 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
103 1867 FW_ASSERT(arguments.m_routine != nullptr);
104
1/1
✓ Branch 9 taken 1867 times.
1867 this->m_name = arguments.m_name;
105 1867 this->m_state = State::STARTING;
106
107
1/1
✓ Branch 2 taken 1867 times.
1867 Arguments wrapped_arguments = arguments;
108 // Intercept routine and argument with the local wrapper
109 1867 this->m_wrapper.m_user_function = arguments.m_routine;
110 1867 this->m_wrapper.m_user_argument = arguments.m_routine_argument;
111 1867 wrapped_arguments.m_routine = Task::TaskRoutineWrapper::run;
112 1867 wrapped_arguments.m_routine_argument = &this->m_wrapper;
113
114
1/1
✓ Branch 23 taken 1867 times.
1867 Task::Status status = this->m_delegate.start(wrapped_arguments);
115
2/2
✓ Branch 0 taken 1863 times.
✓ Branch 1 taken 4 times.
1867 if (status == Task::Status::OP_OK) {
116
1/1
✓ Branch 6 taken 1863 times.
1863 Task::m_lock.lock();
117 1863 this->m_priority = wrapped_arguments.m_priority;
118
1/1
✓ Branch 6 taken 1863 times.
1863 Task::m_lock.unlock();
119
1/1
✓ Branch 2 taken 1863 times.
1863 Task::s_taskMutex.lock();
120 1863 Task::s_numTasks++;
121
1/1
✓ Branch 2 taken 1863 times.
1863 Task::s_taskMutex.unlock();
122
123 // If a registry has been registered, register task to it
124
2/2
✓ Branch 0 taken 798 times.
✓ Branch 1 taken 1065 times.
1863 if (Task::s_taskRegistry) {
125
1/1
✓ Branch 7 taken 798 times.
798 Task::s_taskRegistry->addTask(this);
126 798 this->m_registered = true;
127 }
128 }
129 1867 return status;
130 1867 }
131
132 1862 void Task::onStart() {
133 1862 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
134 1863 this->m_delegate.onStart();
135 1863 }
136
137 6818 void Task::invokeRoutine() {
138 6818 this->m_wrapper.invoke();
139 6818 }
140
141 2671 Task::Status Task::join() {
142 2671 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
143 2671 Task::Status status = Task::Status::INVALID_STATE;
144 2671 Task::State state = this->getState();
145
4/4
✓ Branch 0 taken 818 times.
✓ Branch 1 taken 1853 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 808 times.
2671 if (state == Task::RUNNING || state == STARTING) {
146 1863 status = this->m_delegate.join();
147 1863 this->m_lock.lock();
148
2/2
✓ Branch 0 taken 1862 times.
✓ Branch 1 taken 1 times.
1863 if (status == Task::Status::OP_OK) {
149 1862 this->m_state = Task::State::EXITED;
150 } else {
151 1 this->m_state = Task::State::UNKNOWN;
152 }
153 1863 this->m_lock.unlock();
154 }
155 2671 return status;
156 }
157
158 1 void Task::suspend(Task::SuspensionType suspensionType) {
159 1 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
160 1 this->m_delegate.suspend(suspensionType);
161 1 this->m_lock.lock();
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 this->m_state = (suspensionType == Task::SuspensionType::INTENTIONAL) ? State::SUSPENDED_INTENTIONALLY
163 : State::SUSPENDED_UNINTENTIONALLY;
164 1 this->m_lock.unlock();
165 1 }
166
167 1 void Task::resume() {
168 1 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
169 1 this->m_delegate.resume();
170 1 }
171
172 2815965 bool Task::isCooperative() {
173 2815965 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
174 3004036 return this->m_delegate.isCooperative();
175 }
176
177 20 TaskString Task::getName() {
178
1/1
✓ Branch 5 taken 20 times.
20 Os::ScopeLock lock(this->m_lock);
179
1/1
✓ Branch 4 taken 20 times.
40 return this->m_name;
180 20 }
181
182 3 FwTaskPriorityType Task::getPriority() {
183
1/1
✓ Branch 5 taken 3 times.
3 Os::ScopeLock lock(this->m_lock);
184 6 return this->m_priority;
185 3 }
186
187 1447 TaskHandle* Task::getHandle() {
188 1447 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
189 1447 return this->m_delegate.getHandle();
190 }
191
192 1619 FwSizeType Task::getNumTasks() {
193 1619 Task::s_taskMutex.lock();
194 1619 FwSizeType num_tasks = Task::s_numTasks;
195 1619 Task::s_taskMutex.unlock();
196 1619 return num_tasks;
197 }
198
199 15742 Os::TaskInterface::Status Task::_delay(const Fw::TimeInterval& interval) {
200 15742 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
201 15758 return this->m_delegate._delay(interval);
202 }
203
204 15753 Os::TaskInterface::Status Task::delay(const Fw::TimeInterval& interval) {
205 15753 return Task::getSingleton()._delay(interval);
206 }
207
208 1870 void Task::init() {
209 // Force trigger on the fly singleton setup
210 1870 (void)Task::getSingleton();
211 1870 }
212
213 17544 Task& Task::getSingleton() {
214
5/7
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 17524 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 18 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
17544 static Task s_singleton;
215 17594 return s_singleton;
216 }
217
218 22 void Task::registerTaskRegistry(TaskRegistry* registry) {
219 22 Task::s_taskRegistry = registry;
220 22 }
221 } // namespace Os
222