[PATCH 2/5] pipeline_handler: Call releaseDevice() before unlocking media devices

Hans de Goede hdegoede at redhat.com
Mon Aug 26 10:06:35 CEST 2024


Hi,

On 8/25/24 2:27 AM, Laurent Pinchart wrote:
> On Wed, Aug 21, 2024 at 06:34:17PM +0200, Cheng-Hao Yang wrote:
>> Hi Hans,
>>
>> Thanks for the patch. I've tested it on mtkisp7, and it works fine.
>>
>> Reviewed-by: Harvey Yang <chenghaoyang at chromium.org>
>>
>> One question that might not be related though:
>> `PipelineHandler::release` is defined to be thread safe, while
>> there's no such description for `PipelineHandler::releaseDevice`.
>>
>> In mtkisp7, we have a CL [1] to make sure
>> `PipelineHandler::releaseDevice` is always blockingly executed
>> on  PipelineHandler's thread.
>>
>> Although it makes the normal cases (that it's returning true
>> directly) run longer, as it waits for another thread's execution,
>> it prevents PipelineHandler's mis-implementation.
>> I'd suggest either we do the same in the upstream, or we add
>> the description of being thread-safe for
>> `PipelineHandler::releaseDevice` to remind the developers of
>> pipeline handlers.
> 
> I don't think releaseDevice() qualifies as thread safe. Here's how
> libcamera documents thread safety:
> 
>  * - A **reentrant** function may be called simultaneously from multiple
>  *   threads if and only if each invocation uses a different instance of the
>  *   class. This is the default for all member functions not explictly marked
>  *   otherwise.
>  *
>  * - \anchor thread-safe A **thread-safe** function may be called
>  *   simultaneously from multiple threads on the same instance of a class. A
>  *   thread-safe function is thus reentrant. Thread-safe functions may also be
>  *   called simultaneously with any other reentrant function of the same class
>  *   on the same instance.
> 
> Pipeline handlers shouldn't have to deal with releaseDevice() being
> called concurrently on the same PipelineHandler instance for different
> cameras, which is why the caller serializes the calls.
> 
> releaseDevice() should never race with other pipeline handler calls for
> the same camera. However, it could race with other calls for different
> cameras. We should document this, or change the behaviour.

releaseDevice() is only called from: PipelineHandler::release() which starts with:

void PipelineHandler::release(Camera *camera)
{
        MutexLocker locker(lock_);

so even if an app is releasing 2 cameras from the same pipeline-handler
at the same time (from 2 different threads) then the releaseDevice() calls
will be serialized.

Should I document for v2 that releaseDevice() and the new acquireDevice() calls
are serialized by the PipelineHandler base class ?

Regards,

Hans



> 
>> WDYT?
>>
>> BR,
>> Harvey
>>
>> [1]: https://chromium-review.googlesource.com/c/chromiumos/third_party/libcamera/+/5528925
> 
> The commit message doesn't really explain why the change is needed.
> Could you elaborate, maybe providing an example of incorrect behaviour
> of a pipeline handler implementation with the existing calling
> convention ?
> 
>> On Tue, Aug 20, 2024 at 9:50 PM Hans de Goede wrote:
>>
>>> It is better / more logical to call releaseDevice() before unlocking
>>> the devices. ATM the only pipeline handler implementing releaseDevice()
> 
> s/ATM/At the moment/
> 
>>> is the rpi pipeline handler which releases buffers from its releaseDevice()
>>> implementation.
>>>
>>> Releasing buffers before unlocking the media devices is ok to do
>>> and arguably it is better to release the buffers before unlocking.
>>>
>>> Signed-off-by: Hans de Goede <hdegoede at redhat.com>
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> 
>>> ---
>>>  src/libcamera/pipeline_handler.cpp | 4 ++--
>>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/src/libcamera/pipeline_handler.cpp
>>> b/src/libcamera/pipeline_handler.cpp
>>> index a20cd27d..1fc22d6a 100644
>>> --- a/src/libcamera/pipeline_handler.cpp
>>> +++ b/src/libcamera/pipeline_handler.cpp
>>> @@ -205,11 +205,11 @@ void PipelineHandler::release(Camera *camera)
>>>
>>>         ASSERT(useCount_);
>>>
>>> +       releaseDevice(camera);
>>> +
>>>         if (useCount_ == 1)
>>>                 unlockMediaDevices();
>>>
>>> -       releaseDevice(camera);
>>> -
>>>         --useCount_;
>>>  }
>>>
> 



More information about the libcamera-devel mailing list