Kea  1.9.9-git
timer_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2016-2020 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>
14 
15 #include <boost/scoped_ptr.hpp>
16 
17 #include <functional>
18 #include <utility>
19 
20 using namespace isc;
21 using namespace isc::asiolink;
22 using namespace isc::util;
23 
24 namespace {
25 
31 struct TimerInfo {
33  asiolink::IntervalTimer interval_timer_;
34 
37  asiolink::IntervalTimer::Callback user_callback_;
38 
40  long interval_;
41 
43  asiolink::IntervalTimer::Mode scheduling_mode_;
44 
53  TimerInfo(asiolink::IOService& io_service,
54  const asiolink::IntervalTimer::Callback& user_callback,
55  const long interval,
57  : interval_timer_(io_service),
58  user_callback_(user_callback),
59  interval_(interval),
60  scheduling_mode_(mode) { };
61 };
62 
63 }
64 
65 namespace isc {
66 namespace dhcp {
67 
69 typedef boost::shared_ptr<TimerInfo> TimerInfoPtr;
70 
72 typedef std::map<std::string, TimerInfoPtr> TimerInfoMap;
73 
75 class TimerMgrImpl {
76 public:
77 
79  TimerMgrImpl();
80 
84  void setIOService(const IOServicePtr& io_service);
85 
97  void registerTimer(const std::string& timer_name,
98  const asiolink::IntervalTimer::Callback& callback,
99  const long interval,
100  const asiolink::IntervalTimer::Mode& scheduling_mode);
101 
102 
111  void unregisterTimer(const std::string& timer_name);
112 
117  void unregisterTimers();
118 
124  bool isTimerRegistered(const std::string& timer_name);
125 
127  size_t timersCount() const;
128 
141  void setup(const std::string& timer_name);
142 
148  void cancel(const std::string& timer_name);
149 
150 private:
151 
154 
166  void registerTimerInternal(const std::string& timer_name,
167  const asiolink::IntervalTimer::Callback& callback,
168  const long interval,
169  const asiolink::IntervalTimer::Mode& scheduling_mode);
170 
171 
180  void unregisterTimerInternal(const std::string& timer_name);
181 
186  void unregisterTimersInternal();
187 
200  void setupInternal(const std::string& timer_name);
201 
207  void cancelInternal(const std::string& timer_name);
208 
213  void timerCallback(const std::string& timer_name);
214 
216  asiolink::IOServicePtr io_service_;
217 
220  TimerInfoMap registered_timers_;
221 
223  boost::scoped_ptr<std::mutex> mutex_;
224 };
225 
226 TimerMgrImpl::TimerMgrImpl() : io_service_(new IOService()),
227  registered_timers_(), mutex_(new std::mutex) {
228 }
229 
230 void
232  if (!io_service) {
233  isc_throw(BadValue, "IO service object must not be null for TimerMgr");
234  }
235 
236  io_service_ = io_service;
237 }
238 
239 void
240 TimerMgrImpl::registerTimer(const std::string& timer_name,
241  const IntervalTimer::Callback& callback,
242  const long interval,
243  const IntervalTimer::Mode& scheduling_mode) {
244  if (MultiThreadingMgr::instance().getMode()) {
245  std::lock_guard<std::mutex> lock(*mutex_);
246  registerTimerInternal(timer_name, callback, interval, scheduling_mode);
247  } else {
248  registerTimerInternal(timer_name, callback, interval, scheduling_mode);
249  }
250 }
251 
252 void
253 TimerMgrImpl::registerTimerInternal(const std::string& timer_name,
254  const IntervalTimer::Callback& callback,
255  const long interval,
256  const IntervalTimer::Mode& scheduling_mode) {
257  // Timer name must not be empty.
258  if (timer_name.empty()) {
259  isc_throw(BadValue, "registered timer name must not be empty");
260  }
261 
262  // Must not register two timers under the same name.
263  if (registered_timers_.find(timer_name) != registered_timers_.end()) {
264  isc_throw(BadValue, "trying to register duplicate timer '"
265  << timer_name << "'");
266  }
267 
268  // Create a structure holding the configuration for the timer. It will
269  // create the instance if the IntervalTimer. It will also hold the
270  // callback, interval and scheduling mode parameters.
271  TimerInfoPtr timer_info(new TimerInfo(*io_service_, callback,
272  interval, scheduling_mode));
273 
274  // Actually register the timer.
275  registered_timers_.insert(std::pair<std::string, TimerInfoPtr>(timer_name,
276  timer_info));
277 }
278 
279 void
280 TimerMgrImpl::unregisterTimer(const std::string& timer_name) {
281  if (MultiThreadingMgr::instance().getMode()) {
282  std::lock_guard<std::mutex> lock(*mutex_);
283  unregisterTimerInternal(timer_name);
284  } else {
285  unregisterTimerInternal(timer_name);
286  }
287 }
288 
289 void
290 TimerMgrImpl::unregisterTimerInternal(const std::string& timer_name) {
291  // Find the timer with specified name.
292  TimerInfoMap::iterator timer_info_it = registered_timers_.find(timer_name);
293 
294  // Check if the timer has been registered.
295  if (timer_info_it == registered_timers_.end()) {
296  isc_throw(BadValue, "unable to unregister non existing timer '"
297  << timer_name << "'");
298  }
299 
300  // Cancel any pending asynchronous operation and stop the timer.
301  cancelInternal(timer_name);
302 
303  // Remove the timer.
304  registered_timers_.erase(timer_info_it);
305 }
306 
307 void
309  if (MultiThreadingMgr::instance().getMode()) {
310  std::lock_guard<std::mutex> lock(*mutex_);
311  unregisterTimersInternal();
312  } else {
313  unregisterTimersInternal();
314  }
315 }
316 
317 void
318 TimerMgrImpl::unregisterTimersInternal() {
319  // Copy the map holding timers configuration. This is required so as
320  // we don't cut the branch which we're sitting on when we will be
321  // erasing the timers. We're going to iterate over the register timers
322  // and remove them with the call to unregisterTimer function. But this
323  // function will remove them from the register_timers_ map. If we
324  // didn't work on the copy here, our iterator would invalidate. The
325  // TimerInfo structure is copyable and since it is using the shared
326  // pointers the copy is not expensive. Also this function is called when
327  // the process terminates so it is not critical for performance.
328  TimerInfoMap registered_timers_copy(registered_timers_);
329 
330  // Iterate over the existing timers and unregister them.
331  for (TimerInfoMap::iterator timer_info_it = registered_timers_copy.begin();
332  timer_info_it != registered_timers_copy.end(); ++timer_info_it) {
333  unregisterTimerInternal(timer_info_it->first);
334  }
335 }
336 
337 bool
338 TimerMgrImpl::isTimerRegistered(const std::string& timer_name) {
339  if (MultiThreadingMgr::instance().getMode()) {
340  std::lock_guard<std::mutex> lock(*mutex_);
341  return (registered_timers_.find(timer_name) != registered_timers_.end());
342  } else {
343  return (registered_timers_.find(timer_name) != registered_timers_.end());
344  }
345 }
346 
347 size_t
349  if (MultiThreadingMgr::instance().getMode()) {
350  std::lock_guard<std::mutex> lock(*mutex_);
351  return (registered_timers_.size());
352  } else {
353  return (registered_timers_.size());
354  }
355 }
356 
357 void
358 TimerMgrImpl::setup(const std::string& timer_name) {
359  if (MultiThreadingMgr::instance().getMode()) {
360  std::lock_guard<std::mutex> lock(*mutex_);
361  setupInternal(timer_name);
362  } else {
363  setupInternal(timer_name);
364  }
365 }
366 
367 void
368 TimerMgrImpl::setupInternal(const std::string& timer_name) {
369  // Check if the specified timer exists.
370  TimerInfoMap::const_iterator timer_info_it = registered_timers_.find(timer_name);
371  if (timer_info_it == registered_timers_.end()) {
372  isc_throw(BadValue, "unable to setup timer '" << timer_name << "': "
373  "no such timer registered");
374  }
375 
376  // Schedule the execution of the timer using the parameters supplied
377  // during the registration.
378  const TimerInfoPtr& timer_info = timer_info_it->second;
379  IntervalTimer::Callback cb = std::bind(&TimerMgrImpl::timerCallback, this,
380  timer_name);
381  timer_info->interval_timer_.setup(cb, timer_info->interval_,
382  timer_info->scheduling_mode_);
383 }
384 
385 void
386 TimerMgrImpl::cancel(const std::string& timer_name) {
387  if (MultiThreadingMgr::instance().getMode()) {
388  std::lock_guard<std::mutex> lock(*mutex_);
389  cancelInternal(timer_name);
390  } else {
391  cancelInternal(timer_name);
392  }
393 }
394 
395 void
396 TimerMgrImpl::cancelInternal(const std::string& timer_name) {
397  // Find the timer of our interest.
398  TimerInfoMap::const_iterator timer_info_it = registered_timers_.find(timer_name);
399  if (timer_info_it == registered_timers_.end()) {
400  isc_throw(BadValue, "unable to cancel timer '" << timer_name << "': "
401  "no such timer registered");
402  }
403  // Cancel the timer.
404  timer_info_it->second->interval_timer_.cancel();
405 }
406 
407 void
408 TimerMgrImpl::timerCallback(const std::string& timer_name) {
409  // Find the specified timer setup.
410  TimerInfoMap::iterator timer_info_it = registered_timers_.find(timer_name);
411  if (timer_info_it != registered_timers_.end()) {
412 
413  // Running user-defined operation for the timer. Logging it
414  // on the slightly lower debug level as there may be many
415  // such traces.
418  .arg(timer_info_it->first);
419 
420  std::string error_string;
421  try {
422  timer_info_it->second->user_callback_();
423 
424  } catch (const std::exception& ex){
425  error_string = ex.what();
426 
427  } catch (...) {
428  error_string = "unknown reason";
429  }
430 
431  // Exception was thrown. Log an error.
432  if (!error_string.empty()) {
434  .arg(timer_info_it->first)
435  .arg(error_string);
436  }
437  }
438 }
439 
440 const TimerMgrPtr&
442  static TimerMgrPtr timer_mgr(new TimerMgr());
443  return (timer_mgr);
444 }
445 
446 TimerMgr::TimerMgr()
447  : impl_(new TimerMgrImpl()) {
448 }
449 
451  impl_->unregisterTimers();
452 }
453 
454 void
455 TimerMgr::registerTimer(const std::string& timer_name,
456  const IntervalTimer::Callback& callback,
457  const long interval,
458  const IntervalTimer::Mode& scheduling_mode) {
459 
462  .arg(timer_name)
463  .arg(interval);
464 
465  impl_->registerTimer(timer_name, callback, interval, scheduling_mode);
466 }
467 
468 void
469 TimerMgr::unregisterTimer(const std::string& timer_name) {
470 
473  .arg(timer_name);
474 
475  impl_->unregisterTimer(timer_name);
476 }
477 
478 void
480 
483 
484  impl_->unregisterTimers();
485 }
486 
487 bool
488 TimerMgr::isTimerRegistered(const std::string& timer_name) {
489  return (impl_->isTimerRegistered(timer_name));
490 }
491 
492 size_t
494  return (impl_->timersCount());
495 }
496 
497 void
498 TimerMgr::setup(const std::string& timer_name) {
499 
502  .arg(timer_name);
503 
504  impl_->setup(timer_name);
505 }
506 
507 void
508 TimerMgr::cancel(const std::string& timer_name) {
509 
512  .arg(timer_name);
513 
514  impl_->cancel(timer_name);
515 }
516 
517 void
519  impl_->setIOService(io_service);
520 }
521 
522 } // end of namespace isc::dhcp
523 } // end of namespace isc
void unregisterTimers()
Unregisters all timers.
Definition: timer_mgr.cc:308
boost::shared_ptr< TimerMgr > TimerMgrPtr
Type definition of the shared pointer to TimerMgr.
Definition: timer_mgr.h:24
const isc::log::MessageID DHCPSRV_TIMERMGR_RUN_TIMER_OPERATION
const isc::log::MessageID DHCPSRV_TIMERMGR_UNREGISTER_ALL_TIMERS
const isc::log::MessageID DHCPSRV_TIMERMGR_CALLBACK_FAILED
Implementation of the TimerMgr.
Definition: timer_mgr.cc:75
bool isTimerRegistered(const std::string &timer_name)
Checks if the timer with a specified name has been registered.
Definition: timer_mgr.cc:338
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:240
size_t timersCount() const
Returns the number of registered timers.
Definition: timer_mgr.cc:348
void cancel(const std::string &timer_name)
Cancels the execution of the interval timer.
Definition: timer_mgr.cc:508
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the Timer Manager.
Definition: timer_mgr.cc:518
Manages a pool of asynchronous interval timers.
Definition: timer_mgr.h:62
void cancel(const std::string &timer_name)
Cancels the execution of the interval timer.
Definition: timer_mgr.cc:386
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
STL namespace.
bool isTimerRegistered(const std::string &timer_name)
Checks if the timer with a specified name has been registered.
Definition: timer_mgr.cc:488
~TimerMgr()
Destructor.
Definition: timer_mgr.cc:450
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: edns.h:19
void unregisterTimers()
Unregisters all timers.
Definition: timer_mgr.cc:479
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
boost::shared_ptr< TimerInfo > TimerInfoPtr
A type definition for the pointer to TimerInfo structure.
Definition: timer_mgr.cc:69
const isc::log::MessageID DHCPSRV_TIMERMGR_UNREGISTER_TIMER
void setup(const std::string &timer_name)
Schedules the execution of the interval timer.
Definition: timer_mgr.cc:358
const isc::log::MessageID DHCPSRV_TIMERMGR_STOP_TIMER
void setIOService(const IOServicePtr &io_service)
Sets IO service to be used by the Timer Manager.
Definition: timer_mgr.cc:231
Defines the logger used by the top-level component of kea-dhcp-ddns.
const isc::log::MessageID DHCPSRV_TIMERMGR_REGISTER_TIMER
void unregisterTimer(const std::string &timer_name)
Unregisters specified timer.
Definition: timer_mgr.cc:469
void setup(const std::string &timer_name)
Schedules the execution of the interval timer.
Definition: timer_mgr.cc:498
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
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:455
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
size_t timersCount() const
Returns the number of registered timers.
Definition: timer_mgr.cc:493
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:441
const isc::log::MessageID DHCPSRV_TIMERMGR_START_TIMER
std::map< std::string, TimerInfoPtr > TimerInfoMap
A type definition for the map holding timers configuration.
Definition: timer_mgr.cc:72
void unregisterTimer(const std::string &timer_name)
Unregisters specified timer.
Definition: timer_mgr.cc:280