[libcamera-devel] [RFC PATCH v2 1/3] libcamera: camera: Make stop() idempotent

Kieran Bingham kieran.bingham at ideasonboard.com
Tue May 4 16:48:16 CEST 2021


Hi Nicolas, Jacopo,

On 04/05/2021 15:31, Nícolas F. R. A. Prado wrote:
> Hi Jacopo,
> 
> Em 2021-05-04 04:41, Jacopo Mondi escreveu:
> 
>> Hi Nicolas,
>>
>> On Mon, May 03, 2021 at 04:33:05PM -0300, Nícolas F. R. A. Prado wrote:
>>> Make Camera::stop() idempotent so that it can be called in any state and
>>> consecutive times. When called in any state other than CameraRunning, it
>>> is a no-op. This simplifies the cleanup path for applications.
>>>
>>> Signed-off-by: Nícolas F. R. A. Prado <nfraprado at collabora.com>
>>> ---
>>> Changes in v2:
>>> - Suggested by Kieran:
>>>   - Add new isRunning() function instead of relying on isAccessAllowed()
>>> - Suggested by Laurent:
>>>   - Make stop()'s description clearer
>>>
>>>  src/libcamera/camera.cpp | 20 +++++++++++++++++---
>>>  1 file changed, 17 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
>>> index 1340c266cc5f..1c6c76c7c01e 100644
>>> --- a/src/libcamera/camera.cpp
>>> +++ b/src/libcamera/camera.cpp
>>> @@ -347,6 +347,7 @@ public:
>>>  		const std::set<Stream *> &streams);
>>>  	~Private();
>>>
>>> +	bool isRunning() const;
>>>  	int isAccessAllowed(State state, bool allowDisconnected = false,
>>>  			    const char *from = __builtin_FUNCTION()) const;
>>>  	int isAccessAllowed(State low, State high,
>>> @@ -388,6 +389,15 @@ static const char *const camera_state_names[] = {
>>>  	"Running",
>>>  };
>>>
>>> +bool Camera::Private::isRunning() const
>>> +{
>>> +	State currentState = state_.load(std::memory_order_acquire);
>>> +	if (currentState == CameraRunning)
>>> +		return true;
>>> +
>>> +	return false;
>>> +}
>>> +
>>>  int Camera::Private::isAccessAllowed(State state, bool allowDisconnected,
>>>  				     const char *from) const
>>>  {
>>> @@ -1061,9 +1071,10 @@ int Camera::start(const ControlList *controls)
>>>   * This method stops capturing and processing requests immediately. All pending
>>>   * requests are cancelled and complete synchronously in an error state.
>>>   *
>>> - * \context This function may only be called when the camera is in the Running
>>> - * state as defined in \ref camera_operation, and shall be synchronized by the
>>> - * caller with other functions that affect the camera state.
>>> + * \context This function may be called in any camera state as defined in \ref
>>> + * camera_operation, and shall be synchronized by the caller with other
>>> + * functions that affect the camera state. If called when the camera isn't
>>> + * running, it is a no-op.
>>>   *
>>>   * \return 0 on success or a negative error code otherwise
>>>   * \retval -ENODEV The camera has been disconnected from the system
>>> @@ -1073,6 +1084,9 @@ int Camera::stop()
>>>  {
>>>  	Private *const d = LIBCAMERA_D_PTR();
>>>
>>> +	if (!d->isRunning())
>>> +		return 0;
>>> +
>>
>> This kind of defeats the purpose of the isAccessAllowed() here below.
>>
>> Please note that isAccessAllowed(Private::CameraRunning) will return
>> true only if the camera is running, which is the same thing your new
>> function checks for. Let me guess, you wanted to get rid of the error
>> message ?
> 
> Indeed, I missed that, sorry. In v1 [1] I added other parameters to
> isAccessAllowed() just to be able to exit silently, but Kieran pointed out that
> it would be cleaner with an isRunning() function. So I did that, but forgot to
> remove the isAccessAllowed() below as well.

Yes, the extra checks should be removed.


> 
> [1] https://lists.libcamera.org/pipermail/libcamera-devel/2021-April/019735.html
> 
>>
>> Personally, I would be in favour of calling stop() only when it's
>> appropriate instead of shortcutting the camera state machine. What is
>> the use case that makes it hard to call stop() only when actually
>> required ?
> 
> The use case is always calling stop() in the destructor of the capture in
> lc-compliance, which makes the cleanup path simpler as we can safely fail an
> assert and still have the camera stopped.
> 
> That said, it wouldn't be hard to call stop() only when required. We could track
> whether the camera was started internally in lc-compliance. But it seemed like
> this would be a common pattern and handling it by making Camera::stop() itself
> be idempotent would be beneficial.
> 
> I'll wait for others to comment on this as well.

I think being able to clean up easily on shutdowns is beneficial.

I would consider this use case to be that of being able to call

	p = NULL;
	...
	kfree(p);

rather than
	if (p)
		kfree(p);

It's a convenience feature, so that extra state doesn't have to be
repeatedly maintained elsewhere.

--
Kieran


> 
> Thanks,
> Nícolas
> 
>>
>> Thanks
>> j
>>>  	int ret = d->isAccessAllowed(Private::CameraRunning);
>>>  	if (ret < 0)
>>>  		return ret;
>>> --
>>> 2.31.1
>>>
>>> _______________________________________________
>>> libcamera-devel mailing list
>>> libcamera-devel at lists.libcamera.org
>>> https://lists.libcamera.org/listinfo/libcamera-devel
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
> 

-- 
Regards
--
Kieran


More information about the libcamera-devel mailing list