Skip to content

Commit

Permalink
core: fix sleep delay and simplify process spawning
Browse files Browse the repository at this point in the history
  • Loading branch information
PaideiaDilemma committed Feb 6, 2025
1 parent 15ca902 commit 0b4d1dc
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 50 deletions.
103 changes: 54 additions & 49 deletions src/core/Hypridle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,19 @@ CHypridle::CHypridle() {
}
}

void setupSignals(void) {
struct sigaction sa;

// don't transform child processes into zombies and don't handle SIGCHLD.
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART;
sa.sa_handler = SIG_DFL;
sigaction(SIGCHLD, &sa, NULL);
}

void CHypridle::run() {
setupSignals();

m_sWaylandState.registry = makeShared<CCWlRegistry>((wl_proxy*)wl_display_get_registry(m_sWaylandState.display));
m_sWaylandState.registry->setGlobal([this](CCWlRegistry* r, uint32_t name, const char* interface, uint32_t version) {
const std::string IFACE = interface;
Expand Down Expand Up @@ -234,53 +246,30 @@ void CHypridle::enterEventLoop() {
static void spawn(const std::string& args) {
Debug::log(LOG, "Executing {}", args);

int socket[2];
if (pipe(socket) != 0) {
Debug::log(LOG, "Unable to create pipe for fork");
}

pid_t child, grandchild;
child = fork();
pid_t child = fork();
if (child < 0) {
close(socket[0]);
close(socket[1]);
Debug::log(LOG, "Fail to create the first fork");
return;
}
if (child == 0) {
// run in child

sigset_t set;
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, NULL);

grandchild = fork();
if (grandchild == 0) {
// run in grandchild
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]);
// exit child
_exit(0);
}
// run in parent
close(socket[1]);
read(socket[0], &grandchild, sizeof(grandchild));
close(socket[0]);
// clear child and leave grandchild to init
waitpid(child, NULL, 0);
if (grandchild < 0) {
Debug::log(LOG, "Failed to create the second fork");
Debug::log(ERR, "Failed to fork");
return;
} else if (child == 0) {
setsid();

struct sigaction sa;
// reset signals to the default
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = SIG_DFL;
sigaction(SIGCHLD, &sa, NULL);

// TODO: ??? Why do we need that ???
// We already make sure we have O_CLOEXEC and that should be enough. Still somehow, without this, releasing the inhibitor does not work.
// Somehow related to sdbus::UnixFd calling dup on the fd??
g_pHypridle->closeInhibitFd();

execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
_exit(1);
}

Debug::log(LOG, "Process Created with pid {}", grandchild);
Debug::log(LOG, "Process Created with pid {}", child);
}

void CHypridle::onIdled(SIdleListener* pListener) {
Expand Down Expand Up @@ -424,7 +413,7 @@ static void handleDbusLogin(sdbus::Message msg) {
Debug::log(LOG, "Got Unlock from dbus");

if (!std::string{*UNLOCKCMD}.empty()) {
Debug::log(LOG, "Locking with {}", *UNLOCKCMD);
Debug::log(LOG, "Unlocking with {}", *UNLOCKCMD);
spawn(*UNLOCKCMD);
}
}
Expand Down Expand Up @@ -609,6 +598,11 @@ void CHypridle::handleInhibitOnDbusSleep(bool toSleep) {
}

void CHypridle::inhibitSleep() {
if (m_sDBUSState.sleepInhibitFd.isValid()) {
Debug::log(WARN, "Called inhibitSleep, but previous sleep inhibitor is still active!");
m_sDBUSState.sleepInhibitFd.reset();
}

auto method = m_sDBUSState.login->createMethodCall(sdbus::InterfaceName{"org.freedesktop.login1.Manager"}, sdbus::MethodName{"Inhibit"});
method << "sleep";
method << "hypridle";
Expand All @@ -628,11 +622,18 @@ void CHypridle::inhibitSleep() {
return;
}

reply >> m_sDBUSState.sleepInhibitFd;
Debug::log(TRACE, "Inhibited sleep with fd {}", m_sDBUSState.sleepInhibitFd.get());
} catch (const std::exception& e) { Debug::log(ERR, "Failed to inhibit sleep ({})", e.what()); }
sdbus::UnixFd fd;
// This calls dup on the fd, no F_DUPFD_CLOEXEC :(
// There seems to be no way to get the file descriptor out of the reply other than that.
reply >> fd;

Debug::log(LOG, "Inhibited sleep!");
m_sDBUSState.sleepInhibitFd = Hyprutils::OS::CFileDescriptor(fd.release());
auto flags = m_sDBUSState.sleepInhibitFd.getFlags();
if (!(flags & O_CLOEXEC) && !m_sDBUSState.sleepInhibitFd.setFlags(flags | O_CLOEXEC))
Debug::log(ERR, "Sleep inhibitor has no O_CLOEXEC");

Debug::log(LOG, "Inhibited sleep with fd {}", m_sDBUSState.sleepInhibitFd.get());
} catch (const std::exception& e) { Debug::log(ERR, "Failed to inhibit sleep ({})", e.what()); }
}

void CHypridle::uninhibitSleep() {
Expand All @@ -642,5 +643,9 @@ void CHypridle::uninhibitSleep() {
}

Debug::log(LOG, "Releasing the sleep inhibitor!");
close(m_sDBUSState.sleepInhibitFd.release());
m_sDBUSState.sleepInhibitFd.reset();
}

void CHypridle::closeInhibitFd() {
m_sDBUSState.sleepInhibitFd.reset();
}
5 changes: 4 additions & 1 deletion src/core/Hypridle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <memory>
#include <vector>
#include <sdbus-c++/sdbus-c++.h>
#include <hyprutils/os/FileDescriptor.hpp>
#include <condition_variable>

#include "wayland.hpp"
Expand Down Expand Up @@ -48,6 +49,8 @@ class CHypridle {
void inhibitSleep();
void uninhibitSleep();

void closeInhibitFd();

private:
void setupDBUS();
void enterEventLoop();
Expand Down Expand Up @@ -83,7 +86,7 @@ class CHypridle {
std::unique_ptr<sdbus::IProxy> login;
std::vector<std::unique_ptr<sdbus::IObject>> screenSaverObjects;
std::vector<SDbusInhibitCookie> inhibitCookies;
sdbus::UnixFd sleepInhibitFd;
Hyprutils::OS::CFileDescriptor sleepInhibitFd;
} m_sDBUSState;

struct {
Expand Down

0 comments on commit 0b4d1dc

Please sign in to comment.