[PATCH v2 5/5] libcamera: software_isp: Modify dispatching messages on stop
Milan Zamazal
mzamazal at redhat.com
Tue Feb 25 15:44:03 CET 2025
Hi Laurent,
thank you for review.
Laurent Pinchart <laurent.pinchart at ideasonboard.com> writes:
> Hi Milan,
>
> Thank you for the patch.
>
> On Mon, Feb 24, 2025 at 07:52:35PM +0100, Milan Zamazal wrote:
>> There may be pending messages in SoftwareIsp message queue when
>> SoftwareIsp stops. The call to IPAProxySoft::stop() will dispatch them
>> before SoftwareIsp::stop() finishes. But this is dependent on
>> IPAProxySoft::stop() implementation and we can do better to ensure they
>> are dispatched before SoftwareIsp::stop() finishes.
>>
>> Let's introduce new `receiver' argument to Thread::dispatchMessages(),
>> limiting dispatching the messages to the given receiver. Now we can
>> flush the messages destined for the SoftwareIsp instance explicitly.
>> And the IPA proxy can flush just the messages destined for itself.
>> Other messages of the given thread remain queued and will be handled
>> elsewhere as appropriate.
>>
>> Signed-off-by: Milan Zamazal <mzamazal at redhat.com>
>> ---
>> include/libcamera/base/thread.h | 3 ++-
>> src/libcamera/base/thread.cpp | 15 ++++++++++-----
>
> Could you split this to a separate patch ? Something like
>
> libcamera: base: thread: Support dispatching messages for specific receiver
>
> The Thread::dispatchMessage() function supports filtering messages based
> on their type. It can be useful to also dispatch only messages posted
> for a specific receiver. Add an optional receiver argument to the
> dispatchMessage() function to do so. When set to null (the default
> value), the behaviour of the function is not changed.
>
>> src/libcamera/software_isp/software_isp.cpp | 3 +++
>> .../libcamera_templates/proxy_functions.tmpl | 2 +-
>
> prxoy_function.tmpl can then also be split to a separate patch.
>
> utils: ipc: Only dispatch messages for proxy when stopping thread
>
> When stopping the proxy thread, all messages of InvokeMessage type
> posted to the pipeline handler thread are dispatched, to ensure that all
> signals emitted from the proxy thread and queued for delivery to the
> proxy are delivered synchronously. This unnecessarily delivers queued
> signals for other objects in the pipeline handler thread, possibly
> delaying processing of higher priority events.
>
> Improve the implementation by limiting synchronous delivery to messages
> posted for the proxy.
>
>
>
> In case a problem is found later with the IPA proxy, it will be easier
> to revert this specific change.
>
>> 4 files changed, 16 insertions(+), 7 deletions(-)
>>
>> diff --git a/include/libcamera/base/thread.h b/include/libcamera/base/thread.h
>> index 3cbf6398..b9284c2c 100644
>> --- a/include/libcamera/base/thread.h
>> +++ b/include/libcamera/base/thread.h
>> @@ -48,7 +48,8 @@ public:
>>
>> EventDispatcher *eventDispatcher();
>>
>> - void dispatchMessages(Message::Type type = Message::Type::None);
>> + void dispatchMessages(Message::Type type = Message::Type::None,
>> + Object *receiver = nullptr);
>>
>> protected:
>> int exec();
>> diff --git a/src/libcamera/base/thread.cpp b/src/libcamera/base/thread.cpp
>> index 02128f23..6f22f4ed 100644
>> --- a/src/libcamera/base/thread.cpp
>> +++ b/src/libcamera/base/thread.cpp
>> @@ -603,6 +603,8 @@ void Thread::removeMessages(Object *receiver)
>> /**
>> * \brief Dispatch posted messages for this thread
>> * \param[in] type The message type
>> + * \param[in] receiver If not null, dispatch only messages for the given
>> + * receiver
>> *
>> * This function immediately dispatches all the messages previously posted for
>> * this thread with postMessage() that match the message \a type. If the \a type
>
> Let's expand this paragraph to explain the receiver parameter:
>
> * This function immediately dispatches all the messages of the given \a type
> * previously posted to this thread for the \a receiver with postMessage(). If
> * the \a type is Message::Type::None, all messages types are dispatched. If the
> * \a receiver is null, messages to all receivers are dispatched.
>
> I think you can then shorten the documentation of the parameter:
>
> * \param[in] receiver The receiver whose messages to dispatch
>
>> @@ -616,7 +618,7 @@ void Thread::removeMessages(Object *receiver)
>> * same thread from an object's message handler. It guarantees delivery of
>> * messages in the order they have been posted in all cases.
>> */
>> -void Thread::dispatchMessages(Message::Type type)
>> +void Thread::dispatchMessages(Message::Type type, Object *receiver)
>> {
>> ASSERT(data_ == ThreadData::current());
>>
>> @@ -633,6 +635,9 @@ void Thread::dispatchMessages(Message::Type type)
>> if (type != Message::Type::None && msg->type() != type)
>> continue;
>>
>> + if (receiver && receiver != msg->receiver_)
>> + continue;
>> +
>> /*
>> * Move the message, setting the entry in the list to null. It
>> * will cause recursive calls to ignore the entry, and the erase
>> @@ -640,12 +645,12 @@ void Thread::dispatchMessages(Message::Type type)
>> */
>> std::unique_ptr<Message> message = std::move(msg);
>>
>> - Object *receiver = message->receiver_;
>> - ASSERT(data_ == receiver->thread()->data_);
>> - receiver->pendingMessages_--;
>> + Object *messageReceiver = message->receiver_;
>> + ASSERT(data_ == messageReceiver->thread()->data_);
>> + messageReceiver->pendingMessages_--;
>>
>> locker.unlock();
>> - receiver->message(message.get());
>> + messageReceiver->message(message.get());
>> message.reset();
>> locker.lock();
>> }
>> diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
>> index 3a605ab2..8f5ee774 100644
>> --- a/src/libcamera/software_isp/software_isp.cpp
>> +++ b/src/libcamera/software_isp/software_isp.cpp
>> @@ -13,6 +13,8 @@
>> #include <sys/types.h>
>> #include <unistd.h>
>>
>> +#include <libcamera/base/thread.h>
>> +
>> #include <libcamera/controls.h>
>> #include <libcamera/formats.h>
>> #include <libcamera/stream.h>
>> @@ -339,6 +341,7 @@ void SoftwareIsp::stop()
>> ispWorkerThread_.wait();
>>
>> running_ = false;
>> + Thread::current()->dispatchMessages(Message::Type::InvokeMessage, this);
>
> I'd add a blank line here.
>
> I think you can also swap the two lines. Dispatching the messages first
> will ensure that any queued signal that indicates completion of a buffer
> will be delivered to the pipeline handler. That may push one extra frame
> to the application. On the other hand, as we're stopping the ISP, maybe
> the application doesn't care.
>
> I wonder if we could actually drop the running_ variable now.
I think we can and it works for me. I'll do it in v3.
> By dispatching all pending messages, we ensure that no new calls to
> the IPA will be made from signal handlers invoked from the
> dispatchMessages() call from within ipa_->stop().
>
>> ipa_->stop();
>>
>> for (auto buffer : queuedOutputBuffers_) {
>> diff --git a/utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl b/utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl
>> index b5797b14..25476990 100644
>> --- a/utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl
>> +++ b/utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl
>> @@ -34,7 +34,7 @@
>> thread_.exit();
>> thread_.wait();
>>
>> - Thread::current()->dispatchMessages(Message::Type::InvokeMessage);
>> + Thread::current()->dispatchMessages(Message::Type::InvokeMessage, this);
>>
>> state_ = ProxyStopped;
>> {%- endmacro -%}
More information about the libcamera-devel
mailing list