Kea  1.5.0
timer_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
9 #include <asiolink/io_service.h>
10 #include <dhcpsrv/dhcpsrv_log.h>
11 #include <dhcpsrv/timer_mgr.h>
12 #include <exceptions/exceptions.h>
13 
14 #include <boost/bind.hpp>
15 
16 #include <utility>
17 
18 using namespace isc;
19 using namespace isc::asiolink;
20 
21 namespace {
22 
28 struct TimerInfo {
30  asiolink::IntervalTimer interval_timer_;
31 
34  asiolink::IntervalTimer::Callback user_callback_;
35 
37  long interval_;
38 
40  asiolink::IntervalTimer::Mode scheduling_mode_;
41 
50  TimerInfo(asiolink::IOService& io_service,
51  const asiolink::IntervalTimer::Callback& user_callback,
52  const long interval,
54  : interval_timer_(io_service),
55  user_callback_(user_callback),
56  interval_(interval),
57  scheduling_mode_(mode) { };
58 };
59 
60 }
61 
62 namespace isc {
63 namespace dhcp {
64 
66 typedef boost::shared_ptr<TimerInfo> TimerInfoPtr;
67 
69 typedef std::map<std::string, TimerInfoPtr> TimerInfoMap;
70 
71 
73 class TimerMgrImpl {
74 public:
75 
77  TimerMgrImpl();
78 
82  void setIOService(const IOServicePtr& io_service);
83 
95  void registerTimer(const std::string& timer_name,
96  const asiolink::IntervalTimer::Callback& callback,
97  const long interval,
98  const asiolink::IntervalTimer::Mode& scheduling_mode);
99 
100 
109  void unregisterTimer(const std::string& timer_name);
110 
115  void unregisterTimers();
116 
122  bool isTimerRegistered(const std::string& timer_name);
123 
125  size_t timersCount() const;
126 
139  void setup(const std::string& timer_name);
140 
146  void cancel(const std::string& timer_name);
147 
148 private:
149 
154  void timerCallback(const std::string& timer_name);
155 
157  asiolink::IOServicePtr io_service_;
158 
161  TimerInfoMap registered_timers_;
162 };
163 
164 TimerMgrImpl::TimerMgrImpl() :
165  io_service_(new IOService()), registered_timers_() {
166 }
167 
168 void
170  if (!io_service) {
171  isc_throw(BadValue, "IO service object must not be null for TimerMgr");
172  }
173  io_service_ = io_service;
174 }
175 
176 void
177 TimerMgrImpl::registerTimer(const std::string& timer_name,
178  const IntervalTimer::Callback& callback,
179  const long interval,
180  const IntervalTimer::Mode& scheduling_mode) {
181 
182  // Timer name must not be empty.
183  if (timer_name.empty()) {
184  isc_throw(BadValue, "registered timer name must not be empty");
185  }
186 
187  // Must not register two timers under the same name.
188  if (registered_timers_.find(timer_name) != registered_timers_.end()) {
189  isc_throw(BadValue, "trying to register duplicate timer '"
190  << timer_name << "'");
191  }
192 
193  // Create a structure holding the configuration for the timer. It will
194  // create the instance if the IntervalTimer. It will also hold the
195  // callback, interval and scheduling mode parameters.
196  TimerInfoPtr timer_info(new TimerInfo(*io_service_, callback,
197  interval, scheduling_mode));
198 
199  // Actually register the timer.
200  registered_timers_.insert(std::pair<std::string, TimerInfoPtr>(timer_name,
201  timer_info));
202 }
203 
204 void
205 TimerMgrImpl::unregisterTimer(const std::string& timer_name) {
206 
207  // Find the timer with specified name.
208  TimerInfoMap::iterator timer_info_it = registered_timers_.find(timer_name);
209 
210  // Check if the timer has been registered.
211  if (timer_info_it == registered_timers_.end()) {
212  isc_throw(BadValue, "unable to unregister non existing timer '"
213  << timer_name << "'");
214  }
215 
216  // Cancel any pending asynchronous operation and stop the timer.
217  cancel(timer_name);
218 
219  // Remove the timer.
220  registered_timers_.erase(timer_info_it);
221 }
222 
223 void
225  // Copy the map holding timers configuration. This is required so as
226  // we don't cut the branch which we're sitting on when we will be
227  // erasing the timers. We're going to iterate over the register timers
228  // and remove them with the call to unregisterTimer function. But this
229  // function will remove them from the register_timers_ map. If we
230  // didn't work on the copy here, our iterator would invalidate. The
231  // TimerInfo structure is copyable and since it is using the shared
232  // pointers the copy is not expensive. Also this function is called when
233  // the process terminates so it is not critical for performance.
234  TimerInfoMap registered_timers_copy(registered_timers_);
235 
236  // Iterate over the existing timers and unregister them.
237  for (TimerInfoMap::iterator timer_info_it = registered_timers_copy.begin();
238  timer_info_it != registered_timers_copy.end(); ++timer_info_it) {
239  unregisterTimer(timer_info_it->first);
240  }
241 }
242 
243 bool
244 TimerMgrImpl::isTimerRegistered(const std::string& timer_name) {
245  return (registered_timers_.find(timer_name) != registered_timers_.end());
246 }
247 
248 size_t
250  return (registered_timers_.size());
251 }
252 
253 void
254 TimerMgrImpl::setup(const std::string& timer_name) {
255 
256  // Check if the specified timer exists.
257  TimerInfoMap::const_iterator timer_info_it = registered_timers_.find(timer_name);
258  if (timer_info_it == registered_timers_.end()) {
259  isc_throw(BadValue, "unable to setup timer '" << timer_name << "': "
260  "no such timer registered");
261  }
262 
263  // Schedule the execution of the timer using the parameters supplied
264  // during the registration.
265  const TimerInfoPtr& timer_info = timer_info_it->second;
266  IntervalTimer::Callback cb = boost::bind(&TimerMgrImpl::timerCallback, this,
267  timer_name);
268  timer_info->interval_timer_.setup(cb, timer_info->interval_,
269  timer_info->scheduling_mode_);
270 }
271 
272 void
273 TimerMgrImpl::cancel(const std::string& timer_name) {
274 
275  // Find the timer of our interest.
276  TimerInfoMap::const_iterator timer_info_it = registered_timers_.find(timer_name);
277  if (timer_info_it == registered_timers_.end()) {
278  isc_throw(BadValue, "unable to cancel timer '" << timer_name << "': "
279  "no such timer registered");
280  }
281  // Cancel the timer.
282  timer_info_it->second->interval_timer_.cancel();
283 }
284 
285 void
286 TimerMgrImpl::timerCallback(const std::string& timer_name) {
287  // Find the specified timer setup.
288  TimerInfoMap::iterator timer_info_it = registered_timers_.find(timer_name);
289  if (timer_info_it != registered_timers_.end()) {
290 
291  // Running user-defined operation for the timer. Logging it
292  // on the slightly lower debug level as there may be many
293  // such traces.
295  DHCPSRV_TIMERMGR_RUN_TIMER_OPERATION)
296  .arg(timer_info_it->first);
297 
298  std::string error_string;
299  try {
300  timer_info_it->second->user_callback_();
301 
302  } catch (const std::exception& ex){
303  error_string = ex.what();
304 
305  } catch (...) {
306  error_string = "unknown reason";
307  }
308 
309  // Exception was thrown. Log an error.
310  if (!error_string.empty()) {
311  LOG_ERROR(dhcpsrv_logger, DHCPSRV_TIMERMGR_CALLBACK_FAILED)
312  .arg(timer_info_it->first)
313  .arg(error_string);
314  }
315  }
316 }
317 
318 const TimerMgrPtr&
320  static TimerMgrPtr timer_mgr(new TimerMgr());
321  return (timer_mgr);
322 }
323 
324 TimerMgr::TimerMgr()
325  : impl_(new TimerMgrImpl()) {
326 }
327 
329  impl_->unregisterTimers();
330  delete impl_;
331 }
332 
333 void
334 TimerMgr::registerTimer(const std::string& timer_name,
335  const IntervalTimer::Callback& callback,
336  const long interval,
337  const IntervalTimer::Mode& scheduling_mode) {
338 
340  DHCPSRV_TIMERMGR_REGISTER_TIMER)
341  .arg(timer_name)
342  .arg(interval);
343 
344  impl_->registerTimer(timer_name, callback, interval, scheduling_mode);
345 }
346 
347 void
348 TimerMgr::unregisterTimer(const std::string& timer_name) {
349 
351  DHCPSRV_TIMERMGR_UNREGISTER_TIMER)
352  .arg(timer_name);
353 
354  impl_->unregisterTimer(timer_name);
355 }
356 
357 void
359 
361  DHCPSRV_TIMERMGR_UNREGISTER_ALL_TIMERS);
362 
363  impl_->unregisterTimers();
364 }
365 
366 bool
367 TimerMgr::isTimerRegistered(const std::string& timer_name) {
368  return (impl_->isTimerRegistered(timer_name));
369 }
370 
371 size_t
373  return (impl_->timersCount());
374 }
375 
376 void
377 TimerMgr::setup(const std::string& timer_name) {
378 
380  DHCPSRV_TIMERMGR_START_TIMER)
381  .arg(timer_name);
382 
383  impl_->setup(timer_name);
384 }
385 
386 void
387 TimerMgr::cancel(const std::string& timer_name) {
388 
390  DHCPSRV_TIMERMGR_STOP_TIMER)
391  .arg(timer_name);
392 
393  impl_->cancel(timer_name);
394 }
395 
396 void
398  impl_->setIOService(io_service);
399 }
400 
401 
402 } // end of namespace isc::dhcp
403 } // end of namespace isc
isc::dhcp::TimerMgr::registerTimer
void registerTimer(const std::string &timer_name, const asiolink::IntervalTimer::Callback &callback, const long interval, const asiolink::IntervalTimer::Mode &scheduling_mode)
Registers new timer in the TimerMgr.
Definition: timer_mgr.cc:334
LOG_ERROR
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
isc::dhcp::DHCPSRV_DBG_TRACE_DETAIL
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
isc::dhcp::TimerInfoPtr
boost::shared_ptr< TimerInfo > TimerInfoPtr
A type definition for the pointer to TimerInfo structure.
Definition: timer_mgr.cc:66
isc::dhcp::TimerMgr::unregisterTimer
void unregisterTimer(const std::string &timer_name)
Unregisters specified timer.
Definition: timer_mgr.cc:348
timer_mgr.h
isc::dhcp::TimerMgrImpl::setIOService
void setIOService(const IOServicePtr &io_service)
Sets IO service to be used by the Timer Manager.
Definition: timer_mgr.cc:169
io_service.h
isc::dhcp::TimerMgr::~TimerMgr
~TimerMgr()
Destructor.
Definition: timer_mgr.cc:328
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::dhcp::TimerMgrImpl::registerTimer
void registerTimer(const std::string &timer_name, const asiolink::IntervalTimer::Callback &callback, const long interval, const asiolink::IntervalTimer::Mode &scheduling_mode)
Registers new timer in the TimerMgr.
Definition: timer_mgr.cc:177
isc::dhcp::TimerMgr
Manages a pool of asynchronous interval timers.
Definition: timer_mgr.h:54
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
LOG_DEBUG
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
dhcpsrv_log.h
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::dhcp::TimerMgr::isTimerRegistered
bool isTimerRegistered(const std::string &timer_name)
Checks if the timer with a specified name has been registered.
Definition: timer_mgr.cc:367
isc::dhcp::TimerMgrImpl::setup
void setup(const std::string &timer_name)
Schedules the execution of the interval timer.
Definition: timer_mgr.cc:254
isc::dhcp::DHCPSRV_DBG_TRACE
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
isc::dhcp::TimerInfoMap
std::map< std::string, TimerInfoPtr > TimerInfoMap
A type definition for the map holding timers configuration.
Definition: timer_mgr.cc:69
isc::dhcp::TimerMgr::unregisterTimers
void unregisterTimers()
Unregisters all timers.
Definition: timer_mgr.cc:358
isc::dhcp::TimerMgr::instance
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:319
isc::dhcp::TimerMgr::setup
void setup(const std::string &timer_name)
Schedules the execution of the interval timer.
Definition: timer_mgr.cc:377
isc::dhcp::TimerMgrImpl
Implementation of the TimerMgr.
Definition: timer_mgr.cc:73
isc::dhcp::TimerMgrImpl::cancel
void cancel(const std::string &timer_name)
Cancels the execution of the interval timer.
Definition: timer_mgr.cc:273
isc::dhcp::TimerMgrImpl::timersCount
size_t timersCount() const
Returns the number of registered timers.
Definition: timer_mgr.cc:249
isc::dhcp::TimerMgr::cancel
void cancel(const std::string &timer_name)
Cancels the execution of the interval timer.
Definition: timer_mgr.cc:387
isc::dhcp::TimerMgrImpl::unregisterTimer
void unregisterTimer(const std::string &timer_name)
Unregisters specified timer.
Definition: timer_mgr.cc:205
isc::dhcp::TimerMgr::setIOService
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the Timer Manager.
Definition: timer_mgr.cc:397
isc::dhcp::TimerMgrPtr
boost::shared_ptr< TimerMgr > TimerMgrPtr
Type definition of the shared pointer to TimerMgr.
Definition: timer_mgr.h:22
exceptions.h
isc::dhcp::TimerMgrImpl::unregisterTimers
void unregisterTimers()
Unregisters all timers.
Definition: timer_mgr.cc:224
asio_wrapper.h
isc::dhcp::TimerMgr::timersCount
size_t timersCount() const
Returns the number of registered timers.
Definition: timer_mgr.cc:372
isc::dhcp::TimerMgrImpl::isTimerRegistered
bool isTimerRegistered(const std::string &timer_name)
Checks if the timer with a specified name has been registered.
Definition: timer_mgr.cc:244
isc::dhcp::dhcpsrv_logger
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56