{"id":19374,"url":"https://patchwork.libcamera.org/api/1.1/patches/19374/?format=json","web_url":"https://patchwork.libcamera.org/patch/19374/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20240105164104.78398-4-dan.scally@ideasonboard.com>","date":"2024-01-05T16:41:02","name":"[libcamera-devel,v2,3/5] Documentation: Add Thread support page","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"3cb6ae9cf858eb175587ba0715a1b032cdbbc236","submitter":{"id":156,"url":"https://patchwork.libcamera.org/api/1.1/people/156/?format=json","name":"Dan Scally","email":"dan.scally@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/19374/mbox/","series":[{"id":4134,"url":"https://patchwork.libcamera.org/api/1.1/series/4134/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=4134","date":"2024-01-05T16:40:59","name":"Improve libcamera documentation","version":2,"mbox":"https://patchwork.libcamera.org/series/4134/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/19374/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/19374/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 EAC1AC32BC\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  5 Jan 2024 16:41:28 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7DA2E62B53;\n\tFri,  5 Jan 2024 17:41:28 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B754662B49\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  5 Jan 2024 17:41:22 +0100 (CET)","from mail.ideasonboard.com\n\t(cpc141996-chfd3-2-0-cust928.12-3.cable.virginm.net [86.13.91.161])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 50A8FD49;\n\tFri,  5 Jan 2024 17:40:21 +0100 (CET)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1704472888;\n\tbh=oF2MZX1y0uQraRg0qMd6I/qnzRrOIfwYV/WDvHqU/aA=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=vevVRGA4ic+CjOCPcpoOwYm66/IEvFem6PhG5jeEK1XE4SAO6DqJec9Z/Oi3rT2Sm\n\tC48HInWZj0QgmcReMSSttLbC7t8PWVWOMiMGEI1fs8d18mmAEXh6qTkWP5pugL9yOg\n\tyVY+2Pd8krNDxJ2AEBcY+CIqwZpF4somCVvkI2uw+AGKLuU7HD+iQ5lmAWvB5aIU92\n\t/VM/P7ItxdINahLlsggIHCMmfK8eJWYMzCZjX/kaRhTo2SstfuPyV7hxtDFjWqUOLl\n\tX+1OhaRsVWsb+sBkc7NPHCxeOHdtTJqHEUi15ijcx5x+XeFn7qfdPE/8kL8YUPzmvZ\n\tKppx9k4zSoTpA==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1704472821;\n\tbh=oF2MZX1y0uQraRg0qMd6I/qnzRrOIfwYV/WDvHqU/aA=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=aJE7AVt25UZcSv9oD3ahFUVZDP621em9Gg91ojpgSvulXU0dV/hr/6+eqLeaPOaCx\n\tmvXkEw0jh6xhkryggVFqx1syu9BVemlHJITRDzbLD6dtRQEJHUsLMN/Y0CMKT9L+sV\n\tU49agvfBdCHXlJRChF0RTkAn2ZbjADgiNBuhSVoI="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"aJE7AVt2\"; dkim-atps=neutral","To":"libcamera-devel@lists.libcamera.org","Date":"Fri,  5 Jan 2024 16:41:02 +0000","Message-Id":"<20240105164104.78398-4-dan.scally@ideasonboard.com>","X-Mailer":"git-send-email 2.34.1","In-Reply-To":"<20240105164104.78398-1-dan.scally@ideasonboard.com>","References":"<20240105164104.78398-1-dan.scally@ideasonboard.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH v2 3/5] Documentation: Add Thread support\n\tpage","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>","From":"Daniel Scally via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Daniel Scally <dan.scally@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Move 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\nSigned-off-by: Daniel Scally <dan.scally@ideasonboard.com>\n---\nChanges in v2:\n\n\t- New patch\n\n Documentation/Doxyfile.in     |   6 +-\n Documentation/thread.dox      | 122 +++++++++++++++++++++++++++++++++\n src/libcamera/base/thread.cpp | 123 ----------------------------------\n 3 files changed, 126 insertions(+), 125 deletions(-)\n create mode 100644 Documentation/thread.dox","diff":"diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in\nindex a86ea6c1..48fea8bc 100644\n--- a/Documentation/Doxyfile.in\n+++ b/Documentation/Doxyfile.in\n@@ -21,7 +21,8 @@ CASE_SENSE_NAMES       = YES\n \n QUIET                  = YES\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@@ -30,7 +31,8 @@ INPUT                  = \"@TOP_SRCDIR@/include/libcamera\" \\\n \n FILE_PATTERNS          = *.c \\\n                          *.cpp \\\n-                         *.h\n+                         *.h \\\n+\t\t\t *.dox\n \n RECURSIVE              = YES\n \ndiff --git a/Documentation/thread.dox b/Documentation/thread.dox\nnew file mode 100644\nindex 00000000..805a864e\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 b96951ac..6b034e06 100644\n--- a/src/libcamera/base/thread.cpp\n+++ b/src/libcamera/base/thread.cpp\n@@ -19,88 +19,6 @@\n #include <libcamera/base/message.h>\n #include <libcamera/base/mutex.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@@ -216,47 +134,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":["libcamera-devel","v2","3/5"]}