release() published the handle through ReleaseSlot and only then wrote status = InPreparation. ReleaseSlot makes the handle available to GetImageSlot immediately, and GetImageSlot hands back this very object without resetting it, so the receiver could observe the stale Sending status and throw "Trying to send image that is not in preparation", aborting the collection - or take the opposite interleaving and leak the slot. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
70 lines
2.1 KiB
C++
70 lines
2.1 KiB
C++
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "ZeroCopyReturnValue.h"
|
|
|
|
#include "ImageBuffer.h"
|
|
#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) {
|
|
}
|
|
|
|
void ZeroCopyReturnValue::SetImageNumber(int64_t in_image_number) {
|
|
image_number = in_image_number;
|
|
}
|
|
|
|
void ZeroCopyReturnValue::SetImageSize(size_t in_payload_size) {
|
|
payload_size = in_payload_size;
|
|
}
|
|
|
|
size_t ZeroCopyReturnValue::GetImageSize() const {
|
|
return payload_size;
|
|
}
|
|
|
|
void *ZeroCopyReturnValue::GetImage() const {
|
|
return ptr;
|
|
}
|
|
|
|
void ZeroCopyReturnValue::release() {
|
|
if (status == ImageBufferEntryStatus::InPreparation)
|
|
ReadyToSend();
|
|
|
|
if (status == ImageBufferEntryStatus::Sending) {
|
|
// Reset before releasing: ReleaseSlot puts the handle back on the free list, after which
|
|
// another thread can take this same object out of GetImageSlot() and read status.
|
|
status = ImageBufferEntryStatus::InPreparation;
|
|
buf_ctrl.ReleaseSlot(handle);
|
|
} else {
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"Trying to send image that is not in preparation");
|
|
}
|
|
}
|
|
|
|
int64_t ZeroCopyReturnValue::GetImageNumber() const {
|
|
return image_number;
|
|
}
|
|
|
|
void ZeroCopyReturnValue::SetIndexed(bool input) {
|
|
indexed = input;
|
|
}
|
|
|
|
bool ZeroCopyReturnValue::IsIndexed() const {
|
|
return indexed;
|
|
}
|
|
|
|
uint32_t ZeroCopyReturnValue::GetHandle() const {
|
|
return handle;
|
|
}
|
|
|
|
void ZeroCopyReturnValue::ReadyToSend() {
|
|
if (status == ImageBufferEntryStatus::InPreparation) {
|
|
buf_ctrl.ReadyToSend(handle, image_number, payload_size, indexed);
|
|
status = ImageBufferEntryStatus::Sending;
|
|
} else {
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"Trying to send image that is not in preparation");
|
|
}
|
|
}
|