From 4f9c07b4faafbf6908806f222fe71ef00dec49f4 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 3 Mar 2026 20:54:15 +0100 Subject: [PATCH] ZeroCopyReturnValue: Reset status properly --- common/ZeroCopyReturnValue.cpp | 23 ++++----- tests/ImageBufferTest.cpp | 90 ++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 11 deletions(-) diff --git a/common/ZeroCopyReturnValue.cpp b/common/ZeroCopyReturnValue.cpp index 0e6c5b69..984b9082 100644 --- a/common/ZeroCopyReturnValue.cpp +++ b/common/ZeroCopyReturnValue.cpp @@ -7,8 +7,8 @@ #include "ThreadSafeFIFO.h" ZeroCopyReturnValue::ZeroCopyReturnValue(void *in_ptr, ImageBuffer &in_ctrl, uint32_t in_handle) -: ptr(in_ptr), payload_size(0), image_number(-1), buf_ctrl(in_ctrl), handle(in_handle), -indexed(false) { + : ptr(in_ptr), payload_size(0), image_number(-1), buf_ctrl(in_ctrl), handle(in_handle), + indexed(false) { } void ZeroCopyReturnValue::SetImageNumber(int64_t in_image_number) { @@ -23,20 +23,21 @@ size_t ZeroCopyReturnValue::GetImageSize() const { return payload_size; } -void * ZeroCopyReturnValue::GetImage() const { +void *ZeroCopyReturnValue::GetImage() const { return ptr; } void ZeroCopyReturnValue::release() { - if (status == ImageBufferEntryStatus::InPreparation) - ReadyToSend(); + if (status == ImageBufferEntryStatus::InPreparation) + ReadyToSend(); -if (status == ImageBufferEntryStatus::Sending) { - buf_ctrl.ReleaseSlot(handle); -} else { - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Trying to send image that is not in preparation"); -} + if (status == ImageBufferEntryStatus::Sending) { + buf_ctrl.ReleaseSlot(handle); + status = ImageBufferEntryStatus::InPreparation; + } else { + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Trying to send image that is not in preparation"); + } } int64_t ZeroCopyReturnValue::GetImageNumber() const { diff --git a/tests/ImageBufferTest.cpp b/tests/ImageBufferTest.cpp index f1042dcd..977c5ad8 100644 --- a/tests/ImageBufferTest.cpp +++ b/tests/ImageBufferTest.cpp @@ -243,3 +243,93 @@ TEST_CASE("ImageBuffer_BuffersNotReturned") { REQUIRE(buf_ctrl.GetAvailSlots() == 3); REQUIRE(!buf_ctrl.CheckIfBufferReturned(std::chrono::microseconds(1))); } + +TEST_CASE("ImageBuffer_SlotReuse") { + DiffractionExperiment experiment(DetJF(18,3,8,36)); + + // Only 1 slot so reuse is guaranteed + ImageBuffer buf_ctrl(experiment.GetImageBufferLocationSize()); + buf_ctrl.StartMeasurement(experiment); + + REQUIRE(buf_ctrl.GetStatus().total_slots == 1); + REQUIRE(buf_ctrl.GetAvailSlots() == 1); + + // First cycle: acquire -> ReadyToSend -> release + ZeroCopyReturnValue *ret = buf_ctrl.GetImageSlot(); + REQUIRE(ret != nullptr); + REQUIRE(buf_ctrl.GetAvailSlots() == 0); + + ret->SetImageNumber(0); + ret->SetImageSize(100); + ret->SetIndexed(false); + ret->ReadyToSend(); + + REQUIRE(buf_ctrl.GetStatus().sending_slots == 1); + REQUIRE(buf_ctrl.GetStatus().preparation_slots == 0); + + ret->release(); + + REQUIRE(buf_ctrl.GetAvailSlots() == 1); + REQUIRE(buf_ctrl.GetStatus().sending_slots == 0); + + // Second cycle: reuse the same slot — this is where the bug manifested + ZeroCopyReturnValue *ret2 = buf_ctrl.GetImageSlot(); + REQUIRE(ret2 != nullptr); + REQUIRE(buf_ctrl.GetAvailSlots() == 0); + REQUIRE(buf_ctrl.GetStatus().preparation_slots == 1); + + ret2->SetImageNumber(1); + ret2->SetImageSize(200); + ret2->SetIndexed(true); + REQUIRE_NOTHROW(ret2->ReadyToSend()); + + REQUIRE(buf_ctrl.GetStatus().sending_slots == 1); + REQUIRE(buf_ctrl.GetStatus().preparation_slots == 0); + + REQUIRE_NOTHROW(ret2->release()); + + REQUIRE(buf_ctrl.GetAvailSlots() == 1); + REQUIRE(buf_ctrl.GetStatus().sending_slots == 0); + + // Third cycle: verify it keeps working + ZeroCopyReturnValue *ret3 = buf_ctrl.GetImageSlot(); + REQUIRE(ret3 != nullptr); + + ret3->SetImageNumber(2); + ret3->SetImageSize(300); + ret3->SetIndexed(false); + REQUIRE_NOTHROW(ret3->ReadyToSend()); + REQUIRE_NOTHROW(ret3->release()); + + REQUIRE(buf_ctrl.GetAvailSlots() == 1); + REQUIRE(buf_ctrl.Finalize(std::chrono::microseconds(1))); +} + +TEST_CASE("ImageBuffer_SlotReuse_ReleaseFromInPreparation") { + DiffractionExperiment experiment(DetJF(18,3,8,36)); + + ImageBuffer buf_ctrl(experiment.GetImageBufferLocationSize()); + buf_ctrl.StartMeasurement(experiment); + + // First cycle: acquire -> release directly (skipping explicit ReadyToSend) + ZeroCopyReturnValue *ret = buf_ctrl.GetImageSlot(); + REQUIRE(ret != nullptr); + + ret->SetImageNumber(0); + ret->SetImageSize(100); + ret->release(); + + REQUIRE(buf_ctrl.GetAvailSlots() == 1); + + // Second cycle: reuse after release-from-InPreparation path + ZeroCopyReturnValue *ret2 = buf_ctrl.GetImageSlot(); + REQUIRE(ret2 != nullptr); + + ret2->SetImageNumber(1); + ret2->SetImageSize(200); + REQUIRE_NOTHROW(ret2->ReadyToSend()); + REQUIRE_NOTHROW(ret2->release()); + + REQUIRE(buf_ctrl.GetAvailSlots() == 1); + REQUIRE(buf_ctrl.Finalize(std::chrono::microseconds(1))); +} \ No newline at end of file