1
0
Fork 0

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>
This commit is contained in:
Roman Stratiienko 2021-02-20 13:59:55 +02:00
parent 5128715b42
commit 0fade37afd
13 changed files with 156 additions and 178 deletions

111
utils/UniqueFd.h Normal file
View file

@ -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