[RFC,v1] gstreamer: Be prepared when queueing request
diff mbox series

Message ID 20250909131237.1344483-1-barnabas.pocze@ideasonboard.com
State New
Headers show
Series
  • [RFC,v1] gstreamer: Be prepared when queueing request
Related show

Commit Message

Barnabás Pőcze Sept. 9, 2025, 1:12 p.m. UTC
The moment execution enters `Camera::queueRequest()`, an application must be
prepared to received the corresponding `requestCompleted` signal. However,
the gstreamer element is currently not prepared: it queues the request,
takes a lock, then inserts into a list.

If the request completion handler acquires the lock right after the queueing,
then it will not find the object in the list that it expects. Even potentially
encountering an empty list, running into undefined behaviour when trying
to pop from it.

Fix that by queueing the request after the lock protected insertion.

Bug: https://bugs.libcamera.org/show_bug.cgi?id=238
Fixes: 06bd05beced313 ("gstreamer: Use dedicated lock for request queues")
Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
---

Doing it while holding the lock is not ideal, but the alternative is
getting a raw pointer to the `Request` object beforehand, but that does
not seem too desirable either.

---
 src/gstreamer/gstlibcamerasrc.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--
2.51.0

Comments

Nicolas Dufresne Sept. 9, 2025, 2:34 p.m. UTC | #1
Hi,

Le mardi 09 septembre 2025 à 15:12 +0200, Barnabás Pőcze a écrit :
> The moment execution enters `Camera::queueRequest()`, an application must be
> prepared to received the corresponding `requestCompleted` signal. However,
> the gstreamer element is currently not prepared: it queues the request,
> takes a lock, then inserts into a list.
> 
> If the request completion handler acquires the lock right after the queueing,
> then it will not find the object in the list that it expects. Even potentially
> encountering an empty list, running into undefined behaviour when trying
> to pop from it.
> 
> Fix that by queueing the request after the lock protected insertion.
> 
> Bug: https://bugs.libcamera.org/show_bug.cgi?id=238
> Fixes: 06bd05beced313 ("gstreamer: Use dedicated lock for request queues")
> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
> ---
> 
> Doing it while holding the lock is not ideal, but the alternative is
> getting a raw pointer to the `Request` object beforehand, but that does
> not seem too desirable either.

If we are worried calling into libcamera with uur own lock held, have you
considered pushing it into the list before calling cam_->queueRequest() ? The
camera object in libcamera is supposed to be threadsafe, and we should have
strong ownership on the state and request wrap (if not some reffing is missing I
guess).

Nicolas

p.s. the lock is dangerous if libcamera decides to callback from the caller
thread instead of a separate thread. So calling with lock is implementation
dependant.

> 
> ---
>  src/gstreamer/gstlibcamerasrc.cpp | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/src/gstreamer/gstlibcamerasrc.cpp
> b/src/gstreamer/gstlibcamerasrc.cpp
> index 79a025a57..103dfbca2 100644
> --- a/src/gstreamer/gstlibcamerasrc.cpp
> +++ b/src/gstreamer/gstlibcamerasrc.cpp
> @@ -214,10 +214,10 @@ int GstLibcameraSrcState::queueRequest()
>  	}
> 
>  	GST_TRACE_OBJECT(src_, "Requesting buffers");
> -	cam_->queueRequest(wrap->request_.get());
> 
>  	{
>  		GLibLocker locker(&lock_);
> +		cam_->queueRequest(wrap->request_.get());
>  		queuedRequests_.push(std::move(wrap));
>  	}
> 
> --
> 2.51.0
Barnabás Pőcze Sept. 10, 2025, 2:01 p.m. UTC | #2
Hi

2025. 09. 09. 16:34 keltezéssel, Nicolas Dufresne írta:
> Hi,
> 
> Le mardi 09 septembre 2025 à 15:12 +0200, Barnabás Pőcze a écrit :
>> The moment execution enters `Camera::queueRequest()`, an application must be
>> prepared to received the corresponding `requestCompleted` signal. However,
>> the gstreamer element is currently not prepared: it queues the request,
>> takes a lock, then inserts into a list.
>>
>> If the request completion handler acquires the lock right after the queueing,
>> then it will not find the object in the list that it expects. Even potentially
>> encountering an empty list, running into undefined behaviour when trying
>> to pop from it.
>>
>> Fix that by queueing the request after the lock protected insertion.
>>
>> Bug: https://bugs.libcamera.org/show_bug.cgi?id=238
>> Fixes: 06bd05beced313 ("gstreamer: Use dedicated lock for request queues")
>> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
>> ---
>>
>> Doing it while holding the lock is not ideal, but the alternative is
>> getting a raw pointer to the `Request` object beforehand, but that does
>> not seem too desirable either.
> 
> If we are worried calling into libcamera with uur own lock held, have you
> considered pushing it into the list before calling cam_->queueRequest() ? The
> camera object in libcamera is supposed to be threadsafe, and we should have
> strong ownership on the state and request wrap (if not some reffing is missing I
> guess).

The `RequestWrap` pointer is moved into the container, so one would need to take
a raw pointer to the `Request`. The fact that the request completions handler
unconditionally pops the first element worries me a bit. Although if things have
already gone out of sync there, it might not matter.


> 
> Nicolas
> 
> p.s. the lock is dangerous if libcamera decides to callback from the caller
> thread instead of a separate thread. So calling with lock is implementation
> dependant.

That's true, but currently it is guaranteed. The application developer guide
mentions it explicitly.


Regards,
Barnabás Pőcze

> 
>>
>> ---
>>   src/gstreamer/gstlibcamerasrc.cpp | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/src/gstreamer/gstlibcamerasrc.cpp
>> b/src/gstreamer/gstlibcamerasrc.cpp
>> index 79a025a57..103dfbca2 100644
>> --- a/src/gstreamer/gstlibcamerasrc.cpp
>> +++ b/src/gstreamer/gstlibcamerasrc.cpp
>> @@ -214,10 +214,10 @@ int GstLibcameraSrcState::queueRequest()
>>   	}
>>
>>   	GST_TRACE_OBJECT(src_, "Requesting buffers");
>> -	cam_->queueRequest(wrap->request_.get());
>>
>>   	{
>>   		GLibLocker locker(&lock_);
>> +		cam_->queueRequest(wrap->request_.get());
>>   		queuedRequests_.push(std::move(wrap));
>>   	}
>>
>> --
>> 2.51.0

Patch
diff mbox series

diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
index 79a025a57..103dfbca2 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -214,10 +214,10 @@  int GstLibcameraSrcState::queueRequest()
 	}

 	GST_TRACE_OBJECT(src_, "Requesting buffers");
-	cam_->queueRequest(wrap->request_.get());

 	{
 		GLibLocker locker(&lock_);
+		cam_->queueRequest(wrap->request_.get());
 		queuedRequests_.push(std::move(wrap));
 	}