[libcamera-devel] [PATCH v3 2/4] Documentation: Add Thread support page

Daniel Scally dan.scally at ideasonboard.com
Fri Jan 12 13:14:32 CET 2024


Move the Thread Support page and the section of the Thread class'
documentation dealing with stopping threads from
src/libcamera/base/thread.cpp to a dedicated .dox file at
Documentation/. This is done to support the splitting of the
Documentation into a public and internal version. With a separate
page, references can be made to thread safety without having to
include the Thread class in the doxygen run.

Reviewed-by: Jacopo Mondi <jacopo.mondi at ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
Signed-off-by: Daniel Scally <dan.scally at ideasonboard.com>
---
Changes in v3:

	- None

Changes in v2:

	- New patch

 Documentation/Doxyfile.in     |   6 +-
 Documentation/thread.dox      | 122 +++++++++++++++++++++++++++++++++
 src/libcamera/base/thread.cpp | 123 ----------------------------------
 3 files changed, 126 insertions(+), 125 deletions(-)
 create mode 100644 Documentation/thread.dox

diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in
index a86ea6c1..48fea8bc 100644
--- a/Documentation/Doxyfile.in
+++ b/Documentation/Doxyfile.in
@@ -21,7 +21,8 @@ CASE_SENSE_NAMES       = YES
 
 QUIET                  = YES
 
-INPUT                  = "@TOP_SRCDIR@/include/libcamera" \
+INPUT                  = "@TOP_SRCDIR@/Documentation" \
+                         "@TOP_SRCDIR@/include/libcamera" \
                          "@TOP_SRCDIR@/src/ipa/ipu3" \
                          "@TOP_SRCDIR@/src/ipa/libipa" \
                          "@TOP_SRCDIR@/src/libcamera" \
@@ -30,7 +31,8 @@ INPUT                  = "@TOP_SRCDIR@/include/libcamera" \
 
 FILE_PATTERNS          = *.c \
                          *.cpp \
-                         *.h
+                         *.h \
+			 *.dox
 
 RECURSIVE              = YES
 
diff --git a/Documentation/thread.dox b/Documentation/thread.dox
new file mode 100644
index 00000000..805a864e
--- /dev/null
+++ b/Documentation/thread.dox
@@ -0,0 +1,122 @@
+/**
+ * \page thread Thread Support
+ *
+ * libcamera supports multi-threaded applications through a threading model that
+ * sets precise rules to guarantee thread-safe usage of the API. Additionally,
+ * libcamera makes internal use of threads, and offers APIs that simplify
+ * interactions with application threads. Careful compliance with the threading
+ * model will ensure avoidance of race conditions.
+ *
+ * Every thread created by libcamera is associated with an instance of the
+ * Thread class. Those threads run an internal event loop by default to
+ * dispatch events to objects. Additionally, the main thread of the application
+ * (defined as the thread that calls CameraManager::start()) is also associated
+ * with a Thread instance, but has no event loop accessible to libcamera. Other
+ * application threads are not visible to libcamera.
+ *
+ * \section thread-objects Threads and Objects
+ *
+ * Instances of the Object class and all its derived classes are thread-aware
+ * and are bound to the thread they are created in. They are said to *live* in
+ * a thread, and they interact with the event loop of their thread for the
+ * purpose of message passing and signal delivery. Messages posted to the
+ * object with Object::postMessage() will be delivered from the event loop of
+ * the thread that the object lives in. Signals delivered to the object, unless
+ * explicitly connected with ConnectionTypeDirect, will also be delivered from
+ * the object thread's event loop.
+ *
+ * All Object instances created internally by libcamera are bound to internal
+ * threads. As objects interact with thread event loops for proper operation,
+ * creating an Object instance in a thread that has no internal event loop (such
+ * as the main application thread, or libcamera threads that have a custom main
+ * loop), prevents some features of the Object class from being used. See
+ * Thread::exec() for more details.
+ *
+ * \section thread-signals Threads and Signals
+ *
+ * When sent to a receiver that does not inherit from the Object class, signals
+ * are delivered synchronously in the thread of the sender. When the receiver
+ * inherits from the Object class, delivery is by default asynchronous if the
+ * sender and receiver live in different threads. In that case, the signal is
+ * posted to the receiver's message queue and will be delivered from the
+ * receiver's event loop, running in the receiver's thread. This mechanism can
+ * be overridden by selecting a different connection type when calling
+ * Signal::connect().
+ *
+ * \section thread-reentrancy Reentrancy and Thread-Safety
+ *
+ * Through the documentation, several terms are used to define how classes and
+ * their member functions can be used from multiple threads.
+ *
+ * - A **reentrant** function may be called simultaneously from multiple
+ *   threads if and only if each invocation uses a different instance of the
+ *   class. This is the default for all member functions not explictly marked
+ *   otherwise.
+ *
+ * - \anchor thread-safe A **thread-safe** function may be called
+ *   simultaneously from multiple threads on the same instance of a class. A
+ *   thread-safe function is thus reentrant. Thread-safe functions may also be
+ *   called simultaneously with any other reentrant function of the same class
+ *   on the same instance.
+ *
+ * - \anchor thread-bound A **thread-bound** function may be called only from
+ *   the thread that the class instances lives in (see section \ref
+ *   thread-objects). For instances of classes that do not derive from the
+ *   Object class, this is the thread in which the instance was created. A
+ *   thread-bound function is not thread-safe, and may or may not be reentrant.
+ *
+ * Neither reentrancy nor thread-safety, in this context, mean that a function
+ * may be called simultaneously from the same thread, for instance from a
+ * callback invoked by the function. This may deadlock and isn't allowed unless
+ * separately documented.
+ *
+ * A class is defined as reentrant, thread-safe or thread-bound if all its
+ * member functions are reentrant, thread-safe or thread-bound respectively.
+ * Some member functions may additionally be documented as having additional
+ * thread-related attributes.
+ *
+ * Most classes are reentrant but not thread-safe, as making them fully
+ * thread-safe would incur locking costs considered prohibitive for the
+ * expected use cases.
+ *
+ * \section thread-stop Stopping Threads
+ *
+ * Threads can't be forcibly stopped. Instead, a thread user first requests the
+ * thread to exit and then waits for the thread's main function to react to the
+ * request and return, at which points the thread will stop.
+ *
+ * For threads running exec(), the exit() function is used to request the thread
+ * to exit. For threads subclassing the Thread class and implementing a custom
+ * run() function, a subclass-specific mechanism shall be provided. In either
+ * case, the wait() function shall be called to wait for the thread to stop.
+ *
+ * Due to their asynchronous nature, threads are subject to race conditions when
+ * they stop. This is of particular importance for messages posted to the thread
+ * with postMessage() (and the other mechanisms that rely on it, such as
+ * Object::invokeMethod() or asynchronous signal delivery). To understand the
+ * issues, three contexts need to be considered:
+ *
+ * - The worker is the Thread performing work and being instructed to stop.
+ * - The controller is the context which instructs the worker thread to stop.
+ * - The other contexts are any threads other than the worker and controller
+ *   that interact with the worker thread.
+ *
+ * Messages posted to the worker thread from the controller context before
+ * calling exit() are queued to the thread's message queue, and the Thread class
+ * offers no guarantee that those messages will be processed before the thread
+ * stops. This allows threads to stop fast.
+ *
+ * A thread that requires delivery of messages posted from the controller
+ * context before exit() should reimplement the run() function and call
+ * dispatchMessages() after exec().
+ *
+ * Messages posted to the worker thread from the other contexts are asynchronous
+ * with respect to the exit() call from the controller context. There is no
+ * guarantee as to whether those messages will be processed or not before the
+ * thread stops.
+ *
+ * Messages that are not processed will stay in the queue, in the exact same way
+ * as messages posted after the thread has stopped. They will be processed when
+ * the thread is restarted. If the thread is never restarted, they will be
+ * deleted without being processed when the Thread instance is destroyed.
+ */
diff --git a/src/libcamera/base/thread.cpp b/src/libcamera/base/thread.cpp
index b96951ac..6b034e06 100644
--- a/src/libcamera/base/thread.cpp
+++ b/src/libcamera/base/thread.cpp
@@ -19,88 +19,6 @@
 #include <libcamera/base/message.h>
 #include <libcamera/base/mutex.h>
 
-/**
- * \page thread Thread Support
- *
- * libcamera supports multi-threaded applications through a threading model that
- * sets precise rules to guarantee thread-safe usage of the API. Additionally,
- * libcamera makes internal use of threads, and offers APIs that simplify
- * interactions with application threads. Careful compliance with the threading
- * model will ensure avoidance of race conditions.
- *
- * Every thread created by libcamera is associated with an instance of the
- * Thread class. Those threads run an internal event loop by default to
- * dispatch events to objects. Additionally, the main thread of the application
- * (defined as the thread that calls CameraManager::start()) is also associated
- * with a Thread instance, but has no event loop accessible to libcamera. Other
- * application threads are not visible to libcamera.
- *
- * \section thread-objects Threads and Objects
- *
- * Instances of the Object class and all its derived classes are thread-aware
- * and are bound to the thread they are created in. They are said to *live* in
- * a thread, and they interact with the event loop of their thread for the
- * purpose of message passing and signal delivery. Messages posted to the
- * object with Object::postMessage() will be delivered from the event loop of
- * the thread that the object lives in. Signals delivered to the object, unless
- * explicitly connected with ConnectionTypeDirect, will also be delivered from
- * the object thread's event loop.
- *
- * All Object instances created internally by libcamera are bound to internal
- * threads. As objects interact with thread event loops for proper operation,
- * creating an Object instance in a thread that has no internal event loop (such
- * as the main application thread, or libcamera threads that have a custom main
- * loop), prevents some features of the Object class from being used. See
- * Thread::exec() for more details.
- *
- * \section thread-signals Threads and Signals
- *
- * When sent to a receiver that does not inherit from the Object class, signals
- * are delivered synchronously in the thread of the sender. When the receiver
- * inherits from the Object class, delivery is by default asynchronous if the
- * sender and receiver live in different threads. In that case, the signal is
- * posted to the receiver's message queue and will be delivered from the
- * receiver's event loop, running in the receiver's thread. This mechanism can
- * be overridden by selecting a different connection type when calling
- * Signal::connect().
- *
- * \section thread-reentrancy Reentrancy and Thread-Safety
- *
- * Through the documentation, several terms are used to define how classes and
- * their member functions can be used from multiple threads.
- *
- * - A **reentrant** function may be called simultaneously from multiple
- *   threads if and only if each invocation uses a different instance of the
- *   class. This is the default for all member functions not explictly marked
- *   otherwise.
- *
- * - \anchor thread-safe A **thread-safe** function may be called
- *   simultaneously from multiple threads on the same instance of a class. A
- *   thread-safe function is thus reentrant. Thread-safe functions may also be
- *   called simultaneously with any other reentrant function of the same class
- *   on the same instance.
- *
- * - \anchor thread-bound A **thread-bound** function may be called only from
- *   the thread that the class instances lives in (see section \ref
- *   thread-objects). For instances of classes that do not derive from the
- *   Object class, this is the thread in which the instance was created. A
- *   thread-bound function is not thread-safe, and may or may not be reentrant.
- *
- * Neither reentrancy nor thread-safety, in this context, mean that a function
- * may be called simultaneously from the same thread, for instance from a
- * callback invoked by the function. This may deadlock and isn't allowed unless
- * separately documented.
- *
- * A class is defined as reentrant, thread-safe or thread-bound if all its
- * member functions are reentrant, thread-safe or thread-bound respectively.
- * Some member functions may additionally be documented as having additional
- * thread-related attributes.
- *
- * Most classes are reentrant but not thread-safe, as making them fully
- * thread-safe would incur locking costs considered prohibitive for the
- * expected use cases.
- */
-
 /**
  * \file base/thread.h
  * \brief Thread support
@@ -216,47 +134,6 @@ ThreadData *ThreadData::current()
  * called. The event loop dispatches events (messages, notifiers and timers)
  * sent to the objects living in the thread. This behaviour can be modified by
  * overriding the run() function.
- *
- * \section thread-stop Stopping Threads
- *
- * Threads can't be forcibly stopped. Instead, a thread user first requests the
- * thread to exit and then waits for the thread's main function to react to the
- * request and return, at which points the thread will stop.
- *
- * For threads running exec(), the exit() function is used to request the thread
- * to exit. For threads subclassing the Thread class and implementing a custom
- * run() function, a subclass-specific mechanism shall be provided. In either
- * case, the wait() function shall be called to wait for the thread to stop.
- *
- * Due to their asynchronous nature, threads are subject to race conditions when
- * they stop. This is of particular importance for messages posted to the thread
- * with postMessage() (and the other mechanisms that rely on it, such as
- * Object::invokeMethod() or asynchronous signal delivery). To understand the
- * issues, three contexts need to be considered:
- *
- * - The worker is the Thread performing work and being instructed to stop.
- * - The controller is the context which instructs the worker thread to stop.
- * - The other contexts are any threads other than the worker and controller
- *   that interact with the worker thread.
- *
- * Messages posted to the worker thread from the controller context before
- * calling exit() are queued to the thread's message queue, and the Thread class
- * offers no guarantee that those messages will be processed before the thread
- * stops. This allows threads to stop fast.
- *
- * A thread that requires delivery of messages posted from the controller
- * context before exit() should reimplement the run() function and call
- * dispatchMessages() after exec().
- *
- * Messages posted to the worker thread from the other contexts are asynchronous
- * with respect to the exit() call from the controller context. There is no
- * guarantee as to whether those messages will be processed or not before the
- * thread stops.
- *
- * Messages that are not processed will stay in the queue, in the exact same way
- * as messages posted after the thread has stopped. They will be processed when
- * the thread is restarted. If the thread is never restarted, they will be
- * deleted without being processed when the Thread instance is destroyed.
  */
 
 /**
-- 
2.34.1



More information about the libcamera-devel mailing list