DDS  ver. 3.4
MonitoringThread.h
Go to the documentation of this file.
1 // Copyright 2014 GSI, Inc. All rights reserved.
2 //
3 //
4 //
5 
6 #ifndef __DDS__MonitoringThread__
7 #define __DDS__MonitoringThread__
8 
9 // DDS
10 #include "Logger.h"
11 #include "Process.h"
12 // STL
13 #include <chrono>
14 #include <functional>
15 #include <mutex>
16 #include <thread>
17 // API
18 #include <csignal>
19 
20 namespace dds
21 {
23  {
24  typedef std::function<bool()> callbackFunction_t;
25  // the function to call, the interval (in sec) the function should be called at
26  typedef std::pair<callbackFunction_t, std::chrono::seconds> callbackValue_t;
27 
28  private:
30  {
31  }
33  {
34  }
35 
36  public:
39  {
41  return instance;
42  }
43 
48  void start(double _idleTime, const std::function<void(void)>& _idleCallback)
49  {
50  // Looping monitoring thread with a step of 1 sec up to *Unlimited* sec (size of int)
51  static const std::chrono::seconds INTERVAL_STEP(1);
52  static const std::chrono::seconds WAITING_TIME(20);
53 
54  updateIdle();
55 
56  std::thread t([this, &_idleCallback, _idleTime]() {
57  try
58  {
59  std::chrono::seconds secInterval(0);
60  while (true)
61  {
62  // handle exceptions of the custom actions separately to prevent breaks of the
63  // monitoring thread
64  try
65  {
66  std::lock_guard<std::mutex> lock(m_registeredCallbackFunctionsMutex);
67  // Call registered callback functions
68  // We use Erase-remove idiom to execute callback and remove expired if needed.
69  m_registeredCallbackFunctions.erase(
70  remove_if(m_registeredCallbackFunctions.begin(),
71  m_registeredCallbackFunctions.end(),
72  [&](callbackValue_t& i) {
73  // A callback function can return
74  // false, which
75  // means it wants to be unregistered
76  // (expire)
77  const int nCurInterval = std::chrono::duration<int>(secInterval).count();
78  const int nInterval = std::chrono::duration<int>(i.second).count();
79  if (nCurInterval != 0 && nCurInterval >= nInterval &&
80  0 == (nCurInterval % nInterval))
81  {
83  << "MONITORING: calling callback at interval of "
84  << std::chrono::duration<int>(i.second).count();
85  return (!i.first());
86  }
87  return false;
88  }),
89  m_registeredCallbackFunctions.end());
90  }
91  catch (std::exception& _e)
92  {
93  LOG(MiscCommon::error) << "MonitoringThread exception on custom actions: " << _e.what();
94  }
95  catch (...)
96  {
97  // Ignore any exception here to let the monitoring thread continue whatever it takes
98  }
99 
100  std::chrono::seconds idleTime;
101  // Check if process is idle.
102  {
103  std::lock_guard<std::mutex> lock(m_mutex);
104  std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now();
105  idleTime = std::chrono::duration_cast<std::chrono::seconds>(currentTime - m_startIdleTime);
106  }
107 
108  if (idleTime.count() > _idleTime)
109  {
110  // First call idle callback
111  LOG(MiscCommon::info) << "The process is idle for " << idleTime.count()
112  << " sec. Call idle callback and wait "
113  << std::chrono::duration<int>(WAITING_TIME).count() << "s";
114  // handle exceptions of the custom idle callback separately to prevent breaks of the
115  // monitoring thread
116  try
117  {
118  _idleCallback();
119  }
120  catch (std::exception& _e)
121  {
123  << "MonitoringThread exception on custom idle function: " << _e.what();
124  }
125  catch (...)
126  {
127  // Ignore any exception here to let the monitoring thread continue whatever it takes
128  }
129  std::this_thread::sleep_for(WAITING_TIME);
130 
131  // Call terminate
132  LOG(MiscCommon::info) << "Sending SIGTERM to this process...";
133  std::raise(SIGTERM);
134  std::this_thread::sleep_for(WAITING_TIME);
135 
136  // Kill process
137  LOG(MiscCommon::info) << "The process still exists. Killing the process...";
138  killProcess();
139  }
140 
141  std::this_thread::sleep_for(INTERVAL_STEP);
142  secInterval += INTERVAL_STEP;
143  }
144  }
145  catch (std::exception& _e)
146  {
147  LOG(MiscCommon::error) << "MonitoringThread exception: " << _e.what();
148  }
149  });
150  t.detach();
151  }
152 
153  void updateIdle()
154  {
155  std::lock_guard<std::mutex> lock(m_mutex);
156  m_startIdleTime = std::chrono::steady_clock::now();
157  }
158 
159  void registerCallbackFunction(callbackFunction_t _handler, const std::chrono::seconds& _interval)
160  {
161  std::lock_guard<std::mutex> lock(m_registeredCallbackFunctionsMutex);
162  m_registeredCallbackFunctions.push_back(make_pair(_handler, _interval));
163  }
164 
165  private:
166  void killProcess()
167  {
168  pid_t pidToKill(::getpid());
169  if (pidToKill > 0 && MiscCommon::IsProcessRunning(pidToKill))
170  {
171  LOG(MiscCommon::log_stdout) << " self exiting (" << pidToKill << ")...";
172  // TODO: Maybe we need more validations of the process before
173  // sending a signal. We don't want to kill someone else.
174  kill(pidToKill, SIGTERM);
175 
176  // Waiting for the process to finish
177  size_t iter(0);
178  const size_t max_iter = 30;
179  while (iter <= max_iter)
180  {
181  if (!MiscCommon::IsProcessRunning(pidToKill))
182  {
183  LOG(MiscCommon::log_stdout) << std::endl;
184  break;
185  }
186  LOG(MiscCommon::log_stdout) << ".";
187  sleep(1); // sleeping for 1 second
188  ++iter;
189  }
190  if (MiscCommon::IsProcessRunning(pidToKill))
191  LOG(MiscCommon::error) << "FAILED to close the process.";
192  }
193  }
194 
195  private:
196  std::chrono::steady_clock::time_point m_startIdleTime;
197 
198  std::function<void(void)> m_idleCallback;
199  std::vector<callbackValue_t> m_registeredCallbackFunctions;
200 
201  std::mutex m_registeredCallbackFunctionsMutex;
202 
203  std::mutex m_mutex; // Mutex for updateIdle call
204  };
205 } // namespace dds
206 
207 #endif /* defined(__DDS__MonitoringThread__) */
void start(double _idleTime, const std::function< void(void)> &_idleCallback)
Main function user has to run to start monitoring thread.
Definition: MonitoringThread.h:48
Definition: def.h:154
static CMonitoringThread & instance()
Return singleton instance.
Definition: MonitoringThread.h:38
Definition: MonitoringThread.h:22
#define LOG(severity)
Definition: Logger.h:56
Definition: AgentConnectionManager.h:13
void registerCallbackFunction(callbackFunction_t _handler, const std::chrono::seconds &_interval)
Definition: MonitoringThread.h:159
Definition: def.h:152
void updateIdle()
Definition: MonitoringThread.h:153
Definition: def.h:149
Definition: def.h:150
bool IsProcessRunning(pid_t _PID)
The function checks, whether the process which corresponds to the given _PID can be found.
Definition: Process.h:57