Show a patch.

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

{
    "id": 10556,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/10556/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/10556/",
    "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": "<20201204065452.2764628-5-email@uajain.com>",
    "date": "2020-12-04T06:54:52",
    "name": "[libcamera-devel,v3,4/4] simple-cam: Provide event-loop backed by libevent",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "a3623b3e3fac813d58f05ecf4f0e973c789faf1a",
    "submitter": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/people/1/?format=api",
        "name": "Umang Jain",
        "email": "email@uajain.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/10556/mbox/",
    "series": [
        {
            "id": 1502,
            "url": "https://patchwork.libcamera.org/api/1.1/series/1502/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1502",
            "date": "2020-12-04T06:54:48",
            "name": "simple-cam: Provide event-loop backed by libevent",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/1502/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/10556/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/10556/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 8EA4ABE177\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  4 Dec 2020 06:55:11 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5A40E635DB;\n\tFri,  4 Dec 2020 07:55:11 +0100 (CET)",
            "from mail.uajain.com (static.126.159.217.95.clients.your-server.de\n\t[95.217.159.126])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5648C635D8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  4 Dec 2020 07:55:10 +0100 (CET)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=uajain.com header.i=@uajain.com\n\theader.b=\"j8wXu8R8\"; dkim-atps=neutral",
        "From": "Umang Jain <email@uajain.com>",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=uajain.com; s=mail;\n\tt=1607064909; bh=egQOzgGw04MrvNbjfhHa++HkAr9Z8XG1Ak5+8GUWrPY=;\n\th=From:To:Cc:Subject:In-Reply-To:References;\n\tb=j8wXu8R8jHhIy5xq8rRS+izoOZACslbSgwzgam6irW+a4ljqubV0WdfO+seJqRvzS\n\tdG2dZYyShRz/2V7m9Z3bJvKLuBY6l6o5ModBqGqFp5JhIwWtOeFJttzmToYBvkaPih\n\tWRwQgC6pLQNIgViF0xaBhnAhWPpZiWhwVSBSAGRiNSo2HfTYziO5HxgdxUoebH/fO9\n\tuoVu1M8YKX1Cd0LG4uSSx5E2/iPaLTAwMF9HGS5kPk8xAJRl0eg+2OKBfzjGPS48hq\n\totOJ0pyuo01DZl5i8PBsSHAuGXhPu22hV0WB+KOX1nIGRsizj0kql70PfYsjb9foTG\n\tYBrj4mGT5cvtA==",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Fri,  4 Dec 2020 12:24:52 +0530",
        "Message-Id": "<20201204065452.2764628-5-email@uajain.com>",
        "In-Reply-To": "<20201204065452.2764628-1-email@uajain.com>",
        "References": "<20201204065452.2764628-1-email@uajain.com>",
        "Mime-Version": "1.0",
        "Subject": "[libcamera-devel] [PATCH v3 4/4] simple-cam: Provide event-loop\n\tbacked by libevent",
        "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>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "libcamera moved its EventDispatcher and Timer API to its internal API,\nsince providing an event loop to applications should not be the job of\nlibcamera. Application utility like cam, were ported to use libevent,\nhence inspired from that, un-break simple-cam by using the similar\nimplementation to replace the EventDispatcher and Timer functionality\nby libevent.\n\nSigned-off-by: Umang Jain <email@uajain.com>\n---\n event_loop.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++++++++\n event_loop.h   |  44 +++++++++++++++++++++\n meson.build    |   2 +\n simple-cam.cpp |  35 ++++++++++-------\n 4 files changed, 171 insertions(+), 13 deletions(-)\n create mode 100644 event_loop.cpp\n create mode 100644 event_loop.h",
    "diff": "diff --git a/event_loop.cpp b/event_loop.cpp\nnew file mode 100644\nindex 0000000..f40a635\n--- /dev/null\n+++ b/event_loop.cpp\n@@ -0,0 +1,103 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Copyright (C) 2020, Google Inc.\n+ *\n+ * event_loop.cpp - Event loop based on cam\n+ */\n+\n+#include \"event_loop.h\"\n+\n+#include <assert.h>\n+#include <event2/event.h>\n+#include <event2/thread.h>\n+\n+EventLoop *EventLoop::instance_ = nullptr;\n+\n+EventLoop::EventLoop()\n+{\n+\tassert(!instance_);\n+\n+\tevthread_use_pthreads();\n+\tevent_ = event_base_new();\n+\tinstance_ = this;\n+}\n+\n+EventLoop::~EventLoop()\n+{\n+\tinstance_ = nullptr;\n+\n+\tevent_base_free(event_);\n+\tlibevent_global_shutdown();\n+}\n+\n+int EventLoop::exec()\n+{\n+\texitCode_ = -1;\n+\texit_.store(false, std::memory_order_release);\n+\n+\twhile (!exit_.load(std::memory_order_acquire)) {\n+\t\tdispatchCalls();\n+\t\tevent_base_loop(event_, EVLOOP_NO_EXIT_ON_EMPTY);\n+\t}\n+\n+\treturn exitCode_;\n+}\n+\n+void EventLoop::exit(int code)\n+{\n+\texitCode_ = code;\n+\texit_.store(true, std::memory_order_release);\n+\tinterrupt();\n+}\n+\n+void EventLoop::interrupt()\n+{\n+\tevent_base_loopbreak(event_);\n+}\n+\n+void EventLoop::timeoutTriggered()\n+{\n+\texit();\n+}\n+\n+void timeoutCb(int fd, short event, void *arg)\n+{\n+\tEventLoop *ptr = static_cast<EventLoop *>(arg);\n+\tptr->timeoutTriggered();\n+}\n+\n+void EventLoop::timeout(unsigned int sec)\n+{\n+\tstruct event *ev;\n+\tstruct timeval tv;\n+\n+\ttv.tv_sec = sec;\n+\ttv.tv_usec = 0;\n+\tev = evtimer_new(event_, &timeoutCb, this);\n+\tevtimer_add(ev, &tv);\n+}\n+\n+void EventLoop::callLater(const std::function<void()> &func)\n+{\n+\t{\n+\t\tstd::unique_lock<std::mutex> locker(lock_);\n+\t\tcalls_.push_back(func);\n+\t}\n+\n+\tinterrupt();\n+}\n+\n+void EventLoop::dispatchCalls()\n+{\n+\tstd::unique_lock<std::mutex> locker(lock_);\n+\n+\tfor (auto iter = calls_.begin(); iter != calls_.end(); ) {\n+\t\tstd::function<void()> call = std::move(*iter);\n+\n+\t\titer = calls_.erase(iter);\n+\n+\t\tlocker.unlock();\n+\t\tcall();\n+\t\tlocker.lock();\n+\t}\n+}\ndiff --git a/event_loop.h b/event_loop.h\nnew file mode 100644\nindex 0000000..fcb964f\n--- /dev/null\n+++ b/event_loop.h\n@@ -0,0 +1,44 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Copyright (C) 2020, Google Inc.\n+ *\n+ * event_loop.h - Event loop based on cam's\n+ */\n+#ifndef __SIMPLE_CAM_EVENT_LOOP_H__\n+#define __SIMPLE_CAM_EVENT_LOOP_H__\n+\n+#include <atomic>\n+#include <functional>\n+#include <list>\n+#include <mutex>\n+\n+struct event_base;\n+\n+class EventLoop\n+{\n+public:\n+\tEventLoop();\n+\t~EventLoop();\n+\n+\tvoid exit(int code = 0);\n+\tint exec();\n+\n+\tvoid timeout(unsigned int sec);\n+\tvoid timeoutTriggered();\n+\tvoid callLater(const std::function<void()> &func);\n+\n+private:\n+\tstatic EventLoop *instance_;\n+\n+\tstruct event_base *event_;\n+\tstd::atomic<bool> exit_;\n+\tint exitCode_;\n+\n+\tstd::list<std::function<void()>> calls_;\n+\tstd::mutex lock_;\n+\n+\tvoid interrupt();\n+\tvoid dispatchCalls();\n+};\n+\n+#endif /* __SIMPLE_CAM_EVENT_LOOP_H__ */\ndiff --git a/meson.build b/meson.build\nindex c312f2c..4d580c2 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -8,12 +8,14 @@ project('simple-cam', 'c', 'cpp',\n # simple-cam.cpp is the fully commented application\n src_files = files([\n \t'simple-cam.cpp',\n+\t'event_loop.cpp',\n ])\n \n # Point your PKG_CONFIG_PATH environment variable to the\n # libcamera install path camera.pc file ($prefix/lib/pkgconfig/camera.pc)\n libcamera_deps = [\n       dependency('camera', required : true),\n+      dependency('libevent_pthreads'),\n ]\n \n cpp_arguments = [ '-Wno-unused-parameter', ]\ndiff --git a/simple-cam.cpp b/simple-cam.cpp\nindex bfe30d7..6d1d84f 100644\n--- a/simple-cam.cpp\n+++ b/simple-cam.cpp\n@@ -11,8 +11,13 @@\n \n #include <libcamera/libcamera.h>\n \n+#include \"event_loop.h\"\n+\n+#define TIMEOUT_SEC 3\n+\n using namespace libcamera;\n std::shared_ptr<Camera> camera;\n+EventLoop loop;\n \n /*\n  * --------------------------------------------------------------------\n@@ -21,13 +26,26 @@ std::shared_ptr<Camera> camera;\n  * For each Camera::requestCompleted Signal emitted from the Camera the\n  * connected Slot is invoked.\n  *\n+ * The Slot is invoked in the CameraManager's thread, hence one should avoid\n+ * any heavy processing here. The processing of the request shall be re-directed\n+ * to the application's thread instead, so as not to block the CameraManager's\n+ * thread for large amount of time.\n+ *\n  * The Slot receives the Request as a parameter.\n  */\n+\n+static void processRequest(Request *request);\n+\n static void requestComplete(Request *request)\n {\n \tif (request->status() == Request::RequestCancelled)\n \t\treturn;\n \n+\tloop.callLater(std::bind(&processRequest, request));\n+}\n+\n+static void processRequest(Request *request)\n+{\n \tconst Request::BufferMap &buffers = request->buffers();\n \n \tfor (auto bufferPair : buffers) {\n@@ -320,20 +338,11 @@ int main()\n \t *\n \t * In order to dispatch events received from the video devices, such\n \t * as buffer completions, an event loop has to be run.\n-\t *\n-\t * Libcamera provides its own default event dispatcher realized by\n-\t * polling a set of file descriptors, but applications can integrate\n-\t * their own even loop with the Libcamera EventDispatcher.\n-\t *\n-\t * Here, as an example, run the poll-based EventDispatcher for 3\n-\t * seconds.\n \t */\n-\tEventDispatcher *dispatcher = cm->eventDispatcher();\n-\tTimer timer;\n-\ttimer.start(3000);\n-\twhile (timer.isRunning())\n-\t\tdispatcher->processEvents();\n-\n+\tloop.timeout(TIMEOUT_SEC);\n+\tint ret = loop.exec();\n+\tstd::cout << \"Capture ran for \" << TIMEOUT_SEC << \" seconds and \"\n+\t\t  << \"stopped with exit status: \" << ret << std::endl;\n \t/*\n \t * --------------------------------------------------------------------\n \t * Clean Up\n",
    "prefixes": [
        "libcamera-devel",
        "v3",
        "4/4"
    ]
}