[libcamera-devel] [PATCH 2/3] test: message: Test recursive Thread::dispatchMessages() calls

Jacopo Mondi jacopo at jmondi.org
Mon Jul 5 13:08:29 CEST 2021


Hi Laurent,

On Fri, Jul 02, 2021 at 02:07:40AM +0300, Laurent Pinchart wrote:
> The Thread::dispatchMessages() function needs to support recursive
> calls, for instance to allow flushing delivery of invoked methods. Add a
> corresponding test, which currently fails with a double free.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> ---
>  test/message.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 64 insertions(+), 2 deletions(-)
>
> diff --git a/test/message.cpp b/test/message.cpp
> index eeea57feab76..7895cd7c2106 100644
> --- a/test/message.cpp
> +++ b/test/message.cpp
> @@ -26,8 +26,8 @@ public:
>  		MessageReceived,
>  	};
>
> -	MessageReceiver()
> -		: status_(NoMessage)
> +	MessageReceiver(Object *parent = nullptr)
> +		: Object(parent), status_(NoMessage)
>  	{
>  	}
>
> @@ -52,6 +52,45 @@ private:
>  	Status status_;
>  };
>
> +class RecursiveMessageReceiver : public Object
> +{
> +public:
> +	RecursiveMessageReceiver()
> +		: child_(this), success_(false)
> +	{
> +	}
> +
> +	bool success() const { return success_; }
> +
> +protected:
> +	void message([[maybe_unused]] Message *msg)
> +	{
> +		if (msg->type() != Message::None) {
> +			Object::message(msg);
> +			return;
> +		}
> +
> +		child_.postMessage(std::make_unique<Message>(Message::None));
> +
> +		/*
> +		 * If the child has already received the message, something is
> +		 * wrong.
> +		 */
> +		if (child_.status() != MessageReceiver::NoMessage)
> +			return;
> +
> +		Thread::current()->dispatchMessages(Message::None);
> +
> +		/* The child should now have received the message. */
> +		if (child_.status() == MessageReceiver::MessageReceived)
> +			success_ = true;
> +	}
> +
> +private:
> +	MessageReceiver child_;
> +	bool success_;
> +};
> +
>  class SlowMessageReceiver : public Object
>  {
>  protected:
> @@ -120,6 +159,29 @@ protected:
>
>  		delete slowReceiver;
>
> +		this_thread::sleep_for(chrono::milliseconds(100));
> +
> +		/*
> +		 * Test recursive calls to Thread::dispatchMessages(). Messages
> +		 * should be delivered correctly, without crashes or memory
> +		 * leaks. Two messages need to be posted to ensure we don't only
> +		 * test the simple case of a queue containing a single message.
> +		 */
> +		RecursiveMessageReceiver *recursiveReceiver = new RecursiveMessageReceiver();
> +		recursiveReceiver->moveToThread(&thread_);
> +
> +		recursiveReceiver->postMessage(std::make_unique<Message>(Message::None));
> +		recursiveReceiver->postMessage(std::make_unique<Message>(Message::UserMessage));

I'm not sure why two messages are necessary, also considering that
messages != Message::None are ignored...

If my understanding is correct, a single postMessage() triggers a
dispatcher->interrupt() which triggers a dispatchMessages() as the receiver
runs on a different thread and can be interrupted. The message is then
dispatched and handled by the execution of RecursiveMessageReceiver::message()
call.

>From there we post a message to the child and go throuh the same path if not
that the child runs on the same thread and we have to dispatch
messages forcefully, causing a recursive call to dispatchMessages() on
the same thread of execution.

Am I missing something or is the second message not required ?

Thanks
  j

> +
> +		this_thread::sleep_for(chrono::milliseconds(10));
> +
> +		if (!recursiveReceiver->success()) {
> +			cout << "Recursive message delivery failed" << endl;
> +			return TestFail;
> +		}
> +
> +		delete recursiveReceiver;
> +
>  		return TestPass;
>  	}
>
> --
> Regards,
>
> Laurent Pinchart
>


More information about the libcamera-devel mailing list