GCC Code Coverage Report


Directory: ./
File: ActiveComponentBase.cpp
Date: 2026-09-23 22:12:10
Exec Total Coverage
Lines: 50 60 83.3%
Functions: 12 14 85.7%
Branches: 20 27 74.1%

Line Branch Exec Source
1 #include <Fw/Comp/ActiveComponentBase.hpp>
2 #include <Fw/FPrimeBasicTypes.hpp>
3 #include <Fw/Types/Assert.hpp>
4 #include <Os/TaskString.hpp>
5
6 namespace Fw {
7
8 class ActiveComponentExitSerializableBuffer : public Fw::LinearBufferBase {
9 public:
10 21 ActiveComponentExitSerializableBuffer() : Fw::LinearBufferBase(m_buff, sizeof(m_buff)) {}
11
12 private:
13 U8 m_buff[sizeof(ActiveComponentBase::ACTIVE_COMPONENT_EXIT)];
14 };
15
16
1/1
✓ Branch 2 taken 21 times.
21 ActiveComponentBase::ActiveComponentBase(const char* name) : QueuedComponentBase(name), m_stage(Lifecycle::CREATED) {}
17
18 42 ActiveComponentBase::~ActiveComponentBase() {}
19
20 21 void ActiveComponentBase::init(FwEnumStoreType instance) {
21 21 QueuedComponentBase::init(instance);
22 21 }
23
24 #if FW_OBJECT_TO_STRING == 1
25 ✗ const char* ActiveComponentBase::getToStringFormatString() {
26 ✗ return "ActComp: %s";
27 }
28 #endif
29
30 21 void ActiveComponentBase::start(FwTaskPriorityType priority,
31 FwSizeType stackSize,
32 FwSizeType cpuAffinity,
33 FwTaskIdType identifier) {
34
1/1
✓ Branch 1 taken 21 times.
21 Os::TaskString taskName;
35
36 #if FW_OBJECT_NAMES == 1
37
2/2
✓ Branch 1 taken 21 times.
✓ Branch 4 taken 21 times.
21 taskName = this->getObjName();
38 #else
39 (void)taskName.format("ActComp_%" PRI_FwSizeType, Os::Task::getNumTasks());
40 #endif
41 // Cooperative threads tasks externalize the task loop, and as such use the state machine as their task function
42 // Standard multithreading tasks use the task loop to respectively call the state machine
43
2/3
✓ Branch 1 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
21 Os::Task::taskRoutine routine = (m_task.isCooperative()) ? this->s_taskStateMachine : this->s_taskLoop;
44
1/1
✓ Branch 1 taken 21 times.
21 Os::Task::Arguments arguments(taskName, routine, this, priority, stackSize, cpuAffinity, identifier);
45
1/1
✓ Branch 1 taken 21 times.
21 Os::Task::Status status = this->m_task.start(arguments);
46 21 FW_ASSERT(status == Os::Task::Status::OP_OK, static_cast<FwAssertArgType>(status));
47 21 }
48
49 21 void ActiveComponentBase::exit() {
50
1/1
✓ Branch 1 taken 21 times.
21 ActiveComponentExitSerializableBuffer exitBuff;
51
1/1
✓ Branch 1 taken 21 times.
21 SerializeStatus stat = exitBuff.serializeFrom(static_cast<I32>(ACTIVE_COMPONENT_EXIT));
52 21 FW_ASSERT(FW_SERIALIZE_OK == stat, static_cast<FwAssertArgType>(stat));
53
1/1
✓ Branch 1 taken 21 times.
21 (void)this->m_queue.send(exitBuff, 0, Os::Queue::BlockingType::NONBLOCKING);
54 21 }
55
56 21 Os::Task::Status ActiveComponentBase::join() {
57 21 return this->m_task.join();
58 }
59
60 ✗ Os::Task::Status ActiveComponentBase::join(void** pointer) {
61 ✗ return this->m_task.join();
62 }
63
64 6704 void ActiveComponentBase::s_taskStateMachine(void* component_pointer) {
65 6704 FW_ASSERT(component_pointer != nullptr);
66 // cast void* back to active component
67 6705 ActiveComponentBase* component = static_cast<ActiveComponentBase*>(component_pointer);
68
69 // Each invocation of this function runs a single stage of the thread lifecycle. This has moved the thread
70 // while loop to the top level such that it can be replaced by something else (e.g. cooperative thread
71 // dispatcher) and is not intrinsic to this code.
72
3/5
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 6663 times.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6705 switch (component->m_stage) {
73 // The first stage the active component triggers the "preamble" call before moving into the dispatching
74 // stage of the component thread.
75 21 case Lifecycle::CREATED:
76 21 component->preamble();
77 21 component->m_stage = Lifecycle::DISPATCHING;
78 21 break;
79 // The second stage of the active component triggers the dispatching loop dispatching messages until an
80 // exit message is received.
81 6663 case Lifecycle::DISPATCHING:
82
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 6645 times.
6663 if (component->dispatch() == MsgDispatchStatus::MSG_DISPATCH_EXIT) {
83 21 component->m_stage = Lifecycle::FINALIZING;
84 }
85 6666 break;
86 // The second-to-last stage is where the finalizer is called. This will transition to the final stage
87 // automatically after the finalizer is called
88 21 case Lifecycle::FINALIZING:
89 21 component->finalizer();
90 21 component->m_stage = Lifecycle::DONE;
91 21 break;
92 // The last stage does nothing, cooperative tasks live here forever, threaded tasks exit on this condition
93 ✗ case Lifecycle::DONE:
94 ✗ break;
95 ✗ default:
96 ✗ FW_ASSERT(false);
97 ✗ break;
98 }
99 6708 }
100
101 21 void ActiveComponentBase::s_taskLoop(void* component_pointer) {
102 21 FW_ASSERT(component_pointer != nullptr);
103 21 ActiveComponentBase* component = static_cast<ActiveComponentBase*>(component_pointer);
104 // A non-cooperative task switching implementation is just a while-loop around the active component
105 // state-machine. Here the while loop is at top-level.
106 // @non-terminating@: component lifecycle loop runs until DONE
107
2/2
✓ Branch 0 taken 6709 times.
✓ Branch 1 taken 21 times.
6730 while (component->m_stage != ActiveComponentBase::Lifecycle::DONE) {
108 6709 ActiveComponentBase::s_taskStateMachine(component);
109 }
110 21 }
111
112 6664 ActiveComponentBase::MsgDispatchStatus ActiveComponentBase::dispatch() {
113 // Cooperative tasks should return rather than block when no messages are available
114
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 6660 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 6660 times.
6664 if (this->m_task.isCooperative() and m_queue.getMessagesAvailable() == 0) {
115 ✗ return MsgDispatchStatus::MSG_DISPATCH_EMPTY;
116 }
117 6660 return this->doDispatch();
118 }
119
120 16 void ActiveComponentBase::preamble() {}
121
122 21 void ActiveComponentBase::finalizer() {}
123
124 } // namespace Fw
125