Kea 2.6.0
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
10#include <asiolink/io_service.h>
11#include <dhcpsrv/dhcpsrv_log.h>
12#include <dhcpsrv/timer_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
28using namespace isc;
29using namespace isc::asiolink;
30using namespace isc::util;
31
32namespace {
33
39struct TimerInfo {
41 asiolink::IntervalTimer interval_timer_;
42
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,
65 : interval_timer_(io_service),
66 user_callback_(user_callback),
67 interval_(interval),
68 scheduling_mode_(mode) { };
69};
70
71}
72
73namespace isc {
74namespace dhcp {
75
77typedef boost::shared_ptr<TimerInfo> TimerInfoPtr;
78
80typedef std::map<std::string, TimerInfoPtr> TimerInfoMap;
81
84public:
85
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
157private:
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
233 registered_timers_(), mutex_(new std::mutex) {
234}
235
236void
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
245void
246TimerMgrImpl::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
258void
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
285void
286TimerMgrImpl::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
295void
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
313void
315 if (MultiThreadingMgr::instance().getMode()) {
316 std::lock_guard<std::mutex> lock(*mutex_);
317 unregisterTimersInternal();
318 } else {
319 unregisterTimersInternal();
320 }
321}
322
323void
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
342bool
343TimerMgrImpl::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
352size_t
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
362void
363TimerMgrImpl::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
372void
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
390void
391TimerMgrImpl::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
400void
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
412void
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.
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()) {
439 .arg(timer_info_it->first)
440 .arg(error_string);
441 }
442 }
443}
444
445const TimerMgrPtr&
447 static TimerMgrPtr timer_mgr(new TimerMgr());
448 return (timer_mgr);
449}
450
451TimerMgr::TimerMgr()
452 : impl_(new TimerMgrImpl()) {
453}
454
456 impl_->unregisterTimers();
457}
458
459void
460TimerMgr::registerTimer(const std::string& timer_name,
461 const IntervalTimer::Callback& callback,
462 const long interval,
463 const IntervalTimer::Mode& scheduling_mode) {
464
467 .arg(timer_name)
468 .arg(interval);
469
470 impl_->registerTimer(timer_name, callback, interval, scheduling_mode);
471}
472
473void
474TimerMgr::unregisterTimer(const std::string& timer_name) {
475
478 .arg(timer_name);
479
480 impl_->unregisterTimer(timer_name);
481}
482
483void
485
488
489 impl_->unregisterTimers();
490}
491
492bool
493TimerMgr::isTimerRegistered(const std::string& timer_name) {
494 return (impl_->isTimerRegistered(timer_name));
495}
496
497size_t
499 return (impl_->timersCount());
500}
501
502void
503TimerMgr::setup(const std::string& timer_name) {
504
507 .arg(timer_name);
508
509 impl_->setup(timer_name);
510}
511
512void
513TimerMgr::cancel(const std::string& timer_name) {
514
517 .arg(timer_name);
518
519 impl_->cancel(timer_name);
520}
521
522void
524 impl_->setIOService(io_service);
525}
526
527} // end of namespace isc::dhcp
528} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Implementation of the TimerMgr.
Definition: timer_mgr.cc:83
void unregisterTimers()
Unregisters all timers.
Definition: timer_mgr.cc:314
size_t timersCount() const
Returns the number of registered timers.
Definition: timer_mgr.cc:353
void cancel(const std::string &timer_name)
Cancels the execution of the interval timer.
Definition: timer_mgr.cc:391
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
void unregisterTimer(const std::string &timer_name)
Unregisters specified timer.
Definition: timer_mgr.cc:286
void setup(const std::string &timer_name)
Schedules the execution of the interval timer.
Definition: timer_mgr.cc:363
void setIOService(const IOServicePtr &io_service)
Sets IO service to be used by the Timer Manager.
Definition: timer_mgr.cc:237
TimerMgrImpl()
Constructor.
Definition: timer_mgr.cc:232
bool isTimerRegistered(const std::string &timer_name)
Checks if the timer with a specified name has been registered.
Definition: timer_mgr.cc:343
Manages a pool of asynchronous interval timers.
Definition: timer_mgr.h:62
bool isTimerRegistered(const std::string &timer_name)
Checks if the timer with a specified name has been registered.
Definition: timer_mgr.cc:493
~TimerMgr()
Destructor.
Definition: timer_mgr.cc:455
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the Timer Manager.
Definition: timer_mgr.cc:523
void setup(const std::string &timer_name)
Schedules the execution of the interval timer.
Definition: timer_mgr.cc:503
size_t timersCount() const
Returns the number of registered timers.
Definition: timer_mgr.cc:498
void unregisterTimers()
Unregisters all timers.
Definition: timer_mgr.cc:484
void cancel(const std::string &timer_name)
Cancels the execution of the interval timer.
Definition: timer_mgr.cc:513
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
void unregisterTimer(const std::string &timer_name)
Unregisters specified timer.
Definition: timer_mgr.cc:474
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:446
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
boost::shared_ptr< TimerMgr > TimerMgrPtr
Type definition of the shared pointer to TimerMgr.
Definition: timer_mgr.h:27
const isc::log::MessageID DHCPSRV_TIMERMGR_UNREGISTER_ALL_TIMERS
std::map< std::string, TimerInfoPtr > TimerInfoMap
A type definition for the map holding timers configuration.
Definition: timer_mgr.cc:80
const isc::log::MessageID DHCPSRV_TIMERMGR_STOP_TIMER
const isc::log::MessageID DHCPSRV_TIMERMGR_RUN_TIMER_OPERATION
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
const isc::log::MessageID DHCPSRV_TIMERMGR_START_TIMER
const isc::log::MessageID DHCPSRV_TIMERMGR_UNREGISTER_TIMER
boost::shared_ptr< TimerInfo > TimerInfoPtr
A type definition for the pointer to TimerInfo structure.
Definition: timer_mgr.cc:77
const isc::log::MessageID DHCPSRV_TIMERMGR_REGISTER_TIMER
const isc::log::MessageID DHCPSRV_TIMERMGR_CALLBACK_FAILED
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
Defines the logger used by the top-level component of kea-lfc.