From 32c0fa2f2fe02254d5887b38cf2cffa72ddfd769 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 30 Jan 2025 12:30:12 +0100 Subject: [PATCH] core: begin using CFileDescriptor from hyprutils (#9122) * config: make fd use CFileDescriptor make use of the new hyprutils CFileDescriptor instead of manual FD handling. * hyprctl: make fd use CFileDescriptor make use of the new hyprutils CFileDescriptor instead of manual FD handling. * ikeyboard: make fd use CFileDescriptor make use of the new CFileDescriptor instead of manual FD handling, also in sendKeymap remove dead code, it already early returns if keyboard isnt valid, and dont try to close the FD that ikeyboard owns. * core: make SHMFile functions use CFileDescriptor make SHMFile misc functions use CFileDescriptor and its associated usage in dmabuf and keyboard. * core: make explicit sync use CFileDescriptor begin using CFileDescriptor in explicit sync and its timelines and eglsync usage in opengl, there is still a bit left with manual handling that requires future aquamarine change aswell. * eventmgr: make fd and sockets use CFileDescriptor make use of the hyprutils CFileDescriptor instead of manual FD and socket handling and closing. * eventloopmgr: make timerfd use CFileDescriptor make the timerfd use CFileDescriptor instead of manual fd handling * opengl: make gbm fd use CFileDescriptor make the gbm rendernode fd use CFileDescriptor instead of manual fd handling * core: make selection source/offer use CFileDescriptor make data selection source and offers use CFileDescriptor and its associated use in xwm and protocols * protocols: convert protocols fd to CFileDescriptor make most fd handling use CFileDescriptor in protocols * shm: make SHMPool use CfileDescriptor make SHMPool use CFileDescriptor instead of manual fd handling. * opengl: duplicate fd with CFileDescriptor duplicate fenceFD with CFileDescriptor duplicate instead. * xwayland: make sockets and fds use CFileDescriptor instead of manual opening/closing make sockets and fds use CFileDescriptor * keybindmgr: make sockets and fds use CFileDescriptor make sockets and fds use CFileDescriptor instead of manual handling. --- src/config/ConfigWatcher.cpp | 25 ++- src/config/ConfigWatcher.hpp | 15 +- src/debug/HyprCtl.cpp | 18 +- src/debug/HyprCtl.hpp | 11 +- src/devices/IKeyboard.cpp | 26 ++- src/devices/IKeyboard.hpp | 3 +- src/helpers/MiscFunctions.cpp | 44 +++-- src/helpers/MiscFunctions.hpp | 5 +- src/helpers/Monitor.cpp | 17 +- src/helpers/Monitor.hpp | 1 + src/helpers/sync/SyncTimeline.cpp | 26 ++- src/helpers/sync/SyncTimeline.hpp | 32 ++-- src/managers/EventManager.cpp | 44 +++-- src/managers/EventManager.hpp | 14 +- src/managers/KeybindManager.cpp | 29 ++-- src/managers/eventLoop/EventLoopManager.cpp | 13 +- src/managers/eventLoop/EventLoopManager.hpp | 3 +- src/protocols/DRMLease.cpp | 17 +- src/protocols/DRMLease.hpp | 1 + src/protocols/DRMSyncobj.cpp | 12 +- src/protocols/DRMSyncobj.hpp | 7 +- src/protocols/DataDeviceWlr.cpp | 12 +- src/protocols/DataDeviceWlr.hpp | 3 +- src/protocols/GammaControl.cpp | 15 +- src/protocols/InputMethodV2.cpp | 11 +- src/protocols/LinuxDMABUF.cpp | 37 ++--- src/protocols/LinuxDMABUF.hpp | 9 +- src/protocols/PrimarySelection.cpp | 12 +- src/protocols/PrimarySelection.hpp | 3 +- src/protocols/SecurityContext.cpp | 21 ++- src/protocols/SecurityContext.hpp | 19 ++- src/protocols/VirtualKeyboard.cpp | 10 +- src/protocols/VirtualKeyboard.hpp | 1 + src/protocols/core/DataDevice.cpp | 12 +- src/protocols/core/DataDevice.hpp | 3 +- src/protocols/core/Seat.cpp | 29 +--- src/protocols/core/Shm.cpp | 23 +-- src/protocols/core/Shm.hpp | 14 +- src/protocols/types/DataDevice.hpp | 9 +- src/render/OpenGL.cpp | 41 ++--- src/render/OpenGL.hpp | 13 +- src/render/Renderer.cpp | 20 +-- src/xwayland/Dnd.cpp | 4 +- src/xwayland/Dnd.hpp | 3 +- src/xwayland/Server.cpp | 175 +++++++------------- src/xwayland/Server.hpp | 31 ++-- src/xwayland/XDataSource.cpp | 13 +- src/xwayland/XDataSource.hpp | 5 +- src/xwayland/XWM.cpp | 20 +-- src/xwayland/XWM.hpp | 27 +-- 50 files changed, 427 insertions(+), 531 deletions(-) diff --git a/src/config/ConfigWatcher.cpp b/src/config/ConfigWatcher.cpp index c0a9c5917b8..8d086bac41b 100644 --- a/src/config/ConfigWatcher.cpp +++ b/src/config/ConfigWatcher.cpp @@ -5,27 +5,24 @@ #include #include +using namespace Hyprutils::OS; + CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) { - if (m_inotifyFd < 0) { + if (!m_inotifyFd.isValid()) { Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded"); return; } - const int FLAGS = fcntl(m_inotifyFd, F_GETFL, 0); - if (fcntl(m_inotifyFd, F_SETFL, FLAGS | O_NONBLOCK) < 0) { + // TODO: make CFileDescriptor take F_GETFL, F_SETFL + const int FLAGS = fcntl(m_inotifyFd.get(), F_GETFL, 0); + if (fcntl(m_inotifyFd.get(), F_SETFL, FLAGS | O_NONBLOCK) < 0) { Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded"); - close(m_inotifyFd); - m_inotifyFd = -1; + m_inotifyFd.reset(); return; } } -CConfigWatcher::~CConfigWatcher() { - if (m_inotifyFd >= 0) - close(m_inotifyFd); -} - -int CConfigWatcher::getInotifyFD() { +CFileDescriptor& CConfigWatcher::getInotifyFD() { return m_inotifyFd; } @@ -38,7 +35,7 @@ void CConfigWatcher::setWatchList(const std::vector& paths) { // cleanup old paths for (auto& watch : m_watches) { - inotify_rm_watch(m_inotifyFd, watch.wd); + inotify_rm_watch(m_inotifyFd.get(), watch.wd); } m_watches.clear(); @@ -46,7 +43,7 @@ void CConfigWatcher::setWatchList(const std::vector& paths) { // add new paths for (const auto& path : paths) { m_watches.emplace_back(SInotifyWatch{ - .wd = inotify_add_watch(m_inotifyFd, path.c_str(), IN_MODIFY), + .wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY), .file = path, }); } @@ -58,7 +55,7 @@ void CConfigWatcher::setOnChange(const std::function 0) { + while (read(m_inotifyFd.get(), &ev, sizeof(ev)) > 0) { const auto WD = std::ranges::find_if(m_watches.begin(), m_watches.end(), [wd = ev.wd](const auto& e) { return e.wd == wd; }); if (WD == m_watches.end()) { diff --git a/src/config/ConfigWatcher.hpp b/src/config/ConfigWatcher.hpp index c36ecd17663..979456891b7 100644 --- a/src/config/ConfigWatcher.hpp +++ b/src/config/ConfigWatcher.hpp @@ -3,20 +3,21 @@ #include #include #include +#include class CConfigWatcher { public: CConfigWatcher(); - ~CConfigWatcher(); + ~CConfigWatcher() = default; struct SConfigWatchEvent { std::string file; }; - int getInotifyFD(); - void setWatchList(const std::vector& paths); - void setOnChange(const std::function& fn); - void onInotifyEvent(); + Hyprutils::OS::CFileDescriptor& getInotifyFD(); + void setWatchList(const std::vector& paths); + void setOnChange(const std::function& fn); + void onInotifyEvent(); private: struct SInotifyWatch { @@ -26,7 +27,7 @@ class CConfigWatcher { std::function m_watchCallback; std::vector m_watches; - int m_inotifyFd = -1; + Hyprutils::OS::CFileDescriptor m_inotifyFd; }; -inline UP g_pConfigWatcher = makeUnique(); \ No newline at end of file +inline UP g_pConfigWatcher = makeUnique(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 359428b1af5..cd6451e222f 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -25,6 +25,7 @@ #include using namespace Hyprutils::String; +using namespace Hyprutils::OS; #include #include "../config/ConfigDataValues.hpp" @@ -1680,8 +1681,6 @@ CHyprCtl::CHyprCtl() { CHyprCtl::~CHyprCtl() { if (m_eventSource) wl_event_source_remove(m_eventSource); - if (m_iSocketFD >= 0) - close(m_iSocketFD); if (!m_socketPath.empty()) unlink(m_socketPath.c_str()); } @@ -1840,10 +1839,13 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) return 0; + if (!g_pHyprCtl->m_iSocketFD.isValid()) + return 0; + sockaddr_in clientAddress; socklen_t clientSize = sizeof(clientAddress); - const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); + const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); std::array readBuffer; @@ -1900,9 +1902,9 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { } void CHyprCtl::startHyprCtlSocket() { - m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + m_iSocketFD = CFileDescriptor{socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)}; - if (m_iSocketFD < 0) { + if (!m_iSocketFD.isValid()) { Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); return; } @@ -1913,15 +1915,15 @@ void CHyprCtl::startHyprCtlSocket() { strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str()); - if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { + if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); return; } // 10 max queued. - listen(m_iSocketFD, 10); + listen(m_iSocketFD.get(), 10); Debug::log(LOG, "Hypr socket started at {}", m_socketPath); - m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr); + m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, hyprCtlFDTick, nullptr); } diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index eed8265c373..a95a5f9346b 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -4,6 +4,7 @@ #include "../helpers/MiscFunctions.hpp" #include "../desktop/Window.hpp" #include +#include // exposed for main.cpp std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); @@ -14,12 +15,12 @@ class CHyprCtl { CHyprCtl(); ~CHyprCtl(); - std::string makeDynamicCall(const std::string& input); - SP registerCommand(SHyprCtlCommand cmd); - void unregisterCommand(const SP& cmd); - std::string getReply(std::string); + std::string makeDynamicCall(const std::string& input); + SP registerCommand(SHyprCtlCommand cmd); + void unregisterCommand(const SP& cmd); + std::string getReply(std::string); - int m_iSocketFD = -1; + Hyprutils::OS::CFileDescriptor m_iSocketFD; struct { bool all = false; diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 4623fe84f04..307d840b0e3 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -8,6 +8,8 @@ #include #include +using namespace Hyprutils::OS; + #define LED_COUNT 3 constexpr static std::array MODNAMES = { @@ -41,9 +43,6 @@ void IKeyboard::clearManuallyAllocd() { if (xkbKeymap) xkb_keymap_unref(xkbKeymap); - if (xkbKeymapFD >= 0) - close(xkbKeymapFD); - if (xkbSymState) xkb_state_unref(xkbSymState); @@ -51,7 +50,7 @@ void IKeyboard::clearManuallyAllocd() { xkbKeymap = nullptr; xkbState = nullptr; xkbStaticState = nullptr; - xkbKeymapFD = -1; + xkbKeymapFD.reset(); } void IKeyboard::setKeymap(const SStringRuleNames& rules) { @@ -147,31 +146,30 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { void IKeyboard::updateKeymapFD() { Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName); - if (xkbKeymapFD >= 0) - close(xkbKeymapFD); - xkbKeymapFD = -1; + if (xkbKeymapFD.isValid()) + xkbKeymapFD.reset(); auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1); xkbKeymapString = cKeymapStr; free(cKeymapStr); - int rw, ro; - if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro)) + CFileDescriptor rw, ro; + if (!allocateSHMFilePair(xkbKeymapString.length() + 1, rw, ro)) Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap"); else { - auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0); - close(rw); + auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw.get(), 0); + rw.reset(); if (keymapFDDest == MAP_FAILED) { Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap"); - close(ro); + ro.reset(); } else { memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length()); munmap(keymapFDDest, xkbKeymapString.length() + 1); - xkbKeymapFD = ro; + xkbKeymapFD = std::move(ro); } } - Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD); + Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD.get()); } void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index dce2127a218..aabf4cc21e5 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -6,6 +6,7 @@ #include #include +#include AQUAMARINE_FORWARD(IKeyboard); @@ -96,7 +97,7 @@ class IKeyboard : public IHID { std::string xkbFilePath = ""; std::string xkbKeymapString = ""; - int xkbKeymapFD = -1; + Hyprutils::OS::CFileDescriptor xkbKeymapFD; SStringRuleNames currentRules; int repeatRate = 0; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 5ebb0842c5c..f532617c2c2 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -836,50 +836,48 @@ bool envEnabled(const std::string& env) { return std::string(ENV) == "1"; } -std::pair openExclusiveShm() { +std::pair openExclusiveShm() { // Only absolute paths can be shared across different shm_open() calls std::string name = "/" + g_pTokenManager->getRandomUUID(); for (size_t i = 0; i < 69; ++i) { - int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd >= 0) - return {fd, name}; + CFileDescriptor fd{shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)}; + if (fd.isValid()) + return {std::move(fd), name}; } - return {-1, ""}; + return {{}, ""}; } -int allocateSHMFile(size_t len) { +CFileDescriptor allocateSHMFile(size_t len) { auto [fd, name] = openExclusiveShm(); - if (fd < 0) - return -1; + if (!fd.isValid()) + return {}; shm_unlink(name.c_str()); int ret; do { - ret = ftruncate(fd, len); + ret = ftruncate(fd.get(), len); } while (ret < 0 && errno == EINTR); if (ret < 0) { - close(fd); - return -1; + return {}; } - return fd; + return std::move(fd); } -bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { +bool allocateSHMFilePair(size_t size, CFileDescriptor& rw_fd_ptr, CFileDescriptor& ro_fd_ptr) { auto [fd, name] = openExclusiveShm(); - if (fd < 0) { + if (!fd.isValid()) { return false; } // CLOEXEC is guaranteed to be set by shm_open - int ro_fd = shm_open(name.c_str(), O_RDONLY, 0); - if (ro_fd < 0) { + CFileDescriptor ro_fd{shm_open(name.c_str(), O_RDONLY, 0)}; + if (!ro_fd.isValid()) { shm_unlink(name.c_str()); - close(fd); return false; } @@ -887,24 +885,20 @@ bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { // Make sure the file cannot be re-opened in read-write mode (e.g. via // "/proc/self/fd/" on Linux) - if (fchmod(fd, 0) != 0) { - close(fd); - close(ro_fd); + if (fchmod(fd.get(), 0) != 0) { return false; } int ret; do { - ret = ftruncate(fd, size); + ret = ftruncate(fd.get(), size); } while (ret < 0 && errno == EINTR); if (ret < 0) { - close(fd); - close(ro_fd); return false; } - *rw_fd_ptr = fd; - *ro_fd_ptr = ro_fd; + rw_fd_ptr = std::move(fd); + ro_fd_ptr = std::move(ro_fd); return true; } diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index d08242849ff..bd2886387f8 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../SharedDefs.hpp" #include "../macros.hpp" @@ -35,8 +36,8 @@ double normalizeAngleRad(double ang); std::vector getBacktrace(); void throwError(const std::string& err); bool envEnabled(const std::string& env); -int allocateSHMFile(size_t len); -bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); +Hyprutils::OS::CFileDescriptor allocateSHMFile(size_t len); +bool allocateSHMFilePair(size_t size, Hyprutils::OS::CFileDescriptor& rw_fd_ptr, Hyprutils::OS::CFileDescriptor& ro_fd_ptr); float stringToPercentage(const std::string& VALUE, const float REL); template diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 42acf485127..fc3de3aae4c 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -32,6 +32,7 @@ #include using namespace Hyprutils::String; using namespace Hyprutils::Utils; +using namespace Hyprutils::OS; static int ratHandler(void* data) { g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock()); @@ -1301,19 +1302,15 @@ bool CMonitor::attemptDirectScanout() { // wait for the explicit fence if present, and if kms explicit is allowed bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled; - int explicitWaitFD = -1; + CFileDescriptor explicitWaitFD; if (DOEXPLICIT) { explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint); - if (explicitWaitFD < 0) + if (!explicitWaitFD.isValid()) Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd"); } - DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0; + DOEXPLICIT = DOEXPLICIT && explicitWaitFD.isValid(); - auto cleanup = CScopeGuard([explicitWaitFD, this]() { - output->state->resetExplicitFences(); - if (explicitWaitFD >= 0) - close(explicitWaitFD); - }); + auto cleanup = CScopeGuard([this]() { output->state->resetExplicitFences(); }); timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -1323,8 +1320,8 @@ bool CMonitor::attemptDirectScanout() { output->state->resetExplicitFences(); if (DOEXPLICIT) { - Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD); - output->state->setExplicitInFence(explicitWaitFD); + Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD.get()); + output->state->setExplicitInFence(explicitWaitFD.get()); } bool ok = output->commit(); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 2b02c30a22e..c67bccc525e 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -16,6 +16,7 @@ #include "DamageRing.hpp" #include #include +#include // Enum for the different types of auto directions, e.g. auto-left, auto-up. enum eAutoDirs : uint8_t { diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp index 16b5bd92deb..46b617bc6d6 100644 --- a/src/helpers/sync/SyncTimeline.cpp +++ b/src/helpers/sync/SyncTimeline.cpp @@ -4,6 +4,7 @@ #include #include +using namespace Hyprutils::OS; SP CSyncTimeline::create(int drmFD_) { auto timeline = SP(new CSyncTimeline); @@ -85,10 +86,9 @@ bool CSyncTimeline::addWaiter(const std::function& waiter, uint64_t poin auto w = makeShared(); w->fn = waiter; w->timeline = self; + w->eventFd = CFileDescriptor{eventfd(0, EFD_CLOEXEC)}; - int eventFD = eventfd(0, EFD_CLOEXEC); - - if (eventFD < 0) { + if (!w->eventFd.isValid()) { Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd"); return false; } @@ -97,19 +97,17 @@ bool CSyncTimeline::addWaiter(const std::function& waiter, uint64_t poin .handle = handle, .flags = flags, .point = point, - .fd = eventFD, + .fd = w->eventFd.get(), }; if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) { Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed"); - close(eventFD); return false; } - w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get()); + w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, w->eventFd.get(), WL_EVENT_READABLE, ::handleWaiterFD, w.get()); if (!w->source) { Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed"); - close(eventFD); return false; } @@ -126,32 +124,32 @@ void CSyncTimeline::removeWaiter(SWaiter* w) { std::erase_if(waiters, [w](const auto& e) { return e.get() == w; }); } -int CSyncTimeline::exportAsSyncFileFD(uint64_t src) { +CFileDescriptor CSyncTimeline::exportAsSyncFileFD(uint64_t src) { int sync = -1; uint32_t syncHandle = 0; if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed"); - return -1; + return {}; } if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed"); drmSyncobjDestroy(drmFD, syncHandle); - return -1; + return {}; } if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed"); drmSyncobjDestroy(drmFD, syncHandle); - return -1; + return {}; } drmSyncobjDestroy(drmFD, syncHandle); - return sync; + return CFileDescriptor{sync}; } -bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { +bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, CFileDescriptor& fd) { uint32_t syncHandle = 0; if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { @@ -159,7 +157,7 @@ bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { return false; } - if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) { + if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd.get())) { Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed"); drmSyncobjDestroy(drmFD, syncHandle); return false; diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp index 88ad4921e69..ba65e004d0b 100644 --- a/src/helpers/sync/SyncTimeline.hpp +++ b/src/helpers/sync/SyncTimeline.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../memory/Memory.hpp" /* @@ -20,26 +21,27 @@ class CSyncTimeline { ~CSyncTimeline(); struct SWaiter { - std::function fn; - wl_event_source* source = nullptr; - WP timeline; + std::function fn; + wl_event_source* source = nullptr; + WP timeline; + Hyprutils::OS::CFileDescriptor eventFd; }; // check if the timeline point has been signaled // flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE // std::nullopt on fail - std::optional check(uint64_t point, uint32_t flags); - - bool addWaiter(const std::function& waiter, uint64_t point, uint32_t flags); - void removeWaiter(SWaiter*); - int exportAsSyncFileFD(uint64_t src); - bool importFromSyncFileFD(uint64_t dst, int fd); - bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); - void signal(uint64_t point); - - int drmFD = -1; - uint32_t handle = 0; - WP self; + std::optional check(uint64_t point, uint32_t flags); + + bool addWaiter(const std::function& waiter, uint64_t point, uint32_t flags); + void removeWaiter(SWaiter*); + Hyprutils::OS::CFileDescriptor exportAsSyncFileFD(uint64_t src); + bool importFromSyncFileFD(uint64_t dst, Hyprutils::OS::CFileDescriptor& fd); + bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); + void signal(uint64_t point); + + int drmFD = -1; + uint32_t handle = 0; + WP self; private: CSyncTimeline() = default; diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp index fc55b472553..6231f0bc639 100644 --- a/src/managers/EventManager.cpp +++ b/src/managers/EventManager.cpp @@ -9,9 +9,10 @@ #include #include #include +using namespace Hyprutils::OS; CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) { - if (m_iSocketFD < 0) { + if (!m_iSocketFD.isValid()) { Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work."); return; } @@ -25,31 +26,27 @@ CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_ strncpy(SERVERADDRESS.sun_path, PATH.c_str(), sizeof(SERVERADDRESS.sun_path) - 1); - if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { + if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { Debug::log(ERR, "Couldn't bind the Hyprland Socket 2. (3) IPC will not work."); return; } // 10 max queued. - if (listen(m_iSocketFD, 10) < 0) { + if (listen(m_iSocketFD.get(), 10) < 0) { Debug::log(ERR, "Couldn't listen on the Hyprland Socket 2. (4) IPC will not work."); return; } - m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, onClientEvent, nullptr); + m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, onClientEvent, nullptr); } CEventManager::~CEventManager() { for (const auto& client : m_vClients) { wl_event_source_remove(client.eventSource); - close(client.fd); } if (m_pEventSource != nullptr) wl_event_source_remove(m_pEventSource); - - if (m_iSocketFD >= 0) - close(m_iSocketFD); } int CEventManager::onServerEvent(int fd, uint32_t mask, void* data) { @@ -66,33 +63,31 @@ int CEventManager::onServerEvent(int fd, uint32_t mask) { wl_event_source_remove(m_pEventSource); m_pEventSource = nullptr; - close(fd); - m_iSocketFD = -1; + m_iSocketFD.reset(); return 0; } - sockaddr_in clientAddress; - socklen_t clientSize = sizeof(clientAddress); - const auto ACCEPTEDCONNECTION = accept4(m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK); - if (ACCEPTEDCONNECTION < 0) { + sockaddr_in clientAddress; + socklen_t clientSize = sizeof(clientAddress); + CFileDescriptor ACCEPTEDCONNECTION{accept4(m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK)}; + if (!ACCEPTEDCONNECTION.isValid()) { if (errno != EAGAIN) { Debug::log(ERR, "Socket2 failed receiving connection, errno: {}", errno); wl_event_source_remove(m_pEventSource); m_pEventSource = nullptr; - close(fd); - m_iSocketFD = -1; + m_iSocketFD.reset(); } return 0; } - Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION); + Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION.get()); // add to event loop so we can close it when we need to - auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, 0, onServerEvent, nullptr); + auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION.get(), 0, onServerEvent, nullptr); m_vClients.emplace_back(SClient{ - ACCEPTEDCONNECTION, + std::move(ACCEPTEDCONNECTION), {}, eventSource, }); @@ -113,7 +108,7 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) { // send all queued events while (!CLIENTIT->events.empty()) { const auto& event = CLIENTIT->events.front(); - if (write(CLIENTIT->fd, event->c_str(), event->length()) < 0) + if (write(CLIENTIT->fd.get(), event->c_str(), event->length()) < 0) break; CLIENTIT->events.erase(CLIENTIT->events.begin()); @@ -128,13 +123,12 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) { } std::vector::iterator CEventManager::findClientByFD(int fd) { - return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd == fd; }); + return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd.get() == fd; }); } std::vector::iterator CEventManager::removeClientByFD(int fd) { const auto CLIENTIT = findClientByFD(fd); wl_event_source_remove(CLIENTIT->eventSource); - close(fd); return m_vClients.erase(CLIENTIT); } @@ -157,11 +151,11 @@ void CEventManager::postEvent(const SHyprIPCEvent& event) { for (auto it = m_vClients.begin(); it != m_vClients.end();) { // try to send the event immediately if the queue is empty const auto QUEUESIZE = it->events.size(); - if (QUEUESIZE > 0 || write(it->fd, sharedEvent->c_str(), sharedEvent->length()) < 0) { + if (QUEUESIZE > 0 || write(it->fd.get(), sharedEvent->c_str(), sharedEvent->length()) < 0) { if (QUEUESIZE >= MAX_QUEUED_EVENTS) { // too many events queued, remove the client - Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd); - it = removeClientByFD(it->fd); + Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd.get()); + it = removeClientByFD(it->fd.get()); continue; } diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index 6b506d33869..c8335d205cb 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -1,6 +1,6 @@ #pragma once #include - +#include #include "../defines.hpp" #include "../helpers/memory/Memory.hpp" @@ -26,19 +26,19 @@ class CEventManager { int onClientEvent(int fd, uint32_t mask); struct SClient { - int fd = -1; - std::vector> events; - wl_event_source* eventSource = nullptr; + Hyprutils::OS::CFileDescriptor fd; + std::vector> events; + wl_event_source* eventSource = nullptr; }; std::vector::iterator findClientByFD(int fd); std::vector::iterator removeClientByFD(int fd); private: - int m_iSocketFD = -1; - wl_event_source* m_pEventSource = nullptr; + Hyprutils::OS::CFileDescriptor m_iSocketFD; + wl_event_source* m_pEventSource = nullptr; - std::vector m_vClients; + std::vector m_vClients; }; inline UP g_pEventManager; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2cb77d217c3..247550aed61 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -28,7 +28,9 @@ #include #include +#include using namespace Hyprutils::String; +using namespace Hyprutils::OS; #include #include @@ -853,19 +855,18 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) { const unsigned int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1; // vtnr is bugged for some reason. - unsigned int ttynum = 0; - int fd; - if ((fd = open("/dev/tty", O_RDONLY | O_NOCTTY)) >= 0) { + unsigned int ttynum = 0; + Hyprutils::OS::CFileDescriptor fd{open("/dev/tty", O_RDONLY | O_NOCTTY)}; + if (fd.isValid()) { #if defined(VT_GETSTATE) struct vt_stat st; - if (!ioctl(fd, VT_GETSTATE, &st)) + if (!ioctl(fd.get(), VT_GETSTATE, &st)) ttynum = st.v_active; #elif defined(VT_GETACTIVE) int vt; - if (!ioctl(fd, VT_GETACTIVE, &vt)) + if (!ioctl(fd.get(), VT_GETACTIVE, &vt)) ttynum = vt; #endif - close(fd); } if (ttynum == TTY) @@ -944,11 +945,11 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo Debug::log(LOG, "Unable to create pipe for fork"); } - pid_t child, grandchild; + CFileDescriptor pipeSock[2] = {CFileDescriptor{socket[0]}, CFileDescriptor{socket[1]}}; + + pid_t child, grandchild; child = fork(); if (child < 0) { - close(socket[0]); - close(socket[1]); Debug::log(LOG, "Fail to create the first fork"); return 0; } @@ -967,22 +968,16 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo setenv(e.first.c_str(), e.second.c_str(), 1); } setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); - close(socket[0]); - close(socket[1]); execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); // exit grandchild _exit(0); } - close(socket[0]); - write(socket[1], &grandchild, sizeof(grandchild)); - close(socket[1]); + write(pipeSock[1].get(), &grandchild, sizeof(grandchild)); // exit child _exit(0); } // run in parent - close(socket[1]); - read(socket[0], &grandchild, sizeof(grandchild)); - close(socket[0]); + read(pipeSock[0].get(), &grandchild, sizeof(grandchild)); // clear child and leave grandchild to init waitpid(child, nullptr, 0); if (grandchild < 0) { diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 4021c1717d7..83bdf4a0e9b 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -11,11 +11,12 @@ #include #include +using namespace Hyprutils::OS; #define TIMESPEC_NSEC_PER_SEC 1000000000L CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) { - m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + m_sTimers.timerfd = CFileDescriptor{timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC)}; m_sWayland.loop = wlEventLoop; m_sWayland.display = display; } @@ -31,8 +32,6 @@ CEventLoopManager::~CEventLoopManager() { wl_event_source_remove(m_sIdle.eventSource); if (m_configWatcherInotifySource) wl_event_source_remove(m_configWatcherInotifySource); - if (m_sTimers.timerfd >= 0) - close(m_sTimers.timerfd); } static int timerWrite(int fd, uint32_t mask, void* data) { @@ -52,10 +51,10 @@ static int configWatcherWrite(int fd, uint32_t mask, void* data) { } void CEventLoopManager::enterLoop() { - m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); + m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd.get(), WL_EVENT_READABLE, timerWrite, nullptr); - if (const auto FD = g_pConfigWatcher->getInotifyFD(); FD >= 0) - m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD, WL_EVENT_READABLE, configWatcherWrite, nullptr); + if (const auto& FD = g_pConfigWatcher->getInotifyFD(); FD.isValid()) + m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD.get(), WL_EVENT_READABLE, configWatcherWrite, nullptr); syncPollFDs(); m_sListeners.pollFDsChanged = g_pCompositor->m_pAqBackend->events.pollFDsChanged.registerListener([this](std::any d) { syncPollFDs(); }); @@ -120,7 +119,7 @@ void CEventLoopManager::nudgeTimers() { itimerspec ts = {.it_value = now}; - timerfd_settime(m_sTimers.timerfd, TFD_TIMER_ABSTIME, &ts, nullptr); + timerfd_settime(m_sTimers.timerfd.get(), TFD_TIMER_ABSTIME, &ts, nullptr); } void CEventLoopManager::doLater(const std::function& fn) { diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 95cc61093f1..ebeb21607f7 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -6,6 +6,7 @@ #include #include #include "helpers/signal/Signal.hpp" +#include #include "EventLoopTimer.hpp" @@ -54,7 +55,7 @@ class CEventLoopManager { struct { std::vector> timers; - int timerfd = -1; + Hyprutils::OS::CFileDescriptor timerfd; } m_sTimers; SIdleData m_sIdle; diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 6fdbaf4b98a..e70f0441508 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -4,6 +4,7 @@ #include "managers/eventLoop/EventLoopManager.hpp" #include #include +using namespace Hyprutils::OS; CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) { if UNLIKELY (!good()) @@ -185,15 +186,14 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resourc RESOURCE->parent = self; }); - int fd = ((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD(); - if (fd < 0) { + CFileDescriptor fd{((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD()}; + if (!fd.isValid()) { LOGM(ERR, "Failed to dup fd in lease"); return; } - LOGM(LOG, "Sending DRMFD {} to new lease device", fd); - resource->sendDrmFd(fd); - close(fd); + LOGM(LOG, "Sending DRMFD {} to new lease device", fd.get()); + resource->sendDrmFd(fd.get()); for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) { if (m) @@ -231,16 +231,15 @@ void CDRMLeaseDeviceResource::sendConnector(PHLMONITOR monitor) { } CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backend(drmBackend) { - auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); + auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); - auto fd = drm->getNonMasterFD(); + CFileDescriptor fd{drm->getNonMasterFD()}; - if (fd < 0) { + if (!fd.isValid()) { LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); return; } - close(fd); success = true; name = drm->gpuName; } diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp index ec1e73f206b..c7849149d8a 100644 --- a/src/protocols/DRMLease.hpp +++ b/src/protocols/DRMLease.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "drm-lease-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include /* TODO: this protocol is not made for systems with multiple DRM nodes (e.g. multigpu) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index ce598385c3a..23dafbca8ee 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -6,6 +6,7 @@ #include "../Compositor.hpp" #include +using namespace Hyprutils::OS; CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if UNLIKELY (!good()) @@ -103,7 +104,7 @@ bool CDRMSyncobjSurfaceResource::good() { return resource->resource(); } -CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, int fd_) : fd(fd_), resource(resource_) { +CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, CFileDescriptor fd_) : fd(std::move(fd_)), resource(resource_) { if UNLIKELY (!good()) return; @@ -112,7 +113,7 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SPsetOnDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); resource->setDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); - timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd); + timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd.get()); if (!timeline) { resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Timeline failed importing"); @@ -120,11 +121,6 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP= 0) - close(fd); -} - SP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); return data ? data->self.lock() : nullptr; @@ -171,7 +167,7 @@ CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SPsetImportTimeline([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, int32_t fd) { - auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), fd); + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), CFileDescriptor{fd}); if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); return; diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index 42ecdb3e2fa..8677576f29a 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -4,6 +4,7 @@ #include "WaylandProtocol.hpp" #include "linux-drm-syncobj-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CWLSurfaceResource; class CDRMSyncobjTimelineResource; @@ -32,14 +33,14 @@ class CDRMSyncobjSurfaceResource { class CDRMSyncobjTimelineResource { public: - CDRMSyncobjTimelineResource(SP resource_, int fd_); - ~CDRMSyncobjTimelineResource(); + CDRMSyncobjTimelineResource(SP resource_, Hyprutils::OS::CFileDescriptor fd_); + ~CDRMSyncobjTimelineResource() = default; static SP fromResource(wl_resource*); bool good(); WP self; - int fd = -1; + Hyprutils::OS::CFileDescriptor fd; SP timeline; private: diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index 71ee1c4a9d6..3da5afd6290 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -2,6 +2,7 @@ #include #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" +using namespace Hyprutils::OS; CWLRDataOffer::CWLRDataOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -11,21 +12,20 @@ CWLRDataOffer::CWLRDataOffer(SP resource_, SPsetOnDestroy([this](CZwlrDataControlOfferV1* r) { PROTO::dataWlr->destroyResource(this); }); resource->setReceive([this](CZwlrDataControlOfferV1* r, const char* mime, int32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); - source->send(mime, fd); + source->send(mime, std::move(sendFd)); }); } @@ -77,15 +77,13 @@ std::vector CWLRDataSource::mimes() { return mimeTypes; } -void CWLRDataSource::send(const std::string& mime, uint32_t fd) { +void CWLRDataSource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLRDataSource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CWLRDataSource::accepted(const std::string& mime) { diff --git a/src/protocols/DataDeviceWlr.hpp b/src/protocols/DataDeviceWlr.hpp index 5eef163c0fb..7f14b320d30 100644 --- a/src/protocols/DataDeviceWlr.hpp +++ b/src/protocols/DataDeviceWlr.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "wlr-data-control-unstable-v1.hpp" #include "types/DataDevice.hpp" +#include class CWLRDataControlManagerResource; class CWLRDataSource; @@ -38,7 +39,7 @@ class CWLRDataSource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 43ba9d416e4..0a383e2ec76 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -4,6 +4,7 @@ #include "../helpers/Monitor.hpp" #include "../protocols/core/Output.hpp" #include "../render/Renderer.hpp" +using namespace Hyprutils::OS; CGammaControl::CGammaControl(SP resource_, wl_resource* output) : resource(resource_) { if UNLIKELY (!resource_->resource()) @@ -46,34 +47,33 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out resource->setOnDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); }); resource->setSetGamma([this](CZwlrGammaControlV1* gamma, int32_t fd) { + CFileDescriptor gammaFd{fd}; if UNLIKELY (!pMonitor) { LOGM(ERR, "setGamma for a dead monitor"); resource->sendFailed(); - close(fd); return; } LOGM(LOG, "setGamma for {}", pMonitor->szName); - int fdFlags = fcntl(fd, F_GETFL, 0); + // TODO: make CFileDescriptor getflags use F_GETFL + int fdFlags = fcntl(gammaFd.get(), F_GETFL, 0); if UNLIKELY (fdFlags < 0) { LOGM(ERR, "Failed to get fd flags"); resource->sendFailed(); - close(fd); return; } - if UNLIKELY (fcntl(fd, F_SETFL, fdFlags | O_NONBLOCK) < 0) { + // TODO: make CFileDescriptor setflags use F_SETFL + if UNLIKELY (fcntl(gammaFd.get(), F_SETFL, fdFlags | O_NONBLOCK) < 0) { LOGM(ERR, "Failed to set fd flags"); resource->sendFailed(); - close(fd); return; } - ssize_t readBytes = pread(fd, gammaTable.data(), gammaTable.size() * sizeof(uint16_t), 0); + ssize_t readBytes = pread(gammaFd.get(), gammaTable.data(), gammaTable.size() * sizeof(uint16_t), 0); if (readBytes < 0 || (size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) { LOGM(ERR, "Failed to read bytes"); - close(fd); if ((size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) { gamma->error(ZWLR_GAMMA_CONTROL_V1_ERROR_INVALID_GAMMA, "Gamma ramps size mismatch"); @@ -85,7 +85,6 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out } gammaTableSet = true; - close(fd); // translate the table to AQ format std::vector red, green, blue; diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 796cec06ec8..33121ecd8ac 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -33,25 +33,22 @@ void CInputMethodKeyboardGrabV2::sendKeyboardData(SP keyboard) { pLastKeyboard = keyboard; - int keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); - if UNLIKELY (keymapFD < 0) { + auto keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); + if UNLIKELY (!keymapFD.isValid()) { LOGM(ERR, "Failed to create a keymap file for keyboard grab"); return; } - void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); + void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD.get(), 0); if UNLIKELY (data == MAP_FAILED) { LOGM(ERR, "Failed to mmap a keymap file for keyboard grab"); - close(keymapFD); return; } memcpy(data, keyboard->xkbKeymapString.c_str(), keyboard->xkbKeymapString.length()); munmap(data, keyboard->xkbKeymapString.length() + 1); - resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->xkbKeymapString.length() + 1); - - close(keymapFD); + resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD.get(), keyboard->xkbKeymapString.length() + 1); sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group); diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index d3135da0113..b7b91594847 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -14,6 +14,8 @@ #include "../render/OpenGL.hpp" #include "../Compositor.hpp" +using namespace Hyprutils::OS; + static std::optional devIDFromFD(int fd) { struct stat stat; if (fstat(fd, &stat) != 0) @@ -77,29 +79,21 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry); - int fds[2] = {0}; - allocateSHMFilePair(tableSize, &fds[0], &fds[1]); + CFileDescriptor fds[2]; + allocateSHMFilePair(tableSize, fds[0], fds[1]); - auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); + auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0].get(), 0); if (arr == MAP_FAILED) { LOGM(ERR, "mmap failed"); - close(fds[0]); - close(fds[1]); return; } - close(fds[0]); - std::copy(formatsVec.begin(), formatsVec.end(), arr); munmap(arr, tableSize); - tableFD = fds[1]; -} - -CDMABUFFormatTable::~CDMABUFFormatTable() { - close(tableFD); + tableFD = std::move(fds[1]); } CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs) { @@ -234,18 +228,18 @@ void CLinuxDMABUFParamsResource::create(uint32_t id) { } bool CLinuxDMABUFParamsResource::commence() { - if (PROTO::linuxDma->mainDeviceFD < 0) + if (!PROTO::linuxDma->mainDeviceFD.isValid()) return true; for (int i = 0; i < attrs->planes; i++) { uint32_t handle = 0; - if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD, attrs->fds.at(i), &handle)) { + if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD.get(), attrs->fds.at(i), &handle)) { LOGM(ERR, "Failed to import dmabuf fd"); return false; } - if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD, handle)) { + if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD.get(), handle)) { LOGM(ERR, "Failed to close dmabuf handle"); return false; } @@ -303,7 +297,7 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SPsetDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); auto& formatTable = PROTO::linuxDma->formatTable; - resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize); + resource->sendFormatTable(formatTable->tableFD.get(), formatTable->tableSize); sendDefaultFeedback(); } @@ -472,9 +466,9 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const if (device->available_nodes & (1 << DRM_NODE_RENDER)) { const char* name = device->nodes[DRM_NODE_RENDER]; - mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); + mainDeviceFD = CFileDescriptor{open(name, O_RDWR | O_CLOEXEC)}; drmFreeDevice(&device); - if (mainDeviceFD < 0) { + if (!mainDeviceFD.isValid()) { LOGM(ERR, "failed to open drm dev, disabling linux dmabuf"); removeGlobal(); return; @@ -496,7 +490,7 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { auto newFormatTable = makeUnique(formatTable->rendererTranche, formatTable->monitorTranches); for (auto const& feedback : m_vFeedbacks) { - feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); + feedback->resource->sendFormatTable(newFormatTable->tableFD.get(), newFormatTable->tableSize); if (feedback->lastFeedbackWasScanout) { PHLMONITOR mon; auto HLSurface = CWLSurface::fromResource(feedback->surface); @@ -519,11 +513,6 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { formatTable = std::move(newFormatTable); } -CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { - if (mainDeviceFD >= 0) - close(mainDeviceFD); -} - void CLinuxDMABufV1Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 91cf3283f0f..6c9678787e0 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -9,6 +9,7 @@ #include "../helpers/Format.hpp" #include "../helpers/Monitor.hpp" #include +#include class CDMABuffer; class CWLSurfaceResource; @@ -48,9 +49,9 @@ struct SDMABUFTranche { class CDMABUFFormatTable { public: CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector> tranches); - ~CDMABUFFormatTable(); + ~CDMABUFFormatTable() = default; - int tableFD = -1; + Hyprutils::OS::CFileDescriptor tableFD; size_t tableSize = 0; SDMABUFTranche rendererTranche; std::vector> monitorTranches; @@ -107,7 +108,7 @@ class CLinuxDMABUFResource { class CLinuxDMABufV1Protocol : public IWaylandProtocol { public: CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name); - ~CLinuxDMABufV1Protocol(); + ~CLinuxDMABufV1Protocol() = default; virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); void updateScanoutTranche(SP surface, PHLMONITOR pMonitor); @@ -128,7 +129,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { UP formatTable; dev_t mainDevice; - int mainDeviceFD = -1; + Hyprutils::OS::CFileDescriptor mainDeviceFD; friend class CLinuxDMABUFResource; friend class CLinuxDMABUFFeedbackResource; diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index 567bfdd2359..620f262e52b 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -3,6 +3,7 @@ #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "../config/ConfigValue.hpp" +using namespace Hyprutils::OS; CPrimarySelectionOffer::CPrimarySelectionOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -12,21 +13,20 @@ CPrimarySelectionOffer::CPrimarySelectionOffer(SP r resource->setOnDestroy([this](CZwpPrimarySelectionOfferV1* r) { PROTO::primarySelection->destroyResource(this); }); resource->setReceive([this](CZwpPrimarySelectionOfferV1* r, const char* mime, int32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); - source->send(mime, fd); + source->send(mime, std::move(sendFd)); }); } @@ -78,15 +78,13 @@ std::vector CPrimarySelectionSource::mimes() { return mimeTypes; } -void CPrimarySelectionSource::send(const std::string& mime, uint32_t fd) { +void CPrimarySelectionSource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CPrimarySelectionSource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CPrimarySelectionSource::accepted(const std::string& mime) { diff --git a/src/protocols/PrimarySelection.hpp b/src/protocols/PrimarySelection.hpp index aeebe03c45f..0ecc962b3c3 100644 --- a/src/protocols/PrimarySelection.hpp +++ b/src/protocols/PrimarySelection.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "primary-selection-unstable-v1.hpp" #include "types/DataDevice.hpp" +#include class CPrimarySelectionOffer; class CPrimarySelectionSource; @@ -38,7 +39,7 @@ class CPrimarySelectionSource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp index e5b3cf2ac00..30fca260817 100644 --- a/src/protocols/SecurityContext.cpp +++ b/src/protocols/SecurityContext.cpp @@ -1,6 +1,7 @@ #include "SecurityContext.hpp" #include "../Compositor.hpp" #include +using namespace Hyprutils::OS; static int onListenFdEvent(int fd, uint32_t mask, void* data) { auto sc = (CSecurityContext*)data; @@ -14,8 +15,8 @@ static int onCloseFdEvent(int fd, uint32_t mask, void* data) { return 0; } -SP CSecurityContextSandboxedClient::create(int clientFD_) { - auto p = SP(new CSecurityContextSandboxedClient(clientFD_)); +SP CSecurityContextSandboxedClient::create(CFileDescriptor clientFD_) { + auto p = SP(new CSecurityContextSandboxedClient(std::move(clientFD_))); if (!p->client) return nullptr; return p; @@ -27,8 +28,8 @@ static void onSecurityContextClientDestroy(wl_listener* l, void* d) { client->onDestroy(); } -CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) : clientFD(clientFD_) { - client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD); +CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(CFileDescriptor clientFD_) : clientFD(std::move(clientFD_)) { + client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD.get()); if (!client) return; @@ -41,7 +42,6 @@ CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) CSecurityContextSandboxedClient::~CSecurityContextSandboxedClient() { wl_list_remove(&destroyListener.listener.link); wl_list_init(&destroyListener.listener.link); - close(clientFD); } void CSecurityContextSandboxedClient::onDestroy() { @@ -113,8 +113,8 @@ CSecurityContext::CSecurityContext(SP resource_, int liste LOGM(LOG, "security_context at 0x{:x} commits", (uintptr_t)this); - listenSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, listenFD, WL_EVENT_READABLE, ::onListenFdEvent, this); - closeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, closeFD, 0, ::onCloseFdEvent, this); + listenSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, listenFD.get(), WL_EVENT_READABLE, ::onListenFdEvent, this); + closeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, closeFD.get(), 0, ::onCloseFdEvent, this); if (!listenSource || !closeSource) { r->noMemory(); @@ -144,16 +144,15 @@ void CSecurityContext::onListen(uint32_t mask) { if (!(mask & WL_EVENT_READABLE)) return; - int clientFD = accept(listenFD, nullptr, nullptr); - if UNLIKELY (clientFD < 0) { + CFileDescriptor clientFD{accept(listenFD.get(), nullptr, nullptr)}; + if UNLIKELY (!clientFD.isValid()) { LOGM(ERR, "security_context at 0x{:x} couldn't accept", (uintptr_t)this); return; } - auto newClient = CSecurityContextSandboxedClient::create(clientFD); + auto newClient = CSecurityContextSandboxedClient::create(std::move(clientFD)); if UNLIKELY (!newClient) { LOGM(ERR, "security_context at 0x{:x} couldn't create a client", (uintptr_t)this); - close(clientFD); return; } diff --git a/src/protocols/SecurityContext.hpp b/src/protocols/SecurityContext.hpp index 2bec08d4dcf..56d4f7b41f3 100644 --- a/src/protocols/SecurityContext.hpp +++ b/src/protocols/SecurityContext.hpp @@ -4,19 +4,20 @@ #include #include "WaylandProtocol.hpp" #include "security-context-v1.hpp" +#include class CSecurityContext { public: CSecurityContext(SP resource_, int listenFD_, int closeFD_); ~CSecurityContext(); - bool good(); + bool good(); - std::string sandboxEngine, appID, instanceID; - int listenFD = -1, closeFD = -1; + std::string sandboxEngine, appID, instanceID; + Hyprutils::OS::CFileDescriptor listenFD, closeFD; - void onListen(uint32_t mask); - void onClose(uint32_t mask); + void onListen(uint32_t mask); + void onClose(uint32_t mask); private: SP resource; @@ -44,7 +45,7 @@ struct SCSecurityContextSandboxedClientDestroyWrapper { class CSecurityContextSandboxedClient { public: - static SP create(int clientFD); + static SP create(Hyprutils::OS::CFileDescriptor clientFD); ~CSecurityContextSandboxedClient(); void onDestroy(); @@ -52,10 +53,10 @@ class CSecurityContextSandboxedClient { SCSecurityContextSandboxedClientDestroyWrapper destroyListener; private: - CSecurityContextSandboxedClient(int clientFD_); + CSecurityContextSandboxedClient(Hyprutils::OS::CFileDescriptor clientFD_); - wl_client* client = nullptr; - int clientFD = -1; + wl_client* client = nullptr; + Hyprutils::OS::CFileDescriptor clientFD; friend class CSecurityContextProtocol; friend class CSecurityContext; diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 4fec57c05b6..00aca04112f 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -1,6 +1,7 @@ #include "VirtualKeyboard.hpp" #include #include "../devices/IKeyboard.hpp" +using namespace Hyprutils::OS; CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) { if UNLIKELY (!good()) @@ -51,20 +52,19 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP }); resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) { - auto xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + auto xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + CFileDescriptor keymapFd{fd}; if UNLIKELY (!xkbContext) { LOGM(ERR, "xkbContext creation failed"); r->noMemory(); - close(fd); return; } - auto keymapData = mmap(nullptr, len, PROT_READ, MAP_PRIVATE, fd, 0); + auto keymapData = mmap(nullptr, len, PROT_READ, MAP_PRIVATE, keymapFd.get(), 0); if UNLIKELY (keymapData == MAP_FAILED) { LOGM(ERR, "keymapData alloc failed"); xkb_context_unref(xkbContext); r->noMemory(); - close(fd); return; } @@ -75,7 +75,6 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP LOGM(ERR, "xkbKeymap creation failed"); xkb_context_unref(xkbContext); r->noMemory(); - close(fd); return; } @@ -86,7 +85,6 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP xkb_keymap_unref(xkbKeymap); xkb_context_unref(xkbContext); - close(fd); }); name = "hl-virtual-keyboard"; diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp index 8157b276697..0a13003b385 100644 --- a/src/protocols/VirtualKeyboard.hpp +++ b/src/protocols/VirtualKeyboard.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "virtual-keyboard-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CVirtualKeyboardV1Resource { public: diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index e17b5612fb5..0931608a9db 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -13,6 +13,7 @@ #include "../../managers/HookSystemManager.hpp" #include "../../helpers/Monitor.hpp" #include "../../render/Renderer.hpp" +using namespace Hyprutils::OS; CWLDataOfferResource::CWLDataOfferResource(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -39,15 +40,14 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPsetReceive([this](CWlDataOffer* r, const char* mime, uint32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } @@ -58,7 +58,7 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPaccepted(mime ? mime : ""); } - source->send(mime ? mime : "", fd); + source->send(mime ? mime : "", std::move(sendFd)); recvd = true; @@ -182,15 +182,13 @@ std::vector CWLDataSourceResource::mimes() { return mimeTypes; } -void CWLDataSourceResource::send(const std::string& mime, uint32_t fd) { +void CWLDataSourceResource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLDataSourceResource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CWLDataSourceResource::cancelled() { diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index d8bc2b9ca51..dfea4a71efd 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -16,6 +16,7 @@ #include "../../helpers/signal/Signal.hpp" #include "../../helpers/math/Math.hpp" #include "../types/DataDevice.hpp" +#include class CWLDataDeviceResource; class CWLDataDeviceManagerResource; @@ -63,7 +64,7 @@ class CWLDataSourceResource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual bool hasDnd(); diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index c6b2de0566d..1f07a15e08f 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -321,35 +321,18 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) return; - std::string_view keymap; - int fd; - uint32_t size; - if (keyboard) { - keymap = keyboard->xkbKeymapString; - fd = keyboard->xkbKeymapFD; - size = keyboard->xkbKeymapString.length() + 1; - } else { - fd = open("/dev/null", O_RDONLY | O_CLOEXEC); - if (fd < 0) { - LOGM(ERR, "Failed to open /dev/null"); - return; - } - size = 0; - } + std::string_view keymap = keyboard->xkbKeymapString; + Hyprutils::OS::CFileDescriptor& fd = keyboard->xkbKeymapFD; + uint32_t size = keyboard->xkbKeymapString.length() + 1; - if (keymap == lastKeymap) { - if (!keyboard) - close(fd); + if (keymap == lastKeymap) return; - } + lastKeymap = keymap; const wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; - resource->sendKeymap(format, fd, size); - - if (!keyboard) - close(fd); + resource->sendKeymap(format, fd.get(), size); } void CWLKeyboardResource::sendEnter(SP surface) { diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 1649f82fc1c..e0e6256049d 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -7,6 +7,7 @@ #include "../types/WLBuffer.hpp" #include "../../helpers/Format.hpp" #include "../../render/Renderer.hpp" +using namespace Hyprutils::OS; CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) { if UNLIKELY (!pool_->pool->data) @@ -51,7 +52,7 @@ bool CWLSHMBuffer::isSynchronous() { Aquamarine::SSHMAttrs CWLSHMBuffer::shm() { Aquamarine::SSHMAttrs attrs; attrs.success = true; - attrs.fd = pool->fd; + attrs.fd = pool->fd.get(); attrs.format = NFormatUtils::shmToDRM(fmt); attrs.size = size; attrs.stride = stride; @@ -75,13 +76,12 @@ void CWLSHMBuffer::update(const CRegion& damage) { texture->update(NFormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, damage); } -CSHMPool::CSHMPool(int fd_, size_t size_) : fd(fd_), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) { +CSHMPool::CSHMPool(CFileDescriptor fd_, size_t size_) : fd(std::move(fd_)), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0)) { ; } CSHMPool::~CSHMPool() { munmap(data, size); - close(fd); } void CSHMPool::resize(size_t size_) { @@ -90,23 +90,23 @@ void CSHMPool::resize(size_t size_) { if (data) munmap(data, size); size = size_; - data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0); if UNLIKELY (data == MAP_FAILED) - LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd); + LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd.get()); } -static int shmIsSizeValid(int fd, size_t size) { +static int shmIsSizeValid(CFileDescriptor& fd, size_t size) { struct stat st; - if UNLIKELY (fstat(fd, &st) == -1) { - LOGM(ERR, "Couldn't get stat for fd {} of shm client", fd); + if UNLIKELY (fstat(fd.get(), &st) == -1) { + LOGM(ERR, "Couldn't get stat for fd {} of shm client", fd.get()); return 0; } return (size_t)st.st_size >= size; } -CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t size_) : resource(resource_) { +CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, CFileDescriptor fd_, size_t size_) : resource(resource_) { if UNLIKELY (!good()) return; @@ -115,7 +115,7 @@ CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t return; } - pool = makeShared(fd_, size_); + pool = makeShared(std::move(fd_), size_); resource->setDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); resource->setOnDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); @@ -176,7 +176,8 @@ CWLSHMResource::CWLSHMResource(SP resource_) : resource(resource_) { resource->setOnDestroy([this](CWlShm* r) { PROTO::shm->destroyResource(this); }); resource->setCreatePool([](CWlShm* r, uint32_t id, int32_t fd, int32_t size) { - const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared(makeShared(r->client(), r->version(), id), fd, size)); + CFileDescriptor poolFd{fd}; + const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared(makeShared(r->client(), r->version(), id), std::move(poolFd), size)); if UNLIKELY (!RESOURCE->good()) { r->noMemory(); diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index d7e81367c21..fef821cb36e 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -7,6 +7,8 @@ - wl_buffer with shm */ +#include +#include #include #include #include "../WaylandProtocol.hpp" @@ -18,14 +20,14 @@ class CWLSHMPoolResource; class CSHMPool { public: - CSHMPool(int fd, size_t size); + CSHMPool(Hyprutils::OS::CFileDescriptor fd, size_t size); ~CSHMPool(); - int fd = 0; - size_t size = 0; - void* data = nullptr; + Hyprutils::OS::CFileDescriptor fd; + size_t size = 0; + void* data = nullptr; - void resize(size_t size); + void resize(size_t size); }; class CWLSHMBuffer : public IHLBuffer { @@ -57,7 +59,7 @@ class CWLSHMBuffer : public IHLBuffer { class CWLSHMPoolResource { public: - CWLSHMPoolResource(SP resource_, int fd, size_t size); + CWLSHMPoolResource(SP resource_, Hyprutils::OS::CFileDescriptor fd, size_t size); bool good(); diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp index 62f10de23ab..cbb4b271834 100644 --- a/src/protocols/types/DataDevice.hpp +++ b/src/protocols/types/DataDevice.hpp @@ -7,6 +7,7 @@ #include #include "../../helpers/memory/Memory.hpp" #include "../../helpers/math/Math.hpp" +#include class CWLDataOfferResource; class CX11DataOffer; @@ -24,10 +25,10 @@ class IDataSource { IDataSource() = default; virtual ~IDataSource() = default; - virtual std::vector mimes() = 0; - virtual void send(const std::string& mime, uint32_t fd) = 0; - virtual void accepted(const std::string& mime) = 0; - virtual void cancelled() = 0; + virtual std::vector mimes() = 0; + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd) = 0; + virtual void accepted(const std::string& mime) = 0; + virtual void cancelled() = 0; virtual bool hasDnd(); virtual bool dndDone(); virtual void sendDndFinished(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 78b53c9bc80..e4aadd63dc2 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -19,6 +19,7 @@ #include #include #include +using namespace Hyprutils::OS; const std::vector ASSET_PATHS = { #ifdef DATAROOTDIR @@ -301,11 +302,11 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() : m_iDRMFD(g_pCompositor->m_iDRMFD) { Debug::log(WARN, "EGL: EXT_platform_device or EGL_EXT_device_query not supported, using gbm"); if (EGLEXTENSIONS.contains("KHR_platform_gbm")) { success = true; - m_iGBMFD = openRenderNode(m_iDRMFD); - if (m_iGBMFD < 0) + m_iGBMFD = CFileDescriptor{openRenderNode(m_iDRMFD)}; + if (!m_iGBMFD.isValid()) RASSERT(false, "Couldn't open a gbm fd"); - m_pGbmDevice = gbm_create_device(m_iGBMFD); + m_pGbmDevice = gbm_create_device(m_iGBMFD.get()); if (!m_pGbmDevice) RASSERT(false, "Couldn't open a gbm device"); @@ -371,9 +372,6 @@ CHyprOpenGLImpl::~CHyprOpenGLImpl() { if (m_pGbmDevice) gbm_device_destroy(m_pGbmDevice); - - if (m_iGBMFD >= 0) - close(m_iGBMFD); } std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint format) { @@ -2954,29 +2952,28 @@ std::vector CHyprOpenGLImpl::getDRMFormats() { return drmFormats; } -SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { +SP CHyprOpenGLImpl::createEGLSync(CFileDescriptor fenceFD) { std::vector attribs; - int dupFd = -1; - if (fenceFD > 0) { - dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); - if (dupFd < 0) { + CFileDescriptor dupFd; + if (fenceFD.isValid()) { + dupFd = fenceFD.duplicate(); + if (!dupFd.isValid()) { Debug::log(ERR, "createEGLSync: dup failed"); return nullptr; } // reserve number of elements to avoid reallocations attribs.reserve(3); attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID); - attribs.push_back(dupFd); + attribs.push_back(dupFd.get()); attribs.push_back(EGL_NONE); } EGLSyncKHR sync = m_sProc.eglCreateSyncKHR(m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data()); if (sync == EGL_NO_SYNC_KHR) { Debug::log(ERR, "eglCreateSyncKHR failed"); - if (dupFd >= 0) - close(dupFd); return nullptr; - } + } else + dupFd.take(); // eglCreateSyncKHR only takes ownership on success // we need to flush otherwise we might not get a valid fd glFlush(); @@ -2989,19 +2986,18 @@ SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { auto eglsync = SP(new CEGLSync); eglsync->sync = sync; - eglsync->m_iFd = fd; + eglsync->m_iFd = CFileDescriptor{fd}; return eglsync; } bool CHyprOpenGLImpl::waitForTimelinePoint(SP timeline, uint64_t point) { - int fd = timeline->exportAsSyncFileFD(point); - if (fd < 0) { + auto fd = timeline->exportAsSyncFileFD(point); + if (!fd.isValid()) { Debug::log(ERR, "waitForTimelinePoint: failed to get a fd from explicit timeline"); return false; } - auto sync = g_pHyprOpenGL->createEGLSync(fd); - close(fd); + auto sync = g_pHyprOpenGL->createEGLSync(std::move(fd)); if (!sync) { Debug::log(ERR, "waitForTimelinePoint: failed to get an eglsync from explicit timeline"); return false; @@ -3082,12 +3078,9 @@ CEGLSync::~CEGLSync() { if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE) Debug::log(ERR, "eglDestroySyncKHR failed"); - - if (m_iFd >= 0) - close(m_iFd); } -int CEGLSync::fd() { +CFileDescriptor& CEGLSync::fd() { return m_iFd; } diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 1ebb01628f1..d7abdf639c4 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "../debug/TracyDefines.hpp" @@ -146,15 +147,15 @@ class CEGLSync { public: ~CEGLSync(); - EGLSyncKHR sync = nullptr; + EGLSyncKHR sync = nullptr; - int fd(); - bool wait(); + Hyprutils::OS::CFileDescriptor& fd(); + bool wait(); private: CEGLSync() = default; - int m_iFd = -1; + Hyprutils::OS::CFileDescriptor m_iFd; friend class CHyprOpenGLImpl; }; @@ -228,14 +229,14 @@ class CHyprOpenGLImpl { uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); std::vector getDRMFormats(); EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(int fenceFD); + SP createEGLSync(Hyprutils::OS::CFileDescriptor fenceFD); bool waitForTimelinePoint(SP timeline, uint64_t point); SCurrentRenderData m_RenderData; GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; + Hyprutils::OS::CFileDescriptor m_iGBMFD; gbm_device* m_pGbmDevice = nullptr; EGLContext m_pEglContext = nullptr; EGLDisplay m_pEglDisplay = nullptr; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 67d8b58b151..42445728077 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -36,6 +36,7 @@ #include using namespace Hyprutils::Utils; +using namespace Hyprutils::OS; extern "C" { #include @@ -1462,10 +1463,10 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, Aquamar bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { // apply timelines for explicit sync // save inFD otherwise reset will reset it - auto inFD = pMonitor->output->state->state().explicitInFence; + CFileDescriptor inFD{pMonitor->output->state->state().explicitInFence}; pMonitor->output->state->resetExplicitFences(); - if (inFD >= 0) - pMonitor->output->state->setExplicitInFence(inFD); + if (inFD.isValid()) + pMonitor->output->state->setExplicitInFence(inFD.get()); static auto PHDR = CConfigValue("experimental:hdr"); @@ -1515,7 +1516,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { bool ok = pMonitor->state.commit(); if (!ok) { - if (inFD >= 0) { + if (inFD.isValid()) { Debug::log(TRACE, "Monitor state commit failed, retrying without a fence"); pMonitor->output->state->resetExplicitFences(); ok = pMonitor->state.commit(); @@ -1534,11 +1535,8 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { if (!explicitOptions.explicitEnabled) return ok; - if (inFD >= 0) - close(inFD); - Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size()); - auto sync = g_pHyprOpenGL->createEGLSync(-1); + auto sync = g_pHyprOpenGL->createEGLSync({}); if (!sync) Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed"); @@ -2272,7 +2270,7 @@ void CHyprRenderer::endRender() { auto explicitOptions = getExplicitSyncSettings(); if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { - auto sync = g_pHyprOpenGL->createEGLSync(-1); + auto sync = g_pHyprOpenGL->createEGLSync({}); if (!sync) { Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); return; @@ -2285,12 +2283,12 @@ void CHyprRenderer::endRender() { } auto fd = PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq); - if (fd <= 0) { + if (!fd.isValid()) { Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender"); return; } - PMONITOR->output->state->setExplicitInFence(fd); + PMONITOR->output->state->setExplicitInFence(fd.take()); } else { if (isNvidia() && *PNVIDIAANTIFLICKER) glFinish(); diff --git a/src/xwayland/Dnd.cpp b/src/xwayland/Dnd.cpp index d4ae3780556..16d166ce2f9 100644 --- a/src/xwayland/Dnd.cpp +++ b/src/xwayland/Dnd.cpp @@ -7,6 +7,8 @@ #include "../managers/XWaylandManager.hpp" #include "../desktop/WLSurface.hpp" +using namespace Hyprutils::OS; + #ifndef NO_XWAYLAND static xcb_atom_t dndActionToAtom(uint32_t actions) { if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) @@ -172,7 +174,7 @@ std::vector CX11DataSource::mimes() { return mimeTypes; } -void CX11DataSource::send(const std::string& mime, uint32_t fd) { +void CX11DataSource::send(const std::string& mime, CFileDescriptor fd) { ; } diff --git a/src/xwayland/Dnd.hpp b/src/xwayland/Dnd.hpp index 8da60ddd48e..fb0307963f4 100644 --- a/src/xwayland/Dnd.hpp +++ b/src/xwayland/Dnd.hpp @@ -2,6 +2,7 @@ #include "../protocols/types/DataDevice.hpp" #include +#include #define XDND_VERSION 5 @@ -35,7 +36,7 @@ class CX11DataSource : public IDataSource { ~CX11DataSource() = default; virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual bool hasDnd(); diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index d5dce333809..99bcdf62a06 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -24,70 +24,41 @@ #include "../defines.hpp" #include "../Compositor.hpp" #include "../managers/CursorManager.hpp" +using namespace Hyprutils::OS; // Constants -constexpr int SOCKET_DIR_PERMISSIONS = 0755; -constexpr int SOCKET_BACKLOG = 1; -constexpr int MAX_SOCKET_RETRIES = 32; -constexpr int LOCK_FILE_MODE = 0444; - -static bool setCloseOnExec(int fd, bool cloexec) { - int flags = fcntl(fd, F_GETFD); - if (flags == -1) { - Debug::log(ERR, "fcntl failed"); - return false; - } - - if (cloexec) - flags = flags | FD_CLOEXEC; - else - flags = flags & ~FD_CLOEXEC; - - if (fcntl(fd, F_SETFD, flags) == -1) { - Debug::log(ERR, "fcntl failed"); - return false; - } - - return true; -} - -static void cleanUpSocket(int fd, const char* path) { - close(fd); - if (path[0]) - unlink(path); -} - -static inline void closeSocketSafely(int& fd) { - if (fd >= 0) - close(fd); -} - -static int createSocket(struct sockaddr_un* addr, size_t path_size) { - socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { +constexpr int SOCKET_DIR_PERMISSIONS = 0755; +constexpr int SOCKET_BACKLOG = 1; +constexpr int MAX_SOCKET_RETRIES = 32; +constexpr int LOCK_FILE_MODE = 0444; + +static CFileDescriptor createSocket(struct sockaddr_un* addr, size_t path_size) { + socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; + CFileDescriptor fd{socket(AF_UNIX, SOCK_STREAM, 0)}; + if (!fd.isValid()) { Debug::log(ERR, "Failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - return -1; + return {}; } - if (!setCloseOnExec(fd, true)) { - close(fd); - return -1; + if (!fd.setFlags(fd.getFlags() | FD_CLOEXEC)) { + return {}; } if (addr->sun_path[0]) unlink(addr->sun_path); - if (bind(fd, (struct sockaddr*)addr, size) < 0) { + if (bind(fd.get(), (struct sockaddr*)addr, size) < 0) { Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - cleanUpSocket(fd, addr->sun_path); - return -1; + if (addr->sun_path[0]) + unlink(addr->sun_path); + return {}; } - if (listen(fd, SOCKET_BACKLOG) < 0) { + if (listen(fd.get(), SOCKET_BACKLOG) < 0) { Debug::log(ERR, "Failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - cleanUpSocket(fd, addr->sun_path); - return -1; + if (addr->sun_path[0]) + unlink(addr->sun_path); + return {}; } return fd; @@ -141,7 +112,7 @@ static std::string getSocketPath(int display, bool isLinux) { return std::format("/tmp/.X11-unix/X{}_", display); } -static bool openSockets(std::array& sockets, int display) { +static bool openSockets(std::array& sockets, int display) { if (!ensureSocketDirExists()) return false; @@ -151,17 +122,16 @@ static bool openSockets(std::array& sockets, int display) { path = getSocketPath(display, false); strncpy(addr.sun_path, path.c_str(), path.length() + 1); - sockets[0] = createSocket(&addr, path.length()); - if (sockets[0] < 0) + sockets[0] = CFileDescriptor{createSocket(&addr, path.length())}; + if (!sockets[0].isValid()) return false; path = getSocketPath(display, true); strncpy(addr.sun_path, path.c_str(), path.length() + 1); - sockets[1] = createSocket(&addr, path.length()); - if (sockets[1] < 0) { - close(sockets[0]); - sockets[0] = -1; + sockets[1] = CFileDescriptor{createSocket(&addr, path.length())}; + if (!sockets[1].isValid()) { + sockets[0].reset(); return false; } @@ -174,7 +144,8 @@ static void startServer(void* data) { } static int xwaylandReady(int fd, uint32_t mask, void* data) { - return g_pXWayland->pServer->ready(fd, mask); + CFileDescriptor xwlFd{fd}; + return g_pXWayland->pServer->ready(std::move(xwlFd), mask); } static bool safeRemove(const std::string& path) { @@ -186,38 +157,34 @@ static bool safeRemove(const std::string& path) { bool CXWaylandServer::tryOpenSockets() { for (size_t i = 0; i <= MAX_SOCKET_RETRIES; ++i) { - std::string lockPath = std::format("/tmp/.X{}-lock", i); + std::string lockPath = std::format("/tmp/.X{}-lock", i); - int fd = open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE); - if (fd >= 0) { + CFileDescriptor fd{open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE)}; + if (fd.isValid()) { // we managed to open the lock if (!openSockets(xFDs, i)) { safeRemove(lockPath); - close(fd); continue; } const std::string pidStr = std::to_string(getpid()); - if (write(fd, pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { + if (write(fd.get(), pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { safeRemove(lockPath); - close(fd); continue; } - close(fd); display = i; displayName = std::format(":{}", display); break; } - fd = open(lockPath.c_str(), O_RDONLY | O_CLOEXEC); + fd = CFileDescriptor{open(lockPath.c_str(), O_RDONLY | O_CLOEXEC)}; - if (fd < 0) + if (!fd.isValid()) continue; char pidstr[12] = {0}; - read(fd, pidstr, sizeof(pidstr) - 1); - close(fd); + read(fd.get(), pidstr, sizeof(pidstr) - 1); int32_t pid = 0; try { @@ -249,9 +216,6 @@ CXWaylandServer::~CXWaylandServer() { if (display < 0) return; - closeSocketSafely(xFDs[0]); - closeSocketSafely(xFDs[1]); - std::string lockPath = std::format("/tmp/.X{}-lock", display); safeRemove(lockPath); @@ -277,21 +241,11 @@ void CXWaylandServer::die() { if (pipeSource) wl_event_source_remove(pipeSource); - if (pipeFd >= 0) - close(pipeFd); - - closeSocketSafely(waylandFDs[0]); - closeSocketSafely(waylandFDs[1]); - closeSocketSafely(xwmFDs[0]); - closeSocketSafely(xwmFDs[1]); - // possible crash. Better to leak a bit. //if (xwaylandClient) // wl_client_destroy(xwaylandClient); xwaylandClient = nullptr; - waylandFDs = {-1, -1}; - xwmFDs = {-1, -1}; } bool CXWaylandServer::create() { @@ -307,15 +261,17 @@ bool CXWaylandServer::create() { return true; } -void CXWaylandServer::runXWayland(int notifyFD) { - if (!setCloseOnExec(xFDs[0], false) || !setCloseOnExec(xFDs[1], false) || !setCloseOnExec(waylandFDs[1], false) || !setCloseOnExec(xwmFDs[1], false)) { +void CXWaylandServer::runXWayland(CFileDescriptor& notifyFD) { + if (!xFDs[0].setFlags(xFDs[0].getFlags() & ~FD_CLOEXEC) || !xFDs[1].setFlags(xFDs[1].getFlags() & ~FD_CLOEXEC) || + !waylandFDs[1].setFlags(waylandFDs[1].getFlags() & ~FD_CLOEXEC) || !xwmFDs[1].setFlags(xwmFDs[1].getFlags() & ~FD_CLOEXEC)) { Debug::log(ERR, "Failed to unset cloexec on fds"); _exit(EXIT_FAILURE); } - auto cmd = std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0], xFDs[1], notifyFD, xwmFDs[1]); + auto cmd = + std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0].get(), xFDs[1].get(), notifyFD.get(), xwmFDs[1].get()); - auto waylandSocket = std::format("{}", waylandFDs[1]); + auto waylandSocket = std::format("{}", waylandFDs[1].get()); setenv("WAYLAND_SOCKET", waylandSocket.c_str(), true); Debug::log(LOG, "Starting XWayland with \"{}\", bon voyage!", cmd); @@ -327,40 +283,46 @@ void CXWaylandServer::runXWayland(int notifyFD) { } bool CXWaylandServer::start() { - idleSource = nullptr; - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, waylandFDs.data()) != 0) { + idleSource = nullptr; + int wlPair[2] = {-1, -1}; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, wlPair) != 0) { Debug::log(ERR, "socketpair failed (1)"); die(); return false; } + waylandFDs[0] = CFileDescriptor{wlPair[0]}; + waylandFDs[1] = CFileDescriptor{wlPair[1]}; - if (!setCloseOnExec(waylandFDs[0], true) || !setCloseOnExec(waylandFDs[1], true)) { + if (!waylandFDs[0].setFlags(waylandFDs[0].getFlags() | FD_CLOEXEC) || !waylandFDs[1].setFlags(waylandFDs[1].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (1)"); die(); return false; } - if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmFDs.data()) != 0) { + int xwmPair[2] = {-1, -1}; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmPair) != 0) { Debug::log(ERR, "socketpair failed (2)"); die(); return false; } - if (!setCloseOnExec(xwmFDs[0], true) || !setCloseOnExec(xwmFDs[1], true)) { + xwmFDs[0] = CFileDescriptor{xwmPair[0]}; + xwmFDs[1] = CFileDescriptor{xwmPair[1]}; + + if (!xwmFDs[0].setFlags(xwmFDs[0].getFlags() | FD_CLOEXEC) || !xwmFDs[1].setFlags(xwmFDs[1].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (2)"); die(); return false; } - xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0]); + xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0].get()); if (!xwaylandClient) { Debug::log(ERR, "wl_client_create failed"); die(); return false; } - waylandFDs[0] = -1; + waylandFDs[0].take(); // does this leak? int notify[2] = {-1, -1}; if (pipe(notify) < 0) { @@ -369,22 +331,20 @@ bool CXWaylandServer::start() { return false; } - if (!setCloseOnExec(notify[0], true)) { + CFileDescriptor notifyFds[2] = {CFileDescriptor{notify[0]}, CFileDescriptor{notify[1]}}; + + if (!notifyFds[0].setFlags(notifyFds[0].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (3)"); - close(notify[0]); - close(notify[1]); die(); return false; } - pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notify[0], WL_EVENT_READABLE, ::xwaylandReady, nullptr); - pipeFd = notify[0]; + pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notifyFds[0].get(), WL_EVENT_READABLE, ::xwaylandReady, nullptr); + pipeFd = std::move(notifyFds[0]); serverPID = fork(); if (serverPID < 0) { Debug::log(ERR, "fork failed"); - close(notify[0]); - close(notify[1]); die(); return false; } else if (serverPID == 0) { @@ -393,25 +353,19 @@ bool CXWaylandServer::start() { Debug::log(ERR, "second fork failed"); _exit(1); } else if (pid == 0) - runXWayland(notify[1]); + runXWayland(notifyFds[1]); _exit(0); } - close(notify[1]); - close(waylandFDs[1]); - closeSocketSafely(xwmFDs[1]); - waylandFDs[1] = -1; - xwmFDs[1] = -1; - return true; } -int CXWaylandServer::ready(int fd, uint32_t mask) { +int CXWaylandServer::ready(CFileDescriptor fd, uint32_t mask) { if (mask & WL_EVENT_READABLE) { // xwayland writes twice char buf[64]; - ssize_t n = read(fd, buf, sizeof(buf)); + ssize_t n = read(fd.get(), buf, sizeof(buf)); if (n < 0 && errno != EINTR) { Debug::log(ERR, "Xwayland: read from displayFd failed"); mask = 0; @@ -436,7 +390,6 @@ int CXWaylandServer::ready(int fd, uint32_t mask) { Debug::log(LOG, "XWayland is ready"); - close(fd); wl_event_source_remove(pipeSource); pipeSource = nullptr; diff --git a/src/xwayland/Server.hpp b/src/xwayland/Server.hpp index 7a36a965f9c..ccbcf6ea174 100644 --- a/src/xwayland/Server.hpp +++ b/src/xwayland/Server.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "../helpers/signal/Signal.hpp" struct wl_event_source; @@ -19,7 +20,7 @@ class CXWaylandServer { bool start(); // called on ready - int ready(int fd, uint32_t mask); + int ready(Hyprutils::OS::CFileDescriptor fd, uint32_t mask); void die(); @@ -30,20 +31,20 @@ class CXWaylandServer { wl_client* xwaylandClient = nullptr; private: - bool tryOpenSockets(); - void runXWayland(int notifyFD); - - pid_t serverPID = 0; - - std::string displayName; - int display = -1; - std::array xFDs = {-1, -1}; - std::array xFDReadEvents = {nullptr, nullptr}; - wl_event_source* idleSource = nullptr; - wl_event_source* pipeSource = nullptr; - int pipeFd = -1; - std::array xwmFDs = {-1, -1}; - std::array waylandFDs = {-1, -1}; + bool tryOpenSockets(); + void runXWayland(Hyprutils::OS::CFileDescriptor& notifyFD); + + pid_t serverPID = 0; + + std::string displayName; + int display = -1; + std::array xFDs; + std::array xFDReadEvents = {nullptr, nullptr}; + wl_event_source* idleSource = nullptr; + wl_event_source* pipeSource = nullptr; + Hyprutils::OS::CFileDescriptor pipeFd; + std::array xwmFDs; + std::array waylandFDs; friend class CXWM; }; diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index 4b0c5a295e3..e6282dcbd33 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -5,6 +5,7 @@ #include "XDataSource.hpp" #include +using namespace Hyprutils::OS; CXDataSource::CXDataSource(SXSelection& sel_) : selection(sel_) { xcb_get_property_cookie_t cookie = xcb_get_property(g_pXWayland->pWM->connection, @@ -47,7 +48,7 @@ std::vector CXDataSource::mimes() { return mimeTypes; } -void CXDataSource::send(const std::string& mime, uint32_t fd) { +void CXDataSource::send(const std::string& mime, CFileDescriptor fd) { xcb_atom_t mimeAtom = 0; if (mime == "text/plain") @@ -65,11 +66,10 @@ void CXDataSource::send(const std::string& mime, uint32_t fd) { if (!mimeAtom) { Debug::log(ERR, "[XDataSource] mime atom not found"); - close(fd); return; } - Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd); + Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd.get()); selection.transfer = makeUnique(selection); selection.transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection); @@ -81,8 +81,9 @@ void CXDataSource::send(const std::string& mime, uint32_t fd) { xcb_flush(g_pXWayland->pWM->connection); - fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK); - selection.transfer->wlFD = fd; + //TODO: make CFileDescriptor setflags take SETFL aswell + fcntl(fd.get(), F_SETFL, O_WRONLY | O_NONBLOCK); + selection.transfer->wlFD = std::move(fd); } void CXDataSource::accepted(const std::string& mime) { @@ -101,4 +102,4 @@ eDataSourceType CXDataSource::type() { return DATA_SOURCE_TYPE_X11; } -#endif \ No newline at end of file +#endif diff --git a/src/xwayland/XDataSource.hpp b/src/xwayland/XDataSource.hpp index c629aa2a99d..a61ffcc9039 100644 --- a/src/xwayland/XDataSource.hpp +++ b/src/xwayland/XDataSource.hpp @@ -1,6 +1,7 @@ #pragma once #include "../protocols/types/DataDevice.hpp" +#include struct SXSelection; @@ -9,7 +10,7 @@ class CXDataSource : public IDataSource { CXDataSource(SXSelection&); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); @@ -19,4 +20,4 @@ class CXDataSource : public IDataSource { SXSelection& selection; std::vector mimeTypes; // these two have shared idx std::vector mimeAtoms; // -}; \ No newline at end of file +}; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 6673105e775..81900c7b4c8 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -17,6 +17,7 @@ #include "../managers/SeatManager.hpp" #include "../protocols/XWaylandShell.hpp" #include "../protocols/core/Compositor.hpp" +using namespace Hyprutils::OS; #define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f #define INCR_CHUNK_SIZE (64 * 1024) @@ -883,7 +884,7 @@ void CXWM::getRenderFormat() { free(reply); } -CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) { +CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0].get()) { if (connection.hasError()) { Debug::log(ERR, "[xwm] Couldn't start, error {}", connection.hasError()); @@ -901,7 +902,7 @@ CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) { xcb_screen_iterator_t screen_iterator = xcb_setup_roots_iterator(xcb_get_setup(connection)); screen = screen_iterator.data; - eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, g_pXWayland->pServer->xwmFDs[0], WL_EVENT_READABLE, ::onX11Event, nullptr); + eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, g_pXWayland->pServer->xwmFDs[0].get(), WL_EVENT_READABLE, ::onX11Event, nullptr); wl_event_source_check(eventSource); gatherResources(); @@ -1180,13 +1181,12 @@ void CXWM::getTransferData(SXSelection& sel) { if (sel.transfer->propertyReply->type == HYPRATOMS["INCR"]) { Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); - close(sel.transfer->wlFD); sel.transfer.reset(); return; } else { sel.onWrite(); if (sel.transfer) - sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD, WL_EVENT_WRITABLE, ::writeDataSource, &sel); + sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD.get(), WL_EVENT_WRITABLE, ::writeDataSource, &sel); } } @@ -1361,13 +1361,13 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { // the wayland client might not expect a non-blocking fd // fcntl(p[1], F_SETFL, O_NONBLOCK); - transfer->wlFD = p[0]; + transfer->wlFD = CFileDescriptor{p[0]}; Debug::log(LOG, "[xwm] sending wayland selection to xwayland with mime {}, target {}, fds {} {}", mime, e->target, p[0], p[1]); - selection->send(mime, p[1]); + selection->send(mime, CFileDescriptor{p[1]}); - transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD, WL_EVENT_READABLE, ::readDataSource, this); + transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD.get(), WL_EVENT_READABLE, ::readDataSource, this); return true; } @@ -1376,10 +1376,9 @@ int SXSelection::onWrite() { char* property = (char*)xcb_get_property_value(transfer->propertyReply); int remainder = xcb_get_property_value_length(transfer->propertyReply) - transfer->propertyStart; - ssize_t len = write(transfer->wlFD, property + transfer->propertyStart, remainder); + ssize_t len = write(transfer->wlFD.get(), property + transfer->propertyStart, remainder); if (len == -1) { Debug::log(ERR, "[xwm] write died in transfer get"); - close(transfer->wlFD); transfer.reset(); return 0; } @@ -1389,7 +1388,6 @@ int SXSelection::onWrite() { Debug::log(LOG, "[xwm] wl client read partially: len {}", len); } else { Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); - close(transfer->wlFD); transfer.reset(); } @@ -1397,8 +1395,6 @@ int SXSelection::onWrite() { } SXTransfer::~SXTransfer() { - if (wlFD) - close(wlFD); if (eventSource) wl_event_source_remove(eventSource); if (incomingWindow) diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index dfaf33b91f8..73a02a861a9 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -10,6 +10,7 @@ #include #include #include +#include struct wl_event_source; class CXWaylandSurfaceResource; @@ -18,25 +19,25 @@ struct SXSelection; struct SXTransfer { ~SXTransfer(); - SXSelection& selection; - bool out = true; + SXSelection& selection; + bool out = true; - bool incremental = false; - bool flushOnDelete = false; - bool propertySet = false; + bool incremental = false; + bool flushOnDelete = false; + bool propertySet = false; - int wlFD = -1; - wl_event_source* eventSource = nullptr; + Hyprutils::OS::CFileDescriptor wlFD; + wl_event_source* eventSource = nullptr; - std::vector data; + std::vector data; - xcb_selection_request_event_t request; + xcb_selection_request_event_t request; - int propertyStart; - xcb_get_property_reply_t* propertyReply; - xcb_window_t incomingWindow; + int propertyStart; + xcb_get_property_reply_t* propertyReply; + xcb_window_t incomingWindow; - bool getIncomingSelectionProp(bool erase); + bool getIncomingSelectionProp(bool erase); }; struct SXSelection {