From patchwork Wed Aug 20 08:06:32 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: 24164 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 CFBFCBEFBE for ; Wed, 20 Aug 2025 08:06:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DE20F692D7; Wed, 20 Aug 2025 10:06:37 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="dfBJVqK+"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9D0A2613C5 for ; Wed, 20 Aug 2025 10:06:36 +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 D8DF36AF; Wed, 20 Aug 2025 10:05:37 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1755677138; bh=z4ZIBoRN6ehN+fx5CBr7pRlBc2PEZr2Qt0VxB77FMOw=; h=From:To:Subject:Date:From; b=dfBJVqK+7/nw4Etf1gtHD05MoKhy6XXXVoMdPyW7uAVm6v2NwxzVxPwhz9dmgOWhq 7sS0s1apyQH0WVBvn8NPAxsNZ1vqzP6QyadSvW30/6hUgybohsYFlQO6c0CmmWrc3j 2t6i1Bfr1Q95otcOW7eN1NG0cqmb+a6FZiSbzlGA= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org, Paul Elder Subject: [RFC PATCH v2] apps: cam: Use signalfd Date: Wed, 20 Aug 2025 10:06:32 +0200 Message-ID: <20250820080632.106505-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 Reviewed-by: Laurent Pinchart --- changes in v2: * move into `CamApp::init()` * use `pthread_sigmask()` instead of `sigprocmask()` v1: https://patchwork.libcamera.org/patch/24144/ --- src/apps/cam/main.cpp | 57 ++++++++++++++++++---------------------- src/apps/cam/meson.build | 1 + 2 files changed, 26 insertions(+), 32 deletions(-) -- 2.50.1 diff --git a/src/apps/cam/main.cpp b/src/apps/cam/main.cpp index a1788b7a9..91a29736f 100644 --- a/src/apps/cam/main.cpp +++ b/src/apps/cam/main.cpp @@ -10,8 +10,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -29,13 +31,10 @@ class CamApp public: CamApp(); - static CamApp *instance(); - int init(int argc, char **argv); void cleanup(); int exec(); - void quit(); private: void cameraAdded(std::shared_ptr cam); @@ -46,32 +45,45 @@ private: static std::string cameraName(const Camera *camera); - static CamApp *app_; OptionsParser::Options options_; + UniqueFD signalFd_; + std::unique_ptr cm_; std::atomic_uint loopUsers_; EventLoop loop_; }; -CamApp *CamApp::app_ = nullptr; - CamApp::CamApp() : loopUsers_(0) { - CamApp::app_ = this; -} - -CamApp *CamApp::instance() -{ - return CamApp::app_; } int CamApp::init(int argc, char **argv) { + sigset_t ss; int ret; + sigemptyset(&ss); + sigaddset(&ss, SIGINT); + + ret = -pthread_sigmask(SIG_BLOCK, &ss, nullptr); + if (ret < 0) + return ret; + + signalFd_.reset(signalfd(-1, &ss, SFD_CLOEXEC | SFD_NONBLOCK)); + if (!signalFd_.isValid()) + return -errno; + + loop_.addFdEvent(signalFd_.get(), EventLoop::Read, [this] { + signalfd_siginfo si; + std::ignore = read(signalFd_.get(), &si, sizeof(si)); + + std::cout << "Exiting" << std::endl; + loop_.exit(); + }); + ret = parseOptions(argc, argv); if (ret < 0) return ret; @@ -103,11 +115,6 @@ int CamApp::exec() return ret; } -void CamApp::quit() -{ - loop_.exit(); -} - int CamApp::parseOptions(int argc, char *argv[]) { StreamKeyValueParser streamKeyValue; @@ -205,7 +212,7 @@ void CamApp::cameraRemoved(std::shared_ptr cam) void CamApp::captureDone() { if (--loopUsers_ == 0) - EventLoop::instance()->exit(0); + loop_.exit(0); } int CamApp::run() @@ -345,16 +352,6 @@ std::string CamApp::cameraName(const Camera *camera) return name; } -namespace { - -void signalHandler([[maybe_unused]] int signal) -{ - std::cout << "Exiting" << std::endl; - CamApp::instance()->quit(); -} - -} /* namespace */ - int main(int argc, char **argv) { CamApp app; @@ -364,10 +361,6 @@ int main(int argc, char **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; diff --git a/src/apps/cam/meson.build b/src/apps/cam/meson.build index 2833c86e9..cd7f120f9 100644 --- a/src/apps/cam/meson.build +++ b/src/apps/cam/meson.build @@ -56,6 +56,7 @@ cam = executable('cam', cam_sources, libjpeg, libsdl2, libtiff, + libthreads, libyaml, ], cpp_args : cam_cpp_args,