libcamera: pipeline_handler: cancel waiting requests first
diff mbox series

Message ID 20250623163414.3936727-1-kieran.bingham@ideasonboard.com
State New
Headers show
Series
  • libcamera: pipeline_handler: cancel waiting requests first
Related show

Commit Message

Kieran Bingham June 23, 2025, 4:34 p.m. UTC
When stopping a camera, we may now find that there are requests
queued to the camera but not yet available in the pipeline handler.

These are "waitingReqeusts" which are not yet queued to the device.

While stopping a camera, we ask the pipeline to stop with stopDevice()
and then cancel any waiting requests after.

This however can lead to a race where having stopped the camera and
completed the requests, the pipeline may try to further consume requests
from the waiting lists.

When we call PipelineHandler::stop() we know that we can not process any
of the requests which are sat in the waiting queue, therefore cancel
those first before asking the pipeline handler to complete or cancel and
requests that it has ownership of.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---

Hi Stefan,

Testing your series I discovered this shutdown race.

Without this I get:



[1:48:10.770431125] [2675] FATAL default  6490.777390] audit: type=1701 audit(1741278393.952:115): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=2674 comm="cam" exe="/usr/bin/cam" sig=6 res=1
;34mrkisp1_ipa_proxy.cpp:467 assertion "state_ == ProxyRunning" failed in queueRequestThread()
Backtrace:
/lib/libcamera.so.0.5(_ZN9libcamera3ipa6rkisp114IPAProxyRkISP118queueRequestThreadEjRKNS_11ControlListE+0x94) [0xffffb32d[ 6490.810893] audit: type=1334 audit(1741278393.984:116): prog-id=51 op=LOAD
7f8c]
/lib/libcamera.so.0.5(_ZN9[ 6490.819683] audit: type=1334 audit(1741278393.996:117): prog-id=52 op=LOAD
libcamera3ipa6rkisp114IPAProxyRkI[ 6490.820111] audit: type=1334 audit(1741278393.996:118): prog-id=53 op=LOAD
SP112queueRequestEjRKNS_11ControlListE+0x28) [0xffffb32d8048]
/lib/libcamera.so.0.5(_ZN9libcamera21PipelineHandlerRkISP118queueRequestDeviceEPNS_6CameraEPNS_7RequestE+0x50) [0xffffb3360b14]


This patch ensures that requests which are in the waitingRequests queue
are cancelled first to ensure they don't get processed by the pipeline
after it has completed it's stop().


 src/libcamera/pipeline_handler.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

Comments

Laurent Pinchart June 27, 2025, 6:43 p.m. UTC | #1
On Mon, Jun 23, 2025 at 05:34:14PM +0100, Kieran Bingham wrote:
> When stopping a camera, we may now find that there are requests
> queued to the camera but not yet available in the pipeline handler.
> 
> These are "waitingReqeusts" which are not yet queued to the device.
> 
> While stopping a camera, we ask the pipeline to stop with stopDevice()
> and then cancel any waiting requests after.
> 
> This however can lead to a race where having stopped the camera and
> completed the requests, the pipeline may try to further consume requests
> from the waiting lists.
> 
> When we call PipelineHandler::stop() we know that we can not process any
> of the requests which are sat in the waiting queue, therefore cancel
> those first before asking the pipeline handler to complete or cancel and
> requests that it has ownership of.

Doesn't the lead to requests completing out of order ? We should fix
races, but ensuring strict completion order is important.

> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> ---
> 
> Hi Stefan,
> 
> Testing your series I discovered this shutdown race.
> 
> Without this I get:
> 
> 
> 
> [1:48:10.770431125] [2675] FATAL default  6490.777390] audit: type=1701 audit(1741278393.952:115): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=2674 comm="cam" exe="/usr/bin/cam" sig=6 res=1
> ;34mrkisp1_ipa_proxy.cpp:467 assertion "state_ == ProxyRunning" failed in queueRequestThread()
> Backtrace:
> /lib/libcamera.so.0.5(_ZN9libcamera3ipa6rkisp114IPAProxyRkISP118queueRequestThreadEjRKNS_11ControlListE+0x94) [0xffffb32d[ 6490.810893] audit: type=1334 audit(1741278393.984:116): prog-id=51 op=LOAD
> 7f8c]
> /lib/libcamera.so.0.5(_ZN9[ 6490.819683] audit: type=1334 audit(1741278393.996:117): prog-id=52 op=LOAD
> libcamera3ipa6rkisp114IPAProxyRkI[ 6490.820111] audit: type=1334 audit(1741278393.996:118): prog-id=53 op=LOAD
> SP112queueRequestEjRKNS_11ControlListE+0x28) [0xffffb32d8048]
> /lib/libcamera.so.0.5(_ZN9libcamera21PipelineHandlerRkISP118queueRequestDeviceEPNS_6CameraEPNS_7RequestE+0x50) [0xffffb3360b14]
> 
> 
> This patch ensures that requests which are in the waitingRequests queue
> are cancelled first to ensure they don't get processed by the pipeline
> after it has completed it's stop().
> 
> 
>  src/libcamera/pipeline_handler.cpp | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> index 0389f34486ab..9cd3504dc9db 100644
> --- a/src/libcamera/pipeline_handler.cpp
> +++ b/src/libcamera/pipeline_handler.cpp
> @@ -360,9 +360,6 @@ void PipelineHandler::unlockMediaDevices()
>   */
>  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. */
> @@ -372,8 +369,12 @@ void PipelineHandler::stop(Camera *camera)
>  		cancelRequest(request);
>  	}
>  
> +	/* Stop the pipeline handler and let the queued requests complete. */
> +	stopDevice(camera);
> +
>  	/* Make sure no requests are pending. */
>  	ASSERT(data->queuedRequests_.empty());
> +	ASSERT(data->waitingRequests_.empty());
>  
>  	data->requestSequence_ = 0;
>  }

Patch
diff mbox series

diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 0389f34486ab..9cd3504dc9db 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -360,9 +360,6 @@  void PipelineHandler::unlockMediaDevices()
  */
 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. */
@@ -372,8 +369,12 @@  void PipelineHandler::stop(Camera *camera)
 		cancelRequest(request);
 	}
 
+	/* Stop the pipeline handler and let the queued requests complete. */
+	stopDevice(camera);
+
 	/* Make sure no requests are pending. */
 	ASSERT(data->queuedRequests_.empty());
+	ASSERT(data->waitingRequests_.empty());
 
 	data->requestSequence_ = 0;
 }