GCC Code Coverage Report


Directory: ./
File: Os/Task.cpp
Date: 2026-09-03 21:13:48
Exec Total Coverage
Lines: 129 137 94.2%
Functions: 24 26 92.3%
Branches: 40 50 80.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 1872 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 1872 const FwTaskIdType identifier)
17 1872 : m_name(name),
18 1872 m_routine(routine),
19 1872 m_routine_argument(routine_argument),
20 1872 m_priority(priority),
21 1872 m_stackSize(stackSize),
22 1872 m_cpuAffinity(cpuAffinity),
23 1872 m_identifier(identifier) {
24 1872 FW_ASSERT(routine != nullptr);
25 1872 }
26
27 3703 Task::TaskRoutineWrapper::TaskRoutineWrapper(Task& self) : m_task(self) {}
28
29 13043 void Task::TaskRoutineWrapper::run(void* wrapper_pointer) {
30 13043 FW_ASSERT(wrapper_pointer != nullptr);
31 13043 TaskRoutineWrapper& wrapper = *reinterpret_cast<TaskRoutineWrapper*>(wrapper_pointer);
32 13043 FW_ASSERT(wrapper.m_user_function != nullptr);
33
34 13043 wrapper.m_task.m_lock.lock();
35
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 13043 times.
13043 Task::State state = wrapper.m_task.m_state;
36 13043 wrapper.m_task.m_lock.unlock();
37 13043 FW_ASSERT(state != Task::State::NOT_STARTED);
38 // Run once start code
39
2/2
✓ Branch 0 taken 1868 times.
✓ Branch 1 taken 11175 times.
13043 if (state == Task::State::STARTING) {
40 1868 wrapper.m_task.m_lock.lock();
41 1868 wrapper.m_task.m_state = Task::State::RUNNING;
42 1868 wrapper.m_task.m_lock.unlock();
43 1868 wrapper.m_task.onStart();
44 }
45
46 // Call user function supplying the user argument
47 13043 wrapper.m_user_function(wrapper.m_user_argument);
48 13043 }
49
50 11584 void Task::TaskRoutineWrapper::invoke() {
51 11584 TaskRoutineWrapper::run(this);
52 11584 }
53
54 TaskRegistry* Task::s_taskRegistry = nullptr;
55 FwSizeType Task::s_numTasks = 0;
56 Mutex Task::s_taskMutex;
57
58 7931454 bool TaskInterface::isCooperative() {
59 7931454 return false;
60 }
61
62
5/5
✓ Branch 10 taken 3703 times.
✓ Branch 20 taken 3703 times.
✓ Branch 39 taken 148120 times.
✓ Branch 40 taken 3703 times.
✓ Branch 46 taken 3703 times.
151823 Task::Task() : m_wrapper(*this), m_handle_storage(), m_delegate(*TaskInterface::getDelegate(m_handle_storage)) {}
63
64 22222 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 1303 times.
✓ Branch 1 taken 2400 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1303 times.
✓ Branch 7 taken 810 times.
✓ Branch 8 taken 493 times.
7406 if ((Task::s_taskRegistry != nullptr) && this->m_registered) {
67 1620 Task::s_taskRegistry->removeTask(this);
68 }
69 7406 m_delegate.~TaskInterface();
70 14816 }
71
72 1 void Task::suspend() {
73 1 this->suspend(Task::SuspensionType::UNINTENTIONAL);
74 1 }
75
76 3077 Task::State Task::getState() const {
77 Task::State state;
78 3077 this->m_lock.lock();
79
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 3077 times.
3077 state = this->m_state;
80 3077 this->m_lock.unlock();
81 3077 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 1872 Task::Status Task::start(const Task::Arguments& arguments) {
97
1/1
✓ Branch 1 taken 1872 times.
1872 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 1872 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
103 1872 FW_ASSERT(arguments.m_routine != nullptr);
104
1/1
✓ Branch 9 taken 1872 times.
1872 this->m_name = arguments.m_name;
105 1872 this->m_state = State::STARTING;
106
107
1/1
✓ Branch 2 taken 1872 times.
1872 Arguments wrapped_arguments = arguments;
108 // Intercept routine and argument with the local wrapper
109 1872 this->m_wrapper.m_user_function = arguments.m_routine;
110 1872 this->m_wrapper.m_user_argument = arguments.m_routine_argument;
111 1872 wrapped_arguments.m_routine = Task::TaskRoutineWrapper::run;
112 1872 wrapped_arguments.m_routine_argument = &this->m_wrapper;
113
114
1/1
✓ Branch 23 taken 1872 times.
1872 Task::Status status = this->m_delegate.start(wrapped_arguments);
115
2/2
✓ Branch 0 taken 1868 times.
✓ Branch 1 taken 4 times.
1872 if (status == Task::Status::OP_OK) {
116
1/1
✓ Branch 6 taken 1868 times.
1868 Task::m_lock.lock();
117 1868 this->m_priority = wrapped_arguments.m_priority;
118
1/1
✓ Branch 6 taken 1868 times.
1868 Task::m_lock.unlock();
119
1/1
✓ Branch 2 taken 1868 times.
1868 Task::s_taskMutex.lock();
120 1868 Task::s_numTasks++;
121
1/1
✓ Branch 2 taken 1868 times.
1868 Task::s_taskMutex.unlock();
122
123 // If a registry has been registered, register task to it
124
2/2
✓ Branch 0 taken 810 times.
✓ Branch 1 taken 1058 times.
1868 if (Task::s_taskRegistry) {
125
1/1
✓ Branch 7 taken 810 times.
810 Task::s_taskRegistry->addTask(this);
126 810 this->m_registered = true;
127 }
128 }
129 1872 return status;
130 1872 }
131
132 1868 void Task::onStart() {
133 1868 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
134 1868 this->m_delegate.onStart();
135 1868 }
136
137 11584 void Task::invokeRoutine() {
138 11584 this->m_wrapper.invoke();
139 11584 }
140
141 2661 Task::Status Task::join() {
142 2661 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
143 2661 Task::Status status = Task::Status::INVALID_STATE;
144 2661 Task::State state = this->getState();
145
4/4
✓ Branch 0 taken 799 times.
✓ Branch 1 taken 1862 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 793 times.
2661 if (state == Task::RUNNING || state == STARTING) {
146 1868 status = this->m_delegate.join();
147 1868 this->m_lock.lock();
148
2/2
✓ Branch 0 taken 1867 times.
✓ Branch 1 taken 1 times.
1868 if (status == Task::Status::OP_OK) {
149 1867 this->m_state = Task::State::EXITED;
150 } else {
151 1 this->m_state = Task::State::UNKNOWN;
152 }
153 1868 this->m_lock.unlock();
154 }
155 2661 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 8195890 bool Task::isCooperative() {
173 8195890 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
174 10029626 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 FwTaskPriorityType Task::getPriority() {
183 Os::ScopeLock lock(this->m_lock);
184 return this->m_priority;
185 }
186
187 1459 TaskHandle* Task::getHandle() {
188 1459 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
189 1459 return this->m_delegate.getHandle();
190 }
191
192 1611 FwSizeType Task::getNumTasks() {
193 1611 Task::s_taskMutex.lock();
194 1611 FwSizeType num_tasks = Task::s_numTasks;
195 1611 Task::s_taskMutex.unlock();
196 1611 return num_tasks;
197 }
198
199 11599 Os::TaskInterface::Status Task::_delay(const Fw::TimeInterval& interval) {
200 11599 FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
201 11606 return this->m_delegate._delay(interval);
202 }
203
204 11625 Os::TaskInterface::Status Task::delay(const Fw::TimeInterval& interval) {
205 11625 return Task::getSingleton()._delay(interval);
206 }
207
208 1875 void Task::init() {
209 // Force trigger on the fly singleton setup
210 1875 (void)Task::getSingleton();
211 1875 }
212
213 13477 Task& Task::getSingleton() {
214
4/7
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 13461 times.
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
13477 static Task s_singleton;
215 13456 return s_singleton;
216 }
217
218 17 void Task::registerTaskRegistry(TaskRegistry* registry) {
219 17 Task::s_taskRegistry = registry;
220 17 }
221 } // namespace Os
222