[libcamera-devel] [PATCH v3 04/17] libcamera: base: Introduce UniqueFD
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Mon Nov 29 17:41:10 CET 2021
Hi Jacopo,
On Mon, Nov 29, 2021 at 03:58:26PM +0100, Jacopo Mondi wrote:
> On Mon, Nov 29, 2021 at 01:57:39AM +0200, Laurent Pinchart wrote:
> > From: Hirokazu Honda <hiroh at chromium.org>
> >
> > This introduces UniqueFD. It acts like unique_ptr to a file descriptor.
>
> Have you considered subclassing FileDescriptor and restrict its
> interface to support move-only semantic ?
Not really, as the two are very different beasts.
> > Signed-off-by: Hirokazu Honda <hiroh at chromium.org>
> > Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > ---
> > Changes since v2:
> >
> > - Rename ScopedFD to UniqueFD
> > - Inline most functions to allow compiler optimizations
> > - Bring the API closer to unique_ptr<>
> > - Add swap()
> > - Documentation cleanups
> > - Slip FileDescriptor constructor to separate patch
> > - Fix isValid()
> > ---
> > include/libcamera/base/meson.build | 1 +
> > include/libcamera/base/unique_fd.h | 69 ++++++++++++++++
> > src/libcamera/base/meson.build | 1 +
> > src/libcamera/base/unique_fd.cpp | 123 +++++++++++++++++++++++++++++
> > 4 files changed, 194 insertions(+)
> > create mode 100644 include/libcamera/base/unique_fd.h
> > create mode 100644 src/libcamera/base/unique_fd.cpp
> >
> > diff --git a/include/libcamera/base/meson.build b/include/libcamera/base/meson.build
> > index f73b00917409..cca374a769cc 100644
> > --- a/include/libcamera/base/meson.build
> > +++ b/include/libcamera/base/meson.build
> > @@ -22,6 +22,7 @@ libcamera_base_headers = files([
> > 'span.h',
> > 'thread.h',
> > 'timer.h',
> > + 'unique_fd.h',
> > 'utils.h',
> > ])
> >
> > diff --git a/include/libcamera/base/unique_fd.h b/include/libcamera/base/unique_fd.h
> > new file mode 100644
> > index 000000000000..ae4d96b75797
> > --- /dev/null
> > +++ b/include/libcamera/base/unique_fd.h
> > @@ -0,0 +1,69 @@
> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > +/*
> > + * Copyright (C) 2021, Google Inc.
> > + *
> > + * unique_fd.h - File descriptor wrapper that owns a file descriptor.
> > + */
> > +
> > +#pragma once
> > +
> > +#include <utility>
> > +
> > +#include <libcamera/base/class.h>
> > +#include <libcamera/base/compiler.h>
> > +
> > +namespace libcamera {
> > +
> > +class UniqueFD final
> > +{
> > +public:
> > + UniqueFD()
> > + : fd_(-1)
> > + {
> > + }
> > +
> > + explicit UniqueFD(int fd)
> > + : fd_(fd)
> > + {
> > + }
> > +
> > + UniqueFD(UniqueFD &&other)
> > + : fd_(other.release())
> > + {
> > + }
> > +
> > + ~UniqueFD()
> > + {
> > + reset();
> > + }
> > +
> > + UniqueFD &operator=(UniqueFD &&other)
> > + {
> > + reset(other.release());
> > + return *this;
> > + }
> > +
> > + __nodiscard int release()
> > + {
> > + int fd = fd_;
> > + fd_ = -1;
> > + return fd;
> > + }
>
> Thanks, this will be great for fences
That's why I sent this series ;-)
> > +
> > + void reset(int fd = -1);
> > +
> > + void swap(UniqueFD &other)
> > + {
> > + std::swap(fd_, other.fd_);
> > + }
> > +
> > + int get() const { return fd_; }
> > + bool isValid() const { return fd_ >= 0; }
>
> nit: const functions are usually put first
I've ordered the functions is in the std::unique_ptr<> documentation,
(with isValid() replacing the bool operator), but I can change that if
desired.
> > +
> > +private:
> > + LIBCAMERA_DISABLE_COPY(UniqueFD)
> > +
> > + int fd_;
> > +};
> > +
> > +} /* namespace libcamera */
> > diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build
> > index d5254fda9cbf..b0d85bc19245 100644
> > --- a/src/libcamera/base/meson.build
> > +++ b/src/libcamera/base/meson.build
> > @@ -17,6 +17,7 @@ libcamera_base_sources = files([
> > 'signal.cpp',
> > 'thread.cpp',
> > 'timer.cpp',
> > + 'unique_fd.cpp',
> > 'utils.cpp',
> > ])
> >
> > diff --git a/src/libcamera/base/unique_fd.cpp b/src/libcamera/base/unique_fd.cpp
> > new file mode 100644
> > index 000000000000..83d6919cf623
> > --- /dev/null
> > +++ b/src/libcamera/base/unique_fd.cpp
> > @@ -0,0 +1,123 @@
> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > +/*
> > + * Copyright (C) 2021, Google Inc.
> > + *
> > + * unique_fd.cpp - File descriptor wrapper that owns a file descriptor
> > + */
> > +
> > +#include <libcamera/base/unique_fd.h>
> > +
> > +#include <unistd.h>
> > +#include <utility>
> > +
> > +#include <libcamera/base/log.h>
> > +
> > +/**
> > + * \file base/unique_fd.h
> > + * \brief File descriptor wrapper that owns a file descriptor
> > + */
> > +
> > +namespace libcamera {
> > +
> > +LOG_DEFINE_CATEGORY(UniqueFD)
> > +
> > +/**
> > + * \class UniqueFD
> > + * \brief unique_ptr-like wrapper for a file descriptor
> > + *
> > + * The UniqueFD is a wrapper that owns and manages the lifetime of a file
> > + * descriptor. It is constructed from a numerical file descriptor, and takes
> > + * over its ownership. The file descriptor is closed when the UniqueFD is
>
> Is talking about ownship with raw int correct ?
I think talking about file descriptor ownership makes sense, as that's
what it's all about. It's not about owning the variable passed to the
constructor.
> I would specify that the fd passed in is instead reset to -1
It isn't though. I have thought about it, and researched why
std::unique_ptr<> had a constructor taking a pointer, not an rvalue
reference to the pointer. It seems the C++ authors have decided that it
wouldn't really bring much additional safety to automatically set the
pointer to null. Maybe it should be different here ? I'm not sure.
> > + * destroyed, or when it is assigned another file descriptor with operator=()
> > + * or reset().
> > + */
> > +
> > +/**
> > + * \fn UniqueFD::UniqueFD()
> > + * \brief Construct a UniqueFD that owns no file descriptor
> > + */
> > +
> > +/**
> > + * \fn UniqueFD::UniqueFD(int fd)
> > + * \brief Construct a UniqueFD that owns \a fd
> > + * \param[in] fd A file descriptor to manage
> > + */
> > +
> > +/**
> > + * \fn UniqueFD::UniqueFD(UniqueFD &&other)
> > + * \brief Move constructor, create a UniqueFD by taking over \a other
> > + * \param[in] other The other UniqueFD
> > + *
> > + * Create a UniqueFD by transferring ownership of the file descriptor owned by
> > + * \a other. Upon return, the \a other UniqueFD is invalid.
> > + */
> > +
> > +/**
> > + * \fn UniqueFD::~UniqueFD()
> > + * \brief Destroy the UniqueFD instance
> > + *
> > + * If a file descriptor is owned, it is closed.
> > + */
> > +
> > +/**
> > + * \fn UniqueFD::operator=(UniqueFD &&other)
> > + * \brief Move assignment operator, replace a UniqueFD by taking over \a other
> > + * \param[in] other The other UniqueFD
> > + *
> > + * If this UniqueFD owns a file descriptor, the file descriptor is closed
> > + * first. The file descriptor is then replaced by the one of \a other. Upon
> > + * return, \a other is invalid.
> > + *
> > + * \return A reference to this UniqueFD
> > + */
> > +
> > +/**
> > + * \fn UniqueFD::release()
> > + * \brief Release ownership of the file descriptor without closing it
> > + *
> > + * This function releases and returns the owned file descriptor without closing
> > + * it. The caller owns the returned value and must take care of handling its
> > + * life time to avoid file descriptor leakages. Upon return this UniqueFD is
> > + * invalid.
> > + *
> > + * \return The managed file descriptor, or -1 if no file descriptor was owned
> > + */
> > +
> > +/**
> > + * \brief Replace the managed file descriptor
> > + * \param[in] fd The new file descriptor to manage
> > + *
> > + * Close the managed file descriptor, if any, and replace it with the new \a fd.
> > + *
> > + * Self-resetting (passing an \a fd already managed by this instance) is invalid
> > + * and results in undefined behaviour.
> > + */
> > +void UniqueFD::reset(int fd)
>
> Has we enforce move semantics, shouldn't this take a && and reset fd
> to -1 ?
Same reasoning as for the constructor. We should use rvalue references
for both or none.
> > +{
> > + ASSERT(!isValid() || fd != fd_);
> > +
> > + std::swap(fd, fd_);
> > +
> > + if (fd >= 0)
> > + close(fd);
>
> wouldn't it be more clear to just:
>
> if (fd_ > 0)
> fd_.close();
> fd_ = fd;
>
> /* with the above suggestion: */
> fd = -1;
> ?
I went for swap() to match the behaviour of std::unique_ptr<>, but there
may be no need to in this case. If you prefer the above, I can change
it.
> > +}
> > +
> > +/**
> > + * \fn UniqueFD::swap(UniqueFD &other)
> > + * \brief Swap the managed file descriptors with another UniqueFD
> > + * \param[in] other Another UniqueFD to swap the file descriptor with
> > + */
> > +
> > +/**
> > + * \fn UniqueFD::get()
> > + * \brief Retrieve the managed file descriptor
> > + * \return The managed file descriptor, or -1 if no file descriptor is owned
> > + */
> > +
> > +/**
> > + * \fn UniqueFD::isValid()
> > + * \brief Check if the UniqueFD owns a valid file descriptor
> > + * \return True if the UniqueFD owns a valid file descriptor, false otherwise
> > + */
> > +
> > +} /* namespace libcamera */
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list