From patchwork Fri Aug 15 14:12:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 24144 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 8E508BEFBE for ; Fri, 15 Aug 2025 14:12:43 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C94386924E; Fri, 15 Aug 2025 16:12:42 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="jPGbHIvZ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1414D61443 for ; Fri, 15 Aug 2025 16:12:41 +0200 (CEST) Received: from pb-laptop.local (185.221.141.188.nat.pool.zt.hu [185.221.141.188]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F1B8A56D for ; Fri, 15 Aug 2025 16:11:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1755267106; bh=iSEEvTzxH/kZ6+Qooc2+hH3qsUAIFaVNhsZIqs4+2mI=; h=From:To:Subject:Date:From; b=jPGbHIvZHj8sjVr6364OJ/n4l2Z4RBNykTGYQ1QAhGzuYaQu2+jCQqEmIP1OdOufO fn+9P+dPTbsxiyaHgKMuV6/wPa3shbUzP+W4hXfYeGJURIRVWMsWFIQWvl3XNUkHVU 6OrarDbUetmx/fC1zfzZU1Vn2tbr9AfgXN0OYi8Q= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Subject: [RFC PATCH v1] apps: cam: Use signalfd Date: Fri, 15 Aug 2025 16:12:37 +0200 Message-ID: <20250815141237.2235085-1-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.50.1 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" Use a signalfd to detect `SIGINT` instead of registering a signal handler in order to remove the `CamApp` singleton. This is better than using a normal signal handler: a signal can arrive after the `CamApp` object has been destroyed, leading to a use-after-free. Modifying the `CamApp::app_` in the destructor is not a good alternative because that would not be async signal safe (unless it is made atomic). Signed-off-by: Barnabás Pőcze --- src/apps/cam/main.cpp | 66 +++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 37 deletions(-) -- 2.50.1 diff --git a/src/apps/cam/main.cpp b/src/apps/cam/main.cpp index fa266eca6..cbc85b59f 100644 --- a/src/apps/cam/main.cpp +++ b/src/apps/cam/main.cpp @@ -13,6 +13,8 @@ #include #include +#include + #include #include @@ -27,15 +29,12 @@ using namespace libcamera; class CamApp { public: - CamApp(); - - static CamApp *instance(); + CamApp(EventLoop &loop); int init(int argc, char **argv); void cleanup(); int exec(); - void quit(); private: void cameraAdded(std::shared_ptr cam); @@ -46,26 +45,17 @@ private: static std::string cameraName(const Camera *camera); - static CamApp *app_; OptionsParser::Options options_; std::unique_ptr cm_; std::atomic_uint loopUsers_; - EventLoop loop_; + EventLoop *loop_ = nullptr; }; -CamApp *CamApp::app_ = nullptr; - -CamApp::CamApp() - : loopUsers_(0) -{ - CamApp::app_ = this; -} - -CamApp *CamApp::instance() +CamApp::CamApp(EventLoop &loop) + : loopUsers_(0), loop_(&loop) { - return CamApp::app_; } int CamApp::init(int argc, char **argv) @@ -103,11 +93,6 @@ int CamApp::exec() return ret; } -void CamApp::quit() -{ - loop_.exit(); -} - int CamApp::parseOptions(int argc, char *argv[]) { StreamKeyValueParser streamKeyValue; @@ -205,7 +190,7 @@ void CamApp::cameraRemoved(std::shared_ptr cam) void CamApp::captureDone() { if (--loopUsers_ == 0) - EventLoop::instance()->exit(0); + loop_->exit(0); } int CamApp::run() @@ -290,7 +275,7 @@ int CamApp::run() } if (loopUsers_) - loop_.exec(); + loop_->exec(); /* 6. Stop capture. */ for (const auto &session : sessions) { @@ -345,29 +330,36 @@ std::string CamApp::cameraName(const Camera *camera) return name; } -namespace { - -void signalHandler([[maybe_unused]] int signal) +int main(int argc, char **argv) { - std::cout << "Exiting" << std::endl; - CamApp::instance()->quit(); -} + auto sigfd = [] { + sigset_t ss; -} /* namespace */ + sigemptyset(&ss); + sigaddset(&ss, SIGINT); + sigprocmask(SIG_BLOCK, &ss, nullptr); -int main(int argc, char **argv) -{ - CamApp app; + return UniqueFD(signalfd(-1, &ss, SFD_CLOEXEC | SFD_NONBLOCK)); + }(); + if (!sigfd.isValid()) + return EXIT_FAILURE; + + EventLoop loop; + CamApp app(loop); int ret; + loop.addFdEvent(sigfd.get(), EventLoop::Read, [&] { + signalfd_siginfo si; + std::ignore = read(sigfd.get(), &si, sizeof(si)); + + std::cout << "Exiting" << std::endl; + loop.exit(0); + }); + ret = app.init(argc, argv); if (ret) return ret == -EINTR ? 0 : EXIT_FAILURE; - struct sigaction sa = {}; - sa.sa_handler = &signalHandler; - sigaction(SIGINT, &sa, nullptr); - if (app.exec()) return EXIT_FAILURE;