[libcamera-devel,v1] v4l2_videodevice: Disable the watchdog timer when no buffers are queued
diff mbox series

Message ID 20220505084824.4104296-1-naush@raspberrypi.com
State Accepted
Commit c39b52c1840545bf89ff048764a4b550db465624
Headers show
Series
  • [libcamera-devel,v1] v4l2_videodevice: Disable the watchdog timer when no buffers are queued
Related show

Commit Message

Naushir Patuck May 5, 2022, 8:48 a.m. UTC
Only enable/reset the watchdog timer when there are buffers queued in the V4L2
device. Otherwise, we may trigger spurious warnings when the watchdog times out
even if there are no buffers queued in the device.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 src/libcamera/v4l2_videodevice.cpp | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

Comments

Kieran Bingham May 5, 2022, 9:36 a.m. UTC | #1
Hi Naush,

Quoting Naushir Patuck via libcamera-devel (2022-05-05 09:48:24)
> Only enable/reset the watchdog timer when there are buffers queued in the V4L2
> device. Otherwise, we may trigger spurious warnings when the watchdog times out
> even if there are no buffers queued in the device.

aha yes - I can see how that was tripping up on python interactive
sessions or otherwise underflowing when it's not at all a fault of the
V4L2VideoDevice.


> 
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> ---
>  src/libcamera/v4l2_videodevice.cpp | 22 +++++++++++++++-------
>  1 file changed, 15 insertions(+), 7 deletions(-)
> 
> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
> index 5b4637b1a39e..430715afd554 100644
> --- a/src/libcamera/v4l2_videodevice.cpp
> +++ b/src/libcamera/v4l2_videodevice.cpp
> @@ -1662,8 +1662,11 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer)
>                 return ret;
>         }
>  
> -       if (queuedBuffers_.empty())
> +       if (queuedBuffers_.empty()) {
>                 fdBufferNotifier_->setEnabled(true);
> +               if (watchdogDuration_)
> +                       watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> +       }

I guess this could also be set outside of the if (queuedBuffer_.empty())
- but it would artificially delay the watchdog every time a buffer was
queued. In the event that more than one buffer is required to be queued
(to satisfy internal requirements perhaps?) that might actually be
beneficial ... But I think either way is fine.

>  
>         queuedBuffers_[buf.index] = buffer;
>  
> @@ -1742,16 +1745,21 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
>                 return nullptr;
>         }
>  
> -       if (watchdogDuration_.count())
> -               watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> -
>         cache_->put(buf.index);
>  
>         FrameBuffer *buffer = it->second;
>         queuedBuffers_.erase(it);
>  
> -       if (queuedBuffers_.empty())
> +       if (queuedBuffers_.empty()) {
>                 fdBufferNotifier_->setEnabled(false);
> +               watchdog_.stop();
> +       } else if (watchdogDuration_) {
> +               /*
> +                * Restart the watchdog timer if there are buffers still queued
> +                * in the device.
> +                */
> +               watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));

Why do we need/have all these casts? Is either watchdogDuration_ not a
duration? or is watchdog_.start() not accepting a duration? Either of
those would remove a lot of casting surely?

watchdogDuration_ is a utils::Duration which stores std::nano, and I see
Timer start takes a std::chrono::milliseconds. I think it would make
sense to add a 'void start(std::chrono::duration)' to the timer class
and simplify these casts. But that doesn't have to be fixed in this
patch.

Would you like to do that as a patch on top? If you don't want to let me
know and I'll handle it after this patch is merged.


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>


> +       }
>  
>         buffer->metadata_.status = buf.flags & V4L2_BUF_FLAG_ERROR
>                                  ? FrameMetadata::FrameError
> @@ -1847,7 +1855,7 @@ int V4L2VideoDevice::streamOn()
>         }
>  
>         state_ = State::Streaming;
> -       if (watchdogDuration_.count())
> +       if (watchdogDuration_ && !queuedBuffers_.empty())
>                 watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
>  
>         return 0;
> @@ -1924,7 +1932,7 @@ void V4L2VideoDevice::setDequeueTimeout(utils::Duration timeout)
>         watchdogDuration_ = timeout;
>  
>         watchdog_.stop();
> -       if (watchdogDuration_.count() && state_ == State::Streaming)
> +       if (watchdogDuration_ && state_ == State::Streaming && !queuedBuffers_.empty())
>                 watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
>  }
>  
> -- 
> 2.25.1
>
Naushir Patuck May 5, 2022, 10:15 a.m. UTC | #2
Hi Kieran,

Thank you for the feedback!

On Thu, 5 May 2022 at 10:36, Kieran Bingham <kieran.bingham@ideasonboard.com>
wrote:

> Hi Naush,
>
> Quoting Naushir Patuck via libcamera-devel (2022-05-05 09:48:24)
> > Only enable/reset the watchdog timer when there are buffers queued in
> the V4L2
> > device. Otherwise, we may trigger spurious warnings when the watchdog
> times out
> > even if there are no buffers queued in the device.
>
> aha yes - I can see how that was tripping up on python interactive
> sessions or otherwise underflowing when it's not at all a fault of the
> V4L2VideoDevice.
>
>
> >
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > ---
> >  src/libcamera/v4l2_videodevice.cpp | 22 +++++++++++++++-------
> >  1 file changed, 15 insertions(+), 7 deletions(-)
> >
> > diff --git a/src/libcamera/v4l2_videodevice.cpp
> b/src/libcamera/v4l2_videodevice.cpp
> > index 5b4637b1a39e..430715afd554 100644
> > --- a/src/libcamera/v4l2_videodevice.cpp
> > +++ b/src/libcamera/v4l2_videodevice.cpp
> > @@ -1662,8 +1662,11 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer
> *buffer)
> >                 return ret;
> >         }
> >
> > -       if (queuedBuffers_.empty())
> > +       if (queuedBuffers_.empty()) {
> >                 fdBufferNotifier_->setEnabled(true);
> > +               if (watchdogDuration_)
> > +
>  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> > +       }
>
> I guess this could also be set outside of the if (queuedBuffer_.empty())
> - but it would artificially delay the watchdog every time a buffer was
> queued. In the event that more than one buffer is required to be queued
> (to satisfy internal requirements perhaps?) that might actually be
> beneficial ... But I think either way is fine.
>

It could... I thought it might be ever so slightly more logically correct
if this
was inside the if() block.  I'll keep it in there unless there are further
objections.


>
> >
> >         queuedBuffers_[buf.index] = buffer;
> >
> > @@ -1742,16 +1745,21 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
> >                 return nullptr;
> >         }
> >
> > -       if (watchdogDuration_.count())
> > -
>  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> > -
> >         cache_->put(buf.index);
> >
> >         FrameBuffer *buffer = it->second;
> >         queuedBuffers_.erase(it);
> >
> > -       if (queuedBuffers_.empty())
> > +       if (queuedBuffers_.empty()) {
> >                 fdBufferNotifier_->setEnabled(false);
> > +               watchdog_.stop();
> > +       } else if (watchdogDuration_) {
> > +               /*
> > +                * Restart the watchdog timer if there are buffers still
> queued
> > +                * in the device.
> > +                */
> > +
>  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
>
> Why do we need/have all these casts? Is either watchdogDuration_ not a
> duration? or is watchdog_.start() not accepting a duration? Either of
> those would remove a lot of casting surely?
>

This is a bit of a minor annoyance because of how I defined the underlying
type
of utils::Duration to a double. The std::chrono library forbids implicit
casts
from integer to float types.


> watchdogDuration_ is a utils::Duration which stores std::nano, and I see
> Timer start takes a std::chrono::milliseconds. I think it would make
> sense to add a 'void start(std::chrono::duration)' to the timer class
> and simplify these casts. But that doesn't have to be fixed in this
> patch.
>
> Would you like to do that as a patch on top? If you don't want to let me
> know and I'll handle it after this patch is merged.
>

What we've talked about doing is to switch utils::Duration to use an integer
underlying type, which would allow implicit conversions and remove the ugly
casts like the above. I believe Laurent was still thinking this through as
there
were also plans to make utils::Duration part of the public API...

Regards,
Naush


>
>
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
>
>
> > +       }
> >
> >         buffer->metadata_.status = buf.flags & V4L2_BUF_FLAG_ERROR
> >                                  ? FrameMetadata::FrameError
> > @@ -1847,7 +1855,7 @@ int V4L2VideoDevice::streamOn()
> >         }
> >
> >         state_ = State::Streaming;
> > -       if (watchdogDuration_.count())
> > +       if (watchdogDuration_ && !queuedBuffers_.empty())
> >
>  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> >
> >         return 0;
> > @@ -1924,7 +1932,7 @@ void
> V4L2VideoDevice::setDequeueTimeout(utils::Duration timeout)
> >         watchdogDuration_ = timeout;
> >
> >         watchdog_.stop();
> > -       if (watchdogDuration_.count() && state_ == State::Streaming)
> > +       if (watchdogDuration_ && state_ == State::Streaming &&
> !queuedBuffers_.empty())
> >
>  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
> >  }
> >
> > --
> > 2.25.1
> >
>
Kieran Bingham May 5, 2022, 10:28 a.m. UTC | #3
Quoting Naushir Patuck (2022-05-05 11:15:44)
> Hi Kieran,
> 
> Thank you for the feedback!
> 
> On Thu, 5 May 2022 at 10:36, Kieran Bingham <kieran.bingham@ideasonboard.com>
> wrote:
> 
> > Hi Naush,
> >
> > Quoting Naushir Patuck via libcamera-devel (2022-05-05 09:48:24)
> > > Only enable/reset the watchdog timer when there are buffers queued in
> > the V4L2
> > > device. Otherwise, we may trigger spurious warnings when the watchdog
> > times out
> > > even if there are no buffers queued in the device.
> >
> > aha yes - I can see how that was tripping up on python interactive
> > sessions or otherwise underflowing when it's not at all a fault of the
> > V4L2VideoDevice.
> >
> >
> > >
> > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > > ---
> > >  src/libcamera/v4l2_videodevice.cpp | 22 +++++++++++++++-------
> > >  1 file changed, 15 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/src/libcamera/v4l2_videodevice.cpp
> > b/src/libcamera/v4l2_videodevice.cpp
> > > index 5b4637b1a39e..430715afd554 100644
> > > --- a/src/libcamera/v4l2_videodevice.cpp
> > > +++ b/src/libcamera/v4l2_videodevice.cpp
> > > @@ -1662,8 +1662,11 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer
> > *buffer)
> > >                 return ret;
> > >         }
> > >
> > > -       if (queuedBuffers_.empty())
> > > +       if (queuedBuffers_.empty()) {
> > >                 fdBufferNotifier_->setEnabled(true);
> > > +               if (watchdogDuration_)
> > > +
> >  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> > > +       }
> >
> > I guess this could also be set outside of the if (queuedBuffer_.empty())
> > - but it would artificially delay the watchdog every time a buffer was
> > queued. In the event that more than one buffer is required to be queued
> > (to satisfy internal requirements perhaps?) that might actually be
> > beneficial ... But I think either way is fine.
> >
> 
> It could... I thought it might be ever so slightly more logically correct
> if this
> was inside the if() block.  I'll keep it in there unless there are further
> objections.
> 
> 
> >
> > >
> > >         queuedBuffers_[buf.index] = buffer;
> > >
> > > @@ -1742,16 +1745,21 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
> > >                 return nullptr;
> > >         }
> > >
> > > -       if (watchdogDuration_.count())
> > > -
> >  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> > > -
> > >         cache_->put(buf.index);
> > >
> > >         FrameBuffer *buffer = it->second;
> > >         queuedBuffers_.erase(it);
> > >
> > > -       if (queuedBuffers_.empty())
> > > +       if (queuedBuffers_.empty()) {
> > >                 fdBufferNotifier_->setEnabled(false);
> > > +               watchdog_.stop();
> > > +       } else if (watchdogDuration_) {
> > > +               /*
> > > +                * Restart the watchdog timer if there are buffers still
> > queued
> > > +                * in the device.
> > > +                */
> > > +
> >  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> >
> > Why do we need/have all these casts? Is either watchdogDuration_ not a
> > duration? or is watchdog_.start() not accepting a duration? Either of
> > those would remove a lot of casting surely?
> >
> 
> This is a bit of a minor annoyance because of how I defined the underlying
> type
> of utils::Duration to a double. The std::chrono library forbids implicit
> casts
> from integer to float types.
> 
> 
> > watchdogDuration_ is a utils::Duration which stores std::nano, and I see
> > Timer start takes a std::chrono::milliseconds. I think it would make
> > sense to add a 'void start(std::chrono::duration)' to the timer class
> > and simplify these casts. But that doesn't have to be fixed in this
> > patch.
> >
> > Would you like to do that as a patch on top? If you don't want to let me
> > know and I'll handle it after this patch is merged.
> >
> 
> What we've talked about doing is to switch utils::Duration to use an integer
> underlying type, which would allow implicit conversions and remove the ugly
> casts like the above. I believe Laurent was still thinking this through as
> there
> were also plans to make utils::Duration part of the public API...

Ayeee - I see - not as simple and obvious as I thought it should be
(which explains why it isn't so ...)

Well - I don't think it should affect this patch anyway.

--
Kieran


> 
> Regards,
> Naush
> 
> 
> >
> >
> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> >
> >
> > > +       }
> > >
> > >         buffer->metadata_.status = buf.flags & V4L2_BUF_FLAG_ERROR
> > >                                  ? FrameMetadata::FrameError
> > > @@ -1847,7 +1855,7 @@ int V4L2VideoDevice::streamOn()
> > >         }
> > >
> > >         state_ = State::Streaming;
> > > -       if (watchdogDuration_.count())
> > > +       if (watchdogDuration_ && !queuedBuffers_.empty())
> > >
> >  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> > >
> > >         return 0;
> > > @@ -1924,7 +1932,7 @@ void
> > V4L2VideoDevice::setDequeueTimeout(utils::Duration timeout)
> > >         watchdogDuration_ = timeout;
> > >
> > >         watchdog_.stop();
> > > -       if (watchdogDuration_.count() && state_ == State::Streaming)
> > > +       if (watchdogDuration_ && state_ == State::Streaming &&
> > !queuedBuffers_.empty())
> > >
> >  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
> > >  }
> > >
> > > --
> > > 2.25.1
> > >
> >
David Plowman May 5, 2022, 10:42 a.m. UTC | #4
Hi Naush

Thanks for fixing this!

On Thu, 5 May 2022 at 09:48, Naushir Patuck via libcamera-devel
<libcamera-devel@lists.libcamera.org> wrote:
>
> Only enable/reset the watchdog timer when there are buffers queued in the V4L2
> device. Otherwise, we may trigger spurious warnings when the watchdog times out
> even if there are no buffers queued in the device.
>
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>

Works for me, and on the Picamera2 auto test machine:

Tested-by: David Plowman <david.plowman@raspberrypi.com>

Thanks!
David

> ---
>  src/libcamera/v4l2_videodevice.cpp | 22 +++++++++++++++-------
>  1 file changed, 15 insertions(+), 7 deletions(-)
>
> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
> index 5b4637b1a39e..430715afd554 100644
> --- a/src/libcamera/v4l2_videodevice.cpp
> +++ b/src/libcamera/v4l2_videodevice.cpp
> @@ -1662,8 +1662,11 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer)
>                 return ret;
>         }
>
> -       if (queuedBuffers_.empty())
> +       if (queuedBuffers_.empty()) {
>                 fdBufferNotifier_->setEnabled(true);
> +               if (watchdogDuration_)
> +                       watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> +       }
>
>         queuedBuffers_[buf.index] = buffer;
>
> @@ -1742,16 +1745,21 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
>                 return nullptr;
>         }
>
> -       if (watchdogDuration_.count())
> -               watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> -
>         cache_->put(buf.index);
>
>         FrameBuffer *buffer = it->second;
>         queuedBuffers_.erase(it);
>
> -       if (queuedBuffers_.empty())
> +       if (queuedBuffers_.empty()) {
>                 fdBufferNotifier_->setEnabled(false);
> +               watchdog_.stop();
> +       } else if (watchdogDuration_) {
> +               /*
> +                * Restart the watchdog timer if there are buffers still queued
> +                * in the device.
> +                */
> +               watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> +       }
>
>         buffer->metadata_.status = buf.flags & V4L2_BUF_FLAG_ERROR
>                                  ? FrameMetadata::FrameError
> @@ -1847,7 +1855,7 @@ int V4L2VideoDevice::streamOn()
>         }
>
>         state_ = State::Streaming;
> -       if (watchdogDuration_.count())
> +       if (watchdogDuration_ && !queuedBuffers_.empty())
>                 watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
>
>         return 0;
> @@ -1924,7 +1932,7 @@ void V4L2VideoDevice::setDequeueTimeout(utils::Duration timeout)
>         watchdogDuration_ = timeout;
>
>         watchdog_.stop();
> -       if (watchdogDuration_.count() && state_ == State::Streaming)
> +       if (watchdogDuration_ && state_ == State::Streaming && !queuedBuffers_.empty())
>                 watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
>  }
>
> --
> 2.25.1
>
Naushir Patuck May 10, 2022, 7:58 a.m. UTC | #5
Hi,

On Thu, 5 May 2022 at 09:48, Naushir Patuck <naush@raspberrypi.com> wrote:

> Only enable/reset the watchdog timer when there are buffers queued in the
> V4L2
> device. Otherwise, we may trigger spurious warnings when the watchdog
> times out
> even if there are no buffers queued in the device.
>
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
>

Gentle ping.  This needs one more R-B tag to get merged.

Regards,
Naush


> ---
>  src/libcamera/v4l2_videodevice.cpp | 22 +++++++++++++++-------
>  1 file changed, 15 insertions(+), 7 deletions(-)
>
> diff --git a/src/libcamera/v4l2_videodevice.cpp
> b/src/libcamera/v4l2_videodevice.cpp
> index 5b4637b1a39e..430715afd554 100644
> --- a/src/libcamera/v4l2_videodevice.cpp
> +++ b/src/libcamera/v4l2_videodevice.cpp
> @@ -1662,8 +1662,11 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer
> *buffer)
>                 return ret;
>         }
>
> -       if (queuedBuffers_.empty())
> +       if (queuedBuffers_.empty()) {
>                 fdBufferNotifier_->setEnabled(true);
> +               if (watchdogDuration_)
> +
>  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> +       }
>
>         queuedBuffers_[buf.index] = buffer;
>
> @@ -1742,16 +1745,21 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
>                 return nullptr;
>         }
>
> -       if (watchdogDuration_.count())
> -
>  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> -
>         cache_->put(buf.index);
>
>         FrameBuffer *buffer = it->second;
>         queuedBuffers_.erase(it);
>
> -       if (queuedBuffers_.empty())
> +       if (queuedBuffers_.empty()) {
>                 fdBufferNotifier_->setEnabled(false);
> +               watchdog_.stop();
> +       } else if (watchdogDuration_) {
> +               /*
> +                * Restart the watchdog timer if there are buffers still
> queued
> +                * in the device.
> +                */
> +
>  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> +       }
>
>         buffer->metadata_.status = buf.flags & V4L2_BUF_FLAG_ERROR
>                                  ? FrameMetadata::FrameError
> @@ -1847,7 +1855,7 @@ int V4L2VideoDevice::streamOn()
>         }
>
>         state_ = State::Streaming;
> -       if (watchdogDuration_.count())
> +       if (watchdogDuration_ && !queuedBuffers_.empty())
>
> watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
>
>         return 0;
> @@ -1924,7 +1932,7 @@ void
> V4L2VideoDevice::setDequeueTimeout(utils::Duration timeout)
>         watchdogDuration_ = timeout;
>
>         watchdog_.stop();
> -       if (watchdogDuration_.count() && state_ == State::Streaming)
> +       if (watchdogDuration_ && state_ == State::Streaming &&
> !queuedBuffers_.empty())
>
> watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
>  }
>
> --
> 2.25.1
>
>
Kieran Bingham May 10, 2022, 1:52 p.m. UTC | #6
Quoting Naushir Patuck via libcamera-devel (2022-05-10 08:58:39)
> Hi,
> 
> On Thu, 5 May 2022 at 09:48, Naushir Patuck <naush@raspberrypi.com> wrote:
> 
> > Only enable/reset the watchdog timer when there are buffers queued in the
> > V4L2
> > device. Otherwise, we may trigger spurious warnings when the watchdog
> > times out
> > even if there are no buffers queued in the device.
> >
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> >
> 
> Gentle ping.  This needs one more R-B tag to get merged.

David, can we upgrade your Tested-by: to a Reviewed-by: ? (Or maybe TB
is sufficient?)


> 
> Regards,
> Naush
> 
> 
> > ---
> >  src/libcamera/v4l2_videodevice.cpp | 22 +++++++++++++++-------
> >  1 file changed, 15 insertions(+), 7 deletions(-)
> >
> > diff --git a/src/libcamera/v4l2_videodevice.cpp
> > b/src/libcamera/v4l2_videodevice.cpp
> > index 5b4637b1a39e..430715afd554 100644
> > --- a/src/libcamera/v4l2_videodevice.cpp
> > +++ b/src/libcamera/v4l2_videodevice.cpp
> > @@ -1662,8 +1662,11 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer
> > *buffer)
> >                 return ret;
> >         }
> >
> > -       if (queuedBuffers_.empty())
> > +       if (queuedBuffers_.empty()) {
> >                 fdBufferNotifier_->setEnabled(true);
> > +               if (watchdogDuration_)
> > +
> >  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> > +       }
> >
> >         queuedBuffers_[buf.index] = buffer;
> >
> > @@ -1742,16 +1745,21 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
> >                 return nullptr;
> >         }
> >
> > -       if (watchdogDuration_.count())
> > -
> >  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> > -
> >         cache_->put(buf.index);
> >
> >         FrameBuffer *buffer = it->second;
> >         queuedBuffers_.erase(it);
> >
> > -       if (queuedBuffers_.empty())
> > +       if (queuedBuffers_.empty()) {
> >                 fdBufferNotifier_->setEnabled(false);
> > +               watchdog_.stop();
> > +       } else if (watchdogDuration_) {
> > +               /*
> > +                * Restart the watchdog timer if there are buffers still
> > queued
> > +                * in the device.
> > +                */
> > +
> >  watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> > +       }
> >
> >         buffer->metadata_.status = buf.flags & V4L2_BUF_FLAG_ERROR
> >                                  ? FrameMetadata::FrameError
> > @@ -1847,7 +1855,7 @@ int V4L2VideoDevice::streamOn()
> >         }
> >
> >         state_ = State::Streaming;
> > -       if (watchdogDuration_.count())
> > +       if (watchdogDuration_ && !queuedBuffers_.empty())
> >
> > watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> >
> >         return 0;
> > @@ -1924,7 +1932,7 @@ void
> > V4L2VideoDevice::setDequeueTimeout(utils::Duration timeout)
> >         watchdogDuration_ = timeout;
> >
> >         watchdog_.stop();
> > -       if (watchdogDuration_.count() && state_ == State::Streaming)
> > +       if (watchdogDuration_ && state_ == State::Streaming &&
> > !queuedBuffers_.empty())
> >
> > watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
> >  }
> >
> > --
> > 2.25.1
> >
> >
Laurent Pinchart May 10, 2022, 3:44 p.m. UTC | #7
Hi Naush,

Thank you for the patch.

On Thu, May 05, 2022 at 09:48:24AM +0100, Naushir Patuck via libcamera-devel wrote:
> Only enable/reset the watchdog timer when there are buffers queued in the V4L2
> device. Otherwise, we may trigger spurious warnings when the watchdog times out
> even if there are no buffers queued in the device.
> 
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
>  src/libcamera/v4l2_videodevice.cpp | 22 +++++++++++++++-------
>  1 file changed, 15 insertions(+), 7 deletions(-)
> 
> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
> index 5b4637b1a39e..430715afd554 100644
> --- a/src/libcamera/v4l2_videodevice.cpp
> +++ b/src/libcamera/v4l2_videodevice.cpp
> @@ -1662,8 +1662,11 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer)
>  		return ret;
>  	}
>  
> -	if (queuedBuffers_.empty())
> +	if (queuedBuffers_.empty()) {
>  		fdBufferNotifier_->setEnabled(true);
> +		if (watchdogDuration_)
> +			watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> +	}
>  
>  	queuedBuffers_[buf.index] = buffer;
>  
> @@ -1742,16 +1745,21 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
>  		return nullptr;
>  	}
>  
> -	if (watchdogDuration_.count())
> -		watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> -
>  	cache_->put(buf.index);
>  
>  	FrameBuffer *buffer = it->second;
>  	queuedBuffers_.erase(it);
>  
> -	if (queuedBuffers_.empty())
> +	if (queuedBuffers_.empty()) {
>  		fdBufferNotifier_->setEnabled(false);
> +		watchdog_.stop();
> +	} else if (watchdogDuration_) {
> +		/*
> +		 * Restart the watchdog timer if there are buffers still queued
> +		 * in the device.
> +		 */
> +		watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
> +	}
>  
>  	buffer->metadata_.status = buf.flags & V4L2_BUF_FLAG_ERROR
>  				 ? FrameMetadata::FrameError
> @@ -1847,7 +1855,7 @@ int V4L2VideoDevice::streamOn()
>  	}
>  
>  	state_ = State::Streaming;
> -	if (watchdogDuration_.count())
> +	if (watchdogDuration_ && !queuedBuffers_.empty())
>  		watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
>  
>  	return 0;
> @@ -1924,7 +1932,7 @@ void V4L2VideoDevice::setDequeueTimeout(utils::Duration timeout)
>  	watchdogDuration_ = timeout;
>  
>  	watchdog_.stop();
> -	if (watchdogDuration_.count() && state_ == State::Streaming)
> +	if (watchdogDuration_ && state_ == State::Streaming && !queuedBuffers_.empty())
>  		watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
>  }
>

Patch
diff mbox series

diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
index 5b4637b1a39e..430715afd554 100644
--- a/src/libcamera/v4l2_videodevice.cpp
+++ b/src/libcamera/v4l2_videodevice.cpp
@@ -1662,8 +1662,11 @@  int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer)
 		return ret;
 	}
 
-	if (queuedBuffers_.empty())
+	if (queuedBuffers_.empty()) {
 		fdBufferNotifier_->setEnabled(true);
+		if (watchdogDuration_)
+			watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
+	}
 
 	queuedBuffers_[buf.index] = buffer;
 
@@ -1742,16 +1745,21 @@  FrameBuffer *V4L2VideoDevice::dequeueBuffer()
 		return nullptr;
 	}
 
-	if (watchdogDuration_.count())
-		watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
-
 	cache_->put(buf.index);
 
 	FrameBuffer *buffer = it->second;
 	queuedBuffers_.erase(it);
 
-	if (queuedBuffers_.empty())
+	if (queuedBuffers_.empty()) {
 		fdBufferNotifier_->setEnabled(false);
+		watchdog_.stop();
+	} else if (watchdogDuration_) {
+		/*
+		 * Restart the watchdog timer if there are buffers still queued
+		 * in the device.
+		 */
+		watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
+	}
 
 	buffer->metadata_.status = buf.flags & V4L2_BUF_FLAG_ERROR
 				 ? FrameMetadata::FrameError
@@ -1847,7 +1855,7 @@  int V4L2VideoDevice::streamOn()
 	}
 
 	state_ = State::Streaming;
-	if (watchdogDuration_.count())
+	if (watchdogDuration_ && !queuedBuffers_.empty())
 		watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
 
 	return 0;
@@ -1924,7 +1932,7 @@  void V4L2VideoDevice::setDequeueTimeout(utils::Duration timeout)
 	watchdogDuration_ = timeout;
 
 	watchdog_.stop();
-	if (watchdogDuration_.count() && state_ == State::Streaming)
+	if (watchdogDuration_ && state_ == State::Streaming && !queuedBuffers_.empty())
 		watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
 }