drm_hwcomposer: Rework autofd
Motivation:
Current implementation of UniqueFd can be used in a different ways,
making analytical tracking of FD lifecycle much harder than it may be.
Keep this part clean is very important, since any wrong code may open
a hard-to-detect runtime bugs and fd leaks, which may accidentally slip
into the production.
Implementation:
1. Combine UniqueFd anf OutputFd into single class.
2. Reduce the API to be minimal and sufficient.
3. Document the API and use cases.
4. Move to utils/UniqueFd.h.
5. dup(fd) was replaced with fcntl(fd, F_DUPFD_CLOEXEC)) to
address clang-tidy findings. Find more information at [1]
[1]: https://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-dup.html
Signed-off-by: Roman Stratiienko <r.stratiienko@gmail.com>
diff --git a/utils/UniqueFd.h b/utils/UniqueFd.h
new file mode 100644
index 0000000..1a390ba
--- /dev/null
+++ b/utils/UniqueFd.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015, 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UNIQUEFD_H_
+#define UNIQUEFD_H_
+
+#include <unistd.h>
+
+#include <memory>
+
+namespace android {
+
+/*
+ * Using UniqueFd:
+ * 1. Create UniqueFd object:
+ * auto fd_obj = UniqueFd(open("SomeFile", xxx));
+ *
+ * 2. Check whether the fd_obj is empty:
+ * if (!fd_obj) { return -errno; }
+ *
+ * 3. Accessing the file descriptor:
+ * int ret = read(fd_obj.Get(), buf, buf_size);
+ *
+ * 4. Closing the file:
+ * FD will be closed once execution leaves fd_obj scope (on any return,
+ * exception, destruction of class/struct where object is member, etc.).
+ * User can also force closing the fd_obj by calling:
+ * fd_obj = UniqueFd();
+ * // fd is closed and fd_obj is empty now.
+ *
+ * 5. File descriptor may be transferred to the code, which will close it after
+ * using. This can be done in 2 ways:
+ * a. Duplicate the fd, in this case both fds should be closed separately:
+ * int out_fd = dup(fd_obj.Get();
+ * ...
+ * close(out_fd);
+ * b. Transfer ownership, use this method if you do not need the fd anymore.
+ * int out_fd = fd_obj.Release();
+ * // fd_obj is empty now.
+ * ...
+ * close(out_fd);
+ *
+ * 6. Transferring fd into another UniqueFD object:
+ * UniqueFd fd_obj_2 = std::move(fd_obj);
+ * // fd_obj empty now
+ */
+
+constexpr int kEmptyFd = -1;
+
+class UniqueFd {
+ public:
+ UniqueFd() = default;
+ explicit UniqueFd(int fd) : fd_(fd){};
+
+ auto Release [[nodiscard]] () -> int {
+ return std::exchange(fd_, kEmptyFd);
+ }
+
+ auto Get [[nodiscard]] () const -> int {
+ return fd_;
+ }
+
+ explicit operator bool() const {
+ return fd_ != kEmptyFd;
+ }
+
+ ~UniqueFd() {
+ Set(kEmptyFd);
+ }
+
+ /* Allow move semantics */
+ UniqueFd(UniqueFd &&rhs) noexcept {
+ Set(rhs.Release());
+ }
+
+ auto operator=(UniqueFd &&rhs) noexcept -> UniqueFd & {
+ Set(rhs.Release());
+ return *this;
+ }
+
+ /* Disable copy semantics */
+ UniqueFd(const UniqueFd &) = delete;
+ auto operator=(const UniqueFd &) = delete;
+
+ private:
+ void Set(int new_fd) {
+ if (fd_ != kEmptyFd) {
+ close(fd_);
+ }
+ fd_ = new_fd;
+ }
+
+ int fd_ = kEmptyFd;
+};
+
+} // namespace android
+
+#endif