[libcamera-devel] [PATCH] libcamera: base: thread: Prevent messages to thread without an event loop

Umang Jain umang.jain at ideasonboard.com
Fri Oct 7 11:42:12 CEST 2022


Hi Laurent,

Thank you for the explanation.

Need few clarifications below

On 6/28/22 3:16 PM, Laurent Pinchart via libcamera-devel wrote:
> On Tue, Jun 28, 2022 at 11:09:21AM +0300, Tomi Valkeinen wrote:
>> On 27/06/2022 19:46, Laurent Pinchart wrote:
>>> A message posted to an object bound to a thread without an event loop
>>> will never get delivered. This indicates a bug in the caller, and
>>> materializes in ways that can be hard to debug, such as a signal never
>>> being delivered. Add an assertion in Thread::postMessage() to catch this
>>> at the source.
>>>
>>> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
>>> ---
>>>    src/libcamera/base/thread.cpp | 1 +
>>>    1 file changed, 1 insertion(+)
>>>
>>> diff --git a/src/libcamera/base/thread.cpp b/src/libcamera/base/thread.cpp
>>> index 6bda9d1462f5..6ead1d7c12d0 100644
>>> --- a/src/libcamera/base/thread.cpp
>>> +++ b/src/libcamera/base/thread.cpp
>>> @@ -530,6 +530,7 @@ void Thread::postMessage(std::unique_ptr<Message> msg, Object *receiver)
>>>    	msg->receiver_ = receiver;
>>>    
>>>    	ASSERT(data_ == receiver->thread()->data_);
>>> +	ASSERT(data_ != mainThread.data_);

Simply reading the commit message and inferring, the first change I 
expected was on the lines;
         ASSERT (data_->dispatcher_ != nullptr)

or for readability,

   	ASSERT(receiver->thread()->data_->dispatcher_ != nullptr);


that is, checking the receiver's thread event loop exists or not.
>>>    
>>>    	MutexLocker locker(data_->messages_.mutex_);
>>>    	data_->messages_.list_.push_back(std::move(msg));
>>>
>>> base-commit: 27cc0a6b58bcca32071cb6ab96e5ee79c75031e5
>> So what was the issue with the code I had? The problem is that
>> CameraManager is a libcamera Object, and was associated with the main
>> thread...? And a PyCameraManager which doesn't inherit CameraManager is
>> not an Object and not associated with any thread, so it works?
> That's right. Because PyCameraManager inherited from Object, it
> automatically got support for queued signal delivery, where a signal
> emitted in one thread would be processed in a different thread. This
> mechanism requires the receiving object to be bound to a thread that has
> an event loop managed by libcamera. By default an Object is bound to the
> thread it's created in.
>
> The CameraManager is created in the Python main thread, and the signal
> is emitted from an internal libcamera thread. The signal will thus be
> queued (the default connection type is Auto, which means that signals
> are delivered directly if the receiver object is bound to the thread
> that the signal is emitted from, or queued otherwise), which queues a
> message for the receiver's thread event loop. As the receiver thread is
> the Python main thread (the application thread from a libcamera point of
> view), which doesn't have a libcamera event loop, the message is never
> processed.

I understand the explanation above.

However I'm a bit lost with mainThread static variable. Am I right to 
infer that the mainThread is the Python's main thread in this case? If 
yes, the patch is correct, refraining the messages to be posted to a 
object whose threads has no event loop.

However, how about if the mainThread inherits from libcamera (hence 
Object, Thread, Signal delivery is in place) but tries to send a message 
to another Object bound to itself (i.e. mainThread)
Won't the assertion in this patch fail ?

> If the receiver doesn't inherit from the Object class, then the signal
> will be delivered directly, in the emitter's thread. You can achieve the
> same result with an Object receiver by specifying the direct connection
> type when connecting the signal.
>



More information about the libcamera-devel mailing list