Skip to content

Commit 751ed50

Browse files
authored
Fix #5007 by dropping frame when full (#5019)
* Fix #5007 by dropping frame when full * Formatting
1 parent b0e6c6f commit 751ed50

5 files changed

Lines changed: 55 additions & 2 deletions

File tree

Svc/FrameAccumulator/FrameAccumulator.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,20 @@ void FrameAccumulator ::processRing() {
151151
ComCfg::FrameContext context;
152152
this->dataOut_out(0, buffer, context);
153153
} else {
154-
// No buffer is available, we need to exit and try again later
154+
// No buffer is available
155155
this->log_WARNING_HI_NoBufferAvailable();
156+
// In the case where no buffer is available and the circular buffer is full, we have to drop the buffer
157+
// as there is no other way to retry. Without dropping it, the back pressure would assert the
158+
// processing call, which is built on the assumption that at least one byte would process
159+
if (this->m_inRing.get_free_size() == 0) {
160+
// Discard the whole frame as a last attempt to keep the system afloat
161+
Fw::SerializeStatus serialize_status = this->m_inRing.rotate(size_out);
162+
FW_ASSERT(serialize_status == Fw::SerializeStatus::FW_SERIALIZE_OK);
163+
FW_ASSERT(m_inRing.get_allocated_size() == remaining - size_out,
164+
static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
165+
static_cast<FwAssertArgType>(remaining), static_cast<FwAssertArgType>(size_out));
166+
this->log_WARNING_HI_FrameDetectionValidFrameDropped();
167+
}
156168
break;
157169
}
158170
}

Svc/FrameAccumulator/FrameAccumulator.fpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ module Svc {
2424
severity warning high \
2525
format "Reported size_out={} exceeds accumulation buffer capacity"
2626

27+
@ A frame was detected but dropped because there was no buffer to hold it
28+
event FrameDetectionValidFrameDropped \
29+
severity warning high \
30+
format "A valid frame was detected but dropped"
31+
2732
###############################################################################
2833
# Standard AC Ports for Events
2934
###############################################################################

Svc/FrameAccumulator/test/ut/FrameAccumulatorTestMain.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ TEST(FrameAccumulator, testBufferReturnDeallocation) {
4747
tester.testBufferReturnDeallocation();
4848
}
4949

50+
TEST(FrameAccumulator, testDropValidFrameWhenAllocationFailsAndRingIsFull) {
51+
Svc::FrameAccumulatorTester tester;
52+
tester.testDropValidFrameWhenAllocationFailsAndRingIsFull();
53+
}
54+
5055
TEST(FrameAccumulator, testDetectionErrorHandling) {
5156
Svc::FrameAccumulatorTester tester;
5257
tester.testDetectionErrorHandling();

Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ namespace Svc {
1616

1717
FrameAccumulatorTester ::FrameAccumulatorTester()
1818
: FrameAccumulatorGTestBase("FrameAccumulatorTester", FrameAccumulatorTester::MAX_HISTORY_SIZE),
19-
component("FrameAccumulator") {
19+
component("FrameAccumulator"),
20+
m_failBufferAllocate(false) {
2021
component.configure(this->mockDetector, 1, this->mallocator, 2048);
2122
this->initComponents();
2223
this->connectPorts();
@@ -160,6 +161,28 @@ void FrameAccumulatorTester ::testBufferReturnDeallocation() {
160161
ASSERT_EQ(this->fromPortHistory_bufferDeallocate->at(0).fwBuffer.getSize(), sizeof(data));
161162
}
162163

164+
void FrameAccumulatorTester ::testDropValidFrameWhenAllocationFailsAndRingIsFull() {
165+
U8 data[2048] = {};
166+
Fw::Buffer buffer(data, sizeof(data));
167+
ComCfg::FrameContext context;
168+
const FwSizeType ringCapacity = this->component.m_inRing.get_capacity();
169+
170+
ASSERT_EQ(ringCapacity, sizeof(data));
171+
ASSERT_EQ(this->component.m_inRing.get_free_size(), ringCapacity);
172+
173+
this->m_failBufferAllocate = true;
174+
this->mockDetector.set_next_result(FrameDetector::Status::FRAME_DETECTED, buffer.getSize());
175+
this->invoke_to_dataIn(0, buffer, context);
176+
177+
ASSERT_from_dataReturnOut_SIZE(1); // input buffer ownership was returned
178+
ASSERT_from_dataOut_SIZE(0); // no frame was sent because allocation failed
179+
ASSERT_EQ(this->component.m_inRing.get_allocated_size(), 0);
180+
ASSERT_EQ(this->component.m_inRing.get_free_size(), ringCapacity);
181+
ASSERT_EVENTS_SIZE(2);
182+
ASSERT_EVENTS_NoBufferAvailable_SIZE(1);
183+
ASSERT_EVENTS_FrameDetectionValidFrameDropped_SIZE(1);
184+
}
185+
163186
void FrameAccumulatorTester ::testDetectionErrorHandling() {
164187
FwSizeType too_large_size = this->component.m_inRing.get_capacity() + 1;
165188
// Using buffer_size=1 to simplify test since otherwise Accumulator will loop `buffer_size` times
@@ -247,6 +270,10 @@ void FrameAccumulatorTester ::mockAccumulateFullFrame(U32& frame_size, U32& buff
247270
// ----------------------------------------------------------------------
248271
Fw::Buffer FrameAccumulatorTester ::from_bufferAllocate_handler(FwIndexType portNum, FwSizeType size) {
249272
this->pushFromPortEntry_bufferAllocate(size);
273+
if (this->m_failBufferAllocate) {
274+
this->m_failBufferAllocate = false;
275+
return Fw::Buffer();
276+
}
250277
this->m_buffer.setData(this->m_buffer_slot);
251278
this->m_buffer.setSize(size);
252279
::memset(this->m_buffer.getData(), 0, size);

Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class FrameAccumulatorTester : public FrameAccumulatorGTestBase {
6666
//! Test returning ownership of a buffer
6767
void testBufferReturnDeallocation();
6868

69+
//! Test dropping a detected frame when allocation fails and the ring is full
70+
void testDropValidFrameWhenAllocationFailsAndRingIsFull();
71+
6972
//! Test handling of errors from the FrameDetector (too large size_out)
7073
void testDetectionErrorHandling();
7174

@@ -122,6 +125,7 @@ class FrameAccumulatorTester : public FrameAccumulatorGTestBase {
122125
//! The component under test (should be listed after mallocator for safe destruction)
123126
Svc::FrameAccumulator component;
124127

128+
bool m_failBufferAllocate;
125129
Fw::Buffer m_buffer; // buffer to be returned by mocked bufferAllocate call
126130
U8 m_buffer_slot[2048];
127131
};

0 commit comments

Comments
 (0)