mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-05 17:52:29 +00:00
Signal handler with cleaner shutdown.
Window title and stuff. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@248 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
+3
-1
@@ -11,4 +11,6 @@ rtorrent_LDADD = \
|
||||
$(top_srcdir)/src/input/libsub_input.a
|
||||
|
||||
rtorrent_SOURCES = \
|
||||
main.cc
|
||||
main.cc \
|
||||
signal_handler.cc \
|
||||
signal_handler.h
|
||||
|
||||
@@ -8,6 +8,8 @@ libsub_display_a_SOURCES = \
|
||||
window.cc \
|
||||
window.h \
|
||||
window_download_list.cc \
|
||||
window_download_list.h
|
||||
window_download_list.h \
|
||||
window_title.cc \
|
||||
window_title.h
|
||||
|
||||
INCLUDES = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
|
||||
|
||||
+20
-12
@@ -27,6 +27,20 @@ public:
|
||||
|
||||
void erase() { werase(m_window); }
|
||||
|
||||
void print_border(chtype ls, chtype rs,
|
||||
chtype ts, chtype bs,
|
||||
chtype tl, chtype tr,
|
||||
chtype bl, chtype br) { wborder(m_window, ls, rs, ts, bs, tl, tr, bl, br); }
|
||||
|
||||
// Initialize stdscr.
|
||||
static void init();
|
||||
static void cleanup();
|
||||
|
||||
static int get_screen_width() { int x, y; getmaxyx(stdscr, y, x); return x; }
|
||||
static int get_screen_height() { int x, y; getmaxyx(stdscr, y, x); return y; }
|
||||
|
||||
static void do_update() { doupdate(); }
|
||||
|
||||
void print(int x, int y, const char* str) { mvwprintw(m_window, y, x, str); }
|
||||
|
||||
template <typename A1>
|
||||
@@ -43,19 +57,13 @@ public:
|
||||
void print(int x, int y, const char* str,
|
||||
A1 a1, A2 a2, A3 a3, A4 a4) { mvwprintw(m_window, y, x, str, a1, a2, a3, a4); }
|
||||
|
||||
void print_border(chtype ls, chtype rs,
|
||||
chtype ts, chtype bs,
|
||||
chtype tl, chtype tr,
|
||||
chtype bl, chtype br) { wborder(m_window, ls, rs, ts, bs, tl, tr, bl, br); }
|
||||
template <typename A1, typename A2, typename A3, typename A4, typename A5>
|
||||
void print(int x, int y, const char* str,
|
||||
A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { mvwprintw(m_window, y, x, str, a1, a2, a3, a4, a5); }
|
||||
|
||||
// Initialize stdscr.
|
||||
static void init();
|
||||
static void cleanup();
|
||||
|
||||
static int get_screen_width() { int x, y; getmaxyx(stdscr, y, x); return x; }
|
||||
static int get_screen_height() { int x, y; getmaxyx(stdscr, y, x); return y; }
|
||||
|
||||
static void do_update() { doupdate(); }
|
||||
template <typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
|
||||
void print(int x, int y, const char* str,
|
||||
A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { mvwprintw(m_window, y, x, str, a1, a2, a3, a4, a5, a6); }
|
||||
|
||||
private:
|
||||
WINDOW* m_window;
|
||||
|
||||
@@ -38,10 +38,13 @@ Manager::adjust_layout() {
|
||||
int height = 0, h;
|
||||
|
||||
for (iterator itr = begin(); itr != end(); ++itr, height += h) {
|
||||
h = (*itr)->is_dynamic() ? ((dynamic + countDynamic - 1) / countDynamic) : 0;
|
||||
|
||||
countDynamic--;
|
||||
dynamic -= h;
|
||||
if ((*itr)->is_dynamic()) {
|
||||
dynamic -= h = (dynamic + countDynamic - 1) / countDynamic;
|
||||
countDynamic--;
|
||||
} else {
|
||||
h = 0;
|
||||
}
|
||||
|
||||
h += (*itr)->get_min_height();
|
||||
|
||||
|
||||
@@ -19,12 +19,36 @@ WindowDownloadList::redraw() {
|
||||
|
||||
int pos = 1;
|
||||
|
||||
for (engine::DownloadList::iterator itr = m_downloads->begin(); itr != m_downloads->end(); ++itr, ++pos)
|
||||
m_canvas->print(1, pos, "Download: %s Open: %c Tracker: %c Active: %c",
|
||||
itr->get_download().get_name().c_str(),
|
||||
itr->get_download().is_open() ? 'Y' : 'N',
|
||||
itr->get_download().is_tracker_busy() ? 'Y' : 'N',
|
||||
itr->get_download().is_active() ? 'Y' : 'N');
|
||||
// Remember to check for end of screen too.
|
||||
|
||||
for (engine::DownloadList::iterator itr = m_downloads->begin(); itr != m_downloads->end(); ++itr) {
|
||||
m_canvas->print(0, pos++, "%c %s",
|
||||
false ? '*' : ' ',
|
||||
itr->get_download().get_name().c_str());
|
||||
|
||||
if (itr->get_download().get_chunks_done() != itr->get_download().get_chunks_total() || !itr->get_download().is_open())
|
||||
m_canvas->print(0, pos++, "%c Torrent: %.1f / %.1f MiB Rate:%5.1f /%5.1f KiB Uploaded: %.1f MiB",
|
||||
false ? '*' : ' ',
|
||||
(double)itr->get_download().get_bytes_done() / (double)(1 << 20),
|
||||
(double)itr->get_download().get_bytes_total() / (double)(1 << 20),
|
||||
(double)itr->get_download().get_rate_up() / 1024.0,
|
||||
(double)itr->get_download().get_rate_down() / 1024.0,
|
||||
(double)itr->get_download().get_bytes_up() / (double)(1 << 20));
|
||||
|
||||
else
|
||||
m_canvas->print(0, pos++, "%c Torrent: Done %.1f MiB Rate:%5.1f /%5.1f KiB Uploaded: %.1f MiB",
|
||||
false ? '*' : ' ',
|
||||
(double)itr->get_download().get_bytes_total() / (double)(1 << 20),
|
||||
(double)itr->get_download().get_rate_up() / 1024.0,
|
||||
(double)itr->get_download().get_rate_down() / 1024.0,
|
||||
(double)itr->get_download().get_bytes_up() / (double)(1 << 20));
|
||||
|
||||
m_canvas->print(0, pos++, "%c Tracker: [%c:%i] %s",
|
||||
false ? '*' : ' ',
|
||||
itr->get_download().is_tracker_busy() ? 'C' : ' ',
|
||||
(int)(itr->get_download().get_tracker_timeout() / 1000000),
|
||||
"");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ class WindowDownloadList : public Window {
|
||||
public:
|
||||
WindowDownloadList(engine::DownloadList* d);
|
||||
|
||||
virtual void redraw();
|
||||
virtual void redraw();
|
||||
|
||||
private:
|
||||
engine::DownloadList* m_downloads;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <torrent/torrent.h>
|
||||
|
||||
#include "canvas.h"
|
||||
#include "window_title.h"
|
||||
|
||||
namespace display {
|
||||
|
||||
WindowTitle::WindowTitle() :
|
||||
Window(new Canvas, false, 1) {
|
||||
|
||||
m_title += "rtorrent " VERSION " - ";
|
||||
m_title += torrent::get(torrent::LIBRARY_NAME);
|
||||
}
|
||||
|
||||
void
|
||||
WindowTitle::redraw() {
|
||||
m_canvas->erase();
|
||||
|
||||
m_canvas->print(std::max(0, (m_canvas->get_width() - (int)m_title.size()) / 2 - 4), 0,
|
||||
"*** %s ***", m_title.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef RTORRENT_DISPLAY_WINDOW_TITLE_H
|
||||
#define RTORRENT_DISPLAY_WINDOW_TITLE_H
|
||||
|
||||
#include "window.h"
|
||||
|
||||
namespace display {
|
||||
|
||||
class WindowTitle : public Window {
|
||||
public:
|
||||
WindowTitle();
|
||||
|
||||
virtual void redraw();
|
||||
|
||||
private:
|
||||
std::string m_title;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -16,6 +16,8 @@ public:
|
||||
void open() { m_download.open(); }
|
||||
void close() { m_download.close(); }
|
||||
|
||||
void stop() { m_download.stop(); }
|
||||
|
||||
void hash_check(bool resume = false) { m_download.hash_check(resume); }
|
||||
|
||||
bool operator == (const std::string& str) { return str == m_download.get_hash(); }
|
||||
|
||||
+6
-5
@@ -20,8 +20,7 @@ Poll::poll() {
|
||||
|
||||
m_maxFd = std::max(m_maxFd, 1);
|
||||
|
||||
if (m_readStdin)
|
||||
FD_SET(0, &m_readSet);
|
||||
FD_SET(0, &m_readSet);
|
||||
|
||||
if (m_curlStack.is_busy())
|
||||
m_curlStack.fdset(&m_readSet, &m_writeSet, &m_exceptSet, &m_maxFd);
|
||||
@@ -35,17 +34,19 @@ Poll::poll() {
|
||||
|
||||
m_maxFd = select(m_maxFd, &m_readSet, &m_writeSet, &m_exceptSet, &timeout);
|
||||
|
||||
if (m_maxFd < 0)
|
||||
if (m_maxFd == EINTR)
|
||||
m_slotSelectInterrupted();
|
||||
else if (m_maxFd < 0)
|
||||
throw std::runtime_error("Poll::work(): select error");
|
||||
}
|
||||
|
||||
void
|
||||
Poll::work() {
|
||||
if (m_readStdin && FD_ISSET(0, &m_readSet)) {
|
||||
if (FD_ISSET(0, &m_readSet)) {
|
||||
int key;
|
||||
|
||||
while ((key = getch()) >= 0)
|
||||
m_readStdin(key);
|
||||
m_slotReadStdin(key);
|
||||
}
|
||||
|
||||
if (m_curlStack.is_busy())
|
||||
|
||||
+5
-7
@@ -10,22 +10,20 @@ namespace engine {
|
||||
|
||||
class Poll {
|
||||
public:
|
||||
typedef sigc::slot0<void> Slot;
|
||||
typedef sigc::slot1<void, int> SlotInt;
|
||||
|
||||
Poll() : m_running(true) {}
|
||||
|
||||
bool is_running() { return m_running; }
|
||||
|
||||
void poll();
|
||||
void work();
|
||||
|
||||
void register_http();
|
||||
|
||||
void slot_read_stdin(SlotInt s) { m_readStdin = s; }
|
||||
void slot_read_stdin(SlotInt s) { m_slotReadStdin = s; }
|
||||
void slot_select_interrupted(Slot s) { m_slotSelectInterrupted = s; }
|
||||
|
||||
private:
|
||||
bool m_running;
|
||||
SlotInt m_readStdin;
|
||||
SlotInt m_slotReadStdin;
|
||||
Slot m_slotSelectInterrupted;
|
||||
|
||||
int m_maxFd;
|
||||
fd_set m_readSet;
|
||||
|
||||
+44
-12
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "display/canvas.h"
|
||||
#include "display/manager.h"
|
||||
#include "display/window_title.h"
|
||||
#include "display/window_download_list.h"
|
||||
|
||||
#include "engine/poll.h"
|
||||
@@ -15,24 +16,48 @@
|
||||
#include "input/bindings.h"
|
||||
#include "input/manager.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
#include "signal_handler.h"
|
||||
|
||||
bool start_shutdown = false;
|
||||
bool is_shutting_down = false;
|
||||
|
||||
engine::Poll poll;
|
||||
engine::DownloadList downloads;
|
||||
|
||||
display::Manager displayManager;
|
||||
input::Manager inputManager;
|
||||
|
||||
void
|
||||
set_shutdown() {
|
||||
start_shutdown = true;
|
||||
}
|
||||
|
||||
void
|
||||
do_shutdown() {
|
||||
if (is_shutting_down)
|
||||
// Be quick about it...
|
||||
return;
|
||||
|
||||
is_shutting_down = true;
|
||||
|
||||
torrent::listen_close();
|
||||
|
||||
std::for_each(downloads.begin(), downloads.end(), std::mem_fun_ref(&engine::Download::stop));
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv) {
|
||||
try {
|
||||
|
||||
display::Canvas::init();
|
||||
|
||||
engine::Poll poll;
|
||||
engine::DownloadList downloads;
|
||||
|
||||
display::Manager display;
|
||||
|
||||
input::Manager inputManager;
|
||||
|
||||
inputManager.push_back(new input::Bindings);
|
||||
|
||||
poll.slot_read_stdin(sigc::mem_fun(inputManager, &input::Manager::pressed));
|
||||
poll.register_http();
|
||||
|
||||
display.push_back(new display::WindowDownloadList(&downloads));
|
||||
displayManager.push_back(new display::WindowTitle);
|
||||
displayManager.push_back(new display::WindowDownloadList(&downloads));
|
||||
|
||||
torrent::initialize();
|
||||
torrent::listen_open(6880, 6999);
|
||||
@@ -46,9 +71,14 @@ int main(int argc, char** argv) {
|
||||
itr->hash_check();
|
||||
}
|
||||
|
||||
while (poll.is_running()) {
|
||||
display.adjust_layout();
|
||||
display.do_update();
|
||||
SignalHandler::set_handler(SIGINT, sigc::ptr_fun(&set_shutdown));
|
||||
|
||||
while (!is_shutting_down || !torrent::get(torrent::SHUTDOWN_DONE)) {
|
||||
if (start_shutdown && !is_shutting_down)
|
||||
do_shutdown();
|
||||
|
||||
displayManager.adjust_layout();
|
||||
displayManager.do_update();
|
||||
|
||||
poll.poll();
|
||||
poll.work();
|
||||
@@ -62,5 +92,7 @@ int main(int argc, char** argv) {
|
||||
std::cout << "Caught exception: \"" << e.what() << '"' << std::endl;
|
||||
}
|
||||
|
||||
torrent::cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include "signal_handler.h"
|
||||
|
||||
SignalHandler::Slot SignalHandler::m_handlers[HIGHEST_SIGNAL];
|
||||
|
||||
void
|
||||
SignalHandler::set_default(unsigned int signum) {
|
||||
if (signum >= HIGHEST_SIGNAL)
|
||||
throw std::logic_error("SignalHandler::clear(...) received invalid signal value");
|
||||
|
||||
signal(signum, SIG_DFL);
|
||||
m_handlers[signum].disconnect();
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::set_ignore(unsigned int signum) {
|
||||
if (signum >= HIGHEST_SIGNAL)
|
||||
throw std::logic_error("SignalHandler::clear(...) received invalid signal value");
|
||||
|
||||
signal(signum, SIG_IGN);
|
||||
m_handlers[signum].disconnect();
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::set_handler(unsigned int signum, Slot slot) {
|
||||
if (signum >= HIGHEST_SIGNAL)
|
||||
throw std::logic_error("SignalHandler::handle(...) received invalid signal value");
|
||||
|
||||
if (slot.empty())
|
||||
throw std::logic_error("SignalHandler::handle(...) received an empty slot");
|
||||
|
||||
signal(signum, &SignalHandler::caught);
|
||||
m_handlers[signum] = slot;
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::caught(int signum) {
|
||||
if ((unsigned)signum >= HIGHEST_SIGNAL)
|
||||
throw std::logic_error("SignalHandler::caught(...) received invalid signal from the kernel, bork bork bork");
|
||||
|
||||
if (m_handlers[signum].empty())
|
||||
throw std::logic_error("SignalHandler::caught(...) received a signal we don't have a handler for");
|
||||
|
||||
m_handlers[signum]();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef RTORRENT_SIGNAL_HANDLER_H
|
||||
#define RTORRENT_SIGNAL_HANDLER_H
|
||||
|
||||
#include <signal.h>
|
||||
#include <sigc++/slot.h>
|
||||
|
||||
class SignalHandler {
|
||||
public:
|
||||
typedef sigc::slot0<void> Slot;
|
||||
|
||||
static const unsigned int HIGHEST_SIGNAL = 32;
|
||||
|
||||
static void set_default(unsigned int signum);
|
||||
static void set_ignore(unsigned int signum);
|
||||
static void set_handler(unsigned int signum, Slot slot);
|
||||
|
||||
private:
|
||||
static void caught(int signum);
|
||||
|
||||
static Slot m_handlers[HIGHEST_SIGNAL];
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user