Show a patch.

GET /api/1.1/patches/22434/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 22434,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/22434/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/22434/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20241220150759.709756-9-pobrn@protonmail.com>",
    "date": "2024-12-20T15:08:37",
    "name": "[RFC,v1,08/12] apps: lc-compliance: Remove libevent dependency",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "3d77cbcd2de06852ecfd4f4b536289273ef863d4",
    "submitter": {
        "id": 133,
        "url": "https://patchwork.libcamera.org/api/1.1/people/133/?format=api",
        "name": "Pőcze Barnabás",
        "email": "pobrn@protonmail.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/22434/mbox/",
    "series": [
        {
            "id": 4923,
            "url": "https://patchwork.libcamera.org/api/1.1/series/4923/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4923",
            "date": "2024-12-20T15:08:03",
            "name": "apps: lc-compliance: Multi-stream tests",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/4923/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/22434/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/22434/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id C8E8CC3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 20 Dec 2024 15:08:44 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 64145684B2;\n\tFri, 20 Dec 2024 16:08:44 +0100 (CET)",
            "from mail-40134.protonmail.ch (mail-40134.protonmail.ch\n\t[185.70.40.134])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0294C684AE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 20 Dec 2024 16:08:41 +0100 (CET)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=protonmail.com header.i=@protonmail.com\n\theader.b=\"ZoDjLvxh\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com;\n\ts=protonmail3; t=1734707320; x=1734966520;\n\tbh=T1ArgVyr9LxnraRalmGQSwNWbt3n6iSqk9UDRW1FMM8=;\n\th=Date:To:From:Subject:Message-ID:In-Reply-To:References:\n\tFeedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:\n\tMessage-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post;\n\tb=ZoDjLvxhG56N2fBRxXgeuDse3QR+gblciFP71dreMHmswTzgR7ECSZcf6kQSJAn2f\n\tgGbodGVXWRjl19QRtBsRVrhzWE2VGAXnhV/3D7aW8KdiTwjSFkj7vmKISN3coC2ekH\n\tDoJNrcHb/uQVECErp6rIMz04oGMEFKHxS5PJVrVXi4X6GnFcE/1AE3uupkaNENVHP5\n\tn4Fa8j5iz3FK0kCeAoYaWMiDfbHvy7cJKqKJ8MBhnIteFpXYCLK/KbvZoSgOihhjOC\n\t6aqfo8Gd4lRA8QhSUzldmYR7GDyNp5SSmVjk3hIOUCfBhXkft9MQC3HCcfx6xGrdpH\n\tR5btGgGe7dCmA==",
        "Date": "Fri, 20 Dec 2024 15:08:37 +0000",
        "To": "libcamera-devel@lists.libcamera.org",
        "From": "=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <pobrn@protonmail.com>",
        "Subject": "[RFC PATCH v1 08/12] apps: lc-compliance: Remove libevent dependency",
        "Message-ID": "<20241220150759.709756-9-pobrn@protonmail.com>",
        "In-Reply-To": "<20241220150759.709756-1-pobrn@protonmail.com>",
        "References": "<20241220150759.709756-1-pobrn@protonmail.com>",
        "Feedback-ID": "20568564:user:proton",
        "X-Pm-Message-ID": "5e7dddb2a7e18cb9935e602b516beae085bcff46",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=utf-8",
        "Content-Transfer-Encoding": "quoted-printable",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "libevent is only used as a way to notify the main thread from\nthe CameraManager thread when the capture should be terminated.\n\nNot only is libevent not really necessary and instead can be\nreplaced with a simple combination of C++ STL parts, the current\nusage is prone to race conditions.\n\nSpecifically, the camera's `queueRequest()` might complete the\nrequest before the main thread could set the `loop_` member\nvariable and synchronize with the thread. This is a data race,\npractically resulting in a nullptr or dangling pointer dereference.\n\nThis can easily be triggered by inserting a sufficiently large\ntimeout before `loop_ = new EventLoop;`:\n\n  [46:43:40.529620351] [671833] DEBUG Request request.cpp:129 Request(4:C:0/1:0)\n  ../src/apps/lc-compliance/helpers/capture.cpp:140:14: runtime error: member call on null pointer of type 'struct EventLoop'\n    0 0x632c3e82f81a in CaptureBalanced::requestComplete(libcamera::Request*) ../src/apps/lc-compliance/helpers/capture.cpp:140\n\nSigned-off-by: Barnabás Pőcze <pobrn@protonmail.com>\n---\n README.rst                                 |  2 +-\n src/apps/lc-compliance/helpers/capture.cpp | 23 ++++++------\n src/apps/lc-compliance/helpers/capture.h   | 42 +++++++++++++++++++---\n src/apps/lc-compliance/meson.build         |  7 ++--\n src/apps/meson.build                       |  5 ---\n 5 files changed, 53 insertions(+), 26 deletions(-)",
    "diff": "diff --git a/README.rst b/README.rst\nindex 4068c6cc8..f1749be97 100644\n--- a/README.rst\n+++ b/README.rst\n@@ -97,7 +97,7 @@ for Python bindings: [optional]\n         pybind11-dev\n \n for lc-compliance: [optional]\n-        libevent-dev libgtest-dev\n+        libgtest-dev\n \n for abi-compat.sh: [optional]\n         abi-compliance-checker\ndiff --git a/src/apps/lc-compliance/helpers/capture.cpp b/src/apps/lc-compliance/helpers/capture.cpp\nindex 91c4d4400..b473e0773 100644\n--- a/src/apps/lc-compliance/helpers/capture.cpp\n+++ b/src/apps/lc-compliance/helpers/capture.cpp\n@@ -12,7 +12,7 @@\n using namespace libcamera;\n \n Capture::Capture(std::shared_ptr<Camera> camera)\n-\t: loop_(nullptr), camera_(std::move(camera)),\n+\t: camera_(std::move(camera)),\n \t  allocator_(camera_)\n {\n }\n@@ -52,6 +52,8 @@ void Capture::start()\n \n \tcamera_->requestCompleted.connect(this, &Capture::requestComplete);\n \n+\tresult_.reset();\n+\n \tASSERT_EQ(camera_->start(), 0) << \"Failed to start camera\";\n }\n \n@@ -62,6 +64,8 @@ void Capture::stop()\n \n \tcamera_->stop();\n \n+\tresult_.reset();\n+\n \tcamera_->requestCompleted.disconnect(this);\n \n \tStream *stream = config_->at(0).stream();\n@@ -108,11 +112,10 @@ void CaptureBalanced::capture(unsigned int numRequests)\n \t}\n \n \t/* Run capture session. */\n-\tloop_ = new EventLoop();\n-\tloop_->exec();\n+\tint status = result_.wait();\n \tstop();\n-\tdelete loop_;\n \n+\tASSERT_EQ(status, 0);\n \tASSERT_EQ(captureCount_, captureLimit_);\n }\n \n@@ -132,13 +135,13 @@ void CaptureBalanced::requestComplete(Request *request)\n \n \tcaptureCount_++;\n \tif (captureCount_ >= captureLimit_) {\n-\t\tloop_->exit(0);\n+\t\tresult_.set(0);\n \t\treturn;\n \t}\n \n \trequest->reuse(Request::ReuseBuffers);\n \tif (queueRequest(request))\n-\t\tloop_->exit(-EINVAL);\n+\t\tresult_.set(-EINVAL);\n }\n \n /* CaptureUnbalanced */\n@@ -171,10 +174,8 @@ void CaptureUnbalanced::capture(unsigned int numRequests)\n \t}\n \n \t/* Run capture session. */\n-\tloop_ = new EventLoop();\n-\tint status = loop_->exec();\n+\tint status = result_.wait();\n \tstop();\n-\tdelete loop_;\n \n \tASSERT_EQ(status, 0);\n }\n@@ -183,7 +184,7 @@ void CaptureUnbalanced::requestComplete(Request *request)\n {\n \tcaptureCount_++;\n \tif (captureCount_ >= captureLimit_) {\n-\t\tloop_->exit(0);\n+\t\tresult_.set(0);\n \t\treturn;\n \t}\n \n@@ -192,5 +193,5 @@ void CaptureUnbalanced::requestComplete(Request *request)\n \n \trequest->reuse(Request::ReuseBuffers);\n \tif (camera_->queueRequest(request))\n-\t\tloop_->exit(-EINVAL);\n+\t\tresult_.set(-EINVAL);\n }\ndiff --git a/src/apps/lc-compliance/helpers/capture.h b/src/apps/lc-compliance/helpers/capture.h\nindex a4cc3a99e..8582ade8e 100644\n--- a/src/apps/lc-compliance/helpers/capture.h\n+++ b/src/apps/lc-compliance/helpers/capture.h\n@@ -7,12 +7,13 @@\n \n #pragma once\n \n+#include <condition_variable>\n #include <memory>\n+#include <mutex>\n+#include <optional>\n \n #include <libcamera/libcamera.h>\n \n-#include \"../common/event_loop.h\"\n-\n class Capture\n {\n public:\n@@ -27,12 +28,45 @@ protected:\n \n \tvirtual void requestComplete(libcamera::Request *request) = 0;\n \n-\tEventLoop *loop_;\n-\n \tstd::shared_ptr<libcamera::Camera> camera_;\n \tlibcamera::FrameBufferAllocator allocator_;\n \tstd::unique_ptr<libcamera::CameraConfiguration> config_;\n \tstd::vector<std::unique_ptr<libcamera::Request>> requests_;\n+\n+\tstruct\n+\t{\n+\tprivate:\n+\t\tstd::mutex mutex_;\n+\t\tstd::condition_variable cv_;\n+\t\tstd::optional<int> value_;\n+\n+\tpublic:\n+\t\tint wait()\n+\t\t{\n+\t\t\tstd::unique_lock guard(mutex_);\n+\n+\t\t\tcv_.wait(guard, [&] {\n+\t\t\t\treturn value_.has_value();\n+\t\t\t});\n+\n+\t\t\treturn *value_;\n+\t\t}\n+\n+\t\tvoid set(int value)\n+\t\t{\n+\t\t\tstd::unique_lock guard(mutex_);\n+\n+\t\t\tif (!value_)\n+\t\t\t\tvalue_ = value;\n+\n+\t\t\tcv_.notify_all();\n+\t\t}\n+\n+\t\tvoid reset()\n+\t\t{\n+\t\t\tvalue_.reset();\n+\t\t}\n+\t} result_;\n };\n \n class CaptureBalanced : public Capture\ndiff --git a/src/apps/lc-compliance/meson.build b/src/apps/lc-compliance/meson.build\nindex b1f605f33..0884bc6ca 100644\n--- a/src/apps/lc-compliance/meson.build\n+++ b/src/apps/lc-compliance/meson.build\n@@ -4,13 +4,11 @@ libgtest = dependency('gtest', version : '>=1.10.0',\n                       required : get_option('lc-compliance'),\n                       fallback : ['gtest', 'gtest_dep'])\n \n-if opt_lc_compliance.disabled() or not libevent.found() or not libgtest.found()\n-    lc_compliance_enabled = false\n+lc_compliance_enabled = opt_lc_compliance.allowed() and libgtest.found()\n+if not lc_compliance_enabled\n     subdir_done()\n endif\n \n-lc_compliance_enabled = true\n-\n lc_compliance_sources = files([\n     'environment.cpp',\n     'helpers/capture.cpp',\n@@ -29,7 +27,6 @@ lc_compliance  = executable('lc-compliance', lc_compliance_sources,\n                             dependencies : [\n                                 libatomic,\n                                 libcamera_public,\n-                                libevent,\n                                 libgtest,\n                             ],\n                             include_directories : lc_compliance_includes,\ndiff --git a/src/apps/meson.build b/src/apps/meson.build\nindex af632b9a7..252491441 100644\n--- a/src/apps/meson.build\n+++ b/src/apps/meson.build\n@@ -3,12 +3,7 @@\n opt_cam = get_option('cam')\n opt_lc_compliance = get_option('lc-compliance')\n \n-# libevent is needed by cam and lc-compliance. As they are both feature options,\n-# they can't be combined with simple boolean logic.\n libevent = dependency('libevent_pthreads', required : opt_cam)\n-if not libevent.found()\n-    libevent = dependency('libevent_pthreads', required : opt_lc_compliance)\n-endif\n \n libtiff = dependency('libtiff-4', required : false)\n \n",
    "prefixes": [
        "RFC",
        "v1",
        "08/12"
    ]
}