Skip to content

Commit 8b1d627

Browse files
authored
Add improvements to ComQueue (nasa#4190)
* Move dequeued ComBuffer to persistent memory * Add ordering notes to com interface docs * Add buffer ownership tracking * Assert dequeue status for serialized buffer Added status check for dequeue operation to ensure successful serialization. * Fix static_assert -> static_cast * Fix format
1 parent 73ab962 commit 8b1d627

6 files changed

Lines changed: 43 additions & 37 deletions

File tree

Svc/ComQueue/ComQueue.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ ComQueue ::QueueConfigurationTable ::QueueConfigurationTable() {
3131
ComQueue ::ComQueue(const char* const compName)
3232
: ComQueueComponentBase(compName),
3333
m_state(WAITING),
34+
m_buffer_state(OWNED),
3435
m_allocationId(static_cast<FwEnumStoreType>(-1)),
3536
m_allocator(nullptr),
3637
m_allocation(nullptr) {
@@ -191,6 +192,8 @@ void ComQueue::run_handler(const FwIndexType portNum, U32 context) {
191192

192193
void ComQueue ::dataReturnIn_handler(FwIndexType portNum, Fw::Buffer& data, const ComCfg::FrameContext& context) {
193194
static_assert(std::numeric_limits<FwIndexType>::is_signed, "FwIndexType must be signed");
195+
FW_ASSERT(this->m_buffer_state == UNOWNED);
196+
this->m_buffer_state = OWNED;
194197
// For the buffer queues, the index of the queue is portNum offset by COM_PORT_COUNT since
195198
// the first COM_PORT_COUNT queues are for ComBuffer. So we have for buffer queues:
196199
// queueNum = portNum + COM_PORT_COUNT
@@ -259,7 +262,8 @@ void ComQueue::sendComBuffer(Fw::ComBuffer& comBuffer, FwIndexType queueIndex) {
259262
FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status));
260263
context.set_apid(static_cast<ComCfg::Apid::T>(descriptor));
261264
context.set_comQueueIndex(queueIndex);
262-
265+
FW_ASSERT(this->m_buffer_state == OWNED);
266+
this->m_buffer_state = UNOWNED;
263267
this->dataOut_out(0, outBuffer, context);
264268
// Set state to WAITING for the status to come back
265269
this->m_state = WAITING;
@@ -276,7 +280,8 @@ void ComQueue::sendBuffer(Fw::Buffer& buffer, FwIndexType queueIndex) {
276280
FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status));
277281
context.set_apid(static_cast<ComCfg::Apid::T>(descriptor));
278282
context.set_comQueueIndex(queueIndex);
279-
283+
FW_ASSERT(this->m_buffer_state == OWNED);
284+
this->m_buffer_state = UNOWNED;
280285
this->dataOut_out(0, buffer, context);
281286
// Set state to WAITING for the status to come back
282287
this->m_state = WAITING;
@@ -301,12 +306,19 @@ void ComQueue::processQueue() {
301306

302307
// Send out the message based on the type
303308
if (entry.index < COM_PORT_COUNT) {
304-
Fw::ComBuffer comBuffer;
305-
queue.dequeue(reinterpret_cast<U8*>(&comBuffer), sizeof(comBuffer));
306-
this->sendComBuffer(comBuffer, entry.index);
309+
// Dequeue is reading the whole persisted Fw::ComBuffer object from the queue's storage.
310+
// thus it takes an address to the object to fill and the size of the actual object.
311+
FW_ASSERT(this->m_buffer_state == OWNED);
312+
auto dequeue_status =
313+
queue.dequeue(reinterpret_cast<U8*>(&this->m_dequeued_com_buffer), sizeof(this->m_dequeued_com_buffer));
314+
FW_ASSERT(dequeue_status == Fw::SerializeStatus::FW_SERIALIZE_OK,
315+
static_cast<FwAssertArgType>(dequeue_status));
316+
this->sendComBuffer(this->m_dequeued_com_buffer, entry.index);
307317
} else {
308318
Fw::Buffer buffer;
309-
queue.dequeue(reinterpret_cast<U8*>(&buffer), sizeof(buffer));
319+
auto dequeue_status = queue.dequeue(reinterpret_cast<U8*>(&buffer), sizeof(buffer));
320+
FW_ASSERT(dequeue_status == Fw::SerializeStatus::FW_SERIALIZE_OK,
321+
static_cast<FwAssertArgType>(dequeue_status));
310322
this->sendBuffer(buffer, entry.index);
311323
}
312324

Svc/ComQueue/ComQueue.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ namespace Svc {
2222
// ----------------------------------------------------------------------
2323

2424
class ComQueue final : public ComQueueComponentBase {
25+
//! State of the currently transmitted buffer
26+
enum BufferState { OWNED, UNOWNED };
27+
2528
public:
2629
//!< Count of Fw::Com input ports and thus Fw::Com queues
2730
static const FwIndexType COM_PORT_COUNT = ComQueueComponentBase::NUM_COMPACKETQUEUEIN_INPUT_PORTS;
@@ -197,10 +200,12 @@ class ComQueue final : public ComQueueComponentBase {
197200
// ----------------------------------------------------------------------
198201
// Member variables
199202
// ----------------------------------------------------------------------
203+
Fw::ComBuffer m_dequeued_com_buffer; //!< Store a dequeued com buffer so it does not leave scope
200204
Types::Queue m_queues[TOTAL_PORT_COUNT]; //!< Stores queued data waiting for transmission
201205
QueueMetadata m_prioritizedList[TOTAL_PORT_COUNT]; //!< Priority sorted list of queue metadata
202206
bool m_throttle[TOTAL_PORT_COUNT]; //!< Per-queue EVR throttles
203207
SendState m_state; //!< State of the component
208+
BufferState m_buffer_state; //!< Ownership state of buffer
204209

205210
// Storage for Fw::MemAllocator properties
206211
FwEnumStoreType m_allocationId; //!< Component's allocation ID

Svc/ComQueue/test/ut/ComQueueTestMain.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,6 @@ TEST(Nominal, ContextData) {
3939
tester.testContextData();
4040
}
4141

42-
TEST(Nominal, testBufferQueueReturn) {
43-
Svc::ComQueueTester tester;
44-
tester.testBufferQueueReturn();
45-
}
46-
4742
int main(int argc, char** argv) {
4843
::testing::InitGoogleTest(&argc, argv);
4944
return RUN_ALL_TESTS();

Svc/ComQueue/test/ut/ComQueueTester.cpp

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ void ComQueueTester ::testQueueSend() {
9292
for (FwIndexType portNum = 0; portNum < ComQueue::BUFFER_PORT_COUNT; portNum++) {
9393
invoke_to_bufferQueueIn(portNum, buffer);
9494
emitOneAndCheck(portNum, buffer.getData(), buffer.getSize());
95+
ASSERT_from_bufferReturnOut(portNum, buffer);
9596
}
97+
ASSERT_from_bufferReturnOut_SIZE(ComQueue::BUFFER_PORT_COUNT);
9698
clearFromPortHistory();
9799
component.cleanup();
98100
}
@@ -122,7 +124,9 @@ void ComQueueTester ::testQueuePause() {
122124
invoke_to_comStatusIn(0, state);
123125
invoke_to_comStatusIn(0, state);
124126
emitOneAndCheck(portNum, buffer.getData(), buffer.getSize());
127+
ASSERT_from_bufferReturnOut(portNum, buffer);
125128
}
129+
ASSERT_from_bufferReturnOut_SIZE(ComQueue::BUFFER_PORT_COUNT);
126130
clearFromPortHistory();
127131
component.cleanup();
128132
}
@@ -226,9 +230,9 @@ void ComQueueTester::testExternalQueueOverflow() {
226230
dispatchAll();
227231

228232
if (QueueType::BUFFER_QUEUE == overflow_type) {
229-
// Third message overflowed, so third bufferReturnOut
230-
ASSERT_from_bufferReturnOut_SIZE(3);
231-
ASSERT_from_bufferReturnOut(2, buffer);
233+
// Third message overflowed, emitOne yielded a return, so fourth bufferReturnOut
234+
ASSERT_from_bufferReturnOut_SIZE(4);
235+
ASSERT_from_bufferReturnOut(3, buffer);
232236
}
233237

234238
// emitOne() reset the throttle, then overflow again. So expect a second overflow event
@@ -344,26 +348,9 @@ void ComQueueTester ::testContextData() {
344348
component.cleanup();
345349
}
346350

347-
void ComQueueTester ::testBufferQueueReturn() {
348-
U8 data[BUFFER_LENGTH] = BUFFER_DATA;
349-
Fw::Buffer buffer(&data[0], sizeof(data));
350-
ComCfg::FrameContext context;
351-
configure();
352-
353-
for (FwIndexType portNum = 0; portNum < ComQueue::TOTAL_PORT_COUNT; portNum++) {
354-
clearFromPortHistory();
355-
context.set_comQueueIndex(portNum);
356-
invoke_to_dataReturnIn(0, buffer, context);
357-
// APIDs that correspond to an buffer originating from a Fw.Com port
358-
// do no get deallocated – APIDs that correspond to a Fw.Buffer do
359-
if (portNum < ComQueue::COM_PORT_COUNT) {
360-
ASSERT_from_bufferReturnOut_SIZE(0);
361-
} else {
362-
ASSERT_from_bufferReturnOut_SIZE(1);
363-
ASSERT_from_bufferReturnOut(0, buffer);
364-
}
365-
}
366-
component.cleanup();
351+
void ComQueueTester ::from_dataOut_handler(FwIndexType portNum, Fw::Buffer& data, const ComCfg::FrameContext& context) {
352+
this->pushFromPortEntry_dataOut(data, context);
353+
this->invoke_to_dataReturnIn(0, data, context);
367354
}
368355

369356
} // end namespace Svc

Svc/ComQueue/test/ut/ComQueueTester.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,6 @@ class ComQueueTester : public ComQueueGTestBase {
7777

7878
void testContextData();
7979

80-
void testBufferQueueReturn();
81-
8280
private:
8381
// ----------------------------------------------------------------------
8482
// Helper methods
@@ -92,6 +90,9 @@ class ComQueueTester : public ComQueueGTestBase {
9290
//!
9391
void initComponents();
9492

93+
//! Intercept from data out to return the call
94+
void from_dataOut_handler(FwIndexType portNum, Fw::Buffer& data, const ComCfg::FrameContext& context) override;
95+
9596
private:
9697
// ----------------------------------------------------------------------
9798
// Variables

docs/reference/communication-adapter-interface.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ This port is used to receive a callback returning ownership of the `Fw::Buffer`
6565
This port carries a status of `Fw::Success::SUCCESS` or `Fw::Success::FAILURE` typically in response to a call to the `dataIn` port described above.
6666

6767
> [!NOTE]
68-
> it is critical to obey the protocol as described in the protocol section below.
68+
> It is critical to obey the protocol as described in the protocol section below.
69+
70+
> [!CAUTION]
71+
> Calls to `comStatusOut` must happen after calls to `dataReturnOut` returning the data the com status applies to.
6972
7073
## Communication Queue Protocol
7174

@@ -110,5 +113,8 @@ startup to indicate communication is initially ready and once after each Fw::Suc
110113
communication has been restored. By emitting Fw::Success::SUCCESS after any failure, the communication adapter ensures
111114
that each received message eventually results in a Fw::Success::SUCCESS.
112115

116+
Since the communication status reflects the status of specific data transmission it must be sent after the return (deallocation) of that data.
117+
118+
113119
> [!NOTE]
114120
> It is imperative that *Communication Adapters* implement the `comStatusOut` protocol correctly.

0 commit comments

Comments
 (0)