[libcamera-devel] [PATCH 4/8] libcamera: ipa_module: allow instantiation of IPAInterface

Laurent Pinchart laurent.pinchart at ideasonboard.com
Tue May 28 17:42:31 CEST 2019


Hi Paul,

Thank you for the patch.

On Mon, May 27, 2019 at 06:35:36PM -0400, Paul Elder wrote:
> Add functions for loading the IPAInterface factory function from an IPA
> module shared object, and for creating an instance of an IPAInterface.
> These functions will be used by IPAManager, from which a PipelineHandler
> will request an IPAInterface.
> 
> Also update meson to add the "-ldl" linker argument, to allow loading of
> the factory function from a shared object.
> 
> Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
> ---
>  src/libcamera/include/ipa_module.h | 15 +++++-
>  src/libcamera/ipa_module.cpp       | 80 ++++++++++++++++++++++++++++--
>  src/libcamera/meson.build          |  3 +-
>  3 files changed, 92 insertions(+), 6 deletions(-)
> 
> diff --git a/src/libcamera/include/ipa_module.h b/src/libcamera/include/ipa_module.h
> index a4c6dbd..bb03407 100644
> --- a/src/libcamera/include/ipa_module.h
> +++ b/src/libcamera/include/ipa_module.h
> @@ -7,9 +7,10 @@
>  #ifndef __LIBCAMERA_IPA_MODULE_H__
>  #define __LIBCAMERA_IPA_MODULE_H__
>  
> -#include <string>
> -
> +#include <libcamera/ipa/ipa_interface.h>
>  #include <libcamera/ipa/ipa_module_info.h>
> +#include <memory>
> +#include <string>

We usually put the C++ headers first, followed by a blank line, followed
by the libcamera public headers.

>  namespace libcamera {
>  
> @@ -17,16 +18,26 @@ class IPAModule
>  {
>  public:
>  	explicit IPAModule(const std::string &libPath);
> +	~IPAModule();
>  
>  	bool isValid() const;
>  
>  	const struct IPAModuleInfo &info() const;
>  
> +	bool load();
> +
> +	std::unique_ptr<IPAInterface> createInstance();
> +
>  private:
>  	struct IPAModuleInfo info_;
>  
>  	std::string libPath_;
>  	bool valid_;
> +	bool loaded_;
> +
> +	void *dlhandle_;

s/dlhandle_/dlHandle_/ ?

> +	typedef IPAInterface *(*ipaiFactory)(void);

What does the second i in ipai stand for ?

> +	ipaiFactory ipaCreate_;
>  
>  	int loadIPAModuleInfo();
>  };
> diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp
> index 6e68934..9bb0594 100644
> --- a/src/libcamera/ipa_module.cpp
> +++ b/src/libcamera/ipa_module.cpp
> @@ -7,6 +7,7 @@
>  
>  #include "ipa_module.h"
>  
> +#include <dlfcn.h>
>  #include <elf.h>
>  #include <errno.h>
>  #include <fcntl.h>
> @@ -242,13 +243,11 @@ int elfLoadSymbol(void *dst, size_t size, void *map, size_t soSize,
>   * The IPA module shared object file must be of the same endianness and
>   * bitness as libcamera.
>   *
> - * \todo load funtions from the IPA to be used by pipelines
> - *
>   * The caller shall call the isValid() method after constructing an
>   * IPAModule instance to verify the validity of the IPAModule.
>   */
>  IPAModule::IPAModule(const std::string &libPath)
> -	: libPath_(libPath), valid_(false)
> +	: libPath_(libPath), valid_(false), loaded_(false)

You should initialise dlhandle_ too.

>  {
>  	if (loadIPAModuleInfo() < 0)
>  		return;
> @@ -256,6 +255,12 @@ IPAModule::IPAModule(const std::string &libPath)
>  	valid_ = true;
>  }
>  
> +IPAModule::~IPAModule()
> +{
> +	if (dlhandle_)
> +		dlclose(dlhandle_);
> +}
> +
>  int IPAModule::loadIPAModuleInfo()
>  {
>  	int fd = open(libPath_.c_str(), O_RDONLY);
> @@ -325,4 +330,73 @@ const struct IPAModuleInfo &IPAModule::info() const
>  	return info_;
>  }
>  
> +/**
> + * \brief Load the IPA implementation factory from the shared object
> + *
> + * The IPA module shared object implements an IPAInterface class to be used
> + * by pipeline handlers. This function loads the factory function from the
> + * shared object. Later, createInstance() can be called to instantiate the
> + * IPAInterface.
> + *
> + * This function only needs to be called successfully once, after which

We usually use method instead of function for member functions.

> + * createInstance can be called as many times as IPAInterface instances are
> + * needed.
> + *
> + * Calling this function on an invalid module (as returned by isValid()) is
> + * an error.
> + *
> + * \return true if load was successful, or already loaded, and false otherwise
> + */
> +bool IPAModule::load()
> +{
> +	if (!valid_)
> +		return false;
> +
> +	if (loaded_)
> +		return true;
> +
> +	dlhandle_ = dlopen(libPath_.c_str(), RTLD_LAZY);
> +	if (!dlhandle_) {
> +		LOG(IPAModule, Error) << "Failed to open IPA module shared object"

s/object/object /

> +				      << dlerror();

To shorten the lines, we usually use the following style

		LOG(IPAModule, Error)
			<< "Failed to open IPA module shared object: "
			<< dlerror();

> +		return false;
> +	}
> +
> +	void *symbol = dlsym(dlhandle_, "ipaCreate");
> +	if (!symbol) {
> +		LOG(IPAModule, Error) << "Failed to load ipaCreate() from IPA module shared object"
> +				      << dlerror();

Same here.

> +		dlclose(dlhandle_);

		dlhandle_ = nullptr;

otherwise you will have a double-close.

> +		return false;
> +	}
> +
> +	ipaCreate_ = (ipaiFactory)symbol;
> +
> +	loaded_ = true;
> +
> +	return true;
> +}
> +
> +/**
> + * \brief Instantiate an IPAInterface
> + *
> + * After the IPAInterface implementation factory has been loaded (with load()),
> + * an instance can be created with this function.

To avoid showing too much of the internal details in the documentation,
how about

 * After loading the IPA module with load(), this method creates an
 * instance of the IPA module interface.

> + *
> + * Calling this function on a module that has not yet been loaded, or an
> + * invalid module (as returned by load() and isValid(), respectively) is
> + * an error.
> + *
> + * \return the IPA implementation as a new IPAInterface instance

on success, or nullptr on error.

> + */
> +std::unique_ptr<IPAInterface> IPAModule::createInstance()
> +{
> +	if (!valid_ || !loaded_)
> +		return nullptr;
> +
> +	std::unique_ptr<IPAInterface> ipai(ipaCreate_());
> +
> +	return ipai;

You can simplify this with

	return std::unique_ptr<IPAInterface>(ipaCreate_());

> +}
> +
>  } /* namespace libcamera */
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 07335e5..32f7da4 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -65,7 +65,8 @@ libcamera = shared_library('camera',
>                             libcamera_sources,
>                             install : true,
>                             include_directories : includes,
> -                           dependencies : libudev)
> +                           dependencies : libudev,
> +                           link_args : '-ldl')
>  
>  libcamera_dep = declare_dependency(sources : [libcamera_api, libcamera_h],
>                                     include_directories : libcamera_includes,

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list