From f6b6f15b54c27c144629fec0a880c4f870815011 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo@jmondi.org>
Date: Tue, 26 Oct 2021 15:21:29 +0200
Subject: libcamera: pipeline: Introduce stopDevice()

Since a queue of waiting Requests has been introduced, not all Requests
queued to the PipelineHandler are immediately queued to the device.

As a Camera can be stopped at any time, it is required to complete the
waiting requests after the ones queued to the device had been completed.

Introduce a pure virtual PipelineHandler::stopDevice() function to be
implemented by pipeline handlers and make the PipelineHandler::stop()
function call it before completing pending requests.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 +--
 src/libcamera/pipeline/raspberrypi/raspberrypi.cpp |  4 +--
 src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  4 +--
 src/libcamera/pipeline/simple/simple.cpp           |  4 +--
 src/libcamera/pipeline/uvcvideo/uvcvideo.cpp       |  4 +--
 src/libcamera/pipeline/vimc/vimc.cpp               |  4 +--
 src/libcamera/pipeline_handler.cpp                 | 30 ++++++++++++++++++++--
 7 files changed, 40 insertions(+), 14 deletions(-)

(limited to 'src')

diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 31322062..6c5617cd 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -139,7 +139,7 @@ public:
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
 	int start(Camera *camera, const ControlList *controls) override;
-	void stop(Camera *camera) override;
+	void stopDevice(Camera *camera) override;
 
 	int queueRequestDevice(Camera *camera, Request *request) override;
 
@@ -803,7 +803,7 @@ error:
 	return ret;
 }
 
-void PipelineHandlerIPU3::stop(Camera *camera)
+void PipelineHandlerIPU3::stopDevice(Camera *camera)
 {
 	IPU3CameraData *data = cameraData(camera);
 	int ret = 0;
diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
index 86851ac4..9c171cea 100644
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
@@ -298,7 +298,7 @@ public:
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
 	int start(Camera *camera, const ControlList *controls) override;
-	void stop(Camera *camera) override;
+	void stopDevice(Camera *camera) override;
 
 	int queueRequestDevice(Camera *camera, Request *request) override;
 
@@ -943,7 +943,7 @@ int PipelineHandlerRPi::start(Camera *camera, const ControlList *controls)
 	return 0;
 }
 
-void PipelineHandlerRPi::stop(Camera *camera)
+void PipelineHandlerRPi::stopDevice(Camera *camera)
 {
 	RPiCameraData *data = cameraData(camera);
 
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index 36ef6a02..8cca8a15 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -146,7 +146,7 @@ public:
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
 	int start(Camera *camera, const ControlList *controls) override;
-	void stop(Camera *camera) override;
+	void stopDevice(Camera *camera) override;
 
 	int queueRequestDevice(Camera *camera, Request *request) override;
 
@@ -827,7 +827,7 @@ int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] const ControlL
 	return ret;
 }
 
-void PipelineHandlerRkISP1::stop(Camera *camera)
+void PipelineHandlerRkISP1::stopDevice(Camera *camera)
 {
 	RkISP1CameraData *data = cameraData(camera);
 	int ret;
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 701fb4be..fdff4ebd 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -279,7 +279,7 @@ public:
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
 	int start(Camera *camera, const ControlList *controls) override;
-	void stop(Camera *camera) override;
+	void stopDevice(Camera *camera) override;
 
 	bool match(DeviceEnumerator *enumerator) override;
 
@@ -1036,7 +1036,7 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL
 	return 0;
 }
 
-void SimplePipelineHandler::stop(Camera *camera)
+void SimplePipelineHandler::stopDevice(Camera *camera)
 {
 	SimpleCameraData *data = cameraData(camera);
 	V4L2VideoDevice *video = data->video_;
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index 264f5370..40654a0b 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -74,7 +74,7 @@ public:
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
 	int start(Camera *camera, const ControlList *controls) override;
-	void stop(Camera *camera) override;
+	void stopDevice(Camera *camera) override;
 
 	int queueRequestDevice(Camera *camera, Request *request) override;
 
@@ -250,7 +250,7 @@ int PipelineHandlerUVC::start(Camera *camera, [[maybe_unused]] const ControlList
 	return 0;
 }
 
-void PipelineHandlerUVC::stop(Camera *camera)
+void PipelineHandlerUVC::stopDevice(Camera *camera)
 {
 	UVCCameraData *data = cameraData(camera);
 	data->video_->streamOff();
diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp
index e453091d..29960fe3 100644
--- a/src/libcamera/pipeline/vimc/vimc.cpp
+++ b/src/libcamera/pipeline/vimc/vimc.cpp
@@ -91,7 +91,7 @@ public:
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
 	int start(Camera *camera, const ControlList *controls) override;
-	void stop(Camera *camera) override;
+	void stopDevice(Camera *camera) override;
 
 	int queueRequestDevice(Camera *camera, Request *request) override;
 
@@ -359,7 +359,7 @@ int PipelineHandlerVimc::start(Camera *camera, [[maybe_unused]] const ControlLis
 	return 0;
 }
 
-void PipelineHandlerVimc::stop(Camera *camera)
+void PipelineHandlerVimc::stopDevice(Camera *camera)
 {
 	VimcCameraData *data = cameraData(camera);
 	data->video_->streamOff();
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 2374c289..92b5e3ab 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -267,8 +267,7 @@ void PipelineHandler::unlock()
  */
 
 /**
- * \fn PipelineHandler::stop()
- * \brief Stop capturing from all running streams
+ * \brief Stop capturing from all running streams and cancel pending requests
  * \param[in] camera The camera to stop
  *
  * This function stops capturing and processing requests immediately. All
@@ -276,6 +275,33 @@ void PipelineHandler::unlock()
  *
  * \context This function is called from the CameraManager thread.
  */
+void PipelineHandler::stop(Camera *camera)
+{
+	/* Stop the pipeline handler and let the queued requests complete. */
+	stopDevice(camera);
+
+	/* Cancel and signal as complete all waiting requests. */
+	while (!waitingRequests_.empty()) {
+		Request *request = waitingRequests_.front();
+		waitingRequests_.pop();
+
+		request->_d()->cancel();
+		completeRequest(request);
+	}
+
+	/* Make sure no requests are pending. */
+	Camera::Private *data = camera->_d();
+	ASSERT(data->queuedRequests_.empty());
+}
+
+/**
+ * \fn PipelineHandler::stopDevice()
+ * \brief Stop capturing from all running streams
+ * \param[in] camera The camera to stop
+ *
+ * This function stops capturing and processing requests immediately. All
+ * pending requests are cancelled and complete immediately in an error state.
+ */
 
 /**
  * \brief Determine if the camera has any requests pending
-- 
cgit v1.2.1