[RFC] delayed_controls: avoid reading undefined control value
Milan Zamazal
mzamazal at redhat.com
Wed Dec 11 15:13:49 CET 2024
Laurent Pinchart <laurent.pinchart at ideasonboard.com> writes:
> (CC'ing Naush for the question related to the Raspberry Pi
> implementation)
>
> On Tue, Dec 10, 2024 at 10:39:50PM +0000, Kieran Bingham wrote:
>> Quoting Stanislaw Gruszka (2024-12-06 11:27:43)
>> > Limit ControlRingBuffer index by number of queued entries in order do
>> > avoid reading undefined control value with type ControlTypeNone .
>> >
>> > It can happen at the begging of streaming when ControlRingBuffer is
>>
>> s/begging/beginning/
>>
>> > not yet filled and there are errors on CSI-2 bus resulting dropping
>> > frames. Then we can call to DelayedControls::get() with frame number
>> > that exceed number of saved entries and get below assertion failure:
>> >
>> > ../src/libcamera/delayed_controls.cpp:227:
>> > libcamera::ControlList libcamera::DelayedControls::get(uint32_t):
>> > Assertion `info.type() != ControlTypeNone' failed
>> >
>> > Bug: https://bugs.libcamera.org/show_bug.cgi?id=241
>> > Signed-off-by: Stanislaw Gruszka <stanislaw.gruszka at linux.intel.com>
>> > ---
>> > Notes: When debugging this I notice that the push() and get() are
>> > done in different threads. Maybe mutex should be
>> > used? Not sure how synchronization works for mojom signals
>> > handlers.
>
> The comment related to the SoftwareISP::inputBufferReady signal, in the
> SimpleCameraData::init() function, possibly applies to other signals of
> the SoftwareISP class, although I wouldn't expect it would affect the
> setSensorControls signal. Stanislaw, could you provide more information
> about which threads the push and get functions are called from ?
> Everything should be called from the camera manager thread.
>
> Looking at this more deeply, I think the outputBufferReady and
> statsReady signals may be mishandled, as they seem to be emitted from
> the soft ISP worker thread but not treated the same way as the
> inputBufferReady signal. We shouldn't have to deal with it when
> connecting the signals in the user, the SoftwareISP class should handle
> thread crossing, and emit all its signals from the camera manager
> thread. Milan, is this something you could address ?
Honestly, I usually get confused easily when trying to follow the
related flows and understanding what's what. If I understand it
correctly, the pipeline handler instance is created in the camera
manager thread. Thus inputBufferReady is run there and the other
signals could do the same the same way (there is apparently no reason
why not). Then yes, it could be fixed easily.
BTW there is software ISP TODO #3 where you suggest that statsReady
could be possibly removed completely. When I worked on buffer sharing,
I didn't see an obvious way/reason to do it, so let's fix just what's
immediately wrong about it for now.
>> I thought they would be in the same thread as the CameraManager event
>> loop... Perhaps we could/should have an assertion that the thread is
>> the same - otherwise - yes it would probably need a lock if there's a
>> reader and a writer on both ends of the queue.
>>
>> I'd double check the threading first.
>>
>> > Also I'm not sure if similar change like in this patch
>> > is not needed for rpi DelayedControls
>>
>> Probably. There's very little different between the two implementations,
>> so we should probably keep them aligned with bugfixes at least until
>> someone tries to realign them both again.
>
> Naush, could you check this ?
>
>> It looks like the cookie feature was easier to fork than to add, I can't
>> remember all the details ;_(
>>
>>
>> > Alternative fix would be to pre-fill ControlRingBuffer with
>> > valid control values. Should we care about possibility
>> > of queueCount_ overflowing ?
>>
>> I'm not sure what 'valid' control values would be ? I think just
>> clamping to the most recent data is probably the best we can do ? And 'I
>> think' would reflect the most up to date information we have about
>> what's configured on the sensor - so I think it's still even the 'most
>> correct' (and probably even 'is' correct) data we can return in the
>> get() call in this event.
>>
>>
>> I think I can already throw this on here, it seems like a sane input
>> parameter validation:
>>
>>
>> Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
>>
>> > src/libcamera/delayed_controls.cpp | 2 +-
>> > 1 file changed, 1 insertion(+), 1 deletion(-)
>> >
>> > diff --git a/src/libcamera/delayed_controls.cpp b/src/libcamera/delayed_controls.cpp
>> > index 94d0a575..78b0b8f7 100644
>> > --- a/src/libcamera/delayed_controls.cpp
>> > +++ b/src/libcamera/delayed_controls.cpp
>> > @@ -202,7 +202,7 @@ bool DelayedControls::push(const ControlList &controls)
>> > */
>> > ControlList DelayedControls::get(uint32_t sequence)
>> > {
>> > - unsigned int index = std::max<int>(0, sequence - maxDelay_);
>> > + unsigned int index = std::clamp<int>(sequence - maxDelay_, 0, queueCount_ - 1);
>> >
>> > ControlList out(device_->controls());
>> > for (const auto &ctrl : values_) {
More information about the libcamera-devel
mailing list