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:
rakshasa
2005-01-30 23:10:25 +00:00
parent 3357b5caab
commit c3a4a7d554
14 changed files with 235 additions and 48 deletions
+3 -1
View File
@@ -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
+3 -1
View File
@@ -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
View File
@@ -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;
+6 -3
View File
@@ -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();
+30 -6
View File
@@ -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),
"");
}
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ class WindowDownloadList : public Window {
public:
WindowDownloadList(engine::DownloadList* d);
virtual void redraw();
virtual void redraw();
private:
engine::DownloadList* m_downloads;
+25
View File
@@ -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());
}
}
+20
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+47
View File
@@ -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]();
}
+23
View File
@@ -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