[v1,1/6] libcamera: pipeline_handler: Move waitingRequests_ into camera class
diff mbox series

Message ID 20250630081126.2384387-2-stefan.klug@ideasonboard.com
State New
Headers show
Series
  • rkisp1: Allow usage of more than 4 buffers
Related show

Commit Message

Stefan Klug June 30, 2025, 8:11 a.m. UTC
The waiting requests of one camera should not be able to influence
queuing to another camera. Therefore change the single waitingRequests_
queue into one queue per camera.

Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>

---

Changes in v1:
- Added camera param to doQueueRequests() which allows to remove a loop
---
 include/libcamera/internal/camera.h           |  2 ++
 include/libcamera/internal/pipeline_handler.h |  5 +---
 src/libcamera/pipeline_handler.cpp            | 26 ++++++++++++-------
 3 files changed, 19 insertions(+), 14 deletions(-)

Comments

Umang Jain June 30, 2025, 8:53 a.m. UTC | #1
Hi Stefan,

On Mon, Jun 30, 2025 at 10:11:16AM +0200, Stefan Klug wrote:
> The waiting requests of one camera should not be able to influence
> queuing to another camera. Therefore change the single waitingRequests_
> queue into one queue per camera.

I would just expand on the influence of this common waiting queue,
for e.g. on the stop() cycle, which seems to be a bug now (and fixed
with this patch).

> 
> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
> 
> ---
> 
> Changes in v1:
> - Added camera param to doQueueRequests() which allows to remove a loop
> ---
>  include/libcamera/internal/camera.h           |  2 ++
>  include/libcamera/internal/pipeline_handler.h |  5 +---
>  src/libcamera/pipeline_handler.cpp            | 26 ++++++++++++-------
>  3 files changed, 19 insertions(+), 14 deletions(-)
> 
> diff --git a/include/libcamera/internal/camera.h b/include/libcamera/internal/camera.h
> index 18f5c32a18e4..8a2e9ed5894d 100644
> --- a/include/libcamera/internal/camera.h
> +++ b/include/libcamera/internal/camera.h
> @@ -10,6 +10,7 @@
>  #include <atomic>
>  #include <list>
>  #include <memory>
> +#include <queue>
>  #include <set>
>  #include <stdint.h>
>  #include <string>
> @@ -36,6 +37,7 @@ public:
>  	const PipelineHandler *pipe() const { return pipe_.get(); }
>  
>  	std::list<Request *> queuedRequests_;
> +	std::queue<Request *> waitingRequests_;
>  	ControlInfoMap controlInfo_;
>  	ControlList properties_;
>  
> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> index 972a2fa65310..be017ad47219 100644
> --- a/include/libcamera/internal/pipeline_handler.h
> +++ b/include/libcamera/internal/pipeline_handler.h
> @@ -8,7 +8,6 @@
>  #pragma once
>  
>  #include <memory>
> -#include <queue>
>  #include <string>
>  #include <sys/types.h>
>  #include <vector>
> @@ -89,13 +88,11 @@ private:
>  	virtual void disconnect();
>  
>  	void doQueueRequest(Request *request);
> -	void doQueueRequests();
> +	void doQueueRequests(Camera *camera);
>  
>  	std::vector<std::shared_ptr<MediaDevice>> mediaDevices_;
>  	std::vector<std::weak_ptr<Camera>> cameras_;
>  
> -	std::queue<Request *> waitingRequests_;
> -
>  	const char *name_;
>  	unsigned int useCount_;
>  
> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> index d84dff3c9f19..dc4086aa9bb5 100644
> --- a/src/libcamera/pipeline_handler.cpp
> +++ b/src/libcamera/pipeline_handler.cpp
> @@ -363,15 +363,16 @@ void PipelineHandler::stop(Camera *camera)
>  	/* Stop the pipeline handler and let the queued requests complete. */
>  	stopDevice(camera);
>  
> +	Camera::Private *data = camera->_d();
> +
>  	/* Cancel and signal as complete all waiting requests. */
> -	while (!waitingRequests_.empty()) {
> -		Request *request = waitingRequests_.front();
> -		waitingRequests_.pop();
> +	while (!data->waitingRequests_.empty()) {
> +		Request *request = data->waitingRequests_.front();
> +		data->waitingRequests_.pop();
>  		cancelRequest(request);
>  	}
>  
>  	/* Make sure no requests are pending. */
> -	Camera::Private *data = camera->_d();
>  	ASSERT(data->queuedRequests_.empty());
>  
>  	data->requestSequence_ = 0;
> @@ -414,7 +415,9 @@ void PipelineHandler::registerRequest(Request *request)
>  	 * Connect the request prepared signal to notify the pipeline handler
>  	 * when a request is ready to be processed.
>  	 */
> -	request->_d()->prepared.connect(this, &PipelineHandler::doQueueRequests);
> +	request->_d()->prepared.connect(this, [&]() {
> +		doQueueRequests(request->_d()->camera());
> +	});
>  }
>  
>  /**
> @@ -444,7 +447,9 @@ void PipelineHandler::queueRequest(Request *request)
>  {
>  	LIBCAMERA_TRACEPOINT(request_queue, request);
>  
> -	waitingRequests_.push(request);
> +	Camera *camera = request->_d()->camera();
> +	Camera::Private *data = camera->_d();
> +	data->waitingRequests_.push(request);
>  
>  	request->_d()->prepare(300ms);
>  }
> @@ -478,15 +483,16 @@ void PipelineHandler::doQueueRequest(Request *request)
>   * Iterate the list of waiting requests and queue them to the device one
>   * by one if they have been prepared.
>   */
> -void PipelineHandler::doQueueRequests()
> +void PipelineHandler::doQueueRequests(Camera *camera)
>  {
> -	while (!waitingRequests_.empty()) {
> -		Request *request = waitingRequests_.front();
> +	Camera::Private *data = camera->_d();
> +	while (!data->waitingRequests_.empty()) {
> +		Request *request = data->waitingRequests_.front();
>  		if (!request->_d()->prepared_)
>  			break;
>  
>  		doQueueRequest(request);

nit: I wonder if it would be beneficial (probably in a follow up patch)
to expand the doQueueRequest() function here itself, as the loop is
fetching Camera::Private and Camera pointers again, which is readily
available above, along with request (meant to be queued).

Other than that, this looks good to me:

Reviewed-by: Umang Jain <uajain@igalia.com>

> -		waitingRequests_.pop();
> +		data->waitingRequests_.pop();
>  	}
>  }
>  
> -- 
> 2.48.1
>
Barnabás Pőcze June 30, 2025, 11 a.m. UTC | #2
Hi

2025. 06. 30. 10:11 keltezéssel, Stefan Klug írta:
> The waiting requests of one camera should not be able to influence
> queuing to another camera. Therefore change the single waitingRequests_
> queue into one queue per camera.
> 
> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
> 
> ---
> 
> Changes in v1:
> - Added camera param to doQueueRequests() which allows to remove a loop
> ---
>   include/libcamera/internal/camera.h           |  2 ++
>   include/libcamera/internal/pipeline_handler.h |  5 +---
>   src/libcamera/pipeline_handler.cpp            | 26 ++++++++++++-------
>   3 files changed, 19 insertions(+), 14 deletions(-)
> 
> diff --git a/include/libcamera/internal/camera.h b/include/libcamera/internal/camera.h
> index 18f5c32a18e4..8a2e9ed5894d 100644
> --- a/include/libcamera/internal/camera.h
> +++ b/include/libcamera/internal/camera.h
> @@ -10,6 +10,7 @@
>   #include <atomic>
>   #include <list>
>   #include <memory>
> +#include <queue>
>   #include <set>
>   #include <stdint.h>
>   #include <string>
> @@ -36,6 +37,7 @@ public:
>   	const PipelineHandler *pipe() const { return pipe_.get(); }
>   
>   	std::list<Request *> queuedRequests_;
> +	std::queue<Request *> waitingRequests_;
>   	ControlInfoMap controlInfo_;
>   	ControlList properties_;
>   
> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> index 972a2fa65310..be017ad47219 100644
> --- a/include/libcamera/internal/pipeline_handler.h
> +++ b/include/libcamera/internal/pipeline_handler.h
> @@ -8,7 +8,6 @@
>   #pragma once
>   
>   #include <memory>
> -#include <queue>
>   #include <string>
>   #include <sys/types.h>
>   #include <vector>
> @@ -89,13 +88,11 @@ private:
>   	virtual void disconnect();
>   
>   	void doQueueRequest(Request *request);
> -	void doQueueRequests();
> +	void doQueueRequests(Camera *camera);
>   
>   	std::vector<std::shared_ptr<MediaDevice>> mediaDevices_;
>   	std::vector<std::weak_ptr<Camera>> cameras_;
>   
> -	std::queue<Request *> waitingRequests_;
> -
>   	const char *name_;
>   	unsigned int useCount_;
>   
> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> index d84dff3c9f19..dc4086aa9bb5 100644
> --- a/src/libcamera/pipeline_handler.cpp
> +++ b/src/libcamera/pipeline_handler.cpp
> @@ -363,15 +363,16 @@ void PipelineHandler::stop(Camera *camera)
>   	/* Stop the pipeline handler and let the queued requests complete. */
>   	stopDevice(camera);
>   
> +	Camera::Private *data = camera->_d();
> +
>   	/* Cancel and signal as complete all waiting requests. */
> -	while (!waitingRequests_.empty()) {
> -		Request *request = waitingRequests_.front();
> -		waitingRequests_.pop();
> +	while (!data->waitingRequests_.empty()) {
> +		Request *request = data->waitingRequests_.front();
> +		data->waitingRequests_.pop();
>   		cancelRequest(request);
>   	}
>   
>   	/* Make sure no requests are pending. */
> -	Camera::Private *data = camera->_d();
>   	ASSERT(data->queuedRequests_.empty());
>   
>   	data->requestSequence_ = 0;
> @@ -414,7 +415,9 @@ void PipelineHandler::registerRequest(Request *request)
>   	 * Connect the request prepared signal to notify the pipeline handler
>   	 * when a request is ready to be processed.
>   	 */
> -	request->_d()->prepared.connect(this, &PipelineHandler::doQueueRequests);
> +	request->_d()->prepared.connect(this, [&]() {

This captures `request` by reference, which is a local variable and will
not exists when this callback runs. It should be `[request]` or similar.

This likely explains the CI failure: https://gitlab.freedesktop.org/camera/libcamera/-/pipelines/1460735


Regards,
Barnabás Pőcze


> +		doQueueRequests(request->_d()->camera());
> +	});
>   }
>   
>   /**
> @@ -444,7 +447,9 @@ void PipelineHandler::queueRequest(Request *request)
>   {
>   	LIBCAMERA_TRACEPOINT(request_queue, request);
>   
> -	waitingRequests_.push(request);
> +	Camera *camera = request->_d()->camera();
> +	Camera::Private *data = camera->_d();
> +	data->waitingRequests_.push(request);
>   
>   	request->_d()->prepare(300ms);
>   }
> @@ -478,15 +483,16 @@ void PipelineHandler::doQueueRequest(Request *request)
>    * Iterate the list of waiting requests and queue them to the device one
>    * by one if they have been prepared.
>    */
> -void PipelineHandler::doQueueRequests()
> +void PipelineHandler::doQueueRequests(Camera *camera)
>   {
> -	while (!waitingRequests_.empty()) {
> -		Request *request = waitingRequests_.front();
> +	Camera::Private *data = camera->_d();
> +	while (!data->waitingRequests_.empty()) {
> +		Request *request = data->waitingRequests_.front();
>   		if (!request->_d()->prepared_)
>   			break;
>   
>   		doQueueRequest(request);
> -		waitingRequests_.pop();
> +		data->waitingRequests_.pop();
>   	}
>   }
>
Stefan Klug June 30, 2025, 4:15 p.m. UTC | #3
Hi Barnabás,

Quoting Barnabás Pőcze (2025-06-30 13:00:58)
> Hi
> 
> 2025. 06. 30. 10:11 keltezéssel, Stefan Klug írta:
> > The waiting requests of one camera should not be able to influence
> > queuing to another camera. Therefore change the single waitingRequests_
> > queue into one queue per camera.
> > 
> > Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
> > 
> > ---
> > 
> > Changes in v1:
> > - Added camera param to doQueueRequests() which allows to remove a loop
> > ---
> >   include/libcamera/internal/camera.h           |  2 ++
> >   include/libcamera/internal/pipeline_handler.h |  5 +---
> >   src/libcamera/pipeline_handler.cpp            | 26 ++++++++++++-------
> >   3 files changed, 19 insertions(+), 14 deletions(-)
> > 
> > diff --git a/include/libcamera/internal/camera.h b/include/libcamera/internal/camera.h
> > index 18f5c32a18e4..8a2e9ed5894d 100644
> > --- a/include/libcamera/internal/camera.h
> > +++ b/include/libcamera/internal/camera.h
> > @@ -10,6 +10,7 @@
> >   #include <atomic>
> >   #include <list>
> >   #include <memory>
> > +#include <queue>
> >   #include <set>
> >   #include <stdint.h>
> >   #include <string>
> > @@ -36,6 +37,7 @@ public:
> >       const PipelineHandler *pipe() const { return pipe_.get(); }
> >   
> >       std::list<Request *> queuedRequests_;
> > +     std::queue<Request *> waitingRequests_;
> >       ControlInfoMap controlInfo_;
> >       ControlList properties_;
> >   
> > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> > index 972a2fa65310..be017ad47219 100644
> > --- a/include/libcamera/internal/pipeline_handler.h
> > +++ b/include/libcamera/internal/pipeline_handler.h
> > @@ -8,7 +8,6 @@
> >   #pragma once
> >   
> >   #include <memory>
> > -#include <queue>
> >   #include <string>
> >   #include <sys/types.h>
> >   #include <vector>
> > @@ -89,13 +88,11 @@ private:
> >       virtual void disconnect();
> >   
> >       void doQueueRequest(Request *request);
> > -     void doQueueRequests();
> > +     void doQueueRequests(Camera *camera);
> >   
> >       std::vector<std::shared_ptr<MediaDevice>> mediaDevices_;
> >       std::vector<std::weak_ptr<Camera>> cameras_;
> >   
> > -     std::queue<Request *> waitingRequests_;
> > -
> >       const char *name_;
> >       unsigned int useCount_;
> >   
> > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> > index d84dff3c9f19..dc4086aa9bb5 100644
> > --- a/src/libcamera/pipeline_handler.cpp
> > +++ b/src/libcamera/pipeline_handler.cpp
> > @@ -363,15 +363,16 @@ void PipelineHandler::stop(Camera *camera)
> >       /* Stop the pipeline handler and let the queued requests complete. */
> >       stopDevice(camera);
> >   
> > +     Camera::Private *data = camera->_d();
> > +
> >       /* Cancel and signal as complete all waiting requests. */
> > -     while (!waitingRequests_.empty()) {
> > -             Request *request = waitingRequests_.front();
> > -             waitingRequests_.pop();
> > +     while (!data->waitingRequests_.empty()) {
> > +             Request *request = data->waitingRequests_.front();
> > +             data->waitingRequests_.pop();
> >               cancelRequest(request);
> >       }
> >   
> >       /* Make sure no requests are pending. */
> > -     Camera::Private *data = camera->_d();
> >       ASSERT(data->queuedRequests_.empty());
> >   
> >       data->requestSequence_ = 0;
> > @@ -414,7 +415,9 @@ void PipelineHandler::registerRequest(Request *request)
> >        * Connect the request prepared signal to notify the pipeline handler
> >        * when a request is ready to be processed.
> >        */
> > -     request->_d()->prepared.connect(this, &PipelineHandler::doQueueRequests);
> > +     request->_d()->prepared.connect(this, [&]() {
> 
> This captures `request` by reference, which is a local variable and will
> not exists when this callback runs. It should be `[request]` or similar.
> 
> This likely explains the CI failure: https://gitlab.freedesktop.org/camera/libcamera/-/pipelines/1460735

Ouch, that is a silly one. One of theses if it compiles it runs cases.
I'll fix that.

Thanks,
Stefan

> 
> 
> Regards,
> Barnabás Pőcze
> 
> 
> > +             doQueueRequests(request->_d()->camera());
> > +     });
> >   }
> >   
> >   /**
> > @@ -444,7 +447,9 @@ void PipelineHandler::queueRequest(Request *request)
> >   {
> >       LIBCAMERA_TRACEPOINT(request_queue, request);
> >   
> > -     waitingRequests_.push(request);
> > +     Camera *camera = request->_d()->camera();
> > +     Camera::Private *data = camera->_d();
> > +     data->waitingRequests_.push(request);
> >   
> >       request->_d()->prepare(300ms);
> >   }
> > @@ -478,15 +483,16 @@ void PipelineHandler::doQueueRequest(Request *request)
> >    * Iterate the list of waiting requests and queue them to the device one
> >    * by one if they have been prepared.
> >    */
> > -void PipelineHandler::doQueueRequests()
> > +void PipelineHandler::doQueueRequests(Camera *camera)
> >   {
> > -     while (!waitingRequests_.empty()) {
> > -             Request *request = waitingRequests_.front();
> > +     Camera::Private *data = camera->_d();
> > +     while (!data->waitingRequests_.empty()) {
> > +             Request *request = data->waitingRequests_.front();
> >               if (!request->_d()->prepared_)
> >                       break;
> >   
> >               doQueueRequest(request);
> > -             waitingRequests_.pop();
> > +             data->waitingRequests_.pop();
> >       }
> >   }
> >   
>

Patch
diff mbox series

diff --git a/include/libcamera/internal/camera.h b/include/libcamera/internal/camera.h
index 18f5c32a18e4..8a2e9ed5894d 100644
--- a/include/libcamera/internal/camera.h
+++ b/include/libcamera/internal/camera.h
@@ -10,6 +10,7 @@ 
 #include <atomic>
 #include <list>
 #include <memory>
+#include <queue>
 #include <set>
 #include <stdint.h>
 #include <string>
@@ -36,6 +37,7 @@  public:
 	const PipelineHandler *pipe() const { return pipe_.get(); }
 
 	std::list<Request *> queuedRequests_;
+	std::queue<Request *> waitingRequests_;
 	ControlInfoMap controlInfo_;
 	ControlList properties_;
 
diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
index 972a2fa65310..be017ad47219 100644
--- a/include/libcamera/internal/pipeline_handler.h
+++ b/include/libcamera/internal/pipeline_handler.h
@@ -8,7 +8,6 @@ 
 #pragma once
 
 #include <memory>
-#include <queue>
 #include <string>
 #include <sys/types.h>
 #include <vector>
@@ -89,13 +88,11 @@  private:
 	virtual void disconnect();
 
 	void doQueueRequest(Request *request);
-	void doQueueRequests();
+	void doQueueRequests(Camera *camera);
 
 	std::vector<std::shared_ptr<MediaDevice>> mediaDevices_;
 	std::vector<std::weak_ptr<Camera>> cameras_;
 
-	std::queue<Request *> waitingRequests_;
-
 	const char *name_;
 	unsigned int useCount_;
 
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index d84dff3c9f19..dc4086aa9bb5 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -363,15 +363,16 @@  void PipelineHandler::stop(Camera *camera)
 	/* Stop the pipeline handler and let the queued requests complete. */
 	stopDevice(camera);
 
+	Camera::Private *data = camera->_d();
+
 	/* Cancel and signal as complete all waiting requests. */
-	while (!waitingRequests_.empty()) {
-		Request *request = waitingRequests_.front();
-		waitingRequests_.pop();
+	while (!data->waitingRequests_.empty()) {
+		Request *request = data->waitingRequests_.front();
+		data->waitingRequests_.pop();
 		cancelRequest(request);
 	}
 
 	/* Make sure no requests are pending. */
-	Camera::Private *data = camera->_d();
 	ASSERT(data->queuedRequests_.empty());
 
 	data->requestSequence_ = 0;
@@ -414,7 +415,9 @@  void PipelineHandler::registerRequest(Request *request)
 	 * Connect the request prepared signal to notify the pipeline handler
 	 * when a request is ready to be processed.
 	 */
-	request->_d()->prepared.connect(this, &PipelineHandler::doQueueRequests);
+	request->_d()->prepared.connect(this, [&]() {
+		doQueueRequests(request->_d()->camera());
+	});
 }
 
 /**
@@ -444,7 +447,9 @@  void PipelineHandler::queueRequest(Request *request)
 {
 	LIBCAMERA_TRACEPOINT(request_queue, request);
 
-	waitingRequests_.push(request);
+	Camera *camera = request->_d()->camera();
+	Camera::Private *data = camera->_d();
+	data->waitingRequests_.push(request);
 
 	request->_d()->prepare(300ms);
 }
@@ -478,15 +483,16 @@  void PipelineHandler::doQueueRequest(Request *request)
  * Iterate the list of waiting requests and queue them to the device one
  * by one if they have been prepared.
  */
-void PipelineHandler::doQueueRequests()
+void PipelineHandler::doQueueRequests(Camera *camera)
 {
-	while (!waitingRequests_.empty()) {
-		Request *request = waitingRequests_.front();
+	Camera::Private *data = camera->_d();
+	while (!data->waitingRequests_.empty()) {
+		Request *request = data->waitingRequests_.front();
 		if (!request->_d()->prepared_)
 			break;
 
 		doQueueRequest(request);
-		waitingRequests_.pop();
+		data->waitingRequests_.pop();
 	}
 }