[libcamera-devel] [PATCH v3 17/17] libcamera: base: Rename FileDescriptor to SharedFD

Jacopo Mondi jacopo at jmondi.org
Mon Nov 29 18:30:09 CET 2021


Hi Laurent

On Mon, Nov 29, 2021 at 07:24:47PM +0200, Laurent Pinchart wrote:
> Hi Jacopo,
>
> On Mon, Nov 29, 2021 at 05:00:55PM +0100, Jacopo Mondi wrote:
> > On Mon, Nov 29, 2021 at 01:57:52AM +0200, Laurent Pinchart wrote:
> > > Now that we have a UniqueFD class, the name FileDescriptor is ambiguous.
> > > Rename it to SharedFD.
> > >
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> >
> > makes sense!
>
> Does this mean Rb ? :-)
>

ups :)
Reviewed-by: Jacopo Mondi <jacopo at jmondi.org>

It does!

> > > ---
> > >  include/libcamera/base/file.h                 |   4 +-
> > >  include/libcamera/base/meson.build            |   2 +-
> > >  .../base/{file_descriptor.h => shared_fd.h}   |  20 +-
> > >  include/libcamera/framebuffer.h               |   4 +-
> > >  .../libcamera/internal/ipa_data_serializer.h  |  40 +--
> > >  include/libcamera/internal/ipc_pipe.h         |   8 +-
> > >  include/libcamera/ipa/core.mojom              |   6 +-
> > >  include/libcamera/ipa/raspberrypi.mojom       |   2 +-
> > >  src/android/camera_device.cpp                 |   2 +-
> > >  src/ipa/raspberrypi/raspberrypi.cpp           |   4 +-
> > >  src/libcamera/base/file.cpp                   |   6 +-
> > >  src/libcamera/base/file_descriptor.cpp        | 266 ------------------
> > >  src/libcamera/base/meson.build                |   2 +-
> > >  src/libcamera/base/shared_fd.cpp              | 262 +++++++++++++++++
> > >  src/libcamera/framebuffer.cpp                 |   6 +-
> > >  src/libcamera/ipa_data_serializer.cpp         | 100 +++----
> > >  src/libcamera/ipc_pipe.cpp                    |   4 +-
> > >  .../pipeline/raspberrypi/raspberrypi.cpp      |   6 +-
> > >  src/libcamera/v4l2_videodevice.cpp            |   6 +-
> > >  src/v4l2/v4l2_camera.h                        |   2 +-
> > >  test/meson.build                              |   2 +-
> > >  .../ipa_data_serializer_test.cpp              |  14 +-
> > >  test/{file-descriptor.cpp => shared-fd.cpp}   |  46 +--
> > >  .../module_ipa_proxy.cpp.tmpl                 |   2 +-
> > >  .../module_ipa_proxy.h.tmpl                   |   2 +-
> > >  .../libcamera_templates/proxy_functions.tmpl  |   2 +-
> > >  .../libcamera_templates/serializer.tmpl       |  22 +-
> > >  .../generators/mojom_libcamera_generator.py   |   6 +-
> > >  28 files changed, 422 insertions(+), 426 deletions(-)
> > >  rename include/libcamera/base/{file_descriptor.h => shared_fd.h} (55%)
> > >  delete mode 100644 src/libcamera/base/file_descriptor.cpp
> > >  create mode 100644 src/libcamera/base/shared_fd.cpp
> > >  rename test/{file-descriptor.cpp => shared-fd.cpp} (80%)
> > >
> > > diff --git a/include/libcamera/base/file.h b/include/libcamera/base/file.h
> > > index 47769da7abc2..691b52d6ab2d 100644
> > > --- a/include/libcamera/base/file.h
> > > +++ b/include/libcamera/base/file.h
> > > @@ -21,7 +21,7 @@
> > >
> > >  namespace libcamera {
> > >
> > > -class FileDescriptor;
> > > +class SharedFD;
> > >
> > >  class File
> > >  {
> > > @@ -69,7 +69,7 @@ public:
> > >  	bool unmap(uint8_t *addr);
> > >
> > >  	static bool exists(const std::string &name);
> > > -	static ino_t inode(const FileDescriptor &fd);
> > > +	static ino_t inode(const SharedFD &fd);
> > >
> > >  private:
> > >  	LIBCAMERA_DISABLE_COPY(File)
> > > diff --git a/include/libcamera/base/meson.build b/include/libcamera/base/meson.build
> > > index cca374a769cc..112420dab225 100644
> > > --- a/include/libcamera/base/meson.build
> > > +++ b/include/libcamera/base/meson.build
> > > @@ -11,13 +11,13 @@ libcamera_base_headers = files([
> > >      'event_dispatcher_poll.h',
> > >      'event_notifier.h',
> > >      'file.h',
> > > -    'file_descriptor.h',
> > >      'flags.h',
> > >      'log.h',
> > >      'message.h',
> > >      'object.h',
> > >      'private.h',
> > >      'semaphore.h',
> > > +    'shared_fd.h',
> > >      'signal.h',
> > >      'span.h',
> > >      'thread.h',
> > > diff --git a/include/libcamera/base/file_descriptor.h b/include/libcamera/base/shared_fd.h
> > > similarity index 55%
> > > rename from include/libcamera/base/file_descriptor.h
> > > rename to include/libcamera/base/shared_fd.h
> > > index 12a43f95d414..a786885ceb32 100644
> > > --- a/include/libcamera/base/file_descriptor.h
> > > +++ b/include/libcamera/base/shared_fd.h
> > > @@ -2,7 +2,7 @@
> > >  /*
> > >   * Copyright (C) 2019, Google Inc.
> > >   *
> > > - * file_descriptor.h - File descriptor wrapper
> > > + * shared_fd.h - File descriptor wrapper with shared ownership
> > >   */
> > >
> > >  #pragma once
> > > @@ -13,18 +13,18 @@ namespace libcamera {
> > >
> > >  class UniqueFD;
> > >
> > > -class FileDescriptor final
> > > +class SharedFD final
> > >  {
> > >  public:
> > > -	explicit FileDescriptor(const int &fd = -1);
> > > -	explicit FileDescriptor(int &&fd);
> > > -	explicit FileDescriptor(UniqueFD fd);
> > > -	FileDescriptor(const FileDescriptor &other);
> > > -	FileDescriptor(FileDescriptor &&other);
> > > -	~FileDescriptor();
> > > +	explicit SharedFD(const int &fd = -1);
> > > +	explicit SharedFD(int &&fd);
> > > +	explicit SharedFD(UniqueFD fd);
> > > +	SharedFD(const SharedFD &other);
> > > +	SharedFD(SharedFD &&other);
> > > +	~SharedFD();
> > >
> > > -	FileDescriptor &operator=(const FileDescriptor &other);
> > > -	FileDescriptor &operator=(FileDescriptor &&other);
> > > +	SharedFD &operator=(const SharedFD &other);
> > > +	SharedFD &operator=(SharedFD &&other);
> > >
> > >  	bool isValid() const { return fd_ != nullptr; }
> > >  	int fd() const { return fd_ ? fd_->fd() : -1; }
> > > diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h
> > > index 2fbea9c5be16..357bbe189551 100644
> > > --- a/include/libcamera/framebuffer.h
> > > +++ b/include/libcamera/framebuffer.h
> > > @@ -13,7 +13,7 @@
> > >  #include <vector>
> > >
> > >  #include <libcamera/base/class.h>
> > > -#include <libcamera/base/file_descriptor.h>
> > > +#include <libcamera/base/shared_fd.h>
> > >  #include <libcamera/base/span.h>
> > >
> > >  namespace libcamera {
> > > @@ -51,7 +51,7 @@ class FrameBuffer final : public Extensible
> > >  public:
> > >  	struct Plane {
> > >  		static constexpr unsigned int kInvalidOffset = std::numeric_limits<unsigned int>::max();
> > > -		FileDescriptor fd;
> > > +		SharedFD fd;
> > >  		unsigned int offset = kInvalidOffset;
> > >  		unsigned int length;
> > >  	};
> > > diff --git a/include/libcamera/internal/ipa_data_serializer.h b/include/libcamera/internal/ipa_data_serializer.h
> > > index c2f602d5b7de..a87449c9be48 100644
> > > --- a/include/libcamera/internal/ipa_data_serializer.h
> > > +++ b/include/libcamera/internal/ipa_data_serializer.h
> > > @@ -66,7 +66,7 @@ template<typename T>
> > >  class IPADataSerializer
> > >  {
> > >  public:
> > > -	static std::tuple<std::vector<uint8_t>, std::vector<FileDescriptor>>
> > > +	static std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
> > >  	serialize(const T &data, ControlSerializer *cs = nullptr);
> > >
> > >  	static T deserialize(const std::vector<uint8_t> &data,
> > > @@ -76,12 +76,12 @@ public:
> > >  			     ControlSerializer *cs = nullptr);
> > >
> > >  	static T deserialize(const std::vector<uint8_t> &data,
> > > -			     const std::vector<FileDescriptor> &fds,
> > > +			     const std::vector<SharedFD> &fds,
> > >  			     ControlSerializer *cs = nullptr);
> > >  	static T deserialize(std::vector<uint8_t>::const_iterator dataBegin,
> > >  			     std::vector<uint8_t>::const_iterator dataEnd,
> > > -			     std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > -			     std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > +			     std::vector<SharedFD>::const_iterator fdsBegin,
> > > +			     std::vector<SharedFD>::const_iterator fdsEnd,
> > >  			     ControlSerializer *cs = nullptr);
> > >  };
> > >
> > > @@ -104,11 +104,11 @@ template<typename V>
> > >  class IPADataSerializer<std::vector<V>>
> > >  {
> > >  public:
> > > -	static std::tuple<std::vector<uint8_t>, std::vector<FileDescriptor>>
> > > +	static std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
> > >  	serialize(const std::vector<V> &data, ControlSerializer *cs = nullptr)
> > >  	{
> > >  		std::vector<uint8_t> dataVec;
> > > -		std::vector<FileDescriptor> fdsVec;
> > > +		std::vector<SharedFD> fdsVec;
> > >
> > >  		/* Serialize the length. */
> > >  		uint32_t vecLen = data.size();
> > > @@ -117,7 +117,7 @@ public:
> > >  		/* Serialize the members. */
> > >  		for (auto const &it : data) {
> > >  			std::vector<uint8_t> dvec;
> > > -			std::vector<FileDescriptor> fvec;
> > > +			std::vector<SharedFD> fvec;
> > >
> > >  			std::tie(dvec, fvec) =
> > >  				IPADataSerializer<V>::serialize(it, cs);
> > > @@ -141,11 +141,11 @@ public:
> > >  					  std::vector<uint8_t>::const_iterator dataEnd,
> > >  					  ControlSerializer *cs = nullptr)
> > >  	{
> > > -		std::vector<FileDescriptor> fds;
> > > +		std::vector<SharedFD> fds;
> > >  		return deserialize(dataBegin, dataEnd, fds.cbegin(), fds.end(), cs);
> > >  	}
> > >
> > > -	static std::vector<V> deserialize(std::vector<uint8_t> &data, std::vector<FileDescriptor> &fds,
> > > +	static std::vector<V> deserialize(std::vector<uint8_t> &data, std::vector<SharedFD> &fds,
> > >  					  ControlSerializer *cs = nullptr)
> > >  	{
> > >  		return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end(), cs);
> > > @@ -153,15 +153,15 @@ public:
> > >
> > >  	static std::vector<V> deserialize(std::vector<uint8_t>::const_iterator dataBegin,
> > >  					  std::vector<uint8_t>::const_iterator dataEnd,
> > > -					  std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > -					  [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > +					  std::vector<SharedFD>::const_iterator fdsBegin,
> > > +					  [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
> > >  					  ControlSerializer *cs = nullptr)
> > >  	{
> > >  		uint32_t vecLen = readPOD<uint32_t>(dataBegin, 0, dataEnd);
> > >  		std::vector<V> ret(vecLen);
> > >
> > >  		std::vector<uint8_t>::const_iterator dataIter = dataBegin + 4;
> > > -		std::vector<FileDescriptor>::const_iterator fdIter = fdsBegin;
> > > +		std::vector<SharedFD>::const_iterator fdIter = fdsBegin;
> > >  		for (uint32_t i = 0; i < vecLen; i++) {
> > >  			uint32_t sizeofData = readPOD<uint32_t>(dataIter, 0, dataEnd);
> > >  			uint32_t sizeofFds  = readPOD<uint32_t>(dataIter, 4, dataEnd);
> > > @@ -201,11 +201,11 @@ template<typename K, typename V>
> > >  class IPADataSerializer<std::map<K, V>>
> > >  {
> > >  public:
> > > -	static std::tuple<std::vector<uint8_t>, std::vector<FileDescriptor>>
> > > +	static std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
> > >  	serialize(const std::map<K, V> &data, ControlSerializer *cs = nullptr)
> > >  	{
> > >  		std::vector<uint8_t> dataVec;
> > > -		std::vector<FileDescriptor> fdsVec;
> > > +		std::vector<SharedFD> fdsVec;
> > >
> > >  		/* Serialize the length. */
> > >  		uint32_t mapLen = data.size();
> > > @@ -214,7 +214,7 @@ public:
> > >  		/* Serialize the members. */
> > >  		for (auto const &it : data) {
> > >  			std::vector<uint8_t> dvec;
> > > -			std::vector<FileDescriptor> fvec;
> > > +			std::vector<SharedFD> fvec;
> > >
> > >  			std::tie(dvec, fvec) =
> > >  				IPADataSerializer<K>::serialize(it.first, cs);
> > > @@ -247,11 +247,11 @@ public:
> > >  					  std::vector<uint8_t>::const_iterator dataEnd,
> > >  					  ControlSerializer *cs = nullptr)
> > >  	{
> > > -		std::vector<FileDescriptor> fds;
> > > +		std::vector<SharedFD> fds;
> > >  		return deserialize(dataBegin, dataEnd, fds.cbegin(), fds.end(), cs);
> > >  	}
> > >
> > > -	static std::map<K, V> deserialize(std::vector<uint8_t> &data, std::vector<FileDescriptor> &fds,
> > > +	static std::map<K, V> deserialize(std::vector<uint8_t> &data, std::vector<SharedFD> &fds,
> > >  					  ControlSerializer *cs = nullptr)
> > >  	{
> > >  		return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end(), cs);
> > > @@ -259,8 +259,8 @@ public:
> > >
> > >  	static std::map<K, V> deserialize(std::vector<uint8_t>::const_iterator dataBegin,
> > >  					  std::vector<uint8_t>::const_iterator dataEnd,
> > > -					  std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > -					  [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > +					  std::vector<SharedFD>::const_iterator fdsBegin,
> > > +					  [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
> > >  					  ControlSerializer *cs = nullptr)
> > >  	{
> > >  		std::map<K, V> ret;
> > > @@ -268,7 +268,7 @@ public:
> > >  		uint32_t mapLen = readPOD<uint32_t>(dataBegin, 0, dataEnd);
> > >
> > >  		std::vector<uint8_t>::const_iterator dataIter = dataBegin + 4;
> > > -		std::vector<FileDescriptor>::const_iterator fdIter = fdsBegin;
> > > +		std::vector<SharedFD>::const_iterator fdIter = fdsBegin;
> > >  		for (uint32_t i = 0; i < mapLen; i++) {
> > >  			uint32_t sizeofData = readPOD<uint32_t>(dataIter, 0, dataEnd);
> > >  			uint32_t sizeofFds  = readPOD<uint32_t>(dataIter, 4, dataEnd);
> > > diff --git a/include/libcamera/internal/ipc_pipe.h b/include/libcamera/internal/ipc_pipe.h
> > > index 986f8d886fa6..ab5dd67c3813 100644
> > > --- a/include/libcamera/internal/ipc_pipe.h
> > > +++ b/include/libcamera/internal/ipc_pipe.h
> > > @@ -9,7 +9,7 @@
> > >
> > >  #include <vector>
> > >
> > > -#include <libcamera/base/file_descriptor.h>
> > > +#include <libcamera/base/shared_fd.h>
> > >  #include <libcamera/base/signal.h>
> > >
> > >  #include "libcamera/internal/ipc_unixsocket.h"
> > > @@ -33,17 +33,17 @@ public:
> > >
> > >  	Header &header() { return header_; }
> > >  	std::vector<uint8_t> &data() { return data_; }
> > > -	std::vector<FileDescriptor> &fds() { return fds_; }
> > > +	std::vector<SharedFD> &fds() { return fds_; }
> > >
> > >  	const Header &header() const { return header_; }
> > >  	const std::vector<uint8_t> &data() const { return data_; }
> > > -	const std::vector<FileDescriptor> &fds() const { return fds_; }
> > > +	const std::vector<SharedFD> &fds() const { return fds_; }
> > >
> > >  private:
> > >  	Header header_;
> > >
> > >  	std::vector<uint8_t> data_;
> > > -	std::vector<FileDescriptor> fds_;
> > > +	std::vector<SharedFD> fds_;
> > >  };
> > >
> > >  class IPCPipe
> > > diff --git a/include/libcamera/ipa/core.mojom b/include/libcamera/ipa/core.mojom
> > > index f7eff0c7ab8c..74f3339e56f2 100644
> > > --- a/include/libcamera/ipa/core.mojom
> > > +++ b/include/libcamera/ipa/core.mojom
> > > @@ -32,7 +32,7 @@ module libcamera;
> > >   *   - This attribute instructs the build system that a (de)serializer is
> > >   *     available for the type and there's no need to generate one
> > >   * - hasFd - struct fields or empty structs only
> > > - *   - Designate that this field or empty struct contains a FileDescriptor
> > > + *   - Designate that this field or empty struct contains a SharedFD
> > >   *
> > >   * Rules:
> > >   * - If the type is defined in a libcamera C++ header *and* a (de)serializer is
> > > @@ -60,7 +60,7 @@ module libcamera;
> > >   *     - In mojom, reference the type as FrameBuffer.Plane and only as map/array
> > >   *       member
> > >   * - [skipHeader] and [skipSerdes] only work here in core.mojom
> > > - * - If a field in a struct has a FileDescriptor, but is not explicitly
> > > + * - If a field in a struct has a SharedFD, but is not explicitly
> > >   *   defined so in mojom, then the field must be marked with the [hasFd]
> > >   *   attribute
> > >   *
> > > @@ -71,7 +71,7 @@ module libcamera;
> > >   */
> > >  [skipSerdes, skipHeader] struct ControlInfoMap {};
> > >  [skipSerdes, skipHeader] struct ControlList {};
> > > -[skipSerdes, skipHeader] struct FileDescriptor {};
> > > +[skipSerdes, skipHeader] struct SharedFD {};
> > >
> > >  [skipHeader] struct Point {
> > >  	int32 x;
> > > diff --git a/include/libcamera/ipa/raspberrypi.mojom b/include/libcamera/ipa/raspberrypi.mojom
> > > index e453d46cb14f..acd3cafe6c91 100644
> > > --- a/include/libcamera/ipa/raspberrypi.mojom
> > > +++ b/include/libcamera/ipa/raspberrypi.mojom
> > > @@ -35,7 +35,7 @@ struct ISPConfig {
> > >
> > >  struct IPAConfig {
> > >  	uint32 transform;
> > > -	libcamera.FileDescriptor lsTableHandle;
> > > +	libcamera.SharedFD lsTableHandle;
> > >  };
> > >
> > >  struct StartConfig {
> > > diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
> > > index f2e0bdbdbbf6..1938b10509fa 100644
> > > --- a/src/android/camera_device.cpp
> > > +++ b/src/android/camera_device.cpp
> > > @@ -725,7 +725,7 @@ CameraDevice::createFrameBuffer(const buffer_handle_t camera3buffer,
> > >
> > >  	std::vector<FrameBuffer::Plane> planes(buf.numPlanes());
> > >  	for (size_t i = 0; i < buf.numPlanes(); ++i) {
> > > -		FileDescriptor fd{ camera3buffer->data[i] };
> > > +		SharedFD fd{ camera3buffer->data[i] };
> > >  		if (!fd.isValid()) {
> > >  			LOG(HAL, Fatal) << "No valid fd";
> > >  			return nullptr;
> > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
> > > index c6aec09046f7..aaf629eeb3fc 100644
> > > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > > @@ -15,8 +15,8 @@
> > >
> > >  #include <linux/bcm2835-isp.h>
> > >
> > > -#include <libcamera/base/file_descriptor.h>
> > >  #include <libcamera/base/log.h>
> > > +#include <libcamera/base/shared_fd.h>
> > >  #include <libcamera/base/span.h>
> > >
> > >  #include <libcamera/control_ids.h>
> > > @@ -164,7 +164,7 @@ private:
> > >  	bool processPending_;
> > >
> > >  	/* LS table allocation passed in from the pipeline handler. */
> > > -	FileDescriptor lsTableHandle_;
> > > +	SharedFD lsTableHandle_;
> > >  	void *lsTable_;
> > >
> > >  	/* Distinguish the first camera start from others. */
> > > diff --git a/src/libcamera/base/file.cpp b/src/libcamera/base/file.cpp
> > > index 66c73c406198..3ca9839bb989 100644
> > > --- a/src/libcamera/base/file.cpp
> > > +++ b/src/libcamera/base/file.cpp
> > > @@ -14,8 +14,8 @@
> > >  #include <sys/types.h>
> > >  #include <unistd.h>
> > >
> > > -#include <libcamera/base/file_descriptor.h>
> > >  #include <libcamera/base/log.h>
> > > +#include <libcamera/base/shared_fd.h>
> > >
> > >  /**
> > >   * \file base/file.h
> > > @@ -473,11 +473,11 @@ bool File::exists(const std::string &name)
> > >  }
> > >
> > >  /**
> > > - * \brief Retrieve the inode of a FileDescriptor
> > > + * \brief Retrieve the inode of a SharedFD
> > >   *
> > >   * \return The file descriptor inode on success, or 0 on error
> > >   */
> > > -ino_t File::inode(const FileDescriptor &fd)
> > > +ino_t File::inode(const SharedFD &fd)
> > >  {
> > >  	if (!fd.isValid())
> > >  		return 0;
> > > diff --git a/src/libcamera/base/file_descriptor.cpp b/src/libcamera/base/file_descriptor.cpp
> > > deleted file mode 100644
> > > index a83bf52c31e6..000000000000
> > > --- a/src/libcamera/base/file_descriptor.cpp
> > > +++ /dev/null
> > > @@ -1,266 +0,0 @@
> > > -/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > > -/*
> > > - * Copyright (C) 2019, Google Inc.
> > > - *
> > > - * file_descriptor.cpp - File descriptor wrapper
> > > - */
> > > -
> > > -#include <libcamera/base/file_descriptor.h>
> > > -
> > > -#include <string.h>
> > > -#include <sys/types.h>
> > > -#include <unistd.h>
> > > -#include <utility>
> > > -
> > > -#include <libcamera/base/log.h>
> > > -#include <libcamera/base/unique_fd.h>
> > > -
> > > -/**
> > > - * \file base/file_descriptor.h
> > > - * \brief File descriptor wrapper
> > > - */
> > > -
> > > -namespace libcamera {
> > > -
> > > -LOG_DEFINE_CATEGORY(FileDescriptor)
> > > -
> > > -/**
> > > - * \class FileDescriptor
> > > - * \brief RAII-style wrapper for file descriptors
> > > - *
> > > - * The FileDescriptor class provides RAII-style lifetime management of file
> > > - * descriptors with an efficient mechanism for ownership sharing. At its core,
> > > - * an internal Descriptor object wraps a file descriptor (expressed as a signed
> > > - * integer) with an RAII-style interface. The Descriptor is then implicitly
> > > - * shared with all FileDescriptor instances constructed as copies.
> > > - *
> > > - * When constructed from a numerical file descriptor, the FileDescriptor
> > > - * instance either duplicates or takes over the file descriptor:
> > > - *
> > > - * - The FileDescriptor(const int &) constructor duplicates the numerical file
> > > - *   descriptor and wraps the duplicate in a Descriptor. The caller is
> > > - *   responsible for closing the original file descriptor, and the value
> > > - *   returned by fd() will be different from the value passed to the
> > > - *   constructor.
> > > - *
> > > - * - The FileDescriptor(int &&) constructor takes over the numerical file
> > > - *   descriptor and wraps it in a Descriptor. The caller shall not touch the
> > > - *   original file descriptor once the function returns, and the value returned
> > > - *   by fd() will be identical to the value passed to the constructor.
> > > - *
> > > - * The copy constructor and assignment operator create copies that share the
> > > - * Descriptor, while the move versions of those functions additionally make the
> > > - * other FileDescriptor invalid. When the last FileDescriptor that references a
> > > - * Descriptor is destroyed, the file descriptor is closed.
> > > - *
> > > - * The numerical file descriptor is available through the fd() function. All
> > > - * FileDescriptor instances created as copies of a FileDescriptor will report
> > > - * the same fd() value. Callers can perform operations on the fd(), but shall
> > > - * never close it manually.
> > > - */
> > > -
> > > -/**
> > > - * \brief Create a FileDescriptor copying a given \a fd
> > > - * \param[in] fd File descriptor
> > > - *
> > > - * Construct a FileDescriptor from a numerical file descriptor by duplicating
> > > - * the \a fd, and take ownership of the copy. The original \a fd is left
> > > - * untouched, and the caller is responsible for closing it when appropriate.
> > > - * The duplicated file descriptor will be closed automatically when all
> > > - * FileDescriptor instances that reference it are destroyed.
> > > - *
> > > - * If the \a fd is negative, the FileDescriptor is constructed as invalid and
> > > - * the fd() function will return -1.
> > > - */
> > > -FileDescriptor::FileDescriptor(const int &fd)
> > > -{
> > > -	if (fd < 0)
> > > -		return;
> > > -
> > > -	fd_ = std::make_shared<Descriptor>(fd, true);
> > > -	if (fd_->fd() < 0)
> > > -		fd_.reset();
> > > -}
> > > -
> > > -/**
> > > - * \brief Create a FileDescriptor taking ownership of a given \a fd
> > > - * \param[in] fd File descriptor
> > > - *
> > > - * Construct a FileDescriptor from a numerical file descriptor by taking
> > > - * ownership of the \a fd. The original \a fd is set to -1 and shall not be
> > > - * touched by the caller anymore. In particular, the caller shall not close the
> > > - * original \a fd manually. The duplicated file descriptor will be closed
> > > - * automatically when all FileDescriptor instances that reference it are
> > > - * destroyed.
> > > - *
> > > - * If the \a fd is negative, the FileDescriptor is constructed as invalid and
> > > - * the fd() function will return -1.
> > > - */
> > > -FileDescriptor::FileDescriptor(int &&fd)
> > > -{
> > > -	if (fd < 0)
> > > -		return;
> > > -
> > > -	fd_ = std::make_shared<Descriptor>(fd, false);
> > > -	/*
> > > -	 * The Descriptor constructor can't have failed here, as it took over
> > > -	 * the fd without duplicating it. Just set the original fd to -1 to
> > > -	 * implement move semantics.
> > > -	 */
> > > -	fd = -1;
> > > -}
> > > -
> > > -/**
> > > - * \brief Create a FileDescriptor taking ownership of a given UniqueFD \a fd
> > > - * \param[in] fd UniqueFD
> > > - *
> > > - * Construct a FileDescriptor from UniqueFD by taking ownership of the \a fd.
> > > - * The original \a fd becomes invalid.
> > > - */
> > > -FileDescriptor::FileDescriptor(UniqueFD fd)
> > > -	: FileDescriptor(fd.release())
> > > -{
> > > -}
> > > -
> > > -/**
> > > - * \brief Copy constructor, create a FileDescriptor from a copy of \a other
> > > - * \param[in] other The other FileDescriptor
> > > - *
> > > - * Copying a FileDescriptor implicitly shares ownership of the wrapped file
> > > - * descriptor. The original FileDescriptor is left untouched, and the caller is
> > > - * responsible for destroying it when appropriate. The wrapped file descriptor
> > > - * will be closed automatically when all FileDescriptor instances that
> > > - * reference it are destroyed.
> > > - */
> > > -FileDescriptor::FileDescriptor(const FileDescriptor &other)
> > > -	: fd_(other.fd_)
> > > -{
> > > -}
> > > -
> > > -/**
> > > - * \brief Move constructor, create a FileDescriptor by taking over \a other
> > > - * \param[in] other The other FileDescriptor
> > > - *
> > > - * Moving a FileDescriptor moves the reference to the wrapped descriptor owned
> > > - * by \a other to the new FileDescriptor. The \a other FileDescriptor is
> > > - * invalidated and its fd() function will return -1. The wrapped file descriptor
> > > - * will be closed automatically when all FileDescriptor instances that
> > > - * reference it are destroyed.
> > > - */
> > > -FileDescriptor::FileDescriptor(FileDescriptor &&other)
> > > -	: fd_(std::move(other.fd_))
> > > -{
> > > -}
> > > -
> > > -/**
> > > - * \brief Destroy the FileDescriptor instance
> > > - *
> > > - * Destroying a FileDescriptor instance releases its reference to the wrapped
> > > - * descriptor, if any. When the last instance that references a wrapped
> > > - * descriptor is destroyed, the file descriptor is automatically closed.
> > > - */
> > > -FileDescriptor::~FileDescriptor()
> > > -{
> > > -}
> > > -
> > > -/**
> > > - * \brief Copy assignment operator, replace the wrapped file descriptor with a
> > > - * copy of \a other
> > > - * \param[in] other The other FileDescriptor
> > > - *
> > > - * Copying a FileDescriptor creates a new reference to the wrapped file
> > > - * descriptor owner by \a other. If \a other is invalid, *this will also be
> > > - * invalid. The original FileDescriptor is left untouched, and the caller is
> > > - * responsible for destroying it when appropriate. The wrapped file descriptor
> > > - * will be closed automatically when all FileDescriptor instances that
> > > - * reference it are destroyed.
> > > - *
> > > - * \return A reference to this FileDescriptor
> > > - */
> > > -FileDescriptor &FileDescriptor::operator=(const FileDescriptor &other)
> > > -{
> > > -	fd_ = other.fd_;
> > > -
> > > -	return *this;
> > > -}
> > > -
> > > -/**
> > > - * \brief Move assignment operator, replace the wrapped file descriptor by
> > > - * taking over \a other
> > > - * \param[in] other The other FileDescriptor
> > > - *
> > > - * Moving a FileDescriptor moves the reference to the wrapped descriptor owned
> > > - * by \a other to the new FileDescriptor. If \a other is invalid, *this will
> > > - * also be invalid. The \a other FileDescriptor is invalidated and its fd()
> > > - * function will return -1. The wrapped file descriptor will be closed
> > > - * automatically when all FileDescriptor instances that reference it are
> > > - * destroyed.
> > > - *
> > > - * \return A reference to this FileDescriptor
> > > - */
> > > -FileDescriptor &FileDescriptor::operator=(FileDescriptor &&other)
> > > -{
> > > -	fd_ = std::move(other.fd_);
> > > -
> > > -	return *this;
> > > -}
> > > -
> > > -/**
> > > - * \fn FileDescriptor::isValid()
> > > - * \brief Check if the FileDescriptor instance is valid
> > > - * \return True if the FileDescriptor is valid, false otherwise
> > > - */
> > > -
> > > -/**
> > > - * \fn FileDescriptor::fd()
> > > - * \brief Retrieve the numerical file descriptor
> > > - * \return The numerical file descriptor, which may be -1 if the FileDescriptor
> > > - * instance is invalid
> > > - */
> > > -
> > > -/**
> > > - * \brief Duplicate a FileDescriptor
> > > - *
> > > - * Duplicating a FileDescriptor creates a duplicate of the wrapped file
> > > - * descriptor and returns a UniqueFD that owns the duplicate. The fd() function
> > > - * of the original and the get() function of the duplicate will return different
> > > - * values. The duplicate instance will not be affected by destruction of the
> > > - * original instance or its copies.
> > > - *
> > > - * \return A UniqueFD owning a duplicate of the original file descriptor
> > > - */
> > > -UniqueFD FileDescriptor::dup() const
> > > -{
> > > -	int dupFd = ::dup(fd());
> > > -	if (dupFd == -1) {
> > > -		int ret = -errno;
> > > -		LOG(FileDescriptor, Error)
> > > -			<< "Failed to dup() fd: " << strerror(-ret);
> > > -	}
> > > -
> > > -	return UniqueFD(dupFd);
> > > -}
> > > -
> > > -FileDescriptor::Descriptor::Descriptor(int fd, bool duplicate)
> > > -{
> > > -	if (!duplicate) {
> > > -		fd_ = fd;
> > > -		return;
> > > -	}
> > > -
> > > -	/* Failing to dup() a fd should not happen and is fatal. */
> > > -	fd_ = ::dup(fd);
> > > -	if (fd_ == -1) {
> > > -		int ret = -errno;
> > > -		LOG(FileDescriptor, Fatal)
> > > -			<< "Failed to dup() fd: " << strerror(-ret);
> > > -	}
> > > -}
> > > -
> > > -FileDescriptor::Descriptor::~Descriptor()
> > > -{
> > > -	if (fd_ != -1)
> > > -		close(fd_);
> > > -}
> > > -
> > > -} /* namespace libcamera */
> > > diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build
> > > index b0d85bc19245..ccb746c27466 100644
> > > --- a/src/libcamera/base/meson.build
> > > +++ b/src/libcamera/base/meson.build
> > > @@ -8,12 +8,12 @@ libcamera_base_sources = files([
> > >      'event_dispatcher_poll.cpp',
> > >      'event_notifier.cpp',
> > >      'file.cpp',
> > > -    'file_descriptor.cpp',
> > >      'flags.cpp',
> > >      'log.cpp',
> > >      'message.cpp',
> > >      'object.cpp',
> > >      'semaphore.cpp',
> > > +    'shared_fd.cpp',
> > >      'signal.cpp',
> > >      'thread.cpp',
> > >      'timer.cpp',
> > > diff --git a/src/libcamera/base/shared_fd.cpp b/src/libcamera/base/shared_fd.cpp
> > > new file mode 100644
> > > index 000000000000..05b6892f7e19
> > > --- /dev/null
> > > +++ b/src/libcamera/base/shared_fd.cpp
> > > @@ -0,0 +1,262 @@
> > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > > +/*
> > > + * Copyright (C) 2019, Google Inc.
> > > + *
> > > + * shared_fd.cpp - File descriptor wrapper with shared ownership
> > > + */
> > > +
> > > +#include <libcamera/base/shared_fd.h>
> > > +
> > > +#include <string.h>
> > > +#include <sys/types.h>
> > > +#include <unistd.h>
> > > +#include <utility>
> > > +
> > > +#include <libcamera/base/log.h>
> > > +#include <libcamera/base/unique_fd.h>
> > > +
> > > +/**
> > > + * \file base/shared_fd.h
> > > + * \brief File descriptor wrapper
> > > + */
> > > +
> > > +namespace libcamera {
> > > +
> > > +LOG_DEFINE_CATEGORY(SharedFD)
> > > +
> > > +/**
> > > + * \class SharedFD
> > > + * \brief RAII-style wrapper for file descriptors
> > > + *
> > > + * The SharedFD class provides RAII-style lifetime management of file
> > > + * descriptors with an efficient mechanism for ownership sharing. At its core,
> > > + * an internal Descriptor object wraps a file descriptor (expressed as a signed
> > > + * integer) with an RAII-style interface. The Descriptor is then implicitly
> > > + * shared with all SharedFD instances constructed as copies.
> > > + *
> > > + * When constructed from a numerical file descriptor, the SharedFD instance
> > > + * either duplicates or takes over the file descriptor:
> > > + *
> > > + * - The SharedFD(const int &) constructor duplicates the numerical file
> > > + *   descriptor and wraps the duplicate in a Descriptor. The caller is
> > > + *   responsible for closing the original file descriptor, and the value
> > > + *   returned by fd() will be different from the value passed to the
> > > + *   constructor.
> > > + *
> > > + * - The SharedFD(int &&) constructor takes over the numerical file descriptor
> > > + *   and wraps it in a Descriptor. The caller shall not touch the original file
> > > + *   descriptor once the function returns, and the value returned by fd() will
> > > + *   be identical to the value passed to the constructor.
> > > + *
> > > + * The copy constructor and assignment operator create copies that share the
> > > + * Descriptor, while the move versions of those functions additionally make the
> > > + * other SharedFD invalid. When the last SharedFD that references a Descriptor
> > > + * is destroyed, the file descriptor is closed.
> > > + *
> > > + * The numerical file descriptor is available through the fd() function. All
> > > + * SharedFD instances created as copies of a SharedFD will report the same fd()
> > > + * value. Callers can perform operations on the fd(), but shall never close it
> > > + * manually.
> > > + */
> > > +
> > > +/**
> > > + * \brief Create a SharedFD copying a given \a fd
> > > + * \param[in] fd File descriptor
> > > + *
> > > + * Construct a SharedFD from a numerical file descriptor by duplicating the
> > > + * \a fd, and take ownership of the copy. The original \a fd is left untouched,
> > > + * and the caller is responsible for closing it when appropriate. The duplicated
> > > + * file descriptor will be closed automatically when all SharedFD instances that
> > > + * reference it are destroyed.
> > > + *
> > > + * If the \a fd is negative, the SharedFD is constructed as invalid and the fd()
> > > + * function will return -1.
> > > + */
> > > +SharedFD::SharedFD(const int &fd)
> > > +{
> > > +	if (fd < 0)
> > > +		return;
> > > +
> > > +	fd_ = std::make_shared<Descriptor>(fd, true);
> > > +	if (fd_->fd() < 0)
> > > +		fd_.reset();
> > > +}
> > > +
> > > +/**
> > > + * \brief Create a SharedFD taking ownership of a given \a fd
> > > + * \param[in] fd File descriptor
> > > + *
> > > + * Construct a SharedFD from a numerical file descriptor by taking ownership of
> > > + * the \a fd. The original \a fd is set to -1 and shall not be touched by the
> > > + * caller anymore. In particular, the caller shall not close the original \a fd
> > > + * manually. The duplicated file descriptor will be closed automatically when
> > > + * all SharedFD instances that reference it are destroyed.
> > > + *
> > > + * If the \a fd is negative, the SharedFD is constructed as invalid and the fd()
> > > + * function will return -1.
> > > + */
> > > +SharedFD::SharedFD(int &&fd)
> > > +{
> > > +	if (fd < 0)
> > > +		return;
> > > +
> > > +	fd_ = std::make_shared<Descriptor>(fd, false);
> > > +	/*
> > > +	 * The Descriptor constructor can't have failed here, as it took over
> > > +	 * the fd without duplicating it. Just set the original fd to -1 to
> > > +	 * implement move semantics.
> > > +	 */
> > > +	fd = -1;
> > > +}
> > > +
> > > +/**
> > > + * \brief Create a SharedFD taking ownership of a given UniqueFD \a fd
> > > + * \param[in] fd UniqueFD
> > > + *
> > > + * Construct a SharedFD from UniqueFD by taking ownership of the \a fd. The
> > > + * original \a fd becomes invalid.
> > > + */
> > > +SharedFD::SharedFD(UniqueFD fd)
> > > +	: SharedFD(fd.release())
> > > +{
> > > +}
> > > +
> > > +/**
> > > + * \brief Copy constructor, create a SharedFD from a copy of \a other
> > > + * \param[in] other The other SharedFD
> > > + *
> > > + * Copying a SharedFD implicitly shares ownership of the wrapped file
> > > + * descriptor. The original SharedFD is left untouched, and the caller is
> > > + * responsible for destroying it when appropriate. The wrapped file descriptor
> > > + * will be closed automatically when all SharedFD instances that reference it
> > > + * are destroyed.
> > > + */
> > > +SharedFD::SharedFD(const SharedFD &other)
> > > +	: fd_(other.fd_)
> > > +{
> > > +}
> > > +
> > > +/**
> > > + * \brief Move constructor, create a SharedFD by taking over \a other
> > > + * \param[in] other The other SharedFD
> > > + *
> > > + * Moving a SharedFD moves the reference to the wrapped descriptor owned by
> > > + * \a other to the new SharedFD. The \a other SharedFD is invalidated and its
> > > + * fd() function will return -1. The wrapped file descriptor will be closed
> > > + * automatically when all SharedFD instances that reference it are destroyed.
> > > + */
> > > +SharedFD::SharedFD(SharedFD &&other)
> > > +	: fd_(std::move(other.fd_))
> > > +{
> > > +}
> > > +
> > > +/**
> > > + * \brief Destroy the SharedFD instance
> > > + *
> > > + * Destroying a SharedFD instance releases its reference to the wrapped
> > > + * descriptor, if any. When the last instance that references a wrapped
> > > + * descriptor is destroyed, the file descriptor is automatically closed.
> > > + */
> > > +SharedFD::~SharedFD()
> > > +{
> > > +}
> > > +
> > > +/**
> > > + * \brief Copy assignment operator, replace the wrapped file descriptor with a
> > > + * copy of \a other
> > > + * \param[in] other The other SharedFD
> > > + *
> > > + * Copying a SharedFD creates a new reference to the wrapped file descriptor
> > > + * owner by \a other. If \a other is invalid, *this will also be invalid. The
> > > + * original SharedFD is left untouched, and the caller is responsible for
> > > + * destroying it when appropriate. The wrapped file descriptor will be closed
> > > + * automatically when all SharedFD instances that reference it are destroyed.
> > > + *
> > > + * \return A reference to this SharedFD
> > > + */
> > > +SharedFD &SharedFD::operator=(const SharedFD &other)
> > > +{
> > > +	fd_ = other.fd_;
> > > +
> > > +	return *this;
> > > +}
> > > +
> > > +/**
> > > + * \brief Move assignment operator, replace the wrapped file descriptor by
> > > + * taking over \a other
> > > + * \param[in] other The other SharedFD
> > > + *
> > > + * Moving a SharedFD moves the reference to the wrapped descriptor owned by
> > > + * \a other to the new SharedFD. If \a other is invalid, *this will also be
> > > + * invalid. The \a other SharedFD is invalidated and its fd() function will
> > > + * return -1. The wrapped file descriptor will be closed automatically when
> > > + * all SharedFD instances that reference it are destroyed.
> > > + *
> > > + * \return A reference to this SharedFD
> > > + */
> > > +SharedFD &SharedFD::operator=(SharedFD &&other)
> > > +{
> > > +	fd_ = std::move(other.fd_);
> > > +
> > > +	return *this;
> > > +}
> > > +
> > > +/**
> > > + * \fn SharedFD::isValid()
> > > + * \brief Check if the SharedFD instance is valid
> > > + * \return True if the SharedFD is valid, false otherwise
> > > + */
> > > +
> > > +/**
> > > + * \fn SharedFD::fd()
> > > + * \brief Retrieve the numerical file descriptor
> > > + * \return The numerical file descriptor, which may be -1 if the SharedFD
> > > + * instance is invalid
> > > + */
> > > +
> > > +/**
> > > + * \brief Duplicate a SharedFD
> > > + *
> > > + * Duplicating a SharedFD creates a duplicate of the wrapped file descriptor and
> > > + * returns a UniqueFD that owns the duplicate. The fd() function of the original
> > > + * and the get() function of the duplicate will return different values. The
> > > + * duplicate instance will not be affected by destruction of the original
> > > + * instance or its copies.
> > > + *
> > > + * \return A UniqueFD owning a duplicate of the original file descriptor
> > > + */
> > > +UniqueFD SharedFD::dup() const
> > > +{
> > > +	int dupFd = ::dup(fd());
> > > +	if (dupFd == -1) {
> > > +		int ret = -errno;
> > > +		LOG(SharedFD, Error)
> > > +			<< "Failed to dup() fd: " << strerror(-ret);
> > > +	}
> > > +
> > > +	return UniqueFD(dupFd);
> > > +}
> > > +
> > > +SharedFD::Descriptor::Descriptor(int fd, bool duplicate)
> > > +{
> > > +	if (!duplicate) {
> > > +		fd_ = fd;
> > > +		return;
> > > +	}
> > > +
> > > +	/* Failing to dup() a fd should not happen and is fatal. */
> > > +	fd_ = ::dup(fd);
> > > +	if (fd_ == -1) {
> > > +		int ret = -errno;
> > > +		LOG(SharedFD, Fatal)
> > > +			<< "Failed to dup() fd: " << strerror(-ret);
> > > +	}
> > > +}
> > > +
> > > +SharedFD::Descriptor::~Descriptor()
> > > +{
> > > +	if (fd_ != -1)
> > > +		close(fd_);
> > > +}
> > > +
> > > +} /* namespace libcamera */
> > > diff --git a/src/libcamera/framebuffer.cpp b/src/libcamera/framebuffer.cpp
> > > index f5bcf107d7aa..0a5bf7fdbeb7 100644
> > > --- a/src/libcamera/framebuffer.cpp
> > > +++ b/src/libcamera/framebuffer.cpp
> > > @@ -180,9 +180,9 @@ FrameBuffer::Private::Private()
> > >   * offset and length.
> > >   *
> > >   * To support DMA access, planes are associated with dmabuf objects represented
> > > - * by FileDescriptor handles. The Plane class doesn't handle mapping of the
> > > - * memory to the CPU, but applications and IPAs may use the dmabuf file
> > > - * descriptors to map the plane memory with mmap() and access its contents.
> > > + * by SharedFD handles. The Plane class doesn't handle mapping of the memory to
> > > + * the CPU, but applications and IPAs may use the dmabuf file descriptors to map
> > > + * the plane memory with mmap() and access its contents.
> > >   *
> > >   * \todo Specify how an application shall decide whether to use a single or
> > >   * multiple dmabufs, based on the camera requirements.
> > > diff --git a/src/libcamera/ipa_data_serializer.cpp b/src/libcamera/ipa_data_serializer.cpp
> > > index 82ec9b20a411..0a259305afa2 100644
> > > --- a/src/libcamera/ipa_data_serializer.cpp
> > > +++ b/src/libcamera/ipa_data_serializer.cpp
> > > @@ -31,7 +31,7 @@ LOG_DEFINE_CATEGORY(IPADataSerializer)
> > >   *
> > >   * \todo Harden the vector and map deserializer
> > >   *
> > > - * \todo For FileDescriptors, instead of storing a validity flag, store an
> > > + * \todo For SharedFDs, instead of storing a validity flag, store an
> > >   * index into the fd array. This will allow us to use views instead of copying.
> > >   */
> > >
> > > @@ -112,7 +112,7 @@ namespace {
> > >   * \param[in] cs ControlSerializer
> > >   *
> > >   * This version of deserialize() can be used if the object type \a T and its
> > > - * members don't have any FileDescriptor.
> > > + * members don't have any SharedFD.
> > >   *
> > >   * \a cs is only necessary if the object type \a T or its members contain
> > >   * ControlList or ControlInfoMap.
> > > @@ -132,7 +132,7 @@ namespace {
> > >   * \param[in] cs ControlSerializer
> > >   *
> > >   * This version of deserialize() can be used if the object type \a T and its
> > > - * members don't have any FileDescriptor.
> > > + * members don't have any SharedFD.
> > >   *
> > >   * \a cs is only necessary if the object type \a T or its members contain
> > >   * ControlList or ControlInfoMap.
> > > @@ -143,7 +143,7 @@ namespace {
> > >  /**
> > >   * \fn template<typename T> IPADataSerializer<T>::deserialize(
> > >   * 	const std::vector<uint8_t> &data,
> > > - * 	const std::vector<FileDescriptor> &fds,
> > > + * 	const std::vector<SharedFD> &fds,
> > >   * 	ControlSerializer *cs = nullptr)
> > >   * \brief Deserialize byte vector and fd vector into an object
> > >   * \tparam T Type of object to deserialize to
> > > @@ -152,7 +152,7 @@ namespace {
> > >   * \param[in] cs ControlSerializer
> > >   *
> > >   * This version of deserialize() (or the iterator version) must be used if
> > > - * the object type \a T or its members contain FileDescriptor.
> > > + * the object type \a T or its members contain SharedFD.
> > >   *
> > >   * \a cs is only necessary if the object type \a T or its members contain
> > >   * ControlList or ControlInfoMap.
> > > @@ -164,8 +164,8 @@ namespace {
> > >   * \fn template<typename T> IPADataSerializer::deserialize(
> > >   * 	std::vector<uint8_t>::const_iterator dataBegin,
> > >   * 	std::vector<uint8_t>::const_iterator dataEnd,
> > > - * 	std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > - * 	std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > + * 	std::vector<SharedFD>::const_iterator fdsBegin,
> > > + * 	std::vector<SharedFD>::const_iterator fdsEnd,
> > >   * 	ControlSerializer *cs = nullptr)
> > >   * \brief Deserialize byte vector and fd vector into an object
> > >   * \tparam T Type of object to deserialize to
> > > @@ -176,7 +176,7 @@ namespace {
> > >   * \param[in] cs ControlSerializer
> > >   *
> > >   * This version of deserialize() (or the vector version) must be used if
> > > - * the object type \a T or its members contain FileDescriptor.
> > > + * the object type \a T or its members contain SharedFD.
> > >   *
> > >   * \a cs is only necessary if the object type \a T or its members contain
> > >   * ControlList or ControlInfoMap.
> > > @@ -189,7 +189,7 @@ namespace {
> > >  #define DEFINE_POD_SERIALIZER(type)					\
> > >  									\
> > >  template<>								\
> > > -std::tuple<std::vector<uint8_t>, std::vector<FileDescriptor>>		\
> > > +std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>		\
> > >  IPADataSerializer<type>::serialize(const type &data,			\
> > >  				  [[maybe_unused]] ControlSerializer *cs) \
> > >  {									\
> > > @@ -217,7 +217,7 @@ type IPADataSerializer<type>::deserialize(const std::vector<uint8_t> &data, \
> > >  									\
> > >  template<>								\
> > >  type IPADataSerializer<type>::deserialize(const std::vector<uint8_t> &data, \
> > > -					  [[maybe_unused]] const std::vector<FileDescriptor> &fds, \
> > > +					  [[maybe_unused]] const std::vector<SharedFD> &fds, \
> > >  					  ControlSerializer *cs)	\
> > >  {									\
> > >  	return deserialize(data.cbegin(), data.end(), cs);		\
> > > @@ -226,8 +226,8 @@ type IPADataSerializer<type>::deserialize(const std::vector<uint8_t> &data, \
> > >  template<>								\
> > >  type IPADataSerializer<type>::deserialize(std::vector<uint8_t>::const_iterator dataBegin, \
> > >  					  std::vector<uint8_t>::const_iterator dataEnd, \
> > > -					  [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsBegin, \
> > > -					  [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsEnd, \
> > > +					  [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsBegin, \
> > > +					  [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd, \
> > >  					  ControlSerializer *cs)	\
> > >  {									\
> > >  	return deserialize(dataBegin, dataEnd, cs);			\
> > > @@ -251,7 +251,7 @@ DEFINE_POD_SERIALIZER(double)
> > >   * function parameter serdes).
> > >   */
> > >  template<>
> > > -std::tuple<std::vector<uint8_t>, std::vector<FileDescriptor>>
> > > +std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
> > >  IPADataSerializer<std::string>::serialize(const std::string &data,
> > >  					  [[maybe_unused]] ControlSerializer *cs)
> > >  {
> > > @@ -278,7 +278,7 @@ IPADataSerializer<std::string>::deserialize(std::vector<uint8_t>::const_iterator
> > >  template<>
> > >  std::string
> > >  IPADataSerializer<std::string>::deserialize(const std::vector<uint8_t> &data,
> > > -					    [[maybe_unused]] const std::vector<FileDescriptor> &fds,
> > > +					    [[maybe_unused]] const std::vector<SharedFD> &fds,
> > >  					    [[maybe_unused]] ControlSerializer *cs)
> > >  {
> > >  	return { data.cbegin(), data.cend() };
> > > @@ -288,8 +288,8 @@ template<>
> > >  std::string
> > >  IPADataSerializer<std::string>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
> > >  					    std::vector<uint8_t>::const_iterator dataEnd,
> > > -					    [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > -					    [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > +					    [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsBegin,
> > > +					    [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
> > >  					    [[maybe_unused]] ControlSerializer *cs)
> > >  {
> > >  	return { dataBegin, dataEnd };
> > > @@ -307,7 +307,7 @@ IPADataSerializer<std::string>::deserialize(std::vector<uint8_t>::const_iterator
> > >   * be used. The serialized ControlInfoMap will have zero length.
> > >   */
> > >  template<>
> > > -std::tuple<std::vector<uint8_t>, std::vector<FileDescriptor>>
> > > +std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
> > >  IPADataSerializer<ControlList>::serialize(const ControlList &data, ControlSerializer *cs)
> > >  {
> > >  	if (!cs)
> > > @@ -407,7 +407,7 @@ IPADataSerializer<ControlList>::deserialize(const std::vector<uint8_t> &data,
> > >  template<>
> > >  ControlList
> > >  IPADataSerializer<ControlList>::deserialize(const std::vector<uint8_t> &data,
> > > -					    [[maybe_unused]] const std::vector<FileDescriptor> &fds,
> > > +					    [[maybe_unused]] const std::vector<SharedFD> &fds,
> > >  					    ControlSerializer *cs)
> > >  {
> > >  	return deserialize(data.cbegin(), data.end(), cs);
> > > @@ -417,8 +417,8 @@ template<>
> > >  ControlList
> > >  IPADataSerializer<ControlList>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
> > >  					    std::vector<uint8_t>::const_iterator dataEnd,
> > > -					    [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > -					    [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > +					    [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsBegin,
> > > +					    [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
> > >  					    ControlSerializer *cs)
> > >  {
> > >  	return deserialize(dataBegin, dataEnd, cs);
> > > @@ -431,7 +431,7 @@ IPADataSerializer<ControlList>::deserialize(std::vector<uint8_t>::const_iterator
> > >   * X bytes - Serialized ControlInfoMap (using ControlSerializer)
> > >   */
> > >  template<>
> > > -std::tuple<std::vector<uint8_t>, std::vector<FileDescriptor>>
> > > +std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
> > >  IPADataSerializer<ControlInfoMap>::serialize(const ControlInfoMap &map,
> > >  					     ControlSerializer *cs)
> > >  {
> > > @@ -493,7 +493,7 @@ IPADataSerializer<ControlInfoMap>::deserialize(const std::vector<uint8_t> &data,
> > >  template<>
> > >  ControlInfoMap
> > >  IPADataSerializer<ControlInfoMap>::deserialize(const std::vector<uint8_t> &data,
> > > -					       [[maybe_unused]] const std::vector<FileDescriptor> &fds,
> > > +					       [[maybe_unused]] const std::vector<SharedFD> &fds,
> > >  					       ControlSerializer *cs)
> > >  {
> > >  	return deserialize(data.cbegin(), data.end(), cs);
> > > @@ -503,30 +503,30 @@ template<>
> > >  ControlInfoMap
> > >  IPADataSerializer<ControlInfoMap>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
> > >  					       std::vector<uint8_t>::const_iterator dataEnd,
> > > -					       [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > -					       [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > +					       [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsBegin,
> > > +					       [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
> > >  					       ControlSerializer *cs)
> > >  {
> > >  	return deserialize(dataBegin, dataEnd, cs);
> > >  }
> > >
> > >  /*
> > > - * FileDescriptors are serialized into four bytes that tells if the
> > > - * FileDescriptor is valid or not. If it is valid, then for serialization
> > > - * the fd will be written to the fd vector, or for deserialization the
> > > - * fd vector const_iterator will be valid.
> > > + * SharedFD instances are serialized into four bytes that tells if the SharedFD
> > > + * is valid or not. If it is valid, then for serialization the fd will be
> > > + * written to the fd vector, or for deserialization the fd vector const_iterator
> > > + * will be valid.
> > >   *
> > >   * This validity is necessary so that we don't send -1 fd over sendmsg(). It
> > >   * also allows us to simply send the entire fd vector into the deserializer
> > >   * and it will be recursively consumed as necessary.
> > >   */
> > >  template<>
> > > -std::tuple<std::vector<uint8_t>, std::vector<FileDescriptor>>
> > > -IPADataSerializer<FileDescriptor>::serialize(const FileDescriptor &data,
> > > -					     [[maybe_unused]] ControlSerializer *cs)
> > > +std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
> > > +IPADataSerializer<SharedFD>::serialize(const SharedFD &data,
> > > +				       [[maybe_unused]] ControlSerializer *cs)
> > >  {
> > >  	std::vector<uint8_t> dataVec;
> > > -	std::vector<FileDescriptor> fdVec;
> > > +	std::vector<SharedFD> fdVec;
> > >
> > >  	/*
> > >  	 * Store as uint32_t to prepare for conversion from validity flag
> > > @@ -542,11 +542,11 @@ IPADataSerializer<FileDescriptor>::serialize(const FileDescriptor &data,
> > >  }
> > >
> > >  template<>
> > > -FileDescriptor IPADataSerializer<FileDescriptor>::deserialize([[maybe_unused]] std::vector<uint8_t>::const_iterator dataBegin,
> > > -							      [[maybe_unused]] std::vector<uint8_t>::const_iterator dataEnd,
> > > -							      std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > -							      std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > -							      [[maybe_unused]] ControlSerializer *cs)
> > > +SharedFD IPADataSerializer<SharedFD>::deserialize([[maybe_unused]] std::vector<uint8_t>::const_iterator dataBegin,
> > > +						  [[maybe_unused]] std::vector<uint8_t>::const_iterator dataEnd,
> > > +						  std::vector<SharedFD>::const_iterator fdsBegin,
> > > +						  std::vector<SharedFD>::const_iterator fdsEnd,
> > > +						  [[maybe_unused]] ControlSerializer *cs)
> > >  {
> > >  	ASSERT(std::distance(dataBegin, dataEnd) >= 4);
> > >
> > > @@ -554,13 +554,13 @@ FileDescriptor IPADataSerializer<FileDescriptor>::deserialize([[maybe_unused]] s
> > >
> > >  	ASSERT(!(valid && std::distance(fdsBegin, fdsEnd) < 1));
> > >
> > > -	return valid ? *fdsBegin : FileDescriptor();
> > > +	return valid ? *fdsBegin : SharedFD();
> > >  }
> > >
> > >  template<>
> > > -FileDescriptor IPADataSerializer<FileDescriptor>::deserialize(const std::vector<uint8_t> &data,
> > > -							      const std::vector<FileDescriptor> &fds,
> > > -							      [[maybe_unused]] ControlSerializer *cs)
> > > +SharedFD IPADataSerializer<SharedFD>::deserialize(const std::vector<uint8_t> &data,
> > > +						  const std::vector<SharedFD> &fds,
> > > +						  [[maybe_unused]] ControlSerializer *cs)
> > >  {
> > >  	return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end());
> > >  }
> > > @@ -568,22 +568,22 @@ FileDescriptor IPADataSerializer<FileDescriptor>::deserialize(const std::vector<
> > >  /*
> > >   * FrameBuffer::Plane is serialized as:
> > >   *
> > > - * 4 byte  - FileDescriptor
> > > + * 4 byte  - SharedFD
> > >   * 4 bytes - uint32_t Offset
> > >   * 4 bytes - uint32_t Length
> > >   */
> > >  template<>
> > > -std::tuple<std::vector<uint8_t>, std::vector<FileDescriptor>>
> > > +std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
> > >  IPADataSerializer<FrameBuffer::Plane>::serialize(const FrameBuffer::Plane &data,
> > >  						 [[maybe_unused]] ControlSerializer *cs)
> > >  {
> > >  	std::vector<uint8_t> dataVec;
> > > -	std::vector<FileDescriptor> fdsVec;
> > > +	std::vector<SharedFD> fdsVec;
> > >
> > >  	std::vector<uint8_t> fdBuf;
> > > -	std::vector<FileDescriptor> fdFds;
> > > +	std::vector<SharedFD> fdFds;
> > >  	std::tie(fdBuf, fdFds) =
> > > -		IPADataSerializer<FileDescriptor>::serialize(data.fd);
> > > +		IPADataSerializer<SharedFD>::serialize(data.fd);
> > >  	dataVec.insert(dataVec.end(), fdBuf.begin(), fdBuf.end());
> > >  	fdsVec.insert(fdsVec.end(), fdFds.begin(), fdFds.end());
> > >
> > > @@ -597,13 +597,13 @@ template<>
> > >  FrameBuffer::Plane
> > >  IPADataSerializer<FrameBuffer::Plane>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
> > >  						   std::vector<uint8_t>::const_iterator dataEnd,
> > > -						   std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > -						   [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > +						   std::vector<SharedFD>::const_iterator fdsBegin,
> > > +						   [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
> > >  						   [[maybe_unused]] ControlSerializer *cs)
> > >  {
> > >  	FrameBuffer::Plane ret;
> > >
> > > -	ret.fd = IPADataSerializer<FileDescriptor>::deserialize(dataBegin, dataBegin + 4,
> > > +	ret.fd = IPADataSerializer<SharedFD>::deserialize(dataBegin, dataBegin + 4,
> > >  								fdsBegin, fdsBegin + 1);
> > >  	ret.offset = readPOD<uint32_t>(dataBegin, 4, dataEnd);
> > >  	ret.length = readPOD<uint32_t>(dataBegin, 8, dataEnd);
> > > @@ -614,7 +614,7 @@ IPADataSerializer<FrameBuffer::Plane>::deserialize(std::vector<uint8_t>::const_i
> > >  template<>
> > >  FrameBuffer::Plane
> > >  IPADataSerializer<FrameBuffer::Plane>::deserialize(const std::vector<uint8_t> &data,
> > > -						   const std::vector<FileDescriptor> &fds,
> > > +						   const std::vector<SharedFD> &fds,
> > >  						   ControlSerializer *cs)
> > >  {
> > >  	return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end(), cs);
> > > diff --git a/src/libcamera/ipc_pipe.cpp b/src/libcamera/ipc_pipe.cpp
> > > index ad870fd4137f..3b47032de0a2 100644
> > > --- a/src/libcamera/ipc_pipe.cpp
> > > +++ b/src/libcamera/ipc_pipe.cpp
> > > @@ -87,7 +87,7 @@ IPCMessage::IPCMessage(IPCUnixSocket::Payload &payload)
> > >  	data_ = std::vector<uint8_t>(payload.data.begin() + sizeof(header_),
> > >  				     payload.data.end());
> > >  	for (int32_t &fd : payload.fds)
> > > -		fds_.push_back(FileDescriptor(std::move(fd)));
> > > +		fds_.push_back(SharedFD(std::move(fd)));
> > >  }
> > >
> > >  /**
> > > @@ -112,7 +112,7 @@ IPCUnixSocket::Payload IPCMessage::payload() const
> > >  		       data_.data(), data_.size());
> > >  	}
> > >
> > > -	for (const FileDescriptor &fd : fds_)
> > > +	for (const SharedFD &fd : fds_)
> > >  		payload.fds.push_back(fd.fd());
> > >
> > >  	return payload;
> > > diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > > index ffa51a0c65ca..ea8243912a29 100644
> > > --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > > +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > > @@ -12,7 +12,7 @@
> > >  #include <queue>
> > >  #include <unordered_set>
> > >
> > > -#include <libcamera/base/file_descriptor.h>
> > > +#include <libcamera/base/shared_fd.h>
> > >
> > >  #include <libcamera/camera.h>
> > >  #include <libcamera/control_ids.h>
> > > @@ -228,7 +228,7 @@ public:
> > >
> > >  	/* DMAHEAP allocation helper. */
> > >  	RPi::DmaHeap dmaHeap_;
> > > -	FileDescriptor lsTable_;
> > > +	SharedFD lsTable_;
> > >
> > >  	std::unique_ptr<DelayedControls> delayedCtrls_;
> > >  	bool sensorMetadata_;
> > > @@ -1365,7 +1365,7 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)
> > >  		if (!fd.isValid())
> > >  			return -ENOMEM;
> > >
> > > -		lsTable_ = FileDescriptor(std::move(fd));
> > > +		lsTable_ = SharedFD(std::move(fd));
> > >
> > >  		/* Allow the IPA to mmap the LS table via the file descriptor. */
> > >  		/*
> > > diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
> > > index 3966483a365f..97d431071def 100644
> > > --- a/src/libcamera/v4l2_videodevice.cpp
> > > +++ b/src/libcamera/v4l2_videodevice.cpp
> > > @@ -22,8 +22,8 @@
> > >  #include <linux/version.h>
> > >
> > >  #include <libcamera/base/event_notifier.h>
> > > -#include <libcamera/base/file_descriptor.h>
> > >  #include <libcamera/base/log.h>
> > > +#include <libcamera/base/shared_fd.h>
> > >  #include <libcamera/base/unique_fd.h>
> > >  #include <libcamera/base/utils.h>
> > >
> > > @@ -1325,7 +1325,7 @@ std::unique_ptr<FrameBuffer> V4L2VideoDevice::createBuffer(unsigned int index)
> > >  			return nullptr;
> > >
> > >  		FrameBuffer::Plane plane;
> > > -		plane.fd = FileDescriptor(std::move(fd));
> > > +		plane.fd = SharedFD(std::move(fd));
> > >  		/*
> > >  		 * V4L2 API doesn't provide dmabuf offset information of plane.
> > >  		 * Set 0 as a placeholder offset.
> > > @@ -1354,7 +1354,7 @@ std::unique_ptr<FrameBuffer> V4L2VideoDevice::createBuffer(unsigned int index)
> > >  		ASSERT(numPlanes == 1u);
> > >
> > >  		planes.resize(formatInfo_->numPlanes());
> > > -		const FileDescriptor &fd = planes[0].fd;
> > > +		const SharedFD &fd = planes[0].fd;
> > >  		size_t offset = 0;
> > >
> > >  		for (auto [i, plane] : utils::enumerate(planes)) {
> > > diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h
> > > index 9817fd393d59..586347829845 100644
> > > --- a/src/v4l2/v4l2_camera.h
> > > +++ b/src/v4l2/v4l2_camera.h
> > > @@ -11,8 +11,8 @@
> > >  #include <mutex>
> > >  #include <utility>
> > >
> > > -#include <libcamera/base/file_descriptor.h>
> > >  #include <libcamera/base/semaphore.h>
> > > +#include <libcamera/base/shared_fd.h>
> > >
> > >  #include <libcamera/camera.h>
> > >  #include <libcamera/framebuffer.h>
> > > diff --git a/test/meson.build b/test/meson.build
> > > index 42dfbc1f8ee9..daaa3862cdd6 100644
> > > --- a/test/meson.build
> > > +++ b/test/meson.build
> > > @@ -40,7 +40,6 @@ internal_tests = [
> > >      ['event-dispatcher',                'event-dispatcher.cpp'],
> > >      ['event-thread',                    'event-thread.cpp'],
> > >      ['file',                            'file.cpp'],
> > > -    ['file-descriptor',                 'file-descriptor.cpp'],
> > >      ['flags',                           'flags.cpp'],
> > >      ['hotplug-cameras',                 'hotplug-cameras.cpp'],
> > >      ['mapped-buffer',                   'mapped-buffer.cpp'],
> > > @@ -49,6 +48,7 @@ internal_tests = [
> > >      ['object-delete',                   'object-delete.cpp'],
> > >      ['object-invoke',                   'object-invoke.cpp'],
> > >      ['pixel-format',                    'pixel-format.cpp'],
> > > +    ['shared-fd',                       'shared-fd.cpp'],
> > >      ['signal-threads',                  'signal-threads.cpp'],
> > >      ['threads',                         'threads.cpp'],
> > >      ['timer',                           'timer.cpp'],
> > > diff --git a/test/serialization/ipa_data_serializer_test.cpp b/test/serialization/ipa_data_serializer_test.cpp
> > > index 5fcdcb8eae92..d2050a868b38 100644
> > > --- a/test/serialization/ipa_data_serializer_test.cpp
> > > +++ b/test/serialization/ipa_data_serializer_test.cpp
> > > @@ -53,7 +53,7 @@ template<typename T>
> > >  int testPodSerdes(T in)
> > >  {
> > >  	std::vector<uint8_t> buf;
> > > -	std::vector<FileDescriptor> fds;
> > > +	std::vector<SharedFD> fds;
> > >
> > >  	std::tie(buf, fds) = IPADataSerializer<T>::serialize(in);
> > >  	T out = IPADataSerializer<T>::deserialize(buf, fds);
> > > @@ -72,7 +72,7 @@ int testVectorSerdes(const std::vector<T> &in,
> > >  		     ControlSerializer *cs = nullptr)
> > >  {
> > >  	std::vector<uint8_t> buf;
> > > -	std::vector<FileDescriptor> fds;
> > > +	std::vector<SharedFD> fds;
> > >
> > >  	std::tie(buf, fds) = IPADataSerializer<std::vector<T>>::serialize(in, cs);
> > >  	std::vector<T> out = IPADataSerializer<std::vector<T>>::deserialize(buf, fds, cs);
> > > @@ -92,7 +92,7 @@ int testMapSerdes(const std::map<K, V> &in,
> > >  		  ControlSerializer *cs = nullptr)
> > >  {
> > >  	std::vector<uint8_t> buf;
> > > -	std::vector<FileDescriptor> fds;
> > > +	std::vector<SharedFD> fds;
> > >
> > >  	std::tie(buf, fds) = IPADataSerializer<std::map<K, V>>::serialize(in, cs);
> > >  	std::map<K, V> out = IPADataSerializer<std::map<K, V>>::deserialize(buf, fds, cs);
> > > @@ -198,7 +198,7 @@ private:
> > >  		ControlSerializer cs(ControlSerializer::Role::Proxy);
> > >
> > >  		/*
> > > -		 * We don't test FileDescriptor serdes because it dup()s, so we
> > > +		 * We don't test SharedFD serdes because it dup()s, so we
> > >  		 * can't check for equality.
> > >  		 */
> > >  		std::vector<uint8_t>  vecUint8  = { 1, 2, 3, 4, 5, 6 };
> > > @@ -219,7 +219,7 @@ private:
> > >  		};
> > >
> > >  		std::vector<uint8_t> buf;
> > > -		std::vector<FileDescriptor> fds;
> > > +		std::vector<SharedFD> fds;
> > >
> > >  		if (testVectorSerdes(vecUint8) != TestPass)
> > >  			return TestFail;
> > > @@ -291,7 +291,7 @@ private:
> > >  			{ { "a", { 1, 2, 3 } }, { "b", { 4, 5, 6 } }, { "c", { 7, 8, 9 } } };
> > >
> > >  		std::vector<uint8_t> buf;
> > > -		std::vector<FileDescriptor> fds;
> > > +		std::vector<SharedFD> fds;
> > >
> > >  		if (testMapSerdes(mapUintStr) != TestPass)
> > >  			return TestFail;
> > > @@ -359,7 +359,7 @@ private:
> > >  		std::string strEmpty = "";
> > >
> > >  		std::vector<uint8_t> buf;
> > > -		std::vector<FileDescriptor> fds;
> > > +		std::vector<SharedFD> fds;
> > >
> > >  		if (testPodSerdes(u32min) != TestPass)
> > >  			return TestFail;
> > > diff --git a/test/file-descriptor.cpp b/test/shared-fd.cpp
> > > similarity index 80%
> > > rename from test/file-descriptor.cpp
> > > rename to test/shared-fd.cpp
> > > index 76badc4c5fad..60e5d0aaa395 100644
> > > --- a/test/file-descriptor.cpp
> > > +++ b/test/shared-fd.cpp
> > > @@ -2,7 +2,7 @@
> > >  /*
> > >   * Copyright (C) 2019, Google Inc.
> > >   *
> > > - * file_descriptor.cpp - FileDescriptor test
> > > + * shared_fd.cpp - SharedFD test
> > >   */
> > >
> > >  #include <fcntl.h>
> > > @@ -11,7 +11,7 @@
> > >  #include <sys/types.h>
> > >  #include <unistd.h>
> > >
> > > -#include <libcamera/base/file_descriptor.h>
> > > +#include <libcamera/base/shared_fd.h>
> > >  #include <libcamera/base/utils.h>
> > >
> > >  #include "test.h"
> > > @@ -19,7 +19,7 @@
> > >  using namespace libcamera;
> > >  using namespace std;
> > >
> > > -class FileDescriptorTest : public Test
> > > +class SharedFDTest : public Test
> > >  {
> > >  protected:
> > >  	int init()
> > > @@ -43,8 +43,8 @@ protected:
> > >
> > >  	int run()
> > >  	{
> > > -		/* Test creating empty FileDescriptor. */
> > > -		desc1_ = new FileDescriptor();
> > > +		/* Test creating empty SharedFD. */
> > > +		desc1_ = new SharedFD();
> > >
> > >  		if (desc1_->fd() != -1) {
> > >  			std::cout << "Failed fd numerical check (default constructor)"
> > > @@ -56,10 +56,10 @@ protected:
> > >  		desc1_ = nullptr;
> > >
> > >  		/*
> > > -		 * Test creating FileDescriptor by copying numerical file
> > > +		 * Test creating SharedFD by copying numerical file
> > >  		 * descriptor.
> > >  		 */
> > > -		desc1_ = new FileDescriptor(fd_);
> > > +		desc1_ = new SharedFD(fd_);
> > >  		if (desc1_->fd() == fd_) {
> > >  			std::cout << "Failed fd numerical check (lvalue ref constructor)"
> > >  				  << std::endl;
> > > @@ -84,13 +84,13 @@ protected:
> > >  		}
> > >
> > >  		/*
> > > -		 * Test creating FileDescriptor by taking ownership of
> > > +		 * Test creating SharedFD by taking ownership of
> > >  		 * numerical file descriptor.
> > >  		 */
> > >  		int dupFd = dup(fd_);
> > >  		int dupFdCopy = dupFd;
> > >
> > > -		desc1_ = new FileDescriptor(std::move(dupFd));
> > > +		desc1_ = new SharedFD(std::move(dupFd));
> > >  		if (desc1_->fd() != dupFdCopy) {
> > >  			std::cout << "Failed fd numerical check (rvalue ref constructor)"
> > >  				  << std::endl;
> > > @@ -114,9 +114,9 @@ protected:
> > >  			return TestFail;
> > >  		}
> > >
> > > -		/* Test creating FileDescriptor from other FileDescriptor. */
> > > -		desc1_ = new FileDescriptor(fd_);
> > > -		desc2_ = new FileDescriptor(*desc1_);
> > > +		/* Test creating SharedFD from other SharedFD. */
> > > +		desc1_ = new SharedFD(fd_);
> > > +		desc2_ = new SharedFD(*desc1_);
> > >
> > >  		if (desc1_->fd() == fd_ || desc2_->fd() == fd_ || desc1_->fd() != desc2_->fd()) {
> > >  			std::cout << "Failed fd numerical check (copy constructor)"
> > > @@ -142,10 +142,10 @@ protected:
> > >  		delete desc2_;
> > >  		desc2_ = nullptr;
> > >
> > > -		/* Test creating FileDescriptor by taking over other FileDescriptor. */
> > > -		desc1_ = new FileDescriptor(fd_);
> > > +		/* Test creating SharedFD by taking over other SharedFD. */
> > > +		desc1_ = new SharedFD(fd_);
> > >  		fd = desc1_->fd();
> > > -		desc2_ = new FileDescriptor(std::move(*desc1_));
> > > +		desc2_ = new SharedFD(std::move(*desc1_));
> > >
> > >  		if (desc1_->fd() != -1 || desc2_->fd() != fd) {
> > >  			std::cout << "Failed fd numerical check (move constructor)"
> > > @@ -164,9 +164,9 @@ protected:
> > >  		delete desc2_;
> > >  		desc2_ = nullptr;
> > >
> > > -		/* Test creating FileDescriptor by copy assignment. */
> > > -		desc1_ = new FileDescriptor();
> > > -		desc2_ = new FileDescriptor(fd_);
> > > +		/* Test creating SharedFD by copy assignment. */
> > > +		desc1_ = new SharedFD();
> > > +		desc2_ = new SharedFD(fd_);
> > >
> > >  		fd = desc2_->fd();
> > >  		*desc1_ = *desc2_;
> > > @@ -188,9 +188,9 @@ protected:
> > >  		delete desc2_;
> > >  		desc2_ = nullptr;
> > >
> > > -		/* Test creating FileDescriptor by move assignment. */
> > > -		desc1_ = new FileDescriptor();
> > > -		desc2_ = new FileDescriptor(fd_);
> > > +		/* Test creating SharedFD by move assignment. */
> > > +		desc1_ = new SharedFD();
> > > +		desc2_ = new SharedFD(fd_);
> > >
> > >  		fd = desc2_->fd();
> > >  		*desc1_ = std::move(*desc2_);
> > > @@ -237,7 +237,7 @@ private:
> > >
> > >  	int fd_;
> > >  	ino_t inodeNr_;
> > > -	FileDescriptor *desc1_, *desc2_;
> > > +	SharedFD *desc1_, *desc2_;
> > >  };
> > >
> > > -TEST_REGISTER(FileDescriptorTest)
> > > +TEST_REGISTER(SharedFDTest)
> > > diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl b/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
> > > index d856339aa9ee..c37c4941b528 100644
> > > --- a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
> > > +++ b/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
> > > @@ -237,7 +237,7 @@ void {{proxy_name}}::recvMessage(const IPCMessage &data)
> > >  void {{proxy_name}}::{{method.mojom_name}}IPC(
> > >  	std::vector<uint8_t>::const_iterator data,
> > >  	size_t dataSize,
> > > -	[[maybe_unused]] const std::vector<FileDescriptor> &fds)
> > > +	[[maybe_unused]] const std::vector<SharedFD> &fds)
> > >  {
> > >  {%- for param in method.parameters %}
> > >  	{{param|name}} {{param.mojom_name}};
> > > diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl b/utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl
> > > index ce396c183d0c..c308dd10c7e5 100644
> > > --- a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl
> > > +++ b/utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl
> > > @@ -64,7 +64,7 @@ private:
> > >  	void {{method.mojom_name}}IPC(
> > >  		std::vector<uint8_t>::const_iterator data,
> > >  		size_t dataSize,
> > > -		const std::vector<FileDescriptor> &fds);
> > > +		const std::vector<SharedFD> &fds);
> > >  {% endfor %}
> > >
> > >  	/* Helper class to invoke async functions in another thread. */
> > > diff --git a/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl b/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl
> > > index ebcd2aaaafae..bac826a74c2d 100644
> > > --- a/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl
> > > +++ b/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl
> > > @@ -54,7 +54,7 @@
> > >  {%- for param in params %}
> > >  	std::vector<uint8_t> {{param.mojom_name}}Buf;
> > >  {%- if param|has_fd %}
> > > -	std::vector<FileDescriptor> {{param.mojom_name}}Fds;
> > > +	std::vector<SharedFD> {{param.mojom_name}}Fds;
> > >  	std::tie({{param.mojom_name}}Buf, {{param.mojom_name}}Fds) =
> > >  {%- else %}
> > >  	std::tie({{param.mojom_name}}Buf, std::ignore) =
> > > diff --git a/utils/ipc/generators/libcamera_templates/serializer.tmpl b/utils/ipc/generators/libcamera_templates/serializer.tmpl
> > > index b8ef8e7b974e..77bae36fe6b7 100644
> > > --- a/utils/ipc/generators/libcamera_templates/serializer.tmpl
> > > +++ b/utils/ipc/generators/libcamera_templates/serializer.tmpl
> > > @@ -40,7 +40,7 @@
> > >  		retData.insert(retData.end(), {{field.mojom_name}}.begin(), {{field.mojom_name}}.end());
> > >  {%- elif field|is_fd %}
> > >  		std::vector<uint8_t> {{field.mojom_name}};
> > > -		std::vector<FileDescriptor> {{field.mojom_name}}Fds;
> > > +		std::vector<SharedFD> {{field.mojom_name}}Fds;
> > >  		std::tie({{field.mojom_name}}, {{field.mojom_name}}Fds) =
> > >  			IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}});
> > >  		retData.insert(retData.end(), {{field.mojom_name}}.begin(), {{field.mojom_name}}.end());
> > > @@ -58,7 +58,7 @@
> > >  {%- elif field|is_plain_struct or field|is_array or field|is_map or field|is_str %}
> > >  		std::vector<uint8_t> {{field.mojom_name}};
> > >  	{%- if field|has_fd %}
> > > -		std::vector<FileDescriptor> {{field.mojom_name}}Fds;
> > > +		std::vector<SharedFD> {{field.mojom_name}}Fds;
> > >  		std::tie({{field.mojom_name}}, {{field.mojom_name}}Fds) =
> > >  	{%- else %}
> > >  		std::tie({{field.mojom_name}}, std::ignore) =
> > > @@ -177,7 +177,7 @@
> > >   # \a struct.
> > >   #}
> > >  {%- macro serializer(struct, namespace) %}
> > > -	static std::tuple<std::vector<uint8_t>, std::vector<FileDescriptor>>
> > > +	static std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
> > >  	serialize(const {{struct|name_full}} &data,
> > >  {%- if struct|needs_control_serializer %}
> > >  		  ControlSerializer *cs)
> > > @@ -187,7 +187,7 @@
> > >  	{
> > >  		std::vector<uint8_t> retData;
> > >  {%- if struct|has_fd %}
> > > -		std::vector<FileDescriptor> retFds;
> > > +		std::vector<SharedFD> retFds;
> > >  {%- endif %}
> > >  {%- for field in struct.fields %}
> > >  {{serializer_field(field, namespace, loop)}}
> > > @@ -210,7 +210,7 @@
> > >  {%- macro deserializer_fd(struct, namespace) %}
> > >  	static {{struct|name_full}}
> > >  	deserialize(std::vector<uint8_t> &data,
> > > -		    std::vector<FileDescriptor> &fds,
> > > +		    std::vector<SharedFD> &fds,
> > >  {%- if struct|needs_control_serializer %}
> > >  		    ControlSerializer *cs)
> > >  {%- else %}
> > > @@ -224,8 +224,8 @@
> > >  	static {{struct|name_full}}
> > >  	deserialize(std::vector<uint8_t>::const_iterator dataBegin,
> > >  		    std::vector<uint8_t>::const_iterator dataEnd,
> > > -		    std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > -		    std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > +		    std::vector<SharedFD>::const_iterator fdsBegin,
> > > +		    std::vector<SharedFD>::const_iterator fdsEnd,
> > >  {%- if struct|needs_control_serializer %}
> > >  		    ControlSerializer *cs)
> > >  {%- else %}
> > > @@ -234,7 +234,7 @@
> > >  	{
> > >  		{{struct|name_full}} ret;
> > >  		std::vector<uint8_t>::const_iterator m = dataBegin;
> > > -		std::vector<FileDescriptor>::const_iterator n = fdsBegin;
> > > +		std::vector<SharedFD>::const_iterator n = fdsBegin;
> > >
> > >  		size_t dataSize = std::distance(dataBegin, dataEnd);
> > >  		[[maybe_unused]] size_t fdsSize = std::distance(fdsBegin, fdsEnd);
> > > @@ -255,7 +255,7 @@
> > >  {%- macro deserializer_fd_simple(struct, namespace) %}
> > >  	static {{struct|name_full}}
> > >  	deserialize(std::vector<uint8_t> &data,
> > > -		    [[maybe_unused]] std::vector<FileDescriptor> &fds,
> > > +		    [[maybe_unused]] std::vector<SharedFD> &fds,
> > >  		    ControlSerializer *cs = nullptr)
> > >  	{
> > >  		return IPADataSerializer<{{struct|name_full}}>::deserialize(data.cbegin(), data.cend(), cs);
> > > @@ -264,8 +264,8 @@
> > >  	static {{struct|name_full}}
> > >  	deserialize(std::vector<uint8_t>::const_iterator dataBegin,
> > >  		    std::vector<uint8_t>::const_iterator dataEnd,
> > > -		    [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsBegin,
> > > -		    [[maybe_unused]] std::vector<FileDescriptor>::const_iterator fdsEnd,
> > > +		    [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsBegin,
> > > +		    [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
> > >  		    ControlSerializer *cs = nullptr)
> > >  	{
> > >  		return IPADataSerializer<{{struct|name_full}}>::deserialize(dataBegin, dataEnd, cs);
> > > diff --git a/utils/ipc/generators/mojom_libcamera_generator.py b/utils/ipc/generators/mojom_libcamera_generator.py
> > > index c609f4e5c062..753bfc734e56 100644
> > > --- a/utils/ipc/generators/mojom_libcamera_generator.py
> > > +++ b/utils/ipc/generators/mojom_libcamera_generator.py
> > > @@ -77,7 +77,7 @@ def GetDefaultValue(element):
> > >      if mojom.IsEnumKind(element.kind):
> > >          return f'static_cast<{element.kind.mojom_name}>(0)'
> > >      if isinstance(element.kind, mojom.Struct) and \
> > > -       element.kind.mojom_name == 'FileDescriptor':
> > > +       element.kind.mojom_name == 'SharedFD':
> > >          return '-1'
> > >      return ''
> > >
> > > @@ -140,7 +140,7 @@ def HasFd(element):
> > >          types = GetAllTypes(element)
> > >      else:
> > >          types = GetAllTypes(element.kind)
> > > -    return "FileDescriptor" in types or (attrs is not None and "hasFd" in attrs)
> > > +    return "SharedFD" in types or (attrs is not None and "hasFd" in attrs)
> > >
> > >  def WithDefaultValues(element):
> > >      return [x for x in element if HasDefaultValue(x)]
> > > @@ -221,7 +221,7 @@ def IsEnum(element):
> > >      return mojom.IsEnumKind(element.kind)
> > >
> > >  def IsFd(element):
> > > -    return mojom.IsStructKind(element.kind) and element.kind.mojom_name == "FileDescriptor"
> > > +    return mojom.IsStructKind(element.kind) and element.kind.mojom_name == "SharedFD"
> > >
> > >  def IsMap(element):
> > >      return mojom.IsMapKind(element.kind)
>
> --
> Regards,
>
> Laurent Pinchart


More information about the libcamera-devel mailing list