diff --git a/rak/functional_fun.h b/rak/functional_fun.h index e9eaff2d..ecde2b6d 100644 --- a/rak/functional_fun.h +++ b/rak/functional_fun.h @@ -51,6 +51,8 @@ #ifndef RAK_FUNCTIONAL_FUN_H #define RAK_FUNCTIONAL_FUN_H +#include + namespace rak { template @@ -61,45 +63,20 @@ public: virtual Result operator () () = 0; }; -template -struct function_ref { - explicit function_ref(Base* b) : m_base(b) {} - - Base* m_base; -}; - template class function { public: typedef Result result_type; typedef function_base Base; - function() : m_base(0) {} - function(function_ref f) : m_base(f.m_base) {} - explicit function(function_base* base) { m_base = base; } - - ~function() { delete m_base; } + bool is_valid() const { return m_base.get() != NULL; } - function& operator = (function& f) { m_base = f.release(); return *this; } - - function& operator = (function_ref f) { - if (m_base != f.m_base) { - delete m_base; - m_base = f.m_base; - } - - return *this; - } - - template - operator function_ref () { return function_ref(this->release()); } + void set(Base* base) { m_base = std::auto_ptr(base); } Result operator () () { return (*m_base)(); } private: - Base* release() { Base* tmp = m_base; m_base = 0; return tmp; } - - Base* m_base; + std::auto_ptr m_base; }; template @@ -133,15 +110,15 @@ private: }; template -function +function_base* mem_fn(Object* object, Result (Object::*func)()) { - return function(static_cast*>(new _mem_fn0(object, func))); + return new _mem_fn0(object, func); } template -function +function_base* mem_fn(const Object* object, Result (Object::*func)() const) { - return function(static_cast*>(new _const_mem_fn0(object, func))); + return new _const_mem_fn0(object, func); } } diff --git a/rak/priority_queue.h b/rak/priority_queue.h index c395c2fb..92593033 100644 --- a/rak/priority_queue.h +++ b/rak/priority_queue.h @@ -56,6 +56,8 @@ public: typedef typename base_type::const_iterator const_iterator; typedef typename base_type::value_type value_type; + using base_type::begin; + using base_type::end; using base_type::size; using base_type::empty; @@ -67,34 +69,39 @@ public: } void pop() { - std::pop_heap(base_type::begin(), base_type::end(), m_compare); + std::pop_heap(begin(), end(), m_compare); base_type::pop_back(); } void push(const value_type& value) { base_type::push_back(value); - std::push_heap(base_type::begin(), base_type::end(), m_compare); + std::push_heap(begin(), end(), m_compare); } template iterator find(const Key& key) { - return std::find_if(base_type::begin(), base_type::end(), std::bind2nd(m_equal, key)); + return std::find_if(begin(), end(), std::bind2nd(m_equal, key)); } template - void erase(const Key& key) { - erase(find(key)); + bool erase(const Key& key) { + iterator itr = find(key); + + if (itr == end()) + return false; + + erase(itr); + return true; } // Removes 'itr' from the queue. This assumes 'itr' has been // modified such that it has a higher priority than any other // element in the queue. void erase(iterator itr) { - if (itr == base_type::end()) - return; - - std::push_heap(base_type::begin(), ++itr, m_compare); - pop(); +// std::push_heap(begin(), ++itr, m_compare); +// pop(); + base_type::erase(itr); + std::make_heap(begin(), end(), m_compare); } private: diff --git a/rak/priority_queue_default.h b/rak/priority_queue_default.h index de5a98d5..90432bb2 100644 --- a/rak/priority_queue_default.h +++ b/rak/priority_queue_default.h @@ -47,32 +47,35 @@ namespace rak { class priority_item { public: - bool is_queued() const { return m_time != timer(); } + priority_item() {} + ~priority_item() { + if (is_queued()) + throw std::logic_error("priority_item::~priority_item() called on a queued item."); - void call() { m_slot(); } - void set_slot(function s) { m_slot = s; } + m_time = timer(); + m_slot.set(NULL); + } + + bool is_valid() const { return m_slot.is_valid(); } + bool is_queued() const { return m_time != timer(); } + + void call() { m_slot(); } + void set_slot(function_base* s) { m_slot.set(s); } - const timer& time() const { return m_time; } + const timer& time() const { return m_time; } + void clear_time() { m_time = timer(); } + void set_time(const timer& t) { m_time = t; } - priority_item* prepare(const timer& t); - priority_item* clear() { m_time = timer(); return this; } - - bool compare(const timer& t) const { return m_time > t; } + bool compare(const timer& t) const { return m_time > t; } private: + priority_item(const priority_item&); + void operator = (const priority_item&); + timer m_time; function m_slot; }; -inline priority_item* -priority_item::prepare(const timer& t) { - if (is_queued()) - throw std::logic_error("priority_item::prepare(rak::timer) called on an already queued item."); - - m_time = t; - return this; -} - struct priority_compare { bool operator () (const priority_item* const p1, const priority_item* const p2) const { return p1->time() > p2->time(); @@ -82,6 +85,42 @@ struct priority_compare { typedef std::equal_to priority_equal; typedef priority_queue priority_queue_default; +inline void +priority_queue_insert(priority_queue_default* queue, priority_item* item, timer t) { + if (t == timer()) + throw std::logic_error("priority_queue_insert(...) received a bad timer."); + + if (!item->is_valid()) + throw std::logic_error("priority_queue_insert(...) called on an invalid item."); + + if (item->is_queued()) + throw std::logic_error("priority_queue_insert(...) called on an already queued item."); + + if (queue->find(item) != queue->end()) + throw std::logic_error("priority_queue_insert(...) item found in queue."); + + item->set_time(t); + queue->push(item); +} + +inline void +priority_queue_erase(priority_queue_default* queue, priority_item* item) { + if (!item->is_valid()) + throw std::logic_error("priority_queue_erase(...) called on an invalid item."); + + if (!item->is_queued()) + return; + + // Clear time before erasing to force it to the top. + item->clear_time(); + + if (!queue->erase(item)) + throw std::logic_error("priority_queue_erase(...) could not find item in queue."); + + if (queue->find(item) != queue->end()) + throw std::logic_error("priority_queue_erase(...) item still in queue."); +} + } #endif diff --git a/src/control.cc b/src/control.cc index a47a7b79..2ddfa8ce 100644 --- a/src/control.cc +++ b/src/control.cc @@ -89,7 +89,7 @@ Control::initialize() { void Control::cleanup() { - taskScheduler.erase(m_taskShutdown.clear()); + priority_queue_erase(&taskScheduler, &m_taskShutdown); m_inputStdin->remove(m_core->get_poll_manager()->get_torrent_poll()); @@ -113,7 +113,7 @@ Control::receive_shutdown() { m_shutdownReceived = true; if (!m_taskShutdown.is_queued()) - taskScheduler.push(m_taskShutdown.prepare(cachedTime + 5 * 1000000)); + priority_queue_insert(&taskScheduler, &m_taskShutdown, cachedTime + 5 * 1000000); } else { m_core->shutdown(true); diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index 5984c4eb..a7f66dbe 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -65,8 +65,8 @@ DownloadFactory::DownloadFactory(const std::string& uri, Manager* m) : } DownloadFactory::~DownloadFactory() { - taskScheduler.erase(m_taskLoad.clear()); - taskScheduler.erase(m_taskCommit.clear()); + priority_queue_erase(&taskScheduler, &m_taskLoad); + priority_queue_erase(&taskScheduler, &m_taskCommit); delete m_stream; m_stream = NULL; @@ -74,12 +74,12 @@ DownloadFactory::~DownloadFactory() { void DownloadFactory::load() { - taskScheduler.push(m_taskLoad.prepare(cachedTime)); + priority_queue_insert(&taskScheduler, &m_taskLoad, cachedTime); } void DownloadFactory::commit() { - taskScheduler.push(m_taskCommit.prepare(cachedTime)); + priority_queue_insert(&taskScheduler, &m_taskCommit, cachedTime); } void diff --git a/src/display/manager.cc b/src/display/manager.cc index 482c5c21..00e8f09b 100644 --- a/src/display/manager.cc +++ b/src/display/manager.cc @@ -98,13 +98,21 @@ void Manager::do_update() { Canvas::refresh_std(); - std::list workQueue; +// std::list workQueue; - std::copy(rak::queue_popper(displayScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), cachedTime)), - rak::queue_popper(displayScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), rak::timer())), - std::back_inserter(workQueue)); - std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::clear)); - std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::call)); +// std::copy(rak::queue_popper(displayScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), cachedTime)), +// rak::queue_popper(displayScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), rak::timer())), +// std::back_inserter(workQueue)); +// std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::clear_time)); +// std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::call)); + + while (!displayScheduler.empty() && displayScheduler.top()->time() <= cachedTime) { + rak::priority_item* v = displayScheduler.top(); + displayScheduler.pop(); + + v->clear_time(); + v->call(); + } std::for_each(begin(), end(), rak::if_then(std::mem_fun(&Window::is_active), std::mem_fun(&Window::refresh))); diff --git a/src/display/window.cc b/src/display/window.cc index f90a1a52..78c54d0a 100644 --- a/src/display/window.cc +++ b/src/display/window.cc @@ -54,7 +54,7 @@ Window::Window(Canvas* c, bool d, int h) : } Window::~Window() { - displayScheduler.erase(m_taskUpdate.clear()); + priority_queue_erase(&displayScheduler, &m_taskUpdate); delete m_canvas; } @@ -63,7 +63,7 @@ Window::set_active(bool a) { if (a) mark_dirty(); else - displayScheduler.erase(m_taskUpdate.clear()); + priority_queue_erase(&displayScheduler, &m_taskUpdate); m_active = a; } diff --git a/src/display/window.h b/src/display/window.h index 27508a83..b3b7fc44 100644 --- a/src/display/window.h +++ b/src/display/window.h @@ -92,8 +92,8 @@ protected: inline void Window::mark_dirty() { - displayScheduler.erase(m_taskUpdate.clear()); - displayScheduler.push(m_taskUpdate.prepare(cachedTime)); + priority_queue_erase(&displayScheduler, &m_taskUpdate); + priority_queue_insert(&displayScheduler, &m_taskUpdate, cachedTime); } } diff --git a/src/display/window_download_list.cc b/src/display/window_download_list.cc index 79fb8bd7..d42be3c5 100644 --- a/src/display/window_download_list.cc +++ b/src/display/window_download_list.cc @@ -60,7 +60,7 @@ WindowDownloadList::~WindowDownloadList() { void WindowDownloadList::redraw() { - displayScheduler.push(m_taskUpdate.prepare((cachedTime + 1000000).round_seconds())); + priority_queue_insert(&displayScheduler, &m_taskUpdate, (cachedTime + 1000000).round_seconds()); m_canvas->erase(); diff --git a/src/display/window_download_statusbar.cc b/src/display/window_download_statusbar.cc index 34a84fab..bd08e8ce 100644 --- a/src/display/window_download_statusbar.cc +++ b/src/display/window_download_statusbar.cc @@ -54,7 +54,7 @@ WindowDownloadStatusbar::WindowDownloadStatusbar(core::Download* d) : void WindowDownloadStatusbar::redraw() { - displayScheduler.push(m_taskUpdate.prepare((cachedTime + 1000000).round_seconds())); + priority_queue_insert(&displayScheduler, &m_taskUpdate, (cachedTime + 1000000).round_seconds()); m_canvas->erase(); diff --git a/src/display/window_file_list.cc b/src/display/window_file_list.cc index 8356d8e0..aca0d463 100644 --- a/src/display/window_file_list.cc +++ b/src/display/window_file_list.cc @@ -54,7 +54,7 @@ WindowFileList::WindowFileList(core::Download* d, unsigned int* focus) : void WindowFileList::redraw() { - displayScheduler.push(m_taskUpdate.prepare((cachedTime + 10 * 1000000).round_seconds())); + priority_queue_insert(&displayScheduler, &m_taskUpdate, (cachedTime + 10 * 1000000).round_seconds()); m_canvas->erase(); if (m_download->get_download().size_file_entries() == 0 || diff --git a/src/display/window_http_queue.cc b/src/display/window_http_queue.cc index 5e9a9ea6..fb5ba4ea 100644 --- a/src/display/window_http_queue.cc +++ b/src/display/window_http_queue.cc @@ -58,7 +58,7 @@ WindowHttpQueue::WindowHttpQueue(core::HttpQueue* q) : void WindowHttpQueue::redraw() { - displayScheduler.push(m_taskUpdate.prepare((cachedTime + 1000000).round_seconds())); + priority_queue_insert(&displayScheduler, &m_taskUpdate, (cachedTime + 1000000).round_seconds()); cleanup_list(); diff --git a/src/display/window_peer_info.cc b/src/display/window_peer_info.cc index c8df11bb..f33f8601 100644 --- a/src/display/window_peer_info.cc +++ b/src/display/window_peer_info.cc @@ -57,7 +57,7 @@ WindowPeerInfo::WindowPeerInfo(core::Download* d, PList* l, PList::iterator* f) void WindowPeerInfo::redraw() { - displayScheduler.push(m_taskUpdate.prepare((cachedTime + 1000000).round_seconds())); + priority_queue_insert(&displayScheduler, &m_taskUpdate, (cachedTime + 1000000).round_seconds()); m_canvas->erase(); int y = 0; diff --git a/src/display/window_peer_list.cc b/src/display/window_peer_list.cc index 32410cbb..f2a224e6 100644 --- a/src/display/window_peer_list.cc +++ b/src/display/window_peer_list.cc @@ -56,7 +56,7 @@ WindowPeerList::WindowPeerList(core::Download* d, PList* l, PList::iterator* f) void WindowPeerList::redraw() { - displayScheduler.push(m_taskUpdate.prepare((cachedTime + 1000000).round_seconds())); + priority_queue_insert(&displayScheduler, &m_taskUpdate, (cachedTime + 1000000).round_seconds()); m_canvas->erase(); int x = 2; diff --git a/src/display/window_statusbar.cc b/src/display/window_statusbar.cc index db8fce43..fa370164 100644 --- a/src/display/window_statusbar.cc +++ b/src/display/window_statusbar.cc @@ -56,7 +56,7 @@ WindowStatusbar::WindowStatusbar(core::Manager* c) : void WindowStatusbar::redraw() { - displayScheduler.push(m_taskUpdate.prepare((cachedTime + 1000000).round_seconds())); + priority_queue_insert(&displayScheduler, &m_taskUpdate, (cachedTime + 1000000).round_seconds()); m_canvas->erase(); diff --git a/src/display/window_title.cc b/src/display/window_title.cc index 5f3fbc89..e25922c0 100644 --- a/src/display/window_title.cc +++ b/src/display/window_title.cc @@ -48,7 +48,7 @@ WindowTitle::WindowTitle(const std::string& s) : void WindowTitle::redraw() { - displayScheduler.push(m_taskUpdate.prepare((cachedTime + 1000000).round_seconds())); + priority_queue_insert(&displayScheduler, &m_taskUpdate, (cachedTime + 1000000).round_seconds()); m_canvas->erase(); m_canvas->print(std::max(0, (m_canvas->get_width() - (int)m_title.size()) / 2 - 4), 0, diff --git a/src/display/window_tracker_list.cc b/src/display/window_tracker_list.cc index fe1f8436..f4abbc36 100644 --- a/src/display/window_tracker_list.cc +++ b/src/display/window_tracker_list.cc @@ -55,7 +55,7 @@ WindowTrackerList::WindowTrackerList(core::Download* d, unsigned int* focus) : void WindowTrackerList::redraw() { // TODO: Make this depend on tracker signal. - displayScheduler.push(m_taskUpdate.prepare((cachedTime + 10 * 1000000).round_seconds())); + priority_queue_insert(&displayScheduler, &m_taskUpdate, (cachedTime + 10 * 1000000).round_seconds()); m_canvas->erase(); int pos = 0; diff --git a/src/main.cc b/src/main.cc index fd11f91c..15e6feb6 100644 --- a/src/main.cc +++ b/src/main.cc @@ -181,21 +181,21 @@ load_arg_torrents(Control* c, char** first, char** last) { int main(int argc, char** argv) { - cachedTime = rak::timer::current(); - - OptionHandler optionHandler; - Control uiControl; - - srandom(cachedTime.usec()); - srand48(cachedTime.usec()); - - initialize_option_handler(&uiControl, &optionHandler); - - OptionFile optionFile; - optionFile.slot_option(sigc::mem_fun(optionHandler, &OptionHandler::process)); - try { + cachedTime = rak::timer::current(); + + OptionHandler optionHandler; + Control uiControl; + + srandom(cachedTime.usec()); + srand48(cachedTime.usec()); + + initialize_option_handler(&uiControl, &optionHandler); + + OptionFile optionFile; + optionFile.slot_option(sigc::mem_fun(optionHandler, &OptionHandler::process)); + SignalHandler::set_ignore(SIGPIPE); SignalHandler::set_handler(SIGINT, sigc::mem_fun(uiControl, &Control::receive_shutdown)); SignalHandler::set_handler(SIGSEGV, sigc::bind(sigc::ptr_fun(&do_panic), SIGSEGV)); @@ -221,13 +221,21 @@ main(int argc, char** argv) { cachedTime = rak::timer::current(); - std::list workQueue; +// std::list workQueue; - std::copy(rak::queue_popper(taskScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), cachedTime)), - rak::queue_popper(taskScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), rak::timer())), - std::back_inserter(workQueue)); - std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::clear)); - std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::call)); +// std::copy(rak::queue_popper(taskScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), cachedTime)), +// rak::queue_popper(taskScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), rak::timer())), +// std::back_inserter(workQueue)); +// std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::clear_time)); +// std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::call)); + + while (!taskScheduler.empty() && taskScheduler.top()->time() <= cachedTime) { + rak::priority_item* v = taskScheduler.top(); + taskScheduler.pop(); + + v->clear_time(); + v->call(); + } // This needs to be called every second or so. Currently done by // the throttle task in libtorrent. diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 29839da3..cc0b8c47 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -111,7 +111,7 @@ DownloadList::activate() { if (is_active()) throw std::logic_error("ui::Download::activate() called on an already activated object"); - taskScheduler.push(m_taskUpdate.prepare(cachedTime + 1000000)); + priority_queue_insert(&taskScheduler, &m_taskUpdate, cachedTime + 1000000); m_windowTextInput->set_active(false); @@ -138,7 +138,7 @@ DownloadList::disable() { disable_display(); - taskScheduler.erase(m_taskUpdate.clear()); + priority_queue_erase(&taskScheduler, &m_taskUpdate); m_control->display()->erase(m_window); m_control->display()->erase(m_windowTitle); @@ -303,7 +303,7 @@ void DownloadList::task_update() { m_windowLog->receive_update(); - taskScheduler.push(m_taskUpdate.prepare((cachedTime + 1000000).round_seconds())); + priority_queue_insert(&taskScheduler, &m_taskUpdate, (cachedTime + 1000000).round_seconds()); } void