diff --git a/ChangeLog b/ChangeLog index b95253b5..53955c56 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2007-12-07 Tatsuhiro Tsujikawa + + Fixed the bug#1845750; CTRL+C does not stop torrent. + aria2 repeatedly sends stopped request when tracker returns error code. + * src/AnnounceList.cc + * test/AnnounceListTest.cc + * src/AnnounceTier.h + + Added a message when ctrl-c is hit. + Now second ctrl-c is also handled in signal handler. + * src/RequestGroupMan.{h, cc} + * src/RequestGroup.{h, cc} + * src/MultiUrlRequestInfo.cc + * src/DownloadEngine.cc + * src/TrackerWatcherCommand.cc + 2007-12-06 Tatsuhiro Tsujikawa Code cleanup diff --git a/src/AnnounceList.cc b/src/AnnounceList.cc index c50f7b13..fe0a5071 100644 --- a/src/AnnounceList.cc +++ b/src/AnnounceList.cc @@ -107,6 +107,8 @@ void AnnounceList::announceFailure() { if(currentTrackerInitialized) { currentTracker++; if(currentTracker == (*currentTier)->urls.end()) { + // force next event + (*currentTier)->nextEventIfAfterStarted(); currentTier++; if(currentTier == tiers.end()) { currentTrackerInitialized = false; diff --git a/src/AnnounceTier.h b/src/AnnounceTier.h index 85fdc27b..b211d177 100644 --- a/src/AnnounceTier.h +++ b/src/AnnounceTier.h @@ -72,6 +72,20 @@ public: break; } } + + void nextEventIfAfterStarted() + { + switch(event) { + case STOPPED: + event = HALTED; + break; + case COMPLETED: + event = SEEDING; + break; + default: + break; + } + } }; typedef SharedHandle AnnounceTierHandle; diff --git a/src/DownloadEngine.cc b/src/DownloadEngine.cc index d2e6039b..7fa680a7 100644 --- a/src/DownloadEngine.cc +++ b/src/DownloadEngine.cc @@ -50,7 +50,12 @@ #include #include -volatile sig_atomic_t globalHaltRequested; +// 0 ... running +// 1 ... stop signal detected +// 2 ... stop signal processed by DownloadEngine +// 3 ... 2nd stop signal(force shutdown) detected +// 4 ... 2nd stop signal processed by DownloadEngine +volatile sig_atomic_t globalHaltRequested = 0; SocketEntry::SocketEntry(const SocketHandle& socket, Command* command, @@ -276,10 +281,15 @@ void DownloadEngine::onEndOfRun() void DownloadEngine::afterEachIteration() { - if(globalHaltRequested) { - globalHaltRequested = false; + if(globalHaltRequested == 1) { + logger->notice(_("Shutdown sequence commencing... Press Ctrl-C again for emergency shutdown.")); _haltRequested = true; _requestGroupMan->halt(); + globalHaltRequested = 2; + } else if(globalHaltRequested == 3) { + logger->notice(_("Emergency shutdown sequence commencing...")); + _requestGroupMan->forceHalt(); + globalHaltRequested = 4; } } diff --git a/src/MultiUrlRequestInfo.cc b/src/MultiUrlRequestInfo.cc index fd6e10b0..db129d1f 100644 --- a/src/MultiUrlRequestInfo.cc +++ b/src/MultiUrlRequestInfo.cc @@ -53,7 +53,11 @@ extern volatile sig_atomic_t globalHaltRequested; static void handler(int signal) { - globalHaltRequested = true; + if(globalHaltRequested == 0) { + globalHaltRequested = 1; + } else if(globalHaltRequested == 2) { + globalHaltRequested = 3; + } } MultiUrlRequestInfo::MultiUrlRequestInfo(const RequestGroups& requestGroups, Option* op): @@ -94,8 +98,8 @@ void MultiUrlRequestInfo::execute() // This is done every 1 second. At the same time, it removes finished/error // RequestGroup from DownloadEngine. - Util::setGlobalSignalHandler(SIGINT, handler, SA_RESETHAND); - Util::setGlobalSignalHandler(SIGTERM, handler, SA_RESETHAND); + Util::setGlobalSignalHandler(SIGINT, handler, 0); + Util::setGlobalSignalHandler(SIGTERM, handler, 0); e->run(); diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index 3912cca8..da5a130f 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -95,6 +95,7 @@ RequestGroup::RequestGroup(const Option* option, _dependency(0), _preLocalFileCheckEnabled(true), _haltRequested(false), + _forceHaltRequested(false), _option(option), _logger(LogFactory::getInstance()) { @@ -540,6 +541,12 @@ void RequestGroup::setHaltRequested(bool f) #endif // ENABLE_BITTORRENT } +void RequestGroup::setForceHaltRequested(bool f) +{ + setHaltRequested(f); + _forceHaltRequested = f; +} + void RequestGroup::releaseRuntimeResource() { #ifdef ENABLE_BITTORRENT diff --git a/src/RequestGroup.h b/src/RequestGroup.h index b8cef64f..7ac6da9d 100644 --- a/src/RequestGroup.h +++ b/src/RequestGroup.h @@ -109,6 +109,8 @@ private: bool _haltRequested; + bool _forceHaltRequested; + PreDownloadHandlers _preDownloadHandlers; PostDownloadHandlers _postDownloadHandlers; @@ -262,11 +264,18 @@ public: void setHaltRequested(bool f); + void setForceHaltRequested(bool f); + bool isHaltRequested() const { return _haltRequested; } + bool isForceHaltRequested() const + { + return _forceHaltRequested; + } + void dependsOn(const DependencyHandle& dep); bool isDependencyResolved(); diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index 5fab60eb..f445f226 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -287,6 +287,14 @@ void RequestGroupMan::halt() } } +void RequestGroupMan::forceHalt() +{ + for(RequestGroups::const_iterator itr = _requestGroups.begin(); + itr != _requestGroups.end(); ++itr) { + (*itr)->setForceHaltRequested(true); + } +} + TransferStat RequestGroupMan::calculateStat() { return accumulate(_requestGroups.begin(), _requestGroups.end(), TransferStat(), diff --git a/src/RequestGroupMan.h b/src/RequestGroupMan.h index 96691ebe..3b8e2662 100644 --- a/src/RequestGroupMan.h +++ b/src/RequestGroupMan.h @@ -72,6 +72,8 @@ public: void halt(); + void forceHalt(); + Commands getInitialCommands(DownloadEngine* e); void removeStoppedGroup(); diff --git a/src/TrackerWatcherCommand.cc b/src/TrackerWatcherCommand.cc index 66f6d06f..181c5a2b 100644 --- a/src/TrackerWatcherCommand.cc +++ b/src/TrackerWatcherCommand.cc @@ -64,6 +64,17 @@ TrackerWatcherCommand::~TrackerWatcherCommand() {} bool TrackerWatcherCommand::execute() { + if(_requestGroup->isForceHaltRequested()) { + if(_trackerRequestGroup.isNull()) { + return true; + } else if(_trackerRequestGroup->getNumCommand() == 0 || + _trackerRequestGroup->downloadFinished()) { + return true; + } else { + _trackerRequestGroup->setForceHaltRequested(true); + return false; + } + } if(btAnnounce->noMoreAnnounce()) { logger->debug("no more announce"); return true; diff --git a/test/AnnounceListTest.cc b/test/AnnounceListTest.cc index 9a5b2e86..bf5662ae 100644 --- a/test/AnnounceListTest.cc +++ b/test/AnnounceListTest.cc @@ -12,6 +12,8 @@ class AnnounceListTest:public CppUnit::TestFixture { CPPUNIT_TEST(testMultiElementList); CPPUNIT_TEST(testSingleAndMulti); CPPUNIT_TEST(testNoGroup); + CPPUNIT_TEST(testEvent); + CPPUNIT_TEST(testNextEventIfAfterStarted); CPPUNIT_TEST(testCountStoppedAllowedTier); CPPUNIT_TEST(testCountCompletedAllowedTier); CPPUNIT_TEST(testMoveToStoppedAllowedTier); @@ -28,6 +30,7 @@ public: void testSingleAndMulti(); void testNoGroup(); void testEvent(); + void testNextEventIfAfterStarted(); void testCountStoppedAllowedTier(); void testCountCompletedAllowedTier(); void testMoveToStoppedAllowedTier(); @@ -150,6 +153,26 @@ void AnnounceListTest::testNoGroup() { CPPUNIT_ASSERT(announceList.countTier() == 0); } +void AnnounceListTest::testNextEventIfAfterStarted() { + string peersString = "ll8:tracker1ee"; + Dictionary* announces = (Dictionary*)MetaFileUtil::bdecoding(peersString.c_str(), peersString.size()); + + // ANNOUNCE_LIST + // [ [ tracker1 ] ] + AnnounceList announceList(announces); + announceList.setEvent(AnnounceTier::STOPPED); + announceList.announceFailure(); + announceList.resetTier(); + CPPUNIT_ASSERT_EQUAL(string(""), announceList.getEventString()); + CPPUNIT_ASSERT_EQUAL(AnnounceTier::HALTED, announceList.getEvent()); + + announceList.setEvent(AnnounceTier::COMPLETED); + announceList.announceFailure(); + announceList.resetTier(); + CPPUNIT_ASSERT_EQUAL(string(""), announceList.getEventString()); + CPPUNIT_ASSERT_EQUAL(AnnounceTier::SEEDING, announceList.getEvent()); +} + void AnnounceListTest::testEvent() { string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee"; Dictionary* announces = (Dictionary*)MetaFileUtil::bdecoding(peersString.c_str(), peersString.size());