mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-11 00:29:22 +00:00
input: survive controlling-terminal/pty hangup on stdin
Since the 0.16.13 callback/poll rework, an EPOLLERR on stdin (controlling
terminal or pty hangup) reaches Poll::process(), which aborts the whole
client with an internal_error because InputEvent never registered for error
events:
Poll::process() received error event for event not in error: input-fd:0
Register stdin for error events (insert_error) and handle event_error() by
dropping stdin from the poll set with this_thread::poll()->remove_and_close().
rtorrent then keeps running without keyboard input instead of dying.
remove() guards on the fd state (is_open()), mirroring SCgiTask: event_error()
clears the fd after remove_and_close(), and the shutdown path (Control::cleanup)
still calls remove(); without the guard the second remove_and_close() throws
'event not found' via event_mask(). insert()/remove() take the thread poll
implicitly (this_thread::poll()) instead of a Poll* argument.
This commit is contained in:
committed by
Jari Sundell
parent
acb02379b8
commit
c6de871a77
+2
-2
@@ -76,7 +76,7 @@ Control::initialize() {
|
|||||||
m_ui->init(this);
|
m_ui->init(this);
|
||||||
|
|
||||||
if(!display::Canvas::daemon())
|
if(!display::Canvas::daemon())
|
||||||
m_inputStdin->insert(torrent::this_thread::poll());
|
m_inputStdin->insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -86,7 +86,7 @@ Control::cleanup() {
|
|||||||
torrent::this_thread::scheduler()->erase(&m_task_shutdown);
|
torrent::this_thread::scheduler()->erase(&m_task_shutdown);
|
||||||
|
|
||||||
if(!display::Canvas::daemon())
|
if(!display::Canvas::daemon())
|
||||||
m_inputStdin->remove(torrent::this_thread::poll());
|
m_inputStdin->remove();
|
||||||
|
|
||||||
if (scgi_thread::thread()->is_active())
|
if (scgi_thread::thread()->is_active())
|
||||||
scgi_thread::thread()->stop_thread_wait();
|
scgi_thread::thread()->stop_thread_wait();
|
||||||
|
|||||||
@@ -2,20 +2,34 @@
|
|||||||
|
|
||||||
#include "input_event.h"
|
#include "input_event.h"
|
||||||
|
|
||||||
|
#include <torrent/common.h>
|
||||||
|
#include <torrent/system/poll.h>
|
||||||
|
|
||||||
#include "display/attributes.h"
|
#include "display/attributes.h"
|
||||||
|
|
||||||
namespace input {
|
namespace input {
|
||||||
|
|
||||||
void
|
void
|
||||||
InputEvent::insert(torrent::system::Poll* p) {
|
InputEvent::insert() {
|
||||||
p->open(this);
|
torrent::this_thread::poll()->open(this);
|
||||||
p->insert_read(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
|
void
|
||||||
InputEvent::remove(torrent::system::Poll* p) {
|
InputEvent::remove() {
|
||||||
p->remove_read(this);
|
// The file descriptor doubles as the open-state guard, mirroring SCgiTask.
|
||||||
p->close(this);
|
// 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
|
void
|
||||||
@@ -32,6 +46,14 @@ InputEvent::event_write() {
|
|||||||
|
|
||||||
void
|
void
|
||||||
InputEvent::event_error() {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include <torrent/event.h>
|
#include <torrent/event.h>
|
||||||
#include <torrent/system/poll.h>
|
|
||||||
|
|
||||||
namespace input {
|
namespace input {
|
||||||
|
|
||||||
@@ -16,8 +15,8 @@ public:
|
|||||||
|
|
||||||
const char* type_name() const override { return "input"; }
|
const char* type_name() const override { return "input"; }
|
||||||
|
|
||||||
void insert(torrent::system::Poll* p);
|
void insert();
|
||||||
void remove(torrent::system::Poll* p);
|
void remove();
|
||||||
|
|
||||||
void event_read() override;
|
void event_read() override;
|
||||||
void event_write() override;
|
void event_write() override;
|
||||||
|
|||||||
Reference in New Issue
Block a user