[libcamera-devel] [RFC 04/11] libcamera: media_device: Handle media device fd in acquire() and release()

Laurent Pinchart laurent.pinchart at ideasonboard.com
Wed Apr 17 01:07:38 CEST 2019


Hi Niklas,

Thank you for the patch.

On Sun, Apr 14, 2019 at 03:34:59AM +0200, Niklas Söderlund wrote:
> To gain better control of when a file descriptor is open to the media
> device and reduce the work needed in pipeline handler implementations,
> handle the file descriptor in acquire() and release().
> 
> This changes the current behavior where a file descriptor is only open
> when requested by the pipeline handler to that one is always open as
> long a media device is acquired. This new behavior is desired to allow
> implementing exclusive access to a pipeline handler between processes.

I think this is fine. It might interfere with power handling on the
kernel side, but I don't think the kernel should perform power
management on open/close of media devices, so it's an issue that would
need to be handled there.

> Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> ---
>  src/libcamera/include/media_device.h         |  2 +-
>  src/libcamera/media_device.cpp               | 33 ++++++++++----------
>  src/libcamera/pipeline/ipu3/ipu3.cpp         | 25 +--------------
>  test/media_device/media_device_link_test.cpp |  7 -----
>  test/v4l2_subdevice/v4l2_subdevice_test.cpp  | 10 +-----
>  5 files changed, 19 insertions(+), 58 deletions(-)
> 
> diff --git a/src/libcamera/include/media_device.h b/src/libcamera/include/media_device.h
> index 9f038093b2b22fc7..883985055eb419dd 100644
> --- a/src/libcamera/include/media_device.h
> +++ b/src/libcamera/include/media_device.h
> @@ -27,7 +27,7 @@ public:
>  	~MediaDevice();
>  
>  	bool acquire();
> -	void release() { acquired_ = false; }
> +	void release();
>  	bool busy() const { return acquired_; }
>  
>  	int open();
> diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp
> index 54706bb73a7591d5..644c6143fb15e1fa 100644
> --- a/src/libcamera/media_device.cpp
> +++ b/src/libcamera/media_device.cpp
> @@ -39,10 +39,9 @@ LOG_DEFINE_CATEGORY(MediaDevice)
>   * instance.
>   *
>   * The instance is created with an empty media graph. Before performing any
> - * other operation, it must be opened with the open() function and the media
> - * graph populated by calling populate(). Instances of MediaEntity, MediaPad and
> - * MediaLink are created to model the media graph, and stored in a map indexed
> - * by object id.
> + * other operation, it must be populate by calling populate(). Instances of
> + * MediaEntity, MediaPad and MediaLink are created to model the media graph,
> + * and stored in a map indexed by object id.
>   *
>   * The graph is valid once successfully populated, as reported by the valid()
>   * function. It can be queried to list all entities(), or entities can be
> @@ -50,12 +49,6 @@ LOG_DEFINE_CATEGORY(MediaDevice)
>   * entity to entity through pads and links as exposed by the corresponding
>   * classes.
>   *
> - * An open media device will keep an open file handle for the underlying media
> - * controller device node. It can be closed at any time with a call to close().
> - * This will not invalidate the media graph and all cached media objects remain
> - * valid and can be accessed normally. The device can then be later reopened if
> - * needed to perform other operations that interact with the device node.
> - *
>   * Media device can be claimed for exclusive use with acquire(), released with
>   * release() and tested with busy(). This mechanism is aimed at pipeline
>   * managers to claim media devices they support during enumeration.
> @@ -65,8 +58,8 @@ LOG_DEFINE_CATEGORY(MediaDevice)
>   * \brief Construct a MediaDevice
>   * \param deviceNode The media device node path
>   *
> - * Once constructed the media device is invalid, and must be opened and
> - * populated with open() and populate() before the media graph can be queried.
> + * Once constructed the media device is invalid, and must be populated with
> + * populate() before the media graph can be queried.
>   */
>  MediaDevice::MediaDevice(const std::string &deviceNode)
>  	: deviceNode_(deviceNode), fd_(-1), valid_(false), acquired_(false)
> @@ -106,15 +99,22 @@ bool MediaDevice::acquire()
>  	if (acquired_)
>  		return false;
>  
> +	if (open())
> +		return false;
> +

I think you should document that an acquired media device will keep an
fd open until the device is released.

>  	acquired_ = true;
>  	return true;
>  }
>  
>  /**
> - * \fn MediaDevice::release()
>   * \brief Release a device previously claimed for exclusive use
>   * \sa acquire(), busy()
>   */
> +void MediaDevice::release()
> +{
> +	close();
> +	acquired_ = false;
> +}
>  
>  /**
>   * \fn MediaDevice::busy()
> @@ -127,10 +127,6 @@ bool MediaDevice::acquire()
>  /**
>   * \brief Open a media device and retrieve device information

I think you should remove " and retrieve device information" in the
previous patch that moves information retrieval to populate().

>   *
> - * Before populating the media graph or performing any operation that interact
> - * with the device node associated with the media device, the device node must
> - * be opened.
> - *

And maybe removing "populating the media graph or " in a previous patch
too ?

>   * If the device is already open the function returns -EBUSY.
>   *
>   * \return 0 on success or a negative error code otherwise
> @@ -201,6 +197,9 @@ int MediaDevice::populate()
>  	__u64 version = -1;
>  	int ret;
>  
> +	if (fd_ != -1)
> +		return -EBUSY;
> +

Can this happen ? If you think the check is useful, I would log an error
message, and update the method's documentation.

>  	clear();
>  
>  	ret = open();
> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> index d8de6b3c36314fc0..a87eff8dfec6d143 100644
> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> @@ -468,23 +468,10 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator)
>  	/*
>  	 * Disable all links that are enabled by default on CIO2, as camera
>  	 * creation enables all valid links it finds.
> -	 *
> -	 * Close the CIO2 media device after, as links are enabled and should
> -	 * not need to be changed after.
>  	 */
> -	if (cio2MediaDev_->open())
> +	if (cio2MediaDev_->disableLinks())
>  		return false;
>  
> -	if (cio2MediaDev_->disableLinks()) {
> -		cio2MediaDev_->close();
> -		return false;
> -	}
> -
> -	if (imguMediaDev_->open()) {
> -		cio2MediaDev_->close();
> -		return false;
> -	}
> -
>  	/*
>  	 * FIXME: enabled links in one ImgU instance interfere with capture
>  	 * operations on the other one. This can be easily triggered by
> @@ -516,9 +503,6 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator)
>  	ret = registerCameras();
>  
>  error:

You can remove the error label and return directly instead of using
goto.

> -	cio2MediaDev_->close();
> -	imguMediaDev_->close();
> -
>  	return ret == 0;
>  }
>  
> @@ -961,11 +945,6 @@ int ImgUDevice::enableLinks(bool enable)
>  	std::string inputName = name_ + " input";
>  	int ret;
>  
> -	/* \todo Establish rules to handle media devices open/close. */
> -	ret = media_->open();
> -	if (ret)
> -		return ret;
> -
>  	ret = linkSetup(inputName, 0, name_, PAD_INPUT, enable);
>  	if (ret)
>  		goto done;
> @@ -981,8 +960,6 @@ int ImgUDevice::enableLinks(bool enable)
>  	ret = linkSetup(name_, PAD_STAT, statName, 0, enable);
>  
>  done:

Same here.

> -	media_->close();
> -
>  	return ret;
>  }
>  
> diff --git a/test/media_device/media_device_link_test.cpp b/test/media_device/media_device_link_test.cpp
> index 4b8de3bee722e912..3989da43ca9ec30f 100644
> --- a/test/media_device/media_device_link_test.cpp
> +++ b/test/media_device/media_device_link_test.cpp
> @@ -57,12 +57,6 @@ class MediaDeviceLinkTest : public Test
>  			return TestSkip;
>  		}
>  
> -		if (dev_->open()) {
> -			cerr << "Failed to open media device at "
> -			     << dev_->deviceNode() << endl;
> -			return TestFail;
> -		}
> -
>  		return 0;
>  	}
>  
> @@ -238,7 +232,6 @@ class MediaDeviceLinkTest : public Test
>  
>  	void cleanup()
>  	{
> -		dev_->close();
>  		dev_->release();
>  	}
>  
> diff --git a/test/v4l2_subdevice/v4l2_subdevice_test.cpp b/test/v4l2_subdevice/v4l2_subdevice_test.cpp
> index 21335efbad4d5668..31f3465a7ba3a5b1 100644
> --- a/test/v4l2_subdevice/v4l2_subdevice_test.cpp
> +++ b/test/v4l2_subdevice/v4l2_subdevice_test.cpp
> @@ -51,14 +51,6 @@ int V4L2SubdeviceTest::init()
>  		return TestSkip;
>  	}
>  
> -	int ret = media_->open();
> -	if (ret) {
> -		cerr << "Unable to open media device: " << media_->deviceNode()
> -		     << ": " << strerror(ret) << endl;
> -		media_->release();
> -		return TestSkip;
> -	}
> -
>  	MediaEntity *videoEntity = media_->getEntityByName("Scaler");
>  	if (!videoEntity) {
>  		cerr << "Unable to find media entity 'Scaler'" << endl;
> @@ -67,7 +59,7 @@ int V4L2SubdeviceTest::init()
>  	}
>  
>  	scaler_ = new V4L2Subdevice(videoEntity);
> -	ret = scaler_->open();
> +	int ret = scaler_->open();
>  	if (ret) {
>  		cerr << "Unable to open video subdevice "
>  		     << scaler_->deviceNode() << endl;

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list