[libcamera-devel] [PATCH 1/5] IPAManager: make IPAManager lifetime explicitly managed

Laurent Pinchart laurent.pinchart at ideasonboard.com
Wed Jun 3 22:51:55 CEST 2020


Hi Paul,

Thank you for the patch.

On Wed, Jun 03, 2020 at 11:16:05PM +0900, Paul Elder wrote:
> If any ipa_context instances are destroyed before the IPAManager is
> destroyed, then a segfault will occur when the IPAManager is
> deconstructed, as it tries to destroy all of the IPAs that it manages.

Isn't it the other way around, destroying ipa_context after the
IPAManager, as the modules are unloaded by the IPAManager and the
context function pointers thus become invalid ?

> Fix this by making the lifetime of the IPAManager explicit, and make the
> CameraManager construct and deconstruct (automatically, via a unique
> pointer) the IPAManager.
> 
> Also update the IPA interface test to do the construction and
> deconstruction of the IPAManager, as it does not use the CameraManager.
> 
> Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
> ---
>  include/libcamera/camera_manager.h       |  4 ++++
>  include/libcamera/internal/ipa_manager.h |  7 ++++---
>  src/libcamera/camera_manager.cpp         |  4 +++-
>  src/libcamera/ipa_manager.cpp            | 13 +++++++++++--
>  test/ipa/ipa_interface_test.cpp          |  5 +++++
>  5 files changed, 27 insertions(+), 6 deletions(-)
> 
> diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h
> index 079f848a..8f9398fa 100644
> --- a/include/libcamera/camera_manager.h
> +++ b/include/libcamera/camera_manager.h
> @@ -14,6 +14,8 @@
>  
>  #include <libcamera/object.h>
>  
> +#include "libcamera/internal/ipa_manager.h"
> +

Including an internal header in a public header will cause issues once
libcamera is installed, as the internal headers are not installed. As
you include ipa_manager.h to get the IPAManager class declaration only,
you could just forward-declare it.

>  namespace libcamera {
>  
>  class Camera;
> @@ -48,6 +50,8 @@ private:
>  
>  	class Private;
>  	std::unique_ptr<Private> p_;
> +
> +	std::unique_ptr<IPAManager> ipaManager_;

But let's move this to the CameraManager::Private class, to avoid
exposing the IPAManager in a public header, and to help with ABI
compatibility in the future (any non-static member data of a class is
part of the ABI, the less we expose, the less we risk breaking).

>  };
>  
>  } /* namespace libcamera */
> diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h
> index 2412d757..65303d6d 100644
> --- a/include/libcamera/internal/ipa_manager.h
> +++ b/include/libcamera/internal/ipa_manager.h
> @@ -22,6 +22,9 @@ namespace libcamera {
>  class IPAManager
>  {
>  public:
> +	IPAManager();
> +	~IPAManager();
> +
>  	static IPAManager *instance();
>  
>  	std::unique_ptr<IPAProxy> createIPA(PipelineHandler *pipe,
> @@ -30,9 +33,7 @@ public:
>  
>  private:
>  	std::vector<IPAModule *> modules_;
> -
> -	IPAManager();
> -	~IPAManager();

Ideally the constructor should be private, with a friend class
CameraManager::Private, but that will break the IPA interface test :-S
It would be nice if we could avoid making it public, but otherwise I can
live with that.

> +	static IPAManager *self_;
>  
>  	void parseDir(const char *libDir, unsigned int maxDepth,
>  		      std::vector<std::string> &files);
> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
> index 849377ad..d19348df 100644
> --- a/src/libcamera/camera_manager.cpp
> +++ b/src/libcamera/camera_manager.cpp
> @@ -15,6 +15,7 @@
>  
>  #include "libcamera/internal/device_enumerator.h"
>  #include "libcamera/internal/event_dispatcher_poll.h"
> +#include "libcamera/internal/ipa_manager.h"
>  #include "libcamera/internal/log.h"
>  #include "libcamera/internal/pipeline_handler.h"
>  #include "libcamera/internal/thread.h"
> @@ -246,7 +247,8 @@ void CameraManager::Private::removeCamera(Camera *camera)
>  CameraManager *CameraManager::self_ = nullptr;
>  
>  CameraManager::CameraManager()
> -	: p_(new CameraManager::Private(this))
> +	: p_(new CameraManager::Private(this)), ipaManager_(new IPAManager())

As the IPAManager constructor takes no argument, I think you can embed
an instance in CameraManager (or rather in CameraManager::Private)
instead of using a pointer.

> +

Extra blank line.

>  {
>  	if (self_)
>  		LOG(Camera, Fatal)
> diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp
> index 505cf610..74112cde 100644
> --- a/src/libcamera/ipa_manager.cpp
> +++ b/src/libcamera/ipa_manager.cpp
> @@ -93,8 +93,14 @@ LOG_DEFINE_CATEGORY(IPAManager)
>   * plain C API, or to transmit the data to the isolated process through IPC.
>   */
>  
> +IPAManager *IPAManager::self_ = nullptr;
> +

Now that the constructor is public, it should be documented, especially
to state that nobody but the CameraManager should create an instance of
IPAManager.

/**
 * \brief Construct an IPAManager instance
 *
 * The IPAManager class is meant to only be instantiated once, by the
 * CameraManager. Pipeline handlers shall use the instance() function to access
 * the IPAManager instance.
 */

>  IPAManager::IPAManager()
>  {
> +	if (self_)
> +		LOG(IPAManager, Fatal)
> +			<< "Multiple IPAManager objects are not allowed";
> +
>  	unsigned int ipaCount = 0;
>  
>  	/* User-specified paths take precedence. */
> @@ -134,12 +140,16 @@ IPAManager::IPAManager()
>  	if (!ipaCount)
>  		LOG(IPAManager, Warning)
>  			<< "No IPA found in '" IPA_MODULE_DIR "'";
> +
> +	self_ = this;
>  }
>  
>  IPAManager::~IPAManager()
>  {
>  	for (IPAModule *module : modules_)
>  		delete module;
> +
> +	self_ = nullptr;
>  }
>  
>  /**
> @@ -153,8 +163,7 @@ IPAManager::~IPAManager()
>   */
>  IPAManager *IPAManager::instance()
>  {
> -	static IPAManager ipaManager;
> -	return &ipaManager;
> +	return self_;
>  }

As the only usage of instance() is to call createIPA() in pipeline
handlers, would it make sense (in another patch) to drop the instance()
function, and turn the createIPA() function into a static function
(using self_ to access the IPA manager instance) ?

>  
>  /**
> diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp
> index 2f02af49..153493ba 100644
> --- a/test/ipa/ipa_interface_test.cpp
> +++ b/test/ipa/ipa_interface_test.cpp
> @@ -39,11 +39,15 @@ public:
>  	~IPAInterfaceTest()
>  	{
>  		delete notifier_;
> +		ipa_.reset();
> +		ipaManager_.reset();
>  	}
>  
>  protected:
>  	int init() override
>  	{
> +		ipaManager_ = make_unique<IPAManager>();
> +
>  		/* Create a pipeline handler for vimc. */
>  		std::vector<PipelineHandlerFactory *> &factories =
>  			PipelineHandlerFactory::factories();
> @@ -161,6 +165,7 @@ private:
>  
>  	std::shared_ptr<PipelineHandler> pipe_;
>  	std::unique_ptr<IPAProxy> ipa_;
> +	std::unique_ptr<IPAManager> ipaManager_;
>  	enum IPAOperationCode trace_;
>  	EventNotifier *notifier_;
>  	int fd_;

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list