Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add filedescriptor class #21

Merged
merged 1 commit into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ add_test(
COMMAND hyprutils_os "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
install(TARGETS hyprutils)
install(DIRECTORY "include/hyprutils" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
Expand Down
39 changes: 39 additions & 0 deletions include/hyprutils/os/FileDescriptor.hpp
Original file line number Diff line number Diff line change
@@ -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 changes: 89 additions & 0 deletions src/os/FileDescriptor.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 49 additions & 0 deletions tests/filedescriptor.cpp
Original file line number Diff line number Diff line change
@@ -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;
}