[libcamera-devel] [PATCH v2 3/5] Documentation: Add Thread support page

Jacopo Mondi jacopo.mondi at ideasonboard.com
Tue Jan 9 15:06:19 CET 2024


Hi Dan

On Fri, Jan 05, 2024 at 04:41:02PM +0000, Daniel Scally via libcamera-devel wrote:
> 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.
>
> Signed-off-by: Daniel Scally <dan.scally at ideasonboard.com>

Looks good!

Reviewed-by: Jacopo Mondi <jacopo.mondi at ideasonboard.com>

> ---
> 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