[libcamera-devel] [PATCH v3 16/22] v4l2: v4l2_camera: Don't use libcamera::Semaphore for available buffers
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Wed Jun 24 02:05:01 CEST 2020
Hi again,
On Wed, Jun 24, 2020 at 02:05:25AM +0300, Laurent Pinchart wrote:
> On Wed, Jun 24, 2020 at 04:08:30AM +0900, Paul Elder wrote:
> > In V4L2, a blocked dqbuf should not not also block a streamoff. This
> > means that on streamoff, the blocked dqbuf must return (with error). We
> > cannot do this with the libcamera semaphore, so pull out the necessary
> > components of a semaphore, and put them into V4L2Camera, so that dqbuf
> > from V4L2CameraProxy can wait on a disjunct condition of the
> > availability of the semaphore or the stopping of the stream.
> >
> > Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
> >
> > ---
> > Changes in v3:
> > - don't notify all with the lock held
> >
> > Changes in v2:
> > - remove mutex for isRunning_
> > - use V4L2Camera::isRunning() instead of V4L2CameraProxy::streaming_ in
> > the dqbuf ioctl handler
> > ---
> > src/v4l2/v4l2_camera.cpp | 30 ++++++++++++++++++++++++++++--
> > src/v4l2/v4l2_camera.h | 9 +++++++--
> > src/v4l2/v4l2_camera_proxy.cpp | 11 +++++++++--
> > 3 files changed, 44 insertions(+), 6 deletions(-)
> >
> > diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp
> > index 177b1ea..bdf0036 100644
> > --- a/src/v4l2/v4l2_camera.cpp
> > +++ b/src/v4l2/v4l2_camera.cpp
> > @@ -18,7 +18,7 @@ LOG_DECLARE_CATEGORY(V4L2Compat);
> >
> > V4L2Camera::V4L2Camera(std::shared_ptr<Camera> camera)
> > : camera_(camera), isRunning_(false), bufferAllocator_(nullptr),
> > - efd_(-1)
> > + efd_(-1), bufferAvailableCount_(0)
> > {
> > camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete);
> > }
> > @@ -100,7 +100,11 @@ void V4L2Camera::requestComplete(Request *request)
> > if (ret != sizeof(data))
> > LOG(V4L2Compat, Error) << "Failed to signal eventfd POLLIN";
> >
> > - bufferSema_.release();
> > + {
> > + MutexLocker locker(bufferMutex_);
> > + bufferAvailableCount_++;
> > + }
> > + bufferCV_.notify_all();
> > }
> >
> > int V4L2Camera::configure(StreamConfiguration *streamConfigOut,
> > @@ -144,6 +148,7 @@ int V4L2Camera::allocBuffers(unsigned int count)
> > void V4L2Camera::freeBuffers()
> > {
> > Stream *stream = *camera_->streams().begin();
> > +
>
> This seems unrelated.
>
> > bufferAllocator_->free(stream);
> > }
> >
> > @@ -193,6 +198,7 @@ int V4L2Camera::streamOff()
> > return ret == -EACCES ? -EBUSY : ret;
> >
> > isRunning_ = false;
> > + bufferCV_.notify_all();
> >
> > return 0;
> > }
> > @@ -228,6 +234,26 @@ int V4L2Camera::qbuf(unsigned int index)
> > return 0;
> > }
> >
> > +void V4L2Camera::waitForBufferAvailable()
> > +{
> > + MutexLocker locker(bufferMutex_);
> > + bufferCV_.wait(locker, [&] {
> > + return bufferAvailableCount_ >= 1 || !isRunning_;
> > + });
>
> The correct indentation would be
>
> bufferCV_.wait(locker, [&] {
> return bufferAvailableCount_ >= 1 || !isRunning_;
> });
>
> (indenting lambdas is not very nice :-S)
>
> > + if (isRunning_)
> > + bufferAvailableCount_--;
> > +}
> > +
> > +bool V4L2Camera::isBufferAvailable()
> > +{
> > + MutexLocker locker(bufferMutex_);
> > + if (bufferAvailableCount_ < 1)
> > + return false;
> > +
> > + bufferAvailableCount_--;
> > + return true;
> > +}
> > +
> > bool V4L2Camera::isRunning()
> > {
> > return isRunning_;
> > diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h
> > index ee53c2b..515e906 100644
> > --- a/src/v4l2/v4l2_camera.h
> > +++ b/src/v4l2/v4l2_camera.h
> > @@ -57,9 +57,10 @@ public:
> >
> > int qbuf(unsigned int index);
> >
> > - bool isRunning();
> > + void waitForBufferAvailable();
> > + bool isBufferAvailable();
> >
> > - Semaphore bufferSema_;
> > + bool isRunning();
> >
> > private:
> > void requestComplete(Request *request);
> > @@ -76,6 +77,10 @@ private:
> > std::deque<std::unique_ptr<Buffer>> completedBuffers_;
> >
> > int efd_;
> > +
> > + Mutex bufferMutex_;
> > + std::condition_variable bufferCV_;
> > + unsigned int bufferAvailableCount_;
> > };
> >
> > #endif /* __V4L2_CAMERA_H__ */
> > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
> > index fa58585..8420e23 100644
> > --- a/src/v4l2/v4l2_camera_proxy.cpp
> > +++ b/src/v4l2/v4l2_camera_proxy.cpp
> > @@ -594,10 +594,17 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg)
> > return -EINVAL;
> >
> > if (!(file->nonBlocking()))
> > - vcam_->bufferSema_.acquire();
> > - else if (!vcam_->bufferSema_.tryAcquire())
> > + vcam_->waitForBufferAvailable();
> > + else if (!vcam_->isBufferAvailable())
> > return -EAGAIN;
> >
> > + /*
> > + * We need to check here again in case stream was turned off while we
> > + * were blocked on waitForBufferAvailable.
>
> s/waitForBufferAvailable/waitForBufferAvailable()/
>
> > + */
> > + if (!vcam_->isRunning())
> > + return -EINVAL;
>
> I think there's a small race here in the non-blocking case, as
> isBufferAvailable() could decrement the buffer count and the !running
> case could ignore that. I'm not sure it would have consequences as we
> would be stopping streaming anyway in that case, but regardless, patch
> 22/22 will address that, so
>
> Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
>
> as I'm not concerned about bisection breakages before this series lands.
I take this back, see explanation in my review of 22/22.
> > +
> > updateBuffers();
> >
> > struct v4l2_buffer &buf = buffers_[currentBuf_];
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list