ProcessSignalHandler.cpp
Go to the documentation of this file.
1 #include <signal.h>
2 #include <string>
3 #include <iostream>
4 #include <algorithm>
5 #include <boost/thread/mutex.hpp>
6 #include <boost/bind.hpp>
7 #include <cassert>
8 
9 #include "rms/provider/CETDDS.h"
10 #include "rms/provider/ProcessSignalHandler.h"
11 
12 namespace gov {
13 namespace fnal {
14 namespace cd {
15 namespace rms {
16 namespace base
17 {
18 Notifiable::Notifiable():_beenNotified(false)
19 {
20 
21 }
22 
24 {
25 
26 }
27 
29 {
30  doNotify_impl();
31 }
32 
34 {
35  return hasBeenNotified_impl();
36 }
37 
39 {
40  boost::unique_lock<boost::mutex> guard(_lock);
41  _beenNotified=true;
42 }
43 
45 {
46  boost::unique_lock<boost::mutex> guard(_lock);
47  return _beenNotified;
48 }
49 
50 } // end of namespace base
51 
52 namespace provider {
53 /*
54  * Maintains a list of signal-number--signal-handler pairs;
55  * signalhHandlerList is used by customSignalHandler
56  */
57 ProcessSignalHandler::SignalHandlerPairList ProcessSignalHandler::_signalhHandlerList;
58 
59 template <typename T>
60 bool equal(T * first,T * second)
61 {
62  assert( first != NULL );
63  assert( second != NULL );
64 
65  return first==second;
66 }
67 
68 ProcessSignalHandler::ProcessSignalHandler()
69  : _cleanupRequired( 1 )
70 {
71 
72 }
73 
74 /*
75  * Adds Notifiable to the process exit notification list
76  */
77 void ProcessSignalHandler::addToNotificationList( base::Notifiable* notifiable )
78 {
79  boost::mutex::scoped_lock guard( _listLock );
80 
81  _notificationList.push_back( notifiable );
82 }
83 
84 /*
85  * Removes Notifiable to the process exit notification list
86  */
87 void ProcessSignalHandler::removeFromNotificationList(base::Notifiable* notifiable)
88 {
89  boost::mutex::scoped_lock guard( _listLock );
90 
91  _notificationList.erase(std::remove_if(_notificationList.begin(),_notificationList.end(),
92  boost::bind(equal<base::Notifiable>,notifiable,_1)),_notificationList.end());
93 }
94 
95 /*
96  * Replaces the default process signal handler by customSignalHandler
97  * for a specified signal number
98  */
100 {
101  _signalhHandlerList.push_back( SignalHandlerPair( signalNumber,
102  SignalHandler( boost::bind( &ProcessSignalHandler::processSignal, this, _1, this ) ) ) );
103 
104  struct sigaction action;
105  action.sa_handler = &ProcessSignalHandler::customSignalHandler;
106  sigemptyset( &action.sa_mask );
107  action.sa_flags = 0;
108 
109  if ( sigaction( signalNumber, &action, &_previousSignalHandler ) == -1 )
110  return false; /*sigaction returned an error*/
111 
112  return true;
113 }
114 
115 /*
116  * Frees up resources on the DDS server upon receiving a process signal
117  */
119 {
121 
122  //calls processSignal on a signal handler associated with the signal number
123  for ( SignalHandlerPairIterator handler = ProcessSignalHandler::_signalhHandlerList.begin();
124  handler != end;++handler ) {
125  if ( handler->first == signalNumber )
126  handler->second( signalNumber );
127  }
128 }
129 /*
130  * Acquires a unique lock for RmsLockable::sharedLock and calls performCleanup
131  */
133 {
134  assert( handler != NULL );
135 
136 #if CETDDS_DEBUG1
137  std::cerr << "Processing signal (number=" << signalNumber << ")." << std::endl;
138 #endif
139  boost::recursive_timed_mutex::scoped_lock guard( _selfLock,boost::get_system_time() + boost::posix_time::milliseconds(250) );
140 
141  if ( guard.owns_lock() && handler->_cleanupRequired)
142  {
143  handler->_cleanupRequired = 0;
144 
145  handler->closeDDSConnections();
146 
148 
149  } else if(!guard.owns_lock())
150  {
151  #if CETDDS_DEBUG1
152  std::cerr << "Termination in progress stalling thread." << std::endl;
153  #endif
154 
155  boost::this_thread::sleep(boost::posix_time::milliseconds(5000));
156  }else if (signalNumber==SIGSEGV)
157  {
158  std::cerr << "Warning: Program received signal SIGSEGV, Segmentation fault." << std::endl;
159  }
160 
161  #if CETDDS_DEBUG1
162  std::cout << "Finished processing signal (number=" << signalNumber << ")." << std::endl;
163  #endif
164 
165  _exit(0);
166 }
167 
168 /*
169  * Gracefully closes DDS connections and frees up resources used by this client
170  */
172 {
173 #if CETDDS_DEBUG1
174  std::cout << "Notifying " << _notificationList.size() << " RMS connections to close." << std::endl;
175 #endif
176  boost::mutex::scoped_lock guard( _listLock );
177 
179 
181 
182  for ( NotifiableListIterator notifiable = _notificationList.begin();notifiable != end;++notifiable )
183  (*notifiable )->doNotify(); /*notify DDS resources*/
184 
185 }
186 
187 /*
188  *Terminates DDS connections prior exiting this process
189  */
191 {
192  size_t activeConnectionCount=0;
193 
194  {
195  boost::mutex::scoped_lock guard( _listLock );
196  activeConnectionCount=_notificationList.size();
197  }
198 
199 
200  for (int retryCount=10; activeConnectionCount!=0 && retryCount>0;--retryCount)
201  {
202  usleep(50000);
203 
204  activeConnectionCount=0;
205 
206  boost::mutex::scoped_lock guard( _listLock );
207 
209 
210  for ( NotifiableListIterator notifiable = _notificationList.begin();notifiable != end;++notifiable )
211  if (! (*notifiable )->hasBeenClosed())
212  ++activeConnectionCount;
213  }
214 
215  DDS::DomainParticipantFactory::get_instance()->delete_contained_entities();
216 
217  if(activeConnectionCount!=0)
218  {
219 #if CETDDS_DEBUG1
220  std::cout << "Terminating "<< activeConnectionCount << " RMS connections." << std::endl;
221 #endif
222 
223  boost::mutex::scoped_lock guard( _listLock );
224 
226 
227  for ( NotifiableListIterator notifiable = _notificationList.begin();notifiable != end;++notifiable )
228  {
229  if (! (*notifiable )->hasBeenClosed())
230  (*notifiable )->close(); /*notify DDS resources*/
231  }
232  }
233 }
234 
236 {
237  assert( handler != NULL );
238 
239 #if CETDDS_DEBUG1
240  std::cout << "Finished calling ProcessSignalHandlerDeleter." << std::endl;
241 #endif
242 }
243 
245 {
246  sigset_t sigs;
247  sigemptyset( &sigs );
248  sigaddset( &sigs, SIGTERM );
249  sigaddset( &sigs, SIGINT );
250  sigaddset( &sigs, SIGSEGV );
251 
252  if ( pthread_sigmask( SIG_BLOCK, &sigs, 0 )) {
253  std::cout << "Unable to change signal mask in ctor" << std::endl;
254  }
255 }
256 
258 {
259  sigset_t sigs;
260  sigemptyset( &sigs );
261  sigaddset( &sigs, SIGTERM );
262  sigaddset( &sigs, SIGINT );
263  sigaddset( &sigs, SIGSEGV );
264 
265  if ( pthread_sigmask( SIG_UNBLOCK, &sigs, 0 )) {
266  std::cout << "Unable to change signal mask in dtor" << std::endl;
267  }
268 }
269 
270 
271 
272 } // end of namespace provider
273 
274 
275 } // end of namespace rms
276 } // end of namespace cd
277 } // end of namespace fnal
278 } // end of namespace gov
279 // kate: indent-mode cstyle; space-indent on; indent-width 0;
void processSignal(int signalNumber, ProcessSignalHandler *handler)
static DPSingleton & Instance()
Definition: CETDDS.h:142
void removeFromNotificationList(base::Notifiable *notifiable)
bool equal(T *first, T *second)
OStream cerr
Definition: OStream.cxx:7
const XML_Char int const XML_Char int const XML_Char * base
Definition: expat.h:331
SignalHandlerPairList::iterator SignalHandlerPairIterator
Definition: fnal.py:1
void addToNotificationList(base::Notifiable *notifiable)
OStream cout
Definition: OStream.cxx:6
assert(nhit_max >=nhit_nbins)
double T
Definition: Xdiff_gwt.C:5
c cd(1)