| Kea 3.0.2-git

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