From patchwork Mon Jun 30 08:11:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 23692 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 885D1C3237 for ; Mon, 30 Jun 2025 08:11:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4407F68E0D; Mon, 30 Jun 2025 10:11:54 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="CQNp98F7"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6EF0B68E12 for ; Mon, 30 Jun 2025 10:11:50 +0200 (CEST) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:883b:eaf8:7aec:d1d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id CFEBD16B8; Mon, 30 Jun 2025 10:11:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1751271088; bh=TgrIkSU6tKIpjOwsgYCV1nBzb/y3gOE6vyBU1pvFPmI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CQNp98F7CWOCV4LwaJX5QzFOUIq/meI/cbgll6T0J2DbFNc+tgTjx1sCQofd7p2pS dWLh0MBviVvy2bMnShfo6NrjN05w9I8KyaG42QLvhI8cp2BvoPsKYv9We1XPPKqJGT ByDWKP0mZgPfPoyvffEAu0d7r/CcyWA5Ni18J5O4= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , Kieran Bingham Subject: [PATCH v1 6/6] libcamera: pipeline_handler: cancel waiting requests first Date: Mon, 30 Jun 2025 10:11:21 +0200 Message-ID: <20250630081126.2384387-7-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250630081126.2384387-1-stefan.klug@ideasonboard.com> References: <20250630081126.2384387-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Kieran Bingham 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. Therefore empty the waitingRequests queue before stopping the device and cancel the waitingRequests afterwards. Signed-off-by: Kieran Bingham Signed-off-by: Stefan Klug Reviewed-by: Kieran Bingham --- src/libcamera/pipeline_handler.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 383c6ad0c4aa..207a2bae96d6 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -364,20 +364,28 @@ void PipelineHandler::unlockMediaDevices() */ void PipelineHandler::stop(Camera *camera) { + /* + * Take all waiting requests so that they are not requeued in response + * to completeRequest() being called inside stopDevice(). Cancel them + * after the device to keep them in order. + */ + Camera::Private *data = camera->_d(); + std::queue waitingRequests; + waitingRequests.swap(data->waitingRequests_); + /* 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 (!data->waitingRequests_.empty()) { - Request *request = data->waitingRequests_.front(); - data->waitingRequests_.pop(); + while (!waitingRequests.empty()) { + Request *request = waitingRequests.front(); + waitingRequests.pop(); cancelRequest(request); } /* Make sure no requests are pending. */ ASSERT(data->queuedRequests_.empty()); + ASSERT(data->waitingRequests_.empty()); data->requestSequence_ = 0; }