mirror of
https://github.com/hyprwm/hyprutils.git
synced 2024-12-22 11:59:48 +01:00
os: implent a new FileDescriptor class (#21)
makes you able to RAII the filedescriptor making it somewhat easier to not leak.
This commit is contained in:
parent
e911361a68
commit
2e21319c8e
4 changed files with 185 additions and 0 deletions
|
@ -86,6 +86,14 @@ add_test(
|
||||||
COMMAND hyprutils_os "os")
|
COMMAND hyprutils_os "os")
|
||||||
add_dependencies(tests hyprutils_os)
|
add_dependencies(tests hyprutils_os)
|
||||||
|
|
||||||
|
add_executable(hyprutils_filedescriptor "tests/filedescriptor.cpp")
|
||||||
|
target_link_libraries(hyprutils_filedescriptor PRIVATE hyprutils PkgConfig::deps)
|
||||||
|
add_test(
|
||||||
|
NAME "Filedescriptor"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
|
||||||
|
COMMAND hyprutils_filedescriptor "filedescriptor")
|
||||||
|
add_dependencies(tests hyprutils_filedescriptor)
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
install(TARGETS hyprutils)
|
install(TARGETS hyprutils)
|
||||||
install(DIRECTORY "include/hyprutils" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
install(DIRECTORY "include/hyprutils" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
|
39
include/hyprutils/os/FileDescriptor.hpp
Normal file
39
include/hyprutils/os/FileDescriptor.hpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
namespace Hyprutils {
|
||||||
|
namespace OS {
|
||||||
|
class CFileDescriptor {
|
||||||
|
public:
|
||||||
|
CFileDescriptor() = default;
|
||||||
|
explicit CFileDescriptor(int const fd);
|
||||||
|
CFileDescriptor(CFileDescriptor&&);
|
||||||
|
CFileDescriptor& operator=(CFileDescriptor&&);
|
||||||
|
~CFileDescriptor();
|
||||||
|
|
||||||
|
CFileDescriptor(const CFileDescriptor&) = delete;
|
||||||
|
CFileDescriptor& operator=(const CFileDescriptor&) = delete;
|
||||||
|
|
||||||
|
bool operator==(const CFileDescriptor& rhs) const {
|
||||||
|
return m_fd == rhs.m_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
int get() const;
|
||||||
|
int getFlags() const;
|
||||||
|
bool setFlags(int flags);
|
||||||
|
int take();
|
||||||
|
void reset();
|
||||||
|
CFileDescriptor duplicate(int flags = F_DUPFD_CLOEXEC) const;
|
||||||
|
|
||||||
|
bool isReadable() const;
|
||||||
|
bool isClosed() const;
|
||||||
|
|
||||||
|
static bool isReadable(int fd);
|
||||||
|
static bool isClosed(int fd);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_fd = -1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
89
src/os/FileDescriptor.cpp
Normal file
89
src/os/FileDescriptor.cpp
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <hyprutils/os/FileDescriptor.hpp>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
using namespace Hyprutils::OS;
|
||||||
|
|
||||||
|
CFileDescriptor::CFileDescriptor(int const fd) : m_fd(fd) {}
|
||||||
|
|
||||||
|
CFileDescriptor::CFileDescriptor(CFileDescriptor&& other) : m_fd(std::exchange(other.m_fd, -1)) {}
|
||||||
|
|
||||||
|
CFileDescriptor& CFileDescriptor::operator=(CFileDescriptor&& other) {
|
||||||
|
if (this == &other) // Shit will go haywire if there is duplicate ownership
|
||||||
|
abort();
|
||||||
|
|
||||||
|
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::getFlags() const {
|
||||||
|
return fcntl(m_fd, F_GETFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFileDescriptor::setFlags(int flags) {
|
||||||
|
if (fcntl(m_fd, F_SETFD, flags) == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(int flags) const {
|
||||||
|
if (m_fd == -1)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return CFileDescriptor{fcntl(m_fd, flags, 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);
|
||||||
|
}
|
49
tests/filedescriptor.cpp
Normal file
49
tests/filedescriptor.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#include <hyprutils/os/FileDescriptor.hpp>
|
||||||
|
#include "shared.hpp"
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
using namespace Hyprutils::OS;
|
||||||
|
|
||||||
|
int main(int argc, char** argv, char** envp) {
|
||||||
|
std::string name = "/test_filedescriptors";
|
||||||
|
CFileDescriptor fd(shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600));
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
EXPECT(fd.isValid(), true);
|
||||||
|
EXPECT(fd.isReadable(), true);
|
||||||
|
|
||||||
|
int flags = fd.getFlags();
|
||||||
|
EXPECT(fd.getFlags(), FD_CLOEXEC);
|
||||||
|
flags &= ~FD_CLOEXEC;
|
||||||
|
fd.setFlags(flags);
|
||||||
|
EXPECT(fd.getFlags(), !FD_CLOEXEC);
|
||||||
|
|
||||||
|
CFileDescriptor fd2 = fd.duplicate();
|
||||||
|
EXPECT(fd.isValid(), true);
|
||||||
|
EXPECT(fd.isReadable(), true);
|
||||||
|
EXPECT(fd2.isValid(), true);
|
||||||
|
EXPECT(fd2.isReadable(), true);
|
||||||
|
|
||||||
|
CFileDescriptor fd3(fd2.take());
|
||||||
|
EXPECT(fd.isValid(), true);
|
||||||
|
EXPECT(fd.isReadable(), true);
|
||||||
|
EXPECT(fd2.isValid(), false);
|
||||||
|
EXPECT(fd2.isReadable(), false);
|
||||||
|
|
||||||
|
// .duplicate default flags is FD_CLOEXEC
|
||||||
|
EXPECT(fd3.getFlags(), FD_CLOEXEC);
|
||||||
|
|
||||||
|
fd.reset();
|
||||||
|
fd2.reset();
|
||||||
|
fd3.reset();
|
||||||
|
|
||||||
|
EXPECT(fd.isReadable(), false);
|
||||||
|
EXPECT(fd2.isReadable(), false);
|
||||||
|
EXPECT(fd3.isReadable(), false);
|
||||||
|
|
||||||
|
shm_unlink(name.c_str());
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
Loading…
Reference in a new issue