From ff8bfecf03f196ac7d0a781e589b70d43307e8e5 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 20 Nov 2024 13:50:10 +0100 Subject: [PATCH] filedescriptor: implent a new FileDescriptor class makes you able to RAII the filedescriptor making it somewhat easier to not leak. --- include/hyprutils/utils/FileDescriptor.hpp | 33 ++++++++++ src/utils/FileDescriptor.cpp | 77 ++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 include/hyprutils/utils/FileDescriptor.hpp create mode 100644 src/utils/FileDescriptor.cpp diff --git a/include/hyprutils/utils/FileDescriptor.hpp b/include/hyprutils/utils/FileDescriptor.hpp new file mode 100644 index 0000000..c03aeab --- /dev/null +++ b/include/hyprutils/utils/FileDescriptor.hpp @@ -0,0 +1,33 @@ +#pragma once + +namespace Hyprutils { + namespace Utils { + class CFileDescriptor { + public: + CFileDescriptor() = default; + explicit CFileDescriptor(int fd); + CFileDescriptor(CFileDescriptor&&); + CFileDescriptor& operator=(CFileDescriptor&&); + ~CFileDescriptor(); + + bool operator==(const CFileDescriptor& rhs) const { + return m_fd == rhs.m_fd; + } + + bool isValid() const; + int get() const; + int take(); + void reset(); + CFileDescriptor duplicate() const; + + bool isReadable() const; + bool isClosed() const; + + static bool isReadable(int fd); + static bool isClosed(int fd); + + private: + int m_fd = -1; + }; + }; +}; diff --git a/src/utils/FileDescriptor.cpp b/src/utils/FileDescriptor.cpp new file mode 100644 index 0000000..145b02b --- /dev/null +++ b/src/utils/FileDescriptor.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include + +using namespace Hyprutils::Utils; + +CFileDescriptor::CFileDescriptor(int fd) : m_fd(fd) {} + +CFileDescriptor::CFileDescriptor(CFileDescriptor&& other) : m_fd(std::exchange(other.m_fd, -1)) {} + +CFileDescriptor& CFileDescriptor::operator=(CFileDescriptor&& other) { + if (this == &other) + return *this; + + reset(); + m_fd = std::exchange(other.m_fd, -1); + return *this; +} + +CFileDescriptor::~CFileDescriptor() { + reset(); +} + +bool CFileDescriptor::isValid() const { + return m_fd != -1; +} + +int CFileDescriptor::get() const { + return m_fd; +} + +int CFileDescriptor::take() { + return std::exchange(m_fd, -1); +} + +void CFileDescriptor::reset() { + if (m_fd != -1) { + close(m_fd); + m_fd = -1; + } +} + +CFileDescriptor CFileDescriptor::duplicate() const { + if (m_fd == -1) + return {}; + + return CFileDescriptor{fcntl(m_fd, F_DUPFD_CLOEXEC, 0)}; +} + +bool CFileDescriptor::isClosed() const { + return isClosed(m_fd); +} + +bool CFileDescriptor::isReadable() const { + return isReadable(m_fd); +} + +bool CFileDescriptor::isClosed(int fd) { + pollfd pfd = { + .fd = fd, + .events = POLLIN, + .revents = 0, + }; + + if (poll(&pfd, 1, 0) < 0) + return true; + + return pfd.revents & (POLLHUP | POLLERR); +} + +bool CFileDescriptor::isReadable(int fd) { + pollfd pfd = {.fd = fd, .events = POLLIN, .revents = 0}; + + return poll(&pfd, 1, 0) > 0 && (pfd.revents & POLLIN); +}