ExitManager.cc

Go to the documentation of this file.
00001 
00006 extern "C"
00007 {
00008  #include <sys/types.h>
00009  #include <signal.h>
00010 }
00011 
00012 
00026 class ExitManager
00027 {
00028 public:
00029   typedef void (*cleanup_function)(void);
00030 private:
00031   static stack<cleanup_function> cleanup_functions;
00032 #ifdef USE_NETWORK
00033   static CMutex Mutex, AliveMutex;
00034 public:
00035   static void register_cancel(const pthread_t tid = pthread_self());
00036   static void unregister_cancel(const pthread_t tid = pthread_self());
00037   static void cancel_registered_threads();
00038 #endif
00039 
00040 public:
00041   static void register_exithandler(cleanup_function a_cleanup_function);
00042   // the difference between atexit and register_exithandler is that
00043   // the exithandlers registered by exithandler are only called, when
00044   // StopFactorization is invoked (and not on other kinds of termination).
00045 
00046   static void StopFactorization();
00047 };
00048 stack<ExitManager::cleanup_function> ExitManager::cleanup_functions;
00049 
00050 
00051 #ifdef USE_NETWORK
00052 
00053 CMutex ExitManager::Mutex, ExitManager::AliveMutex;
00054 set<pthread_t> pending_threads;
00055 
00056 
00058 void ExitManager::register_cancel(const pthread_t tid /* = pthread_self() */)
00059 {
00060   Mutex.lock();
00061   pending_threads.insert(tid);
00062   Mutex.unlock();
00063 }
00064 
00066 void ExitManager::unregister_cancel(const pthread_t tid /* = pthread_self() */)
00067 {
00068   Mutex.lock();
00069   pending_threads.erase(tid);
00070   Mutex.unlock();
00071 }
00072 
00074 void ExitManager::cancel_registered_threads()
00075 {
00076   Mutex.lock(); // only one thread may proceed...
00077   pthread_t tid = pthread_self();
00078   for (set<pthread_t>::const_iterator p=pending_threads.begin(); p!=pending_threads.end(); ++p)
00079    if (*p != tid)
00080     {
00081 #ifdef VERBOSE_INFO
00082       cout << "cancelling thread " << *p << endl;
00083 #endif
00084       int result=pthread_cancel(*p);
00085 #ifdef VERBOSE_WARN
00086       if (result<0) cerr << "cancel request failed for " << *p << endl;
00087 #endif
00088     }
00089   usleep(100000); // wait a small amount of time for possibly deferred cancellation
00090   Mutex.unlock();
00091 }
00092 
00093 #endif
00094 
00095 
00097 void ExitManager::register_exithandler(cleanup_function a_cleanup_function)
00098 {
00099   cleanup_functions.push(a_cleanup_function);
00100 }
00101 
00102 
00103 #ifdef USE_NETWORK
00104 static pthread_t tid_caller = 0;
00105 static void catch_sigint(int signr)
00106 {
00107   cout << "Signal " << signr << " received. (ThreadId=" << pthread_self() << ")" << endl;
00108   if (pthread_self()!=tid_caller)
00109    {
00110      cout << "going down: ThreadId=" << pthread_self() << endl;
00111      exit(0);
00112    }
00113 }
00114 #endif
00115 
00116 
00118 void ExitManager::StopFactorization()
00119 {
00120 #ifdef VERBOSE_INFO
00121   MARK;
00122   cout << "ExitManager::StopFactorization() called." << endl;
00123 #endif
00124   if (XML_StatusFile!="")
00125    {
00126      // write a (final) status report
00127 #ifdef VERBOSE_NOTICE
00128      cout << "writing XML Status Report to \"" << XML_StatusFile << "\"" << endl;
00129 #endif
00130      ofstream StatusReport;
00131      StatusReport.open(XML_StatusFile.c_str(),ios::in|ios::out|ios::ate);
00132      if (StatusReport) StatusReport.seekp(0,ios::end);
00133      else
00134       {
00135         StatusReport.close();
00136         StatusReport.clear();
00137         StatusReport.open(XML_StatusFile.c_str(),ios::in|ios::out|ios::trunc);
00138       }
00139      if ( (StatusReport) && StatusReport.tellp()<=std::streampos(0) )
00140       {
00141         StatusReport << "<?xml version=\"1.0\"?>" << endl
00142                      << "<?xml-stylesheet href=\"qsieve-status.xsl\" type=\"text/xsl\" ?>" << endl
00143                      << endl << "<LOGFILE>" << endl << "</LOGFILE>" << flush;
00144       }
00145      if (StatusReport)
00146       {
00147         StatusReport.seekp(-10,ios::end); // overwrite "</LOGFILE>"
00148         // remark: strange! seekp(-10,ios::end) will be ignored, if "ios::in" in open is missing!
00149         statistical_data::XML_StatusReport(StatusReport);
00150         StatusReport << "</LOGFILE>" << flush;
00151       }
00152      if (StatusReport)
00153       {
00154 #ifdef VERBOSE_INFO
00155         cout << "Status report written." << endl;
00156 #endif
00157       }
00158      else
00159       {
00160         cout << "Status report not written due to a failure!" << endl;
00161       }
00162    }
00163   if (PrintSummary) FoundFactors.PrettyPrint(cout); // print a summary on screen
00164 #ifdef USE_NETWORK
00165   AliveMutex.lock(); // only one thread may proceed...
00166   // only one thread may proceed...
00167   cancel_registered_threads(); // does a Mutex.lock(),
00168 #endif
00169 #ifdef VERBOSE_INFO
00170   cout << "calling registered cleanup-functions...." << endl;
00171 #endif
00172   while (!cleanup_functions.empty())
00173    {
00174      cleanup_function a_cleanup_function = cleanup_functions.top(); // pop next cleanup function
00175      a_cleanup_function(); // and call it
00176      cleanup_functions.pop();
00177    }
00178 #ifdef VERBOSE_NOTICE
00179   cout << "going down..." << endl;
00180 #endif
00181 
00182 #ifdef USE_NETWORK
00183   // exit(0) does not work well sometimes:
00184   // at least for linuxthreads,  sometimes there are still threads
00185   // that simply ignore, that the program is going down.
00186   // for this reason we send a kill signal to all processes in the current group.
00187   tid_caller=pthread_self();
00188   signal(SIGINT,catch_sigint);
00189   kill(0,SIGINT); // desperately convincing the group to commit suicide :-(
00190 #endif
00191 
00192   exit(0); // terminate program
00193 }

Generated on Wed Nov 7 23:29:25 2007 for Qsieve by  doxygen 1.5.4