helpers: Add an async dialog box impl (#9919)
Adds an async dialog box, way safer than our previous local solution for ANR
This commit is contained in:
parent
e96b8ce4cc
commit
3c128679ee
8 changed files with 215 additions and 76 deletions
|
|
@ -39,8 +39,6 @@ CANRManager::CANRManager() {
|
|||
}
|
||||
|
||||
void CANRManager::onTick() {
|
||||
std::erase_if(m_data, [](const auto& e) { return e->isDefunct(); });
|
||||
|
||||
static auto PENABLEANR = CConfigValue<Hyprlang::INT>("misc:enable_anr_dialog");
|
||||
static auto PANRTHRESHOLD = CConfigValue<Hyprlang::INT>("misc:anr_missed_pings");
|
||||
|
||||
|
|
@ -68,7 +66,7 @@ void CANRManager::onTick() {
|
|||
continue;
|
||||
|
||||
if (data->missedResponses >= *PANRTHRESHOLD) {
|
||||
if (!data->isThreadRunning() && !data->dialogThreadSaidWait) {
|
||||
if (!data->isRunning() && !data->dialogSaidWait) {
|
||||
data->runDialog("Application Not Responding", firstWindow->m_szTitle, firstWindow->m_szClass, data->getPid());
|
||||
|
||||
for (const auto& w : g_pCompositor->m_vWindows) {
|
||||
|
|
@ -81,11 +79,11 @@ void CANRManager::onTick() {
|
|||
*w->m_notRespondingTint = 0.2F;
|
||||
}
|
||||
}
|
||||
} else if (data->isThreadRunning())
|
||||
} else if (data->isRunning())
|
||||
data->killDialog();
|
||||
|
||||
if (data->missedResponses == 0)
|
||||
data->dialogThreadSaidWait = false;
|
||||
data->dialogSaidWait = false;
|
||||
|
||||
data->missedResponses++;
|
||||
|
||||
|
|
@ -115,7 +113,7 @@ void CANRManager::onResponse(SP<CXWaylandSurface> pXwaylandSurface) {
|
|||
|
||||
void CANRManager::onResponse(SP<CANRManager::SANRData> data) {
|
||||
data->missedResponses = 0;
|
||||
if (data->isThreadRunning())
|
||||
if (data->isRunning())
|
||||
data->killDialog();
|
||||
}
|
||||
|
||||
|
|
@ -158,64 +156,39 @@ CANRManager::SANRData::SANRData(PHLWINDOW pWindow) :
|
|||
}
|
||||
|
||||
CANRManager::SANRData::~SANRData() {
|
||||
if (dialogThread.joinable()) {
|
||||
if (dialogBox && dialogBox->isRunning())
|
||||
killDialog();
|
||||
// dangerous: might lock if the above failed!!
|
||||
dialogThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void CANRManager::SANRData::runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID) {
|
||||
if (!dialogThreadExited)
|
||||
if (dialogBox && dialogBox->isRunning())
|
||||
killDialog();
|
||||
|
||||
// dangerous: might lock if the above failed!!
|
||||
if (dialogThread.joinable())
|
||||
dialogThread.join();
|
||||
dialogBox = CAsyncDialogBox::create(title,
|
||||
std::format("Application {} with class of {} is not responding.\nWhat do you want to do with it?", appName.empty() ? "unknown" : appName,
|
||||
appClass.empty() ? "unknown" : appClass),
|
||||
std::vector<std::string>{"Terminate", "Wait"});
|
||||
|
||||
dialogThreadExited = false;
|
||||
dialogThreadSaidWait = false;
|
||||
dialogThread = std::thread([title, appName, appClass, dialogWmPID, this]() {
|
||||
SP<CProcess> proc = makeShared<CProcess>("hyprland-dialog",
|
||||
std::vector<std::string>{"--title", title, "--text",
|
||||
std::format("Application {} with class of {} is not responding.\nWhat do you want to do with it?",
|
||||
appName.empty() ? "unknown" : appName, appClass.empty() ? "unknown" : appClass),
|
||||
"--buttons", "Terminate;Wait"});
|
||||
|
||||
dialogProc = proc;
|
||||
proc->runSync();
|
||||
|
||||
dialogThreadExited = true;
|
||||
|
||||
if (proc->stdOut().empty())
|
||||
return;
|
||||
|
||||
if (proc->stdOut().starts_with("Terminate"))
|
||||
kill(dialogWmPID, SIGKILL);
|
||||
if (proc->stdOut().starts_with("Wait"))
|
||||
dialogThreadSaidWait = true;
|
||||
dialogBox->open([dialogWmPID, this](std::string result) {
|
||||
if (result.starts_with("Terminate"))
|
||||
::kill(dialogWmPID, SIGKILL);
|
||||
else if (result.starts_with("Wait"))
|
||||
dialogSaidWait = true;
|
||||
else
|
||||
Debug::log(ERR, "CANRManager::SANRData::runDialog: lambda: unrecognized result: {}", result);
|
||||
});
|
||||
}
|
||||
|
||||
bool CANRManager::SANRData::isThreadRunning() {
|
||||
if (dialogThread.native_handle() == 0)
|
||||
return false;
|
||||
if (dialogThreadExited)
|
||||
return false;
|
||||
return pthread_kill(dialogThread.native_handle(), 0) != ESRCH;
|
||||
bool CANRManager::SANRData::isRunning() {
|
||||
return dialogBox && dialogBox->isRunning();
|
||||
}
|
||||
|
||||
void CANRManager::SANRData::killDialog() {
|
||||
if (!dialogProc)
|
||||
if (!dialogBox)
|
||||
return;
|
||||
|
||||
if (!dialogProc->pid()) {
|
||||
Debug::log(ERR, "ANR: cannot kill dialogProc, as it doesn't have a pid.");
|
||||
dialogProc = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
kill(dialogProc->pid(), SIGKILL);
|
||||
dialogBox->kill();
|
||||
dialogBox = nullptr;
|
||||
}
|
||||
|
||||
bool CANRManager::SANRData::fitsWindow(PHLWINDOW pWindow) const {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@
|
|||
#include <hyprutils/os/FileDescriptor.hpp>
|
||||
#include "./eventLoop/EventLoopTimer.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include "../helpers/AsyncDialogBox.hpp"
|
||||
#include <vector>
|
||||
|
||||
class CXDGWMBase;
|
||||
|
|
@ -32,22 +31,21 @@ class CANRManager {
|
|||
SANRData(PHLWINDOW pWindow);
|
||||
~SANRData();
|
||||
|
||||
WP<CXWaylandSurface> xwaylandSurface;
|
||||
WP<CXDGWMBase> xdgBase;
|
||||
WP<CXWaylandSurface> xwaylandSurface;
|
||||
WP<CXDGWMBase> xdgBase;
|
||||
|
||||
int missedResponses = 0;
|
||||
std::thread dialogThread;
|
||||
SP<Hyprutils::OS::CProcess> dialogProc;
|
||||
std::atomic<bool> dialogThreadExited = false;
|
||||
std::atomic<bool> dialogThreadSaidWait = false;
|
||||
int missedResponses = 0;
|
||||
|
||||
void runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID);
|
||||
bool isThreadRunning();
|
||||
void killDialog();
|
||||
bool isDefunct() const;
|
||||
bool fitsWindow(PHLWINDOW pWindow) const;
|
||||
pid_t getPid() const;
|
||||
void ping();
|
||||
bool dialogSaidWait = false;
|
||||
SP<CAsyncDialogBox> dialogBox;
|
||||
|
||||
void runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID);
|
||||
bool isRunning();
|
||||
void killDialog();
|
||||
bool isDefunct() const;
|
||||
bool fitsWindow(PHLWINDOW pWindow) const;
|
||||
pid_t getPid() const;
|
||||
void ping();
|
||||
};
|
||||
|
||||
void onResponse(SP<SANRData> data);
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ class CEventLoopManager {
|
|||
wl_event_source* m_configWatcherInotifySource = nullptr;
|
||||
|
||||
friend class CSyncTimeline;
|
||||
friend class CAsyncDialogBox;
|
||||
};
|
||||
|
||||
inline UP<CEventLoopManager> g_pEventLoopManager;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue