[libcamera-devel,v2,01/10] libcamera: ScopedFD: Introduce ScopedFD
diff mbox series

Message ID 20210610075027.523672-2-hiroh@chromium.org
State Superseded
Headers show
Series
  • Introduce ScopedFD
Related show

Commit Message

Hirokazu Honda June 10, 2021, 7:50 a.m. UTC
This introduces ScopedFD. It acts like unique_ptr to a file
descriptor.

Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
---
 include/libcamera/file_descriptor.h |   3 +
 include/libcamera/meson.build       |   1 +
 include/libcamera/scoped_fd.h       |  36 ++++++++
 src/libcamera/file_descriptor.cpp   |  20 +++++
 src/libcamera/meson.build           |   1 +
 src/libcamera/scoped_fd.cpp         | 129 ++++++++++++++++++++++++++++
 6 files changed, 190 insertions(+)
 create mode 100644 include/libcamera/scoped_fd.h
 create mode 100644 src/libcamera/scoped_fd.cpp

Patch
diff mbox series

diff --git a/include/libcamera/file_descriptor.h b/include/libcamera/file_descriptor.h
index d514aac7..1d71d58c 100644
--- a/include/libcamera/file_descriptor.h
+++ b/include/libcamera/file_descriptor.h
@@ -11,11 +11,14 @@ 
 
 namespace libcamera {
 
+class ScopedFD;
+
 class FileDescriptor final
 {
 public:
 	explicit FileDescriptor(const int &fd = -1);
 	explicit FileDescriptor(int &&fd);
+	explicit FileDescriptor(ScopedFD &&fd);
 	FileDescriptor(const FileDescriptor &other);
 	FileDescriptor(FileDescriptor &&other);
 	~FileDescriptor();
diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
index 086c958b..e1c8b253 100644
--- a/include/libcamera/meson.build
+++ b/include/libcamera/meson.build
@@ -15,6 +15,7 @@  libcamera_public_headers = files([
     'object.h',
     'pixel_format.h',
     'request.h',
+    'scoped_fd.h',
     'signal.h',
     'span.h',
     'stream.h',
diff --git a/include/libcamera/scoped_fd.h b/include/libcamera/scoped_fd.h
new file mode 100644
index 00000000..d91b53b4
--- /dev/null
+++ b/include/libcamera/scoped_fd.h
@@ -0,0 +1,36 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021, Google Inc.
+ *
+ * scoped_fd.h - File descriptor wrapper that owns a file descriptor.
+ */
+#ifndef __LIBCAMERA_SCOPED_FD_H__
+#define __LIBCAMERA_SCOPED_FD_H__
+
+#include <libcamera/class.h>
+#include <libcamera/compiler.h>
+
+namespace libcamera {
+
+class ScopedFD final
+{
+public:
+	explicit ScopedFD(const int fd = -1);
+	~ScopedFD();
+	ScopedFD(ScopedFD &&other);
+	ScopedFD &operator=(ScopedFD &&other);
+
+	bool isValid() const { return fd_ == -1; }
+	int get() const { return fd_; }
+	void reset(int fd = -1);
+	__nodiscard int release();
+
+private:
+	int fd_;
+
+	LIBCAMERA_DISABLE_COPY(ScopedFD)
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_SCOPED_FD_H__ */
diff --git a/src/libcamera/file_descriptor.cpp b/src/libcamera/file_descriptor.cpp
index 8b505ed3..4d30b757 100644
--- a/src/libcamera/file_descriptor.cpp
+++ b/src/libcamera/file_descriptor.cpp
@@ -11,6 +11,8 @@ 
 #include <unistd.h>
 #include <utility>
 
+#include <libcamera/scoped_fd.h>
+
 #include "libcamera/internal/log.h"
 
 /**
@@ -108,6 +110,24 @@  FileDescriptor::FileDescriptor(int &&fd)
 	fd = -1;
 }
 
+/**
+ * \brief Create a FileDescriptor taking ownership of a given ScopedFD \a fd
+ * \param[in] fd ScopedFD
+ *
+ * Construct a FileDescriptor from ScopedFD by taking ownership of the \a fd.
+ * The original \a fd becomes invalid. 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() method will return -1.
+ */
+FileDescriptor::FileDescriptor(ScopedFD &&fd)
+	: FileDescriptor(fd.release())
+{
+}
+
 /**
  * \brief Copy constructor, create a FileDescriptor from a copy of \a other
  * \param[in] other The other FileDescriptor
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 7e19a177..ed311acf 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -44,6 +44,7 @@  libcamera_sources = files([
     'process.cpp',
     'pub_key.cpp',
     'request.cpp',
+    'scoped_fd.cpp',
     'semaphore.cpp',
     'signal.cpp',
     'stream.cpp',
diff --git a/src/libcamera/scoped_fd.cpp b/src/libcamera/scoped_fd.cpp
new file mode 100644
index 00000000..106386dd
--- /dev/null
+++ b/src/libcamera/scoped_fd.cpp
@@ -0,0 +1,129 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021, Google Inc.
+ *
+ * scoped_fd.cpp - File descriptor wrapper that owns a file descriptor.
+ */
+
+#include <libcamera/scoped_fd.h>
+
+#include <unistd.h>
+
+#include "libcamera/internal/log.h"
+
+/**
+ * \file scoped_fd.h
+ * \brief File descriptor wrapper that owns a file descriptor
+ */
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(ScopedFD)
+
+/**
+ * \class ScopedFD
+ * \brief unique_ptr like wrapper for a file descriptor
+ *
+ * The ScopedFD provides RAII-style lifetime management of a file descriptor.
+ * It doesn't allow the shared ownership unlike FileDescriptor. It is
+ * constructed from a numerical file descriptor and takes over the ownership of
+ * the file descriptor. When the ScopedFD is destroyed, the managed file
+ * descriptor is closed.
+ */
+
+/**
+ * \brief Create a ScopedFD taking over a given \a fd
+ * \param[in] fd a numerical file descriptor
+ *
+ * Construct a ScopedFD from a numerical file descriptor and take ownership of
+ * the file descriptor. The given file descriptor is automatically closed when
+ * the ScopedFD is destructed.
+ */
+ScopedFD::ScopedFD(const int fd)
+	: fd_(fd >= 0 ? fd : -1)
+{
+}
+
+/**
+ * \brief Destroy the ScopedFD instance
+ *
+ * The owned file descriptor is automatically closed if it is valid.
+ */
+ScopedFD::~ScopedFD()
+{
+	reset();
+}
+
+/**
+ * \brief Move constructor, create a ScopedFD by taking over \a other
+ * \param[in] other The other ScopedFD
+ *
+ * Create a ScopedFD that takes the ownership of the file descriptor owned by \a
+ * other. Upon return, the \a other ScopedFD is invalid.
+ */
+ScopedFD::ScopedFD(ScopedFD &&other)
+	: fd_(other.release())
+{
+}
+
+/**
+ * \brief Move assignment operator, replace a ScopedFD by taking over \a other
+ * \param[in] other The other ScopedFD
+ *
+ * If this ScopedFD has a valid 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 ScopedFD
+ */
+ScopedFD &ScopedFD::operator=(ScopedFD &&other)
+{
+	reset(other.release());
+
+	return *this;
+}
+
+/**
+ * \fn ScopedFD::isValid()
+ * \brief Check if the ScopedFD has a valid file descriptor
+ * \return True if the ScopedFD has a valid file descriptor, false otherwise
+ */
+
+/**
+ * \fn ScopedFD::get()
+ * \brief Retrieve the numerical file descriptor
+ * \return The numerical file descriptor
+ */
+
+/**
+ * \fn ScopedFD::reset()
+ * \brief Swap the owned file descriptor with \a fd. The originally owned file
+ * descriptor is closed.
+ * \param[in] fd a numerical file descriptor
+ */
+void ScopedFD::reset(int fd)
+{
+	ASSERT(!isValid() || fd != fd_);
+	if (isValid())
+		close(fd_);
+	fd_ = fd;
+}
+
+/**
+ * \fn ScopedFD::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 the ScopedFD is
+ * invalid.
+ *
+ * \return The numerical file descriptor
+ */
+int ScopedFD::release()
+{
+	int fd = fd_;
+	fd_ = -1;
+	return fd;
+}
+} /* namespace libcamera */