From 3df7567ddfa0fde05b205a3a038cb2ec4e669cde Mon Sep 17 00:00:00 2001 From: rakshasa Date: Wed, 27 Jul 2005 18:39:57 +0000 Subject: [PATCH] * Rewrote 'select' based polling in the client and finished the 'epoll' code. The client selects whichever is available on the current platform. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@510 e378c898-3ddf-0310-93e7-cc216c733640 --- src/core/Makefile.am | 8 +- src/core/curl_stack.cc | 23 +++-- src/core/curl_stack.h | 28 +++--- src/core/manager.cc | 21 +++- src/core/manager.h | 6 +- src/core/poll.cc | 143 ---------------------------- src/core/poll_manager.cc | 70 ++++++++++++++ src/core/{poll.h => poll_manager.h} | 56 +++++------ src/core/poll_manager_epoll.cc | 112 ++++++++++++++++++++++ src/core/poll_manager_epoll.h | 65 +++++++++++++ src/core/poll_manager_select.cc | 98 +++++++++++++++++++ src/core/poll_manager_select.h | 65 +++++++++++++ src/input/Makefile.am | 2 + src/input/input_event.cc | 73 ++++++++++++++ src/input/input_event.h | 67 +++++++++++++ src/main.cc | 16 ++-- src/ui/control.cc | 23 +++++ src/ui/control.h | 9 +- 18 files changed, 677 insertions(+), 208 deletions(-) delete mode 100644 src/core/poll.cc create mode 100644 src/core/poll_manager.cc rename src/core/{poll.h => poll_manager.h} (63%) create mode 100644 src/core/poll_manager_epoll.cc create mode 100644 src/core/poll_manager_epoll.h create mode 100644 src/core/poll_manager_select.cc create mode 100644 src/core/poll_manager_select.h create mode 100644 src/input/input_event.cc create mode 100644 src/input/input_event.h diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 6c17eefa..fd764514 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -22,7 +22,11 @@ libsub_core_a_SOURCES = \ log.h \ manager.cc \ manager.h \ - poll.cc \ - poll.h + poll_manager.cc \ + poll_manager.h \ + poll_manager_epoll.cc \ + poll_manager_epoll.h \ + poll_manager_select.cc \ + poll_manager_select.h INCLUDES = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir) diff --git a/src/core/curl_stack.cc b/src/core/curl_stack.cc index 8e012db9..8200abd4 100644 --- a/src/core/curl_stack.cc +++ b/src/core/curl_stack.cc @@ -37,7 +37,9 @@ #include "config.h" #include +#include #include +#include #include #include "rak/functional.h" @@ -89,10 +91,14 @@ CurlStack::perform() { } while (code == CURLM_CALL_MULTI_PERFORM); } -void -CurlStack::fdset(fd_set* readfds, fd_set* writefds, fd_set* exceptfds, int* maxFd) { - if (curl_multi_fdset((CURLM*)m_handle, readfds, writefds, exceptfds, maxFd) > 0) - throw torrent::local_error("Error calling curl_multi_fdset"); +unsigned int +CurlStack::fdset(fd_set* readfds, fd_set* writefds, fd_set* exceptfds) { + int maxFd = 0; + + if (curl_multi_fdset((CURLM*)m_handle, readfds, writefds, exceptfds, &maxFd) != 0) + throw std::runtime_error("Error calling curl_multi_fdset"); + + return std::max(maxFd, 0); } void @@ -121,13 +127,18 @@ CurlStack::remove_get(CurlGet* get) { } void -CurlStack::init() { +CurlStack::global_init() { curl_global_init(CURL_GLOBAL_ALL); } void -CurlStack::cleanup() { +CurlStack::global_cleanup() { curl_global_cleanup(); } +CurlStack::SlotFactory +CurlStack::get_http_factory() { + return sigc::bind(sigc::ptr_fun(&CurlGet::new_object), this); +} + } diff --git a/src/core/curl_stack.h b/src/core/curl_stack.h index a748d573..611752a7 100644 --- a/src/core/curl_stack.h +++ b/src/core/curl_stack.h @@ -38,6 +38,7 @@ #define RTORRENT_CORE_CURL_STACK_H #include +#include namespace core { @@ -47,34 +48,37 @@ class CurlStack { public: friend class CurlGet; - typedef std::list CurlGetList; + typedef std::list CurlGetList; + typedef sigc::slot0 SlotFactory; CurlStack(); ~CurlStack(); - int get_size() const { return m_size; } - bool is_busy() const { return !m_getList.empty(); } + int get_size() const { return m_size; } + bool is_busy() const { return !m_getList.empty(); } - void perform(); + void perform(); // TODO: Set fd_set's only once? - void fdset(fd_set* readfds, fd_set* writefds, fd_set* exceptfds, int* maxFd); + unsigned int fdset(fd_set* readfds, fd_set* writefds, fd_set* exceptfds); - static void init(); - static void cleanup(); + SlotFactory get_http_factory(); + + static void global_init(); + static void global_cleanup(); protected: - void add_get(CurlGet* get); - void remove_get(CurlGet* get); + void add_get(CurlGet* get); + void remove_get(CurlGet* get); private: CurlStack(const CurlStack&); void operator = (const CurlStack&); - void* m_handle; + void* m_handle; - int m_size; - CurlGetList m_getList; + int m_size; + CurlGetList m_getList; }; } diff --git a/src/core/manager.cc b/src/core/manager.cc index cabaca27..7fe37bd8 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -48,9 +48,11 @@ #include #include +#include "curl_get.h" #include "download.h" #include "manager.h" -#include "curl_get.h" +#include "poll_manager_epoll.h" +#include "poll_manager_select.h" namespace core { @@ -69,17 +71,26 @@ Manager::Manager() : m_portFirst(6890), m_portLast(6999), m_checkHash(true) { + + // Consider doing this somewhere else. + if ((m_pollManager = PollManagerEPoll::create(sysconf(_SC_OPEN_MAX))) != NULL) + m_logImportant.push_front("Using 'epoll' based polling"); + else if ((m_pollManager = PollManagerSelect::create(sysconf(_SC_OPEN_MAX))) != NULL) + m_logImportant.push_front("Using 'select' based polling"); + else + throw std::runtime_error("Could not create any PollManager"); } Manager::~Manager() { + delete m_pollManager; } void Manager::initialize() { - torrent::Http::set_factory(m_poll.get_http_factory()); - m_httpQueue.slot_factory(m_poll.get_http_factory()); + torrent::Http::set_factory(m_pollManager->get_http_stack()->get_http_factory()); + m_httpQueue.slot_factory(m_pollManager->get_http_stack()->get_http_factory()); - CurlStack::init(); + CurlStack::global_init(); listen_open(); if (torrent::get_max_open_files() + torrent::get_max_open_sockets() + 32 > FD_SETSIZE) { @@ -125,7 +136,7 @@ Manager::cleanup() { // any more. torrent::cleanup(); - CurlStack::cleanup(); + CurlStack::global_cleanup(); } void diff --git a/src/core/manager.h b/src/core/manager.h index 4538101f..575bc50f 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -43,7 +43,7 @@ #include "download_store.h" #include "hash_queue.h" #include "http_queue.h" -#include "poll.h" +#include "poll_manager.h" #include "log.h" namespace torrent { @@ -66,7 +66,7 @@ public: HashQueue& get_hash_queue() { return m_hashQueue; } HttpQueue& get_http_queue() { return m_httpQueue; } - Poll& get_poll() { return m_poll; } + PollManager* get_poll_manager() { return m_pollManager; } Log& get_log_important() { return m_logImportant; } Log& get_log_complete() { return m_logComplete; } @@ -108,7 +108,7 @@ private: HashQueue m_hashQueue; HttpQueue m_httpQueue; - Poll m_poll; + PollManager* m_pollManager; Log m_logImportant; Log m_logComplete; diff --git a/src/core/poll.cc b/src/core/poll.cc deleted file mode 100644 index f8c8dfb5..00000000 --- a/src/core/poll.cc +++ /dev/null @@ -1,143 +0,0 @@ -// rTorrent - BitTorrent client -// Copyright (C) 2005, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "poll.h" -#include "curl_get.h" - -namespace core { - -Poll::Poll() : - m_readSet(new fd_set), - m_writeSet(new fd_set), - m_exceptSet(new fd_set), -// m_torrentPoll(new torrent::PollSelect) - m_torrentPoll(torrent::PollEPoll::create()) -{ - if (m_torrentPoll == NULL) - throw std::runtime_error("Could not initialize torrent::PollEPoll"); -} - -Poll::~Poll() { - delete m_readSet; - delete m_writeSet; - delete m_exceptSet; - delete m_torrentPoll; -} - -void -Poll::poll(utils::Timer timeout) { - // Do we want to clear m_maxFd in torrent::mark? - //m_maxFd = 0; - - FD_ZERO(m_readSet); - FD_ZERO(m_writeSet); - FD_ZERO(m_exceptSet); - - FD_SET(0, m_readSet); - - FD_SET(m_torrentPoll->get_fd(), m_readSet); - m_maxFd = m_torrentPoll->get_fd(); -// m_maxFd = m_torrentPoll->mark(m_readSet, m_writeSet, m_exceptSet); - - if (m_curlStack.is_busy()) { - int n = 0; - - m_curlStack.fdset(m_readSet, m_writeSet, m_exceptSet, &n); - m_maxFd = std::max(m_maxFd, n); - } - - timeval t = std::min(timeout, utils::Timer(torrent::get_next_timeout())).tval(); - - if (m_maxFd >= FD_SETSIZE) - throw std::runtime_error("Poll::work(): max fd >= FD_SETSIZE"); - - errno = 0; - m_maxFd = select(m_maxFd + 1, m_readSet, m_writeSet, m_exceptSet, &t); - - if (m_maxFd >= 0) - return work(); - - if (errno == EINTR) { - m_slotSelectInterrupted(); - return work_input(); - } - - throw std::runtime_error("Poll::work(): select error"); -} - -void -Poll::work() { - if (FD_ISSET(0, m_readSet)) - work_input(); - - if (m_curlStack.is_busy()) - m_curlStack.perform(); - - torrent::perform(); - if (FD_ISSET(m_torrentPoll->get_fd(), m_readSet)) { - // m_torrentPoll->work(m_readSet, m_writeSet, m_exceptSet); - m_torrentPoll->wait(0); - m_torrentPoll->work(); - torrent::perform(); - } -} - -void -Poll::work_input() { - int key; - - while ((key = getch()) != ERR) - m_slotReadStdin(key); -} - -Poll::SlotFactory -Poll::get_http_factory() { - return sigc::bind(sigc::ptr_fun(&core::CurlGet::new_object), &m_curlStack); -} - -} diff --git a/src/core/poll_manager.cc b/src/core/poll_manager.cc new file mode 100644 index 00000000..554da8e9 --- /dev/null +++ b/src/core/poll_manager.cc @@ -0,0 +1,70 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include + +#include "poll_manager.h" + +namespace core { + +PollManager::PollManager(int maxOpenSockets) { + // Add a hack here to create larger fd_set's, depending on a USE + // flag. + + m_maxOpenSockets = maxOpenSockets; + m_readSet = new fd_set; + m_writeSet = new fd_set; + m_errorSet = new fd_set; +} + +PollManager::~PollManager() { + delete m_readSet; + delete m_writeSet; + delete m_errorSet; +} + +void +PollManager::check_error() { + if (errno != EINTR) + throw std::runtime_error("Poll::work(): select error"); + + m_signalInterrupted.emit(); +} + +} diff --git a/src/core/poll.h b/src/core/poll_manager.h similarity index 63% rename from src/core/poll.h rename to src/core/poll_manager.h index 489066fa..93535427 100644 --- a/src/core/poll.h +++ b/src/core/poll_manager.h @@ -34,59 +34,55 @@ // Skomakerveien 33 // 3185 Skoppum, NORWAY -#ifndef RTORRENT_CORE_POLL_H -#define RTORRENT_CORE_POLL_H +#ifndef RTORRENT_CORE_POLL_MANAGER_H +#define RTORRENT_CORE_POLL_MANAGER_H #include -#include +#include -#include "utils/timer.h" #include "curl_stack.h" +#include "utils/timer.h" namespace torrent { - class PollSelect; - class PollEPoll; + class Poll; } namespace core { -class CurlGet; +// CurlStack really should be somewhere else, but that won't happen +// until they add an epoll friendly API. -class Poll { +class PollManager { public: - typedef sigc::slot0 Slot; - typedef sigc::slot1 SlotInt; - typedef sigc::slot0 SlotFactory; + typedef sigc::signal0 Signal; - Poll(); - ~Poll(); + PollManager(int maxOpenSockets); + virtual ~PollManager(); - void poll(utils::Timer t); + unsigned int get_max_open_sockets() const { return m_maxOpenSockets; } + CurlStack* get_http_stack() { return &m_httpStack; } - SlotFactory get_http_factory(); - torrent::Poll* get_torrent_poll() { return reinterpret_cast(m_torrentPoll); } + virtual torrent::Poll* get_torrent_poll() = 0; - void slot_read_stdin(SlotInt s) { m_slotReadStdin = s; } - void slot_select_interrupted(Slot s) { m_slotSelectInterrupted = s; } + virtual void poll(utils::Timer timeout) = 0; -private: - Poll(const Poll&); - void operator = (const Poll&); + // Use a signal, connect checking for input and updating the display. + Signal& signal_interrupted() { return m_signalInterrupted; } - void work(); - void work_input(); +protected: + PollManager(const PollManager&); + void operator = (const PollManager&); - SlotInt m_slotReadStdin; - Slot m_slotSelectInterrupted; + void check_error(); + + unsigned int m_maxOpenSockets; + CurlStack m_httpStack; - int m_maxFd; fd_set* m_readSet; fd_set* m_writeSet; - fd_set* m_exceptSet; + fd_set* m_errorSet; - CurlStack m_curlStack; -// torrent::PollSelect* m_torrentPoll; - torrent::PollEPoll* m_torrentPoll; + Signal m_signalInterrupted; }; } diff --git a/src/core/poll_manager_epoll.cc b/src/core/poll_manager_epoll.cc new file mode 100644 index 00000000..6438654a --- /dev/null +++ b/src/core/poll_manager_epoll.cc @@ -0,0 +1,112 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include +#include + +#include "poll_manager_epoll.h" + +namespace core { + +PollManagerEPoll* +PollManagerEPoll::create(int maxOpenSockets) { + torrent::PollEPoll* p = torrent::PollEPoll::create(maxOpenSockets); + + if (p == NULL) + return NULL; + + PollManagerEPoll* manager = new PollManagerEPoll(maxOpenSockets); + manager->m_poll = p; + + return manager; +} + +PollManagerEPoll::~PollManagerEPoll() { + delete m_poll; +} + +torrent::Poll* +PollManagerEPoll::get_torrent_poll() { + return m_poll; +} + +void +PollManagerEPoll::poll(utils::Timer timeout) { + timeout = std::min(timeout, utils::Timer(torrent::get_next_timeout())); + + if (m_httpStack.is_busy()) { + // When we're using libcurl we need to use select, but as this is + // inefficient we try avoiding it whenever possible. + FD_ZERO(m_readSet); + FD_ZERO(m_writeSet); + FD_ZERO(m_errorSet); + FD_SET(m_poll->get_fd(), m_readSet); + + unsigned int maxFd = std::max((unsigned int)m_poll->get_fd(), + m_httpStack.fdset(m_readSet, m_writeSet, m_errorSet)); + + if (maxFd >= m_maxOpenSockets) + throw std::runtime_error("Error polling, maxFd >= m_maxOpenSockets"); + + timeval t = timeout.tval(); + + if (select(maxFd + 1, m_readSet, m_writeSet, m_errorSet, &t) == -1) + return check_error(); + + m_httpStack.perform(); + + if (!FD_ISSET(m_poll->get_fd(), m_readSet)) + return; + + // Clear the timeout since we've already used it in the select call. + timeout = utils::Timer(); + } + + // Yes, below is how much code really *should* have been in this + // function. ;) + torrent::perform(); + + if (m_poll->poll(timeout.usec() / 1000) == -1) + return check_error(); + + m_poll->perform(); + torrent::perform(); +} + +} diff --git a/src/core/poll_manager_epoll.h b/src/core/poll_manager_epoll.h new file mode 100644 index 00000000..ef441f40 --- /dev/null +++ b/src/core/poll_manager_epoll.h @@ -0,0 +1,65 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_CORE_POLL_MANAGER_EPOLL_H +#define RTORRENT_CORE_POLL_MANAGER_EPOLL_H + +#include "poll_manager.h" + +namespace torrent { + class PollEPoll; +} + +namespace core { + +class PollManagerEPoll : public PollManager { +public: + static PollManagerEPoll* create(int maxOpenSockets); + ~PollManagerEPoll(); + + torrent::Poll* get_torrent_poll(); + + void poll(utils::Timer timeout); + +private: + PollManagerEPoll(int maxOpenSockets) : PollManager(maxOpenSockets) {} + + torrent::PollEPoll* m_poll; +}; + +} + +#endif diff --git a/src/core/poll_manager_select.cc b/src/core/poll_manager_select.cc new file mode 100644 index 00000000..aab5e6d3 --- /dev/null +++ b/src/core/poll_manager_select.cc @@ -0,0 +1,98 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include +#include + +#include "poll_manager_select.h" + +namespace core { + +PollManagerSelect* +PollManagerSelect::create(int maxOpenSockets) { + torrent::PollSelect* p = torrent::PollSelect::create(maxOpenSockets); + + if (p == NULL) + return NULL; + + PollManagerSelect* manager = new PollManagerSelect(maxOpenSockets); + manager->m_poll = p; + + return manager; +} + +PollManagerSelect::~PollManagerSelect() { + delete m_poll; +} + +torrent::Poll* +PollManagerSelect::get_torrent_poll() { + return m_poll; +} + +void +PollManagerSelect::poll(utils::Timer timeout) { + timeout = std::min(timeout, utils::Timer(torrent::get_next_timeout())); + + FD_ZERO(m_readSet); + FD_ZERO(m_writeSet); + FD_ZERO(m_errorSet); + + unsigned int maxFd = m_poll->fdset(m_readSet, m_writeSet, m_errorSet); + + if (m_httpStack.is_busy()) + maxFd = std::max(maxFd, m_httpStack.fdset(m_readSet, m_writeSet, m_errorSet)); + + if (maxFd >= m_maxOpenSockets) + throw std::runtime_error("Error polling, maxFd >= m_maxOpenSockets"); + + timeval t = timeout.tval(); + + if (select(maxFd + 1, m_readSet, m_writeSet, m_errorSet, &t) == -1) + return check_error(); + + if (m_httpStack.is_busy()) + m_httpStack.perform(); + + torrent::perform(); + m_poll->perform(m_readSet, m_writeSet, m_errorSet); + torrent::perform(); +} + +} diff --git a/src/core/poll_manager_select.h b/src/core/poll_manager_select.h new file mode 100644 index 00000000..a76771c8 --- /dev/null +++ b/src/core/poll_manager_select.h @@ -0,0 +1,65 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_CORE_POLL_MANAGER_SELECT_H +#define RTORRENT_CORE_POLL_MANAGER_SELECT_H + +#include "poll_manager.h" + +namespace torrent { + class PollSelect; +} + +namespace core { + +class PollManagerSelect : public PollManager { +public: + static PollManagerSelect* create(int maxOpenSockets); + ~PollManagerSelect(); + + torrent::Poll* get_torrent_poll(); + + void poll(utils::Timer timeout); + +private: + PollManagerSelect(int maxOpenSockets) : PollManager(maxOpenSockets) {} + + torrent::PollSelect* m_poll; +}; + +} + +#endif diff --git a/src/input/Makefile.am b/src/input/Makefile.am index 31285ff1..4ac2af1a 100644 --- a/src/input/Makefile.am +++ b/src/input/Makefile.am @@ -3,6 +3,8 @@ noinst_LIBRARIES = libsub_input.a libsub_input_a_SOURCES = \ bindings.cc \ bindings.h \ + input_event.cc \ + input_event.h \ manager.cc \ manager.h \ path_input.cc \ diff --git a/src/input/input_event.cc b/src/input/input_event.cc new file mode 100644 index 00000000..c25d601f --- /dev/null +++ b/src/input/input_event.cc @@ -0,0 +1,73 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include + +#include "input_event.h" + +namespace input { + +void +InputEvent::insert(torrent::Poll* p) { + p->open(this); + p->insert_read(this); +} + +void +InputEvent::remove(torrent::Poll* p) { + p->remove_read(this); + p->close(this); +} + +void +InputEvent::event_read() { + int c = getch(); + + if (c != ERR) + m_slotPressed(c); +} + +void +InputEvent::event_write() { +} + +void +InputEvent::event_error() { +} + +} diff --git a/src/input/input_event.h b/src/input/input_event.h new file mode 100644 index 00000000..9e8ec806 --- /dev/null +++ b/src/input/input_event.h @@ -0,0 +1,67 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_INPUT_INPUT_EVENT_H +#define RTORRENT_INPUT_INPUT_EVENT_H + +#include +#include +#include + +namespace input { + +class InputEvent : public torrent::Event { +public: + typedef sigc::slot SlotInt; + + InputEvent(int fd) { m_fileDesc = fd; } + + void insert(torrent::Poll* p); + void remove(torrent::Poll* p); + + void event_read(); + void event_write(); + void event_error(); + + void slot_pressed(SlotInt s) { m_slotPressed = s; } + +private: + SlotInt m_slotPressed; +}; + +} + +#endif diff --git a/src/main.cc b/src/main.cc index 571a4d4c..8ea96b73 100644 --- a/src/main.cc +++ b/src/main.cc @@ -196,8 +196,8 @@ initialize_display(ui::Control* c) { void initialize_core(ui::Control* c) { - c->get_core().get_poll().slot_read_stdin(sigc::mem_fun(c->get_input(), &input::Manager::pressed)); - c->get_core().get_poll().slot_select_interrupted(sigc::ptr_fun(display::Canvas::do_update)); + c->get_core().get_poll_manager()->signal_interrupted().connect(sigc::mem_fun(c->get_input_stdin(), &input::InputEvent::event_read)); + c->get_core().get_poll_manager()->signal_interrupted().connect(sigc::ptr_fun(display::Canvas::do_update)); c->get_core().initialize(); } @@ -223,7 +223,7 @@ main(int argc, char** argv) { SignalHandler::set_handler(SIGFPE, sigc::bind(sigc::ptr_fun(&do_panic), SIGFPE)); // Need to initialize this before parseing options. - torrent::initialize(uiControl.get_core().get_poll().get_torrent_poll()); + torrent::initialize(uiControl.get_core().get_poll_manager()->get_torrent_poll()); if (getenv("HOME")) load_option_file(getenv("HOME") + std::string("/.rtorrent.rc"), &optionHandler); @@ -235,6 +235,8 @@ main(int argc, char** argv) { uiControl.get_ui().init(&uiControl); + uiControl.initialize(); + load_session_torrents(&uiControl); load_arg_torrents(&uiControl, argv + firstArg, argv + argc); @@ -251,11 +253,13 @@ main(int argc, char** argv) { uiControl.get_display().do_update(); // Do shutdown check before poll, not after. - uiControl.get_core().get_poll().poll(!utils::taskScheduler.empty() ? - utils::taskScheduler.get_next_timeout() - utils::Timer::cache() : - 60 * 1000000); + uiControl.get_core().get_poll_manager()->poll(!utils::taskScheduler.empty() ? + utils::taskScheduler.get_next_timeout() - utils::Timer::cache() : + 60 * 1000000); } + uiControl.cleanup(); + uiControl.get_ui().cleanup(); uiControl.get_core().cleanup(); diff --git a/src/ui/control.cc b/src/ui/control.cc index d524d175..af945ab8 100644 --- a/src/ui/control.cc +++ b/src/ui/control.cc @@ -36,10 +36,33 @@ #include "config.h" +#include + #include "control.h" namespace ui { +Control::Control() : + m_shutdownReceived(false) { + + m_inputStdin = new input::InputEvent(STDIN_FILENO); + m_inputStdin->slot_pressed(sigc::mem_fun(m_input, &input::Manager::pressed)); +} + +Control::~Control() { + delete m_inputStdin; +} + +void +Control::initialize() { + m_inputStdin->insert(m_core.get_poll_manager()->get_torrent_poll()); +} + +void +Control::cleanup() { + m_inputStdin->remove(m_core.get_poll_manager()->get_torrent_poll()); +} + // I think it should be safe to initiate the shutdown from anywhere, // but if it isn't, use a delay task. void diff --git a/src/ui/control.h b/src/ui/control.h index 750d342b..93da7f36 100644 --- a/src/ui/control.h +++ b/src/ui/control.h @@ -42,6 +42,7 @@ #include "core/manager.h" #include "display/manager.h" #include "input/manager.h" +#include "input/input_event.h" #include "root.h" @@ -49,7 +50,8 @@ namespace ui { class Control { public: - Control() : m_shutdownReceived(false) {} + Control(); + ~Control(); bool is_shutdown_completed() { return m_shutdownReceived && torrent::is_inactive(); } bool is_shutdown_received() { return m_shutdownReceived; } @@ -58,6 +60,10 @@ public: core::Manager& get_core() { return m_core; } display::Manager& get_display() { return m_display; } input::Manager& get_input() { return m_input; } + input::InputEvent* get_input_stdin() { return m_inputStdin; } + + void initialize(); + void cleanup(); void receive_shutdown(); @@ -71,6 +77,7 @@ private: core::Manager m_core; display::Manager m_display; input::Manager m_input; + input::InputEvent* m_inputStdin; }; }