Kea 2.5.5
timer_mgr.cc
Go to the documentation of this file.
1// Copyright (C) 2016-2021 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(asiolink::IOService& 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
110
119 void unregisterTimer(const std::string& timer_name);
120
125 void unregisterTimers();
126
132 bool isTimerRegistered(const std::string& timer_name);
133
135 size_t timersCount() const;
136
149 void setup(const std::string& timer_name);
150
156 void cancel(const std::string& timer_name);
157
158private:
159
162
174 void registerTimerInternal(const std::string& timer_name,
175 const asiolink::IntervalTimer::Callback& callback,
176 const long interval,
177 const asiolink::IntervalTimer::Mode& scheduling_mode);
178
179
188 void unregisterTimerInternal(const std::string& timer_name);
189
194 void unregisterTimersInternal();
195
208 void setupInternal(const std::string& timer_name);
209
215 void cancelInternal(const std::string& timer_name);
216
221 void timerCallback(const std::string& timer_name);
222
224 asiolink::IOServicePtr io_service_;
225
228 TimerInfoMap registered_timers_;
229
231 boost::scoped_ptr<std::mutex> mutex_;
232};
233
235 registered_timers_(), mutex_(new std::mutex) {
236}
237
238void
240 if (!io_service) {
241 isc_throw(BadValue, "IO service object must not be null for TimerMgr");
242 }
243
244 io_service_ = io_service;
245}
246
247void
248TimerMgrImpl::registerTimer(const std::string& timer_name,
249 const IntervalTimer::Callback& callback,
250 const long interval,
251 const IntervalTimer::Mode& scheduling_mode) {
252 if (MultiThreadingMgr::instance().getMode()) {
253 std::lock_guard<std::mutex> lock(*mutex_);
254 registerTimerInternal(timer_name, callback, interval, scheduling_mode);
255 } else {
256 registerTimerInternal(timer_name, callback, interval, scheduling_mode);
257 }
258}
259
260void
261TimerMgrImpl::registerTimerInternal(const std::string& timer_name,
262 const IntervalTimer::Callback& callback,
263 const long interval,
264 const IntervalTimer::Mode& scheduling_mode) {
265 // Timer name must not be empty.
266 if (timer_name.empty()) {
267 isc_throw(BadValue, "registered timer name must not be empty");
268 }
269
270 // Must not register two timers under the same name.
271 if (registered_timers_.find(timer_name) != registered_timers_.end()) {
272 isc_throw(BadValue, "trying to register duplicate timer '"
273 << timer_name << "'");
274 }
275
276 // Create a structure holding the configuration for the timer. It will
277 // create the instance if the IntervalTimer. It will also hold the
278 // callback, interval and scheduling mode parameters.
279 TimerInfoPtr timer_info(new TimerInfo(*io_service_, callback,
280 interval, scheduling_mode));
281
282 // Actually register the timer.
283 registered_timers_.insert(std::pair<std::string, TimerInfoPtr>(timer_name,
284 timer_info));
285}
286
287void
288TimerMgrImpl::unregisterTimer(const std::string& timer_name) {
289 if (MultiThreadingMgr::instance().getMode()) {
290 std::lock_guard<std::mutex> lock(*mutex_);
291 unregisterTimerInternal(timer_name);
292 } else {
293 unregisterTimerInternal(timer_name);
294 }
295}
296
297void
298TimerMgrImpl::unregisterTimerInternal(const std::string& timer_name) {
299 // Find the timer with specified name.
300 TimerInfoMap::iterator timer_info_it = registered_timers_.find(timer_name);
301
302 // Check if the timer has been registered.
303 if (timer_info_it == registered_timers_.end()) {
304 isc_throw(BadValue, "unable to unregister non existing timer '"
305 << timer_name << "'");
306 }
307
308 // Cancel any pending asynchronous operation and stop the timer.
309 cancelInternal(timer_name);
310
311 // Remove the timer.
312 registered_timers_.erase(timer_info_it);
313}
314
315void
317 if (MultiThreadingMgr::instance().getMode()) {
318 std::lock_guard<std::mutex> lock(*mutex_);
319 unregisterTimersInternal();
320 } else {
321 unregisterTimersInternal();
322 }
323}
324
325void
326TimerMgrImpl::unregisterTimersInternal() {
327 // Copy the map holding timers configuration. This is required so as
328 // we don't cut the branch which we're sitting on when we will be
329 // erasing the timers. We're going to iterate over the register timers
330 // and remove them with the call to unregisterTimer function. But this
331 // function will remove them from the register_timers_ map. If we
332 // didn't work on the copy here, our iterator would invalidate. The
333 // TimerInfo structure is copyable and since it is using the shared
334 // pointers the copy is not expensive. Also this function is called when
335 // the process terminates so it is not critical for performance.
336 TimerInfoMap registered_timers_copy(registered_timers_);
337
338 // Iterate over the existing timers and unregister them.
339 for (TimerInfoMap::iterator timer_info_it = registered_timers_copy.begin();
340 timer_info_it != registered_timers_copy.end(); ++timer_info_it) {
341 unregisterTimerInternal(timer_info_it->first);
342 }
343}
344
345bool
346TimerMgrImpl::isTimerRegistered(const std::string& timer_name) {
347 if (MultiThreadingMgr::instance().getMode()) {
348 std::lock_guard<std::mutex> lock(*mutex_);
349 return (registered_timers_.find(timer_name) != registered_timers_.end());
350 } else {
351 return (registered_timers_.find(timer_name) != registered_timers_.end());
352 }
353}
354
355size_t
357 if (MultiThreadingMgr::instance().getMode()) {
358 std::lock_guard<std::mutex> lock(*mutex_);
359 return (registered_timers_.size());
360 } else {
361 return (registered_timers_.size());
362 }
363}
364
365void
366TimerMgrImpl::setup(const std::string& timer_name) {
367 if (MultiThreadingMgr::instance().getMode()) {
368 std::lock_guard<std::mutex> lock(*mutex_);
369 setupInternal(timer_name);
370 } else {
371 setupInternal(timer_name);
372 }
373}
374
375void
376TimerMgrImpl::setupInternal(const std::string& timer_name) {
377 // Check if the specified timer exists.
378 TimerInfoMap::const_iterator timer_info_it = registered_timers_.find(timer_name);
379 if (timer_info_it == registered_timers_.end()) {
380 isc_throw(BadValue, "unable to setup timer '" << timer_name << "': "
381 "no such timer registered");
382 }
383
384 // Schedule the execution of the timer using the parameters supplied
385 // during the registration.
386 const TimerInfoPtr& timer_info = timer_info_it->second;
387 IntervalTimer::Callback cb = std::bind(&TimerMgrImpl::timerCallback, this,
388 timer_name);
389 timer_info->interval_timer_.setup(cb, timer_info->interval_,
390 timer_info->scheduling_mode_);
391}
392
393void
394TimerMgrImpl::cancel(const std::string& timer_name) {
395 if (MultiThreadingMgr::instance().getMode()) {
396 std::lock_guard<std::mutex> lock(*mutex_);
397 cancelInternal(timer_name);
398 } else {
399 cancelInternal(timer_name);
400 }
401}
402
403void
404TimerMgrImpl::cancelInternal(const std::string& timer_name) {
405 // Find the timer of our interest.
406 TimerInfoMap::const_iterator timer_info_it = registered_timers_.find(timer_name);
407 if (timer_info_it == registered_timers_.end()) {
408 isc_throw(BadValue, "unable to cancel timer '" << timer_name << "': "
409 "no such timer registered");
410 }
411 // Cancel the timer.
412 timer_info_it->second->interval_timer_.cancel();
413}
414
415void
416TimerMgrImpl::timerCallback(const std::string& timer_name) {
417 // Find the specified timer setup.
418 TimerInfoMap::iterator timer_info_it = registered_timers_.find(timer_name);
419 if (timer_info_it != registered_timers_.end()) {
420
421 // Running user-defined operation for the timer. Logging it
422 // on the slightly lower debug level as there may be many
423 // such traces.
426 .arg(timer_info_it->first);
427
428 std::string error_string;
429 try {
430 timer_info_it->second->user_callback_();
431
432 } catch (const std::exception& ex){
433 error_string = ex.what();
434
435 } catch (...) {
436 error_string = "unknown reason";
437 }
438
439 // Exception was thrown. Log an error.
440 if (!error_string.empty()) {
442 .arg(timer_info_it->first)
443 .arg(error_string);
444 }
445 }
446}
447
448const TimerMgrPtr&
450 static TimerMgrPtr timer_mgr(new TimerMgr());
451 return (timer_mgr);
452}
453
454TimerMgr::TimerMgr()
455 : impl_(new TimerMgrImpl()) {
456}
457
459 impl_->unregisterTimers();
460}
461
462void
463TimerMgr::registerTimer(const std::string& timer_name,
464 const IntervalTimer::Callback& callback,
465 const long interval,
466 const IntervalTimer::Mode& scheduling_mode) {
467
470 .arg(timer_name)
471 .arg(interval);
472
473 impl_->registerTimer(timer_name, callback, interval, scheduling_mode);
474}
475
476void
477TimerMgr::unregisterTimer(const std::string& timer_name) {
478
481 .arg(timer_name);
482
483 impl_->unregisterTimer(timer_name);
484}
485
486void
488
491
492 impl_->unregisterTimers();
493}
494
495bool
496TimerMgr::isTimerRegistered(const std::string& timer_name) {
497 return (impl_->isTimerRegistered(timer_name));
498}
499
500size_t
502 return (impl_->timersCount());
503}
504
505void
506TimerMgr::setup(const std::string& timer_name) {
507
510 .arg(timer_name);
511
512 impl_->setup(timer_name);
513}
514
515void
516TimerMgr::cancel(const std::string& timer_name) {
517
520 .arg(timer_name);
521
522 impl_->cancel(timer_name);
523}
524
525void
527 impl_->setIOService(io_service);
528}
529
530} // end of namespace isc::dhcp
531} // 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:316
size_t timersCount() const
Returns the number of registered timers.
Definition: timer_mgr.cc:356
void cancel(const std::string &timer_name)
Cancels the execution of the interval timer.
Definition: timer_mgr.cc:394
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:248
void unregisterTimer(const std::string &timer_name)
Unregisters specified timer.
Definition: timer_mgr.cc:288
void setup(const std::string &timer_name)
Schedules the execution of the interval timer.
Definition: timer_mgr.cc:366
void setIOService(const IOServicePtr &io_service)
Sets IO service to be used by the Timer Manager.
Definition: timer_mgr.cc:239
TimerMgrImpl()
Constructor.
Definition: timer_mgr.cc:234
bool isTimerRegistered(const std::string &timer_name)
Checks if the timer with a specified name has been registered.
Definition: timer_mgr.cc:346
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:496
~TimerMgr()
Destructor.
Definition: timer_mgr.cc:458
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the Timer Manager.
Definition: timer_mgr.cc:526
void setup(const std::string &timer_name)
Schedules the execution of the interval timer.
Definition: timer_mgr.cc:506
size_t timersCount() const
Returns the number of registered timers.
Definition: timer_mgr.cc:501
void unregisterTimers()
Unregisters all timers.
Definition: timer_mgr.cc:487
void cancel(const std::string &timer_name)
Cancels the execution of the interval timer.
Definition: timer_mgr.cc:516
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:463
void unregisterTimer(const std::string &timer_name)
Unregisters specified timer.
Definition: timer_mgr.cc:477
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:449
#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
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.