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 }