[libcamera-devel] [PATCH 1/4] libcamera: mediadevice: Fix graph parsing error handling

Jacopo Mondi jacopo at jmondi.org
Wed Jan 2 10:15:23 CET 2019


Hi Laurent,
   thanks for the patches

A bit late, as this has been pushed already, but for the record.

On Tue, Jan 01, 2019 at 11:23:25PM +0200, Laurent Pinchart wrote:
> Most errors recorded during graph parsing are logged but not propagated
> to the caller. Fix this and delete objects that are created but not
> successfully added to the graph to avoid memory leaks. As the error code
> returned from the addObject() and populate*() functions doesn't matter
> much, turn them into bool functions.
>

Thanks, originally addObject() had void return value, I then returned
and error code, but ignored it in the caller. Quite silly.

> Additionally, add a way to query whether the media graph was valid, and
> clear objects before populating the graph to avoid leaking them.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> ---
>  src/libcamera/include/media_device.h | 10 ++--
>  src/libcamera/media_device.cpp       | 75 +++++++++++++++++-----------
>  2 files changed, 53 insertions(+), 32 deletions(-)
>
> diff --git a/src/libcamera/include/media_device.h b/src/libcamera/include/media_device.h
> index bca7c9a19471..74a67c81398a 100644
> --- a/src/libcamera/include/media_device.h
> +++ b/src/libcamera/include/media_device.h
> @@ -28,6 +28,7 @@ public:
>  	void close();
>
>  	int populate();
> +	bool valid() const { return valid_; }
>
>  	const std::string driver() const { return driver_; }
>  	const std::string devnode() const { return devnode_; }
> @@ -37,18 +38,19 @@ private:
>  	std::string driver_;
>  	std::string devnode_;
>  	int fd_;
> +	bool valid_;
>
>  	std::map<unsigned int, MediaObject *> objects_;
>  	MediaObject *object(unsigned int id);
> -	int addObject(MediaObject *obj);
> +	bool addObject(MediaObject *obj);
>  	void clear();
>
>  	std::vector<MediaEntity *> entities_;
>  	MediaEntity *getEntityByName(const std::string &name);
>
> -	void populateEntities(const struct media_v2_topology &topology);
> -	int populatePads(const struct media_v2_topology &topology);
> -	int populateLinks(const struct media_v2_topology &topology);
> +	bool populateEntities(const struct media_v2_topology &topology);
> +	bool populatePads(const struct media_v2_topology &topology);
> +	bool populateLinks(const struct media_v2_topology &topology);
>  };
>
>  } /* namespace libcamera */
> diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp
> index d9a5196ac28c..fd5a31746075 100644
> --- a/src/libcamera/media_device.cpp
> +++ b/src/libcamera/media_device.cpp
> @@ -56,7 +56,7 @@ namespace libcamera {
>   * \param devnode The media device node path
>   */
>  MediaDevice::MediaDevice(const std::string &devnode)
> -	: devnode_(devnode), fd_(-1)
> +	: devnode_(devnode), fd_(-1), valid_(false)
>  {
>  }
>
> @@ -99,6 +99,7 @@ void MediaDevice::clear()
>
>  	objects_.clear();
>  	entities_.clear();
> +	valid_ = false;
>  }
>
>  /**
> @@ -163,18 +164,18 @@ void MediaDevice::close()
>   * Add a new object to the global objects pool and fail if the object
>   * has already been registered.
>   */
> -int MediaDevice::addObject(MediaObject *obj)
> +bool MediaDevice::addObject(MediaObject *obj)
>  {
>
>  	if (objects_.find(obj->id()) != objects_.end()) {
>  		LOG(Error) << "Element with id " << obj->id()
>  			   << " already enumerated.";
> -		return -EEXIST;
> +		return false;
>  	}
>
>  	objects_[obj->id()] = obj;
>
> -	return 0;
> +	return true;
>  }
>
>  /*
> @@ -201,7 +202,7 @@ MediaEntity *MediaDevice::getEntityByName(const std::string &name)
>  	return nullptr;
>  }
>
> -int MediaDevice::populateLinks(const struct media_v2_topology &topology)
> +bool MediaDevice::populateLinks(const struct media_v2_topology &topology)
>  {
>  	media_v2_link *mediaLinks = reinterpret_cast<media_v2_link *>
>  				    (topology.ptr_links);
> @@ -222,7 +223,7 @@ int MediaDevice::populateLinks(const struct media_v2_topology &topology)
>  		if (!source) {
>  			LOG(Error) << "Failed to find pad with id: "
>  				   << source_id;
> -			return -ENODEV;
> +			return false;
>  		}
>
>  		unsigned int sink_id = mediaLinks[i].sink_id;
> @@ -231,20 +232,23 @@ int MediaDevice::populateLinks(const struct media_v2_topology &topology)
>  		if (!sink) {
>  			LOG(Error) << "Failed to find pad with id: "
>  				   << sink_id;
> -			return -ENODEV;
> +			return false;
>  		}
>
>  		MediaLink *link = new MediaLink(&mediaLinks[i], source, sink);
> +		if (!addObject(link)) {
> +			delete link;
> +			return false;
> +		}
> +
>  		source->addLink(link);
>  		sink->addLink(link);
> -
> -		addObject(link);
>  	}
>
> -	return 0;
> +	return true;
>  }
>
> -int MediaDevice::populatePads(const struct media_v2_topology &topology)
> +bool MediaDevice::populatePads(const struct media_v2_topology &topology)
>  {
>  	media_v2_pad *mediaPads = reinterpret_cast<media_v2_pad *>
>  				  (topology.ptr_pads);
> @@ -258,16 +262,19 @@ int MediaDevice::populatePads(const struct media_v2_topology &topology)
>  		if (!mediaEntity) {
>  			LOG(Error) << "Failed to find entity with id: "
>  				   << entity_id;
> -			return -ENODEV;
> +			return false;
>  		}
>
>  		MediaPad *pad = new MediaPad(&mediaPads[i], mediaEntity);
> -		mediaEntity->addPad(pad);
> +		if (!addObject(pad)) {
> +			delete pad;
> +			return false;
> +		}
>
> -		addObject(pad);
> +		mediaEntity->addPad(pad);
>  	}
>
> -	return 0;
> +	return true;
>  }
>
>  /*
> @@ -275,17 +282,22 @@ int MediaDevice::populatePads(const struct media_v2_topology &topology)
>   * reference in the MediaObject global pool and in the global vector of
>   * entities.
>   */
> -void MediaDevice::populateEntities(const struct media_v2_topology &topology)
> +bool MediaDevice::populateEntities(const struct media_v2_topology &topology)
>  {
>  	media_v2_entity *mediaEntities = reinterpret_cast<media_v2_entity *>
>  					 (topology.ptr_entities);
>
>  	for (unsigned int i = 0; i < topology.num_entities; ++i) {
>  		MediaEntity *entity = new MediaEntity(&mediaEntities[i]);
> +		if (!addObject(entity)) {
> +			delete entity;
> +			return false;
> +		}
>
> -		addObject(entity);
>  		entities_.push_back(entity);
>  	}
> +
> +	return true;
>  }
>
>  /**
> @@ -311,6 +323,8 @@ int MediaDevice::populate()
>  	__u64 version = -1;
>  	int ret;
>
> +	clear();
> +
>  	/*
>  	 * Keep calling G_TOPOLOGY until the version number stays stable.
>  	 */
> @@ -343,24 +357,29 @@ int MediaDevice::populate()
>  	}
>
>  	/* Populate entities, pads and links. */
> -	populateEntities(topology);
> -
> -	ret = populatePads(topology);
> -	if (ret)
> -		goto error_free_objs;
> -
> -	ret = populateLinks(topology);
> -error_free_objs:
> -	if (ret)
> -		clear();
> +	if (populateEntities(topology) &&
> +	    populatePads(topology) &&
> +	    populateLinks(topology))
> +		valid_ = true;
>
>  	delete[] links;
>  	delete[] ents;
>  	delete[] pads;
>
> -	return ret;
> +	if (!valid_) {
> +		clear();
> +		return -EINVAL;
> +	}
}
>
> +/**
> + * \fn MediaDevice::valid()
> + * \brief Query whether the media graph is valid

\brief Query whether the media graph has been populated and is valid

I feel the useful information here is that the graph is populated and
its media objects can be accessed. I would convey that in documenting
the method.

Thanks
   j

> + * \return true if the media graph is valid, false otherwise
> + */
> +
>  /**
>   * \var MediaDevice::objects_
>   * \brief Global map of media objects (entities, pads, links) keyed by their
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.libcamera.org/pipermail/libcamera-devel/attachments/20190102/cb436acf/attachment-0001.sig>


More information about the libcamera-devel mailing list