瀏覽代碼

2007-12-07 Tatsuhiro Tsujikawa <tujikawa at rednoah com>

	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
Tatsuhiro Tsujikawa 18 年之前
父節點
當前提交
bb4bff2c2a

+ 16 - 0
ChangeLog

@@ -1,3 +1,19 @@
+2007-12-07  Tatsuhiro Tsujikawa  <tujikawa at rednoah com>
+
+	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  <tujikawa at rednoah dot com>
 
 	Code cleanup

+ 2 - 0
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;

+ 14 - 0
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<AnnounceTier> AnnounceTierHandle;

+ 13 - 3
src/DownloadEngine.cc

@@ -50,7 +50,12 @@
 #include <fcntl.h>
 #include <signal.h>
 
-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;
   }
 }
 

+ 7 - 3
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();
     

+ 7 - 0
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

+ 9 - 0
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();

+ 8 - 0
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(),

+ 2 - 0
src/RequestGroupMan.h

@@ -72,6 +72,8 @@ public:
   
   void halt();
 
+  void forceHalt();
+
   Commands getInitialCommands(DownloadEngine* e);
 
   void removeStoppedGroup();

+ 11 - 0
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;

+ 23 - 0
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());