Patch Detail
Show a patch.
GET /api/patches/20800/?format=api
{ "id": 20800, "url": "https://patchwork.libcamera.org/api/patches/20800/?format=api", "web_url": "https://patchwork.libcamera.org/patch/20800/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/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": "<20240805143654.20870-15-laurent.pinchart@ideasonboard.com>", "date": "2024-08-05T14:36:50", "name": "[v5,14/18] Documentation: Add Thread support page", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "7a8428cf78b677f796d4993527666aa6de68ac2e", "submitter": { "id": 2, "url": "https://patchwork.libcamera.org/api/people/2/?format=api", "name": "Laurent Pinchart", "email": "laurent.pinchart@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/20800/mbox/", "series": [ { "id": 4488, "url": "https://patchwork.libcamera.org/api/series/4488/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4488", "date": "2024-08-05T14:36:36", "name": "Split libcamera documentation in public and internal APIs", "version": 5, "mbox": "https://patchwork.libcamera.org/series/4488/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/20800/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/20800/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 41623C323E\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 5 Aug 2024 14:38:03 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CBE01633CB;\n\tMon, 5 Aug 2024 16:38:02 +0200 (CEST)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3C26D63387\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 5 Aug 2024 16:37:37 +0200 (CEST)", "from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A9906581;\n\tMon, 5 Aug 2024 16:36:45 +0200 (CEST)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"qr954QoL\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1722868605;\n\tbh=LvAu4hGvEP8ZD/cqX5EvLhlb4PGOskR21ySZOIdeq3Q=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=qr954QoLvyr+PrCOng/WhJlik3bEg545mriWOOdJiZbys+1PrUX4zbIiB4+jr136t\n\tXtfsBQWOszUjucJ8eD5OiLerMmsKFUzc0FmSij/yG+U3ikfvupqIbn7aAh+SHhmp/J\n\tD/pVH/yKxLPZoZ8H4Twx7vn9OQAYQqdRXUoKsPPM=", "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Daniel Scally <dan.scally@ideasonboard.com>", "Subject": "[PATCH v5 14/18] Documentation: Add Thread support page", "Date": "Mon, 5 Aug 2024 17:36:50 +0300", "Message-ID": "<20240805143654.20870-15-laurent.pinchart@ideasonboard.com>", "X-Mailer": "git-send-email 2.44.2", "In-Reply-To": "<20240805143654.20870-1-laurent.pinchart@ideasonboard.com>", "References": "<20240805143654.20870-1-laurent.pinchart@ideasonboard.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "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": "From: Daniel Scally <dan.scally@ideasonboard.com>\n\nMove the Thread Support page and the section of the Thread class'\ndocumentation dealing with stopping threads from\nsrc/libcamera/base/thread.cpp to a dedicated .dox file at\nDocumentation/. This is done to support the splitting of the\nDocumentation into a public and internal version. With a separate\npage, references can be made to thread safety without having to\ninclude the Thread class in the doxygen run.\n\nReviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\nSigned-off-by: Daniel Scally <dan.scally@ideasonboard.com>\n---\n Documentation/Doxyfile.in | 4 +-\n Documentation/thread.dox | 122 +++++++++++++++++++++++++++++++++\n src/libcamera/base/thread.cpp | 123 ----------------------------------\n 3 files changed, 125 insertions(+), 124 deletions(-)\n create mode 100644 Documentation/thread.dox", "diff": "diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in\nindex 62e63968ce62..6e5a3830ec38 100644\n--- a/Documentation/Doxyfile.in\n+++ b/Documentation/Doxyfile.in\n@@ -23,7 +23,8 @@ CASE_SENSE_NAMES = YES\n QUIET = YES\n WARN_AS_ERROR = @WARN_AS_ERROR@\n \n-INPUT = \"@TOP_SRCDIR@/include/libcamera\" \\\n+INPUT = \"@TOP_SRCDIR@/Documentation\" \\\n+ \"@TOP_SRCDIR@/include/libcamera\" \\\n \"@TOP_SRCDIR@/src/ipa/ipu3\" \\\n \"@TOP_SRCDIR@/src/ipa/libipa\" \\\n \"@TOP_SRCDIR@/src/libcamera\" \\\n@@ -32,6 +33,7 @@ INPUT = \"@TOP_SRCDIR@/include/libcamera\" \\\n \n FILE_PATTERNS = *.c \\\n *.cpp \\\n+ *.dox \\\n *.h\n \n RECURSIVE = YES\ndiff --git a/Documentation/thread.dox b/Documentation/thread.dox\nnew file mode 100644\nindex 000000000000..805a864eef12\n--- /dev/null\n+++ b/Documentation/thread.dox\n@@ -0,0 +1,122 @@\n+/**\n+ * \\page thread Thread Support\n+ *\n+ * libcamera supports multi-threaded applications through a threading model that\n+ * sets precise rules to guarantee thread-safe usage of the API. Additionally,\n+ * libcamera makes internal use of threads, and offers APIs that simplify\n+ * interactions with application threads. Careful compliance with the threading\n+ * model will ensure avoidance of race conditions.\n+ *\n+ * Every thread created by libcamera is associated with an instance of the\n+ * Thread class. Those threads run an internal event loop by default to\n+ * dispatch events to objects. Additionally, the main thread of the application\n+ * (defined as the thread that calls CameraManager::start()) is also associated\n+ * with a Thread instance, but has no event loop accessible to libcamera. Other\n+ * application threads are not visible to libcamera.\n+ *\n+ * \\section thread-objects Threads and Objects\n+ *\n+ * Instances of the Object class and all its derived classes are thread-aware\n+ * and are bound to the thread they are created in. They are said to *live* in\n+ * a thread, and they interact with the event loop of their thread for the\n+ * purpose of message passing and signal delivery. Messages posted to the\n+ * object with Object::postMessage() will be delivered from the event loop of\n+ * the thread that the object lives in. Signals delivered to the object, unless\n+ * explicitly connected with ConnectionTypeDirect, will also be delivered from\n+ * the object thread's event loop.\n+ *\n+ * All Object instances created internally by libcamera are bound to internal\n+ * threads. As objects interact with thread event loops for proper operation,\n+ * creating an Object instance in a thread that has no internal event loop (such\n+ * as the main application thread, or libcamera threads that have a custom main\n+ * loop), prevents some features of the Object class from being used. See\n+ * Thread::exec() for more details.\n+ *\n+ * \\section thread-signals Threads and Signals\n+ *\n+ * When sent to a receiver that does not inherit from the Object class, signals\n+ * are delivered synchronously in the thread of the sender. When the receiver\n+ * inherits from the Object class, delivery is by default asynchronous if the\n+ * sender and receiver live in different threads. In that case, the signal is\n+ * posted to the receiver's message queue and will be delivered from the\n+ * receiver's event loop, running in the receiver's thread. This mechanism can\n+ * be overridden by selecting a different connection type when calling\n+ * Signal::connect().\n+ *\n+ * \\section thread-reentrancy Reentrancy and Thread-Safety\n+ *\n+ * Through the documentation, several terms are used to define how classes and\n+ * their member functions can be used from multiple threads.\n+ *\n+ * - A **reentrant** function may be called simultaneously from multiple\n+ * threads if and only if each invocation uses a different instance of the\n+ * class. This is the default for all member functions not explictly marked\n+ * otherwise.\n+ *\n+ * - \\anchor thread-safe A **thread-safe** function may be called\n+ * simultaneously from multiple threads on the same instance of a class. A\n+ * thread-safe function is thus reentrant. Thread-safe functions may also be\n+ * called simultaneously with any other reentrant function of the same class\n+ * on the same instance.\n+ *\n+ * - \\anchor thread-bound A **thread-bound** function may be called only from\n+ * the thread that the class instances lives in (see section \\ref\n+ * thread-objects). For instances of classes that do not derive from the\n+ * Object class, this is the thread in which the instance was created. A\n+ * thread-bound function is not thread-safe, and may or may not be reentrant.\n+ *\n+ * Neither reentrancy nor thread-safety, in this context, mean that a function\n+ * may be called simultaneously from the same thread, for instance from a\n+ * callback invoked by the function. This may deadlock and isn't allowed unless\n+ * separately documented.\n+ *\n+ * A class is defined as reentrant, thread-safe or thread-bound if all its\n+ * member functions are reentrant, thread-safe or thread-bound respectively.\n+ * Some member functions may additionally be documented as having additional\n+ * thread-related attributes.\n+ *\n+ * Most classes are reentrant but not thread-safe, as making them fully\n+ * thread-safe would incur locking costs considered prohibitive for the\n+ * expected use cases.\n+ *\n+ * \\section thread-stop Stopping Threads\n+ *\n+ * Threads can't be forcibly stopped. Instead, a thread user first requests the\n+ * thread to exit and then waits for the thread's main function to react to the\n+ * request and return, at which points the thread will stop.\n+ *\n+ * For threads running exec(), the exit() function is used to request the thread\n+ * to exit. For threads subclassing the Thread class and implementing a custom\n+ * run() function, a subclass-specific mechanism shall be provided. In either\n+ * case, the wait() function shall be called to wait for the thread to stop.\n+ *\n+ * Due to their asynchronous nature, threads are subject to race conditions when\n+ * they stop. This is of particular importance for messages posted to the thread\n+ * with postMessage() (and the other mechanisms that rely on it, such as\n+ * Object::invokeMethod() or asynchronous signal delivery). To understand the\n+ * issues, three contexts need to be considered:\n+ *\n+ * - The worker is the Thread performing work and being instructed to stop.\n+ * - The controller is the context which instructs the worker thread to stop.\n+ * - The other contexts are any threads other than the worker and controller\n+ * that interact with the worker thread.\n+ *\n+ * Messages posted to the worker thread from the controller context before\n+ * calling exit() are queued to the thread's message queue, and the Thread class\n+ * offers no guarantee that those messages will be processed before the thread\n+ * stops. This allows threads to stop fast.\n+ *\n+ * A thread that requires delivery of messages posted from the controller\n+ * context before exit() should reimplement the run() function and call\n+ * dispatchMessages() after exec().\n+ *\n+ * Messages posted to the worker thread from the other contexts are asynchronous\n+ * with respect to the exit() call from the controller context. There is no\n+ * guarantee as to whether those messages will be processed or not before the\n+ * thread stops.\n+ *\n+ * Messages that are not processed will stay in the queue, in the exact same way\n+ * as messages posted after the thread has stopped. They will be processed when\n+ * the thread is restarted. If the thread is never restarted, they will be\n+ * deleted without being processed when the Thread instance is destroyed.\n+ */\ndiff --git a/src/libcamera/base/thread.cpp b/src/libcamera/base/thread.cpp\nindex 72733431a22e..1962dd32787c 100644\n--- a/src/libcamera/base/thread.cpp\n+++ b/src/libcamera/base/thread.cpp\n@@ -20,88 +20,6 @@\n #include <libcamera/base/mutex.h>\n #include <libcamera/base/object.h>\n \n-/**\n- * \\page thread Thread Support\n- *\n- * libcamera supports multi-threaded applications through a threading model that\n- * sets precise rules to guarantee thread-safe usage of the API. Additionally,\n- * libcamera makes internal use of threads, and offers APIs that simplify\n- * interactions with application threads. Careful compliance with the threading\n- * model will ensure avoidance of race conditions.\n- *\n- * Every thread created by libcamera is associated with an instance of the\n- * Thread class. Those threads run an internal event loop by default to\n- * dispatch events to objects. Additionally, the main thread of the application\n- * (defined as the thread that calls CameraManager::start()) is also associated\n- * with a Thread instance, but has no event loop accessible to libcamera. Other\n- * application threads are not visible to libcamera.\n- *\n- * \\section thread-objects Threads and Objects\n- *\n- * Instances of the Object class and all its derived classes are thread-aware\n- * and are bound to the thread they are created in. They are said to *live* in\n- * a thread, and they interact with the event loop of their thread for the\n- * purpose of message passing and signal delivery. Messages posted to the\n- * object with Object::postMessage() will be delivered from the event loop of\n- * the thread that the object lives in. Signals delivered to the object, unless\n- * explicitly connected with ConnectionTypeDirect, will also be delivered from\n- * the object thread's event loop.\n- *\n- * All Object instances created internally by libcamera are bound to internal\n- * threads. As objects interact with thread event loops for proper operation,\n- * creating an Object instance in a thread that has no internal event loop (such\n- * as the main application thread, or libcamera threads that have a custom main\n- * loop), prevents some features of the Object class from being used. See\n- * Thread::exec() for more details.\n- *\n- * \\section thread-signals Threads and Signals\n- *\n- * When sent to a receiver that does not inherit from the Object class, signals\n- * are delivered synchronously in the thread of the sender. When the receiver\n- * inherits from the Object class, delivery is by default asynchronous if the\n- * sender and receiver live in different threads. In that case, the signal is\n- * posted to the receiver's message queue and will be delivered from the\n- * receiver's event loop, running in the receiver's thread. This mechanism can\n- * be overridden by selecting a different connection type when calling\n- * Signal::connect().\n- *\n- * \\section thread-reentrancy Reentrancy and Thread-Safety\n- *\n- * Through the documentation, several terms are used to define how classes and\n- * their member functions can be used from multiple threads.\n- *\n- * - A **reentrant** function may be called simultaneously from multiple\n- * threads if and only if each invocation uses a different instance of the\n- * class. This is the default for all member functions not explictly marked\n- * otherwise.\n- *\n- * - \\anchor thread-safe A **thread-safe** function may be called\n- * simultaneously from multiple threads on the same instance of a class. A\n- * thread-safe function is thus reentrant. Thread-safe functions may also be\n- * called simultaneously with any other reentrant function of the same class\n- * on the same instance.\n- *\n- * - \\anchor thread-bound A **thread-bound** function may be called only from\n- * the thread that the class instances lives in (see section \\ref\n- * thread-objects). For instances of classes that do not derive from the\n- * Object class, this is the thread in which the instance was created. A\n- * thread-bound function is not thread-safe, and may or may not be reentrant.\n- *\n- * Neither reentrancy nor thread-safety, in this context, mean that a function\n- * may be called simultaneously from the same thread, for instance from a\n- * callback invoked by the function. This may deadlock and isn't allowed unless\n- * separately documented.\n- *\n- * A class is defined as reentrant, thread-safe or thread-bound if all its\n- * member functions are reentrant, thread-safe or thread-bound respectively.\n- * Some member functions may additionally be documented as having additional\n- * thread-related attributes.\n- *\n- * Most classes are reentrant but not thread-safe, as making them fully\n- * thread-safe would incur locking costs considered prohibitive for the\n- * expected use cases.\n- */\n-\n /**\n * \\file base/thread.h\n * \\brief Thread support\n@@ -217,47 +135,6 @@ ThreadData *ThreadData::current()\n * called. The event loop dispatches events (messages, notifiers and timers)\n * sent to the objects living in the thread. This behaviour can be modified by\n * overriding the run() function.\n- *\n- * \\section thread-stop Stopping Threads\n- *\n- * Threads can't be forcibly stopped. Instead, a thread user first requests the\n- * thread to exit and then waits for the thread's main function to react to the\n- * request and return, at which points the thread will stop.\n- *\n- * For threads running exec(), the exit() function is used to request the thread\n- * to exit. For threads subclassing the Thread class and implementing a custom\n- * run() function, a subclass-specific mechanism shall be provided. In either\n- * case, the wait() function shall be called to wait for the thread to stop.\n- *\n- * Due to their asynchronous nature, threads are subject to race conditions when\n- * they stop. This is of particular importance for messages posted to the thread\n- * with postMessage() (and the other mechanisms that rely on it, such as\n- * Object::invokeMethod() or asynchronous signal delivery). To understand the\n- * issues, three contexts need to be considered:\n- *\n- * - The worker is the Thread performing work and being instructed to stop.\n- * - The controller is the context which instructs the worker thread to stop.\n- * - The other contexts are any threads other than the worker and controller\n- * that interact with the worker thread.\n- *\n- * Messages posted to the worker thread from the controller context before\n- * calling exit() are queued to the thread's message queue, and the Thread class\n- * offers no guarantee that those messages will be processed before the thread\n- * stops. This allows threads to stop fast.\n- *\n- * A thread that requires delivery of messages posted from the controller\n- * context before exit() should reimplement the run() function and call\n- * dispatchMessages() after exec().\n- *\n- * Messages posted to the worker thread from the other contexts are asynchronous\n- * with respect to the exit() call from the controller context. There is no\n- * guarantee as to whether those messages will be processed or not before the\n- * thread stops.\n- *\n- * Messages that are not processed will stay in the queue, in the exact same way\n- * as messages posted after the thread has stopped. They will be processed when\n- * the thread is restarted. If the thread is never restarted, they will be\n- * deleted without being processed when the Thread instance is destroyed.\n */\n \n /**\n", "prefixes": [ "v5", "14/18" ] }