| 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 | 20 | 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 20 times.
|
20 | ActiveComponentBase::ActiveComponentBase(const char* name) : QueuedComponentBase(name), m_stage(Lifecycle::CREATED) {} |
| 17 | |||
| 18 | 40 | ActiveComponentBase::~ActiveComponentBase() {} | |
| 19 | |||
| 20 | 20 | void ActiveComponentBase::init(FwEnumStoreType instance) { | |
| 21 | 20 | QueuedComponentBase::init(instance); | |
| 22 | 20 | } | |
| 23 | |||
| 24 | #if FW_OBJECT_TO_STRING == 1 | ||
| 25 | ✗ | const char* ActiveComponentBase::getToStringFormatString() { | |
| 26 | ✗ | return "ActComp: %s"; | |
| 27 | } | ||
| 28 | #endif | ||
| 29 | |||
| 30 | 20 | void ActiveComponentBase::start(FwTaskPriorityType priority, | |
| 31 | FwSizeType stackSize, | ||
| 32 | FwSizeType cpuAffinity, | ||
| 33 | FwTaskIdType identifier) { | ||
| 34 |
1/1✓ Branch 1 taken 20 times.
|
20 | Os::TaskString taskName; |
| 35 | |||
| 36 | #if FW_OBJECT_NAMES == 1 | ||
| 37 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
|
20 | 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 20 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
|
20 | Os::Task::taskRoutine routine = (m_task.isCooperative()) ? this->s_taskStateMachine : this->s_taskLoop; |
| 44 |
1/1✓ Branch 1 taken 20 times.
|
20 | Os::Task::Arguments arguments(taskName, routine, this, priority, stackSize, cpuAffinity, identifier); |
| 45 |
1/1✓ Branch 1 taken 20 times.
|
20 | Os::Task::Status status = this->m_task.start(arguments); |
| 46 | 20 | FW_ASSERT(status == Os::Task::Status::OP_OK, static_cast<FwAssertArgType>(status)); | |
| 47 | 20 | } | |
| 48 | |||
| 49 | 20 | void ActiveComponentBase::exit() { | |
| 50 |
1/1✓ Branch 1 taken 20 times.
|
20 | ActiveComponentExitSerializableBuffer exitBuff; |
| 51 |
1/1✓ Branch 1 taken 20 times.
|
20 | SerializeStatus stat = exitBuff.serializeFrom(static_cast<I32>(ACTIVE_COMPONENT_EXIT)); |
| 52 | 20 | FW_ASSERT(FW_SERIALIZE_OK == stat, static_cast<FwAssertArgType>(stat)); | |
| 53 |
1/1✓ Branch 1 taken 20 times.
|
20 | (void)this->m_queue.send(exitBuff, 0, Os::Queue::BlockingType::NONBLOCKING); |
| 54 | 20 | } | |
| 55 | |||
| 56 | 20 | Os::Task::Status ActiveComponentBase::join() { | |
| 57 | 20 | return this->m_task.join(); | |
| 58 | } | ||
| 59 | |||
| 60 | ✗ | Os::Task::Status ActiveComponentBase::join(void** pointer) { | |
| 61 | ✗ | return this->m_task.join(); | |
| 62 | } | ||
| 63 | |||
| 64 | 6092 | void ActiveComponentBase::s_taskStateMachine(void* component_pointer) { | |
| 65 | 6092 | FW_ASSERT(component_pointer != nullptr); | |
| 66 | // cast void* back to active component | ||
| 67 | 6090 | 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 20 times.
✓ Branch 1 taken 6051 times.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6090 | 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 | 20 | case Lifecycle::CREATED: | |
| 76 | 20 | component->preamble(); | |
| 77 | 20 | component->m_stage = Lifecycle::DISPATCHING; | |
| 78 | 20 | break; | |
| 79 | // The second stage of the active component triggers the dispatching loop dispatching messages until an | ||
| 80 | // exit message is received. | ||
| 81 | 6051 | case Lifecycle::DISPATCHING: | |
| 82 |
2/2✓ Branch 1 taken 19 times.
✓ Branch 2 taken 6035 times.
|
6051 | if (component->dispatch() == MsgDispatchStatus::MSG_DISPATCH_EXIT) { |
| 83 | 19 | component->m_stage = Lifecycle::FINALIZING; | |
| 84 | } | ||
| 85 | 6054 | 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 | 19 | case Lifecycle::FINALIZING: | |
| 89 | 19 | component->finalizer(); | |
| 90 | 20 | component->m_stage = Lifecycle::DONE; | |
| 91 | 20 | 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 | 6094 | } | |
| 100 | |||
| 101 | 20 | void ActiveComponentBase::s_taskLoop(void* component_pointer) { | |
| 102 | 20 | FW_ASSERT(component_pointer != nullptr); | |
| 103 | 20 | 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 6090 times.
✓ Branch 1 taken 20 times.
|
6110 | while (component->m_stage != ActiveComponentBase::Lifecycle::DONE) { |
| 108 | 6090 | ActiveComponentBase::s_taskStateMachine(component); | |
| 109 | } | ||
| 110 | 20 | } | |
| 111 | |||
| 112 | 6049 | 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 6045 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 6045 times.
|
6049 | if (this->m_task.isCooperative() and m_queue.getMessagesAvailable() == 0) { |
| 115 | ✗ | return MsgDispatchStatus::MSG_DISPATCH_EMPTY; | |
| 116 | } | ||
| 117 | 6045 | return this->doDispatch(); | |
| 118 | } | ||
| 119 | |||
| 120 | 15 | void ActiveComponentBase::preamble() {} | |
| 121 | |||
| 122 | 19 | void ActiveComponentBase::finalizer() {} | |
| 123 | |||
| 124 | } // namespace Fw | ||
| 125 |