diff --git a/src/control.cc b/src/control.cc index b5ffb9b6..7e2d8a25 100644 --- a/src/control.cc +++ b/src/control.cc @@ -76,7 +76,7 @@ Control::initialize() { m_ui->init(this); if(!display::Canvas::daemon()) - m_inputStdin->insert(torrent::this_thread::poll()); + m_inputStdin->insert(); } void @@ -86,7 +86,7 @@ Control::cleanup() { torrent::this_thread::scheduler()->erase(&m_task_shutdown); if(!display::Canvas::daemon()) - m_inputStdin->remove(torrent::this_thread::poll()); + m_inputStdin->remove(); if (scgi_thread::thread()->is_active()) scgi_thread::thread()->stop_thread_wait(); diff --git a/src/input/input_event.cc b/src/input/input_event.cc index 1eab3760..67f1518c 100644 --- a/src/input/input_event.cc +++ b/src/input/input_event.cc @@ -2,20 +2,34 @@ #include "input_event.h" +#include +#include + #include "display/attributes.h" namespace input { void -InputEvent::insert(torrent::system::Poll* p) { - p->open(this); - p->insert_read(this); +InputEvent::insert() { + torrent::this_thread::poll()->open(this); + torrent::this_thread::poll()->insert_read(this); + // EPOLLERR/EPOLLHUP is always delivered by epoll regardless of registration; + // register for it so a controlling-terminal/pty hangup on stdin is dispatched + // to event_error() instead of aborting the whole client (see event_error()). + torrent::this_thread::poll()->insert_error(this); } void -InputEvent::remove(torrent::system::Poll* p) { - p->remove_read(this); - p->close(this); +InputEvent::remove() { + // The file descriptor doubles as the open-state guard, mirroring SCgiTask. + // event_error() may already have dropped stdin from the poll set and cleared + // the fd; the shutdown path (Control::cleanup) still calls remove(), and a + // second remove_and_close() would throw "event not found" via event_mask(). + if (!is_open()) + return; + + torrent::this_thread::poll()->remove_and_close(this); + set_file_descriptor(-1); } void @@ -32,6 +46,14 @@ InputEvent::event_write() { void InputEvent::event_error() { + // The controlling terminal/pty hung up (EPOLLERR on stdin). Drop stdin from + // the poll set instead of letting Poll::process() throw an internal_error and + // kill the client -- a regression introduced with the 0.16.13 callback/poll + // rework. rtorrent keeps running with no keyboard input. Once removed the + // event is out of the poll table, so no further event_error() is dispatched + // to it; clearing the fd lets the shutdown remove() no-op. + torrent::this_thread::poll()->remove_and_close(this); + set_file_descriptor(-1); } } diff --git a/src/input/input_event.h b/src/input/input_event.h index 7082ca3e..945605d9 100644 --- a/src/input/input_event.h +++ b/src/input/input_event.h @@ -4,7 +4,6 @@ #include #include -#include namespace input { @@ -16,8 +15,8 @@ public: const char* type_name() const override { return "input"; } - void insert(torrent::system::Poll* p); - void remove(torrent::system::Poll* p); + void insert(); + void remove(); void event_read() override; void event_write() override;