From 517454b413f7d30b3b3434fdc6623915f203558b Mon Sep 17 00:00:00 2001 From: Xirvik Support <31997142+xirvik@users.noreply.github.com> Date: Thu, 18 Jun 2026 22:34:17 +0000 Subject: [PATCH] control: close directory watch on quick shutdown (fix SIGABRT at exit) Control::handle_shutdown() closes m_directory_events (the inotify directory watch) only in the normal-shutdown branch (!m_shutdownQuick). On a quick shutdown (SIGTERM -> receive_quick_shutdown) the m_shutdownQuick branch skips it, so the watch stays registered in the poll. ~Control() then destroys the still-open directory_events and Event::~Event()'s assert(m_poll_event == nullptr) (added with the 0.16.13 poll/event rework) aborts: main -> Control::~Control() -> ~directory_events -> ~Event() -> abort Close it in Control::cleanup() instead, which runs on every shutdown path after the session is saved; close() is idempotent, so the normal path that already closed it in handle_shutdown() is unaffected. Reproducible: configure a directory.watch.added watch, then SIGTERM the client -> SIGABRT (core in Event::~Event); SIGINT (normal shutdown) is clean. With this change SIGTERM exits cleanly too. --- src/control.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/control.cc b/src/control.cc index 7e2d8a25..888408cf 100644 --- a/src/control.cc +++ b/src/control.cc @@ -88,6 +88,15 @@ Control::cleanup() { if(!display::Canvas::daemon()) m_inputStdin->remove(); + // Close the directory watch (inotify) Event on every shutdown path. + // handle_shutdown() only closes it on a normal shutdown; a quick shutdown + // (SIGTERM -> receive_quick_shutdown) takes the m_shutdownQuick branch and + // skips it, leaving directory_events registered in the poll. ~Control() would + // then destroy it while still open and trip the Event::~Event() assert + // (m_poll_event == nullptr) -> SIGABRT. close() is idempotent (no-op when the + // normal path already closed it). + m_directory_events->close(); + if (scgi_thread::thread()->is_active()) scgi_thread::thread()->stop_thread_wait();