timer_mgr.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. // Copyright (C) 2016 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. #include <config.h>
  7. #include <asiolink/asio_wrapper.h>
  8. #include <asiolink/io_service.h>
  9. #include <dhcp/iface_mgr.h>
  10. #include <dhcpsrv/dhcpsrv_log.h>
  11. #include <dhcpsrv/timer_mgr.h>
  12. #include <exceptions/exceptions.h>
  13. #include <util/threads/sync.h>
  14. #include <util/threads/thread.h>
  15. #include <util/watch_socket.h>
  16. #include <boost/bind.hpp>
  17. #include <utility>
  18. using namespace isc;
  19. using namespace isc::asiolink;
  20. using namespace isc::util;
  21. using namespace isc::util::thread;
  22. namespace {
  23. /// @brief Simple RAII object setting value to true while in scope.
  24. ///
  25. /// This class is useful to temporarly set the value to true and
  26. /// automatically reset it to false when the object is destroyed
  27. /// as a result of return or exception.
  28. class ScopedTrue {
  29. public:
  30. /// @brief Constructor.
  31. ///
  32. /// Sets the boolean value to true.
  33. ///
  34. /// @param value reference to the value to be set to true.
  35. ScopedTrue(bool& value, Mutex& mutex)
  36. : value_(value), mutex_(mutex) {
  37. Mutex::Locker lock(mutex_);
  38. value_ = true;
  39. }
  40. /// @brief Destructor.
  41. ///
  42. /// Sets the value to false.
  43. ~ScopedTrue() {
  44. Mutex::Locker lock(mutex_);
  45. value_ = false;
  46. }
  47. private:
  48. /// @brief Reference to the controlled value.
  49. bool& value_;
  50. /// @brief Mutex to be used to lock while performing write
  51. /// operations.
  52. Mutex& mutex_;
  53. };
  54. /// @brief Structure holding information for a single timer.
  55. ///
  56. /// This structure holds the instance of the watch socket being used to
  57. /// signal that the timer is "ready". It also holds the instance of the
  58. /// interval timer and other parameters pertaining to it.
  59. struct TimerInfo {
  60. /// @brief Instance of the watch socket.
  61. util::WatchSocket watch_socket_;
  62. /// @brief Instance of the interval timer.
  63. asiolink::IntervalTimer interval_timer_;
  64. /// @brief Holds the pointer to the callback supplied when registering
  65. /// the timer.
  66. asiolink::IntervalTimer::Callback user_callback_;
  67. /// @brief Interval timer interval supplied during registration.
  68. long interval_;
  69. /// @brief Interval timer scheduling mode supplied during registration.
  70. asiolink::IntervalTimer::Mode scheduling_mode_;
  71. /// @brief Constructor.
  72. ///
  73. /// @param io_service Reference to the IO service to be used by the
  74. /// interval timer created.
  75. /// @param user_callback Pointer to the callback function supplied
  76. /// during the timer registration.
  77. /// @param interval Timer interval in milliseconds.
  78. /// @param mode Interval timer scheduling mode.
  79. TimerInfo(asiolink::IOService& io_service,
  80. const asiolink::IntervalTimer::Callback& user_callback,
  81. const long interval,
  82. const asiolink::IntervalTimer::Mode& mode)
  83. : watch_socket_(),
  84. interval_timer_(io_service),
  85. user_callback_(user_callback),
  86. interval_(interval),
  87. scheduling_mode_(mode) { };
  88. };
  89. }
  90. namespace isc {
  91. namespace dhcp {
  92. /// @brief A type definition for the pointer to @c TimerInfo structure.
  93. typedef boost::shared_ptr<TimerInfo> TimerInfoPtr;
  94. /// @brief A type definition for the map holding timers configuration.
  95. typedef std::map<std::string, TimerInfoPtr> TimerInfoMap;
  96. /// @brief Implementation of the @c TimerMgr
  97. class TimerMgrImpl {
  98. public:
  99. /// @brief Constructor.
  100. TimerMgrImpl();
  101. /// @brief Returns a reference to IO service used by the @c TimerMgr.
  102. asiolink::IOService& getIOService() const {
  103. return (*io_service_);
  104. }
  105. /// @brief Registers new timers in the @c TimerMgr.
  106. ///
  107. /// @param timer_name Unique name for the timer.
  108. /// @param callback Pointer to the callback function to be invoked
  109. /// when the timer elapses, e.g. function processing expired leases
  110. /// in the DHCP server.
  111. /// @param interval Timer interval in milliseconds.
  112. /// @param scheduling_mode Scheduling mode of the timer as described in
  113. /// @c asiolink::IntervalTimer::Mode.
  114. ///
  115. /// @throw BadValue if the timer name is invalid or duplicate.
  116. /// @throw InvalidOperation if the worker thread is running.
  117. void registerTimer(const std::string& timer_name,
  118. const asiolink::IntervalTimer::Callback& callback,
  119. const long interval,
  120. const asiolink::IntervalTimer::Mode& scheduling_mode);
  121. /// @brief Unregisters specified timer.
  122. ///
  123. /// This method cancels the timer if it is setup. It removes the external
  124. /// socket from the @c IfaceMgr and closes it. It finally removes the
  125. /// timer from the internal collection of timers.
  126. ///
  127. /// @param timer_name Name of the timer to be unregistered.
  128. ///
  129. /// @throw BadValue if the specified timer hasn't been registered.
  130. void unregisterTimer(const std::string& timer_name);
  131. /// @brief Unregisters all timers.
  132. ///
  133. /// This method must be explicitly called prior to termination of the
  134. /// process.
  135. void unregisterTimers();
  136. /// @brief Returns the number of registered timers.
  137. size_t timersCount() const;
  138. /// @brief Schedules the execution of the interval timer.
  139. ///
  140. /// This method schedules the timer, i.e. the callback will be executed
  141. /// after specified interval elapses. The interval has been specified
  142. /// during timer registration. Depending on the mode selected during the
  143. /// timer registration, the callback will be executed once after it has
  144. /// been scheduled or until it is cancelled. Though, in the former case
  145. /// the timer can be re-scheduled in the callback function.
  146. ///
  147. /// @param timer_name Unique timer name.
  148. ///
  149. /// @throw BadValue if the timer hasn't been registered.
  150. void setup(const std::string& timer_name);
  151. /// @brief Cancels the execution of the interval timer.
  152. ///
  153. /// @param timer_name Unique timer name.
  154. ///
  155. /// @throw BadValue if the timer hasn't been registered.
  156. void cancel(const std::string& timer_name);
  157. /// @brief Checks if the thread is running.
  158. ///
  159. /// @return true if the thread is running.
  160. bool threadRunning() const;
  161. /// @brief Starts thread.
  162. void createThread();
  163. /// @brief Stops thread gracefully.
  164. ///
  165. /// This methods unblocks worker thread if it is blocked waiting for
  166. /// any handlers and stops it. Outstanding handlers are later executed
  167. /// in the main thread and all watch sockets are cleared.
  168. ///
  169. /// @param run_pending_callbacks Indicates if the pending callbacks
  170. /// should be executed (if true).
  171. void stopThread(const bool run_pending_callbacks);
  172. private:
  173. /// @name Internal callbacks.
  174. //@{
  175. ///
  176. /// @brief Callback function to be executed for each interval timer when
  177. /// its scheduled interval elapses.
  178. ///
  179. /// This method marks the @c util::Watch socket associated with the
  180. /// timer as ready (writes data to a pipe). This method will BLOCK until
  181. /// @c TimerMgrImpl::ifaceMgrCallback is executed from the main thread by
  182. /// the @c IfaceMgr.
  183. ///
  184. /// @param timer_name Unique timer name to be passed to the callback.
  185. void timerCallback(const std::string& timer_name);
  186. /// @brief Callback function installed on the @c IfaceMgr and associated
  187. /// with the particular timer.
  188. ///
  189. /// This callback function is executed by the @c IfaceMgr when the data
  190. /// over the specific @c util::WatchSocket is received. This method clears
  191. /// the socket (reads the data from the pipe) and executes the callback
  192. /// supplied when the timer was registered.
  193. ///
  194. /// @param timer_name Unique timer name.
  195. void ifaceMgrCallback(const std::string& timer_name);
  196. //@}
  197. /// @name Methods to handle ready sockets.
  198. //@{
  199. ///
  200. /// @brief Clear ready sockets and optionally run callbacks.
  201. ///
  202. /// This method is called by the @c TimerMgr::stopThread method
  203. /// to clear watch sockets which may be marked as ready. It will
  204. /// also optionally run callbacks installed for the timers which
  205. /// marked sockets as ready.
  206. ///
  207. /// @param run_pending_callbacks Indicates if the callbacks should
  208. /// be executed for the sockets being cleared (if true).
  209. void clearReadySockets(const bool run_pending_callbacks);
  210. /// @brief Clears a socket and optionally runs a callback.
  211. ///
  212. /// This method clears the ready socket pointed to by the specified
  213. /// iterator. If the @c run_callback is set, the callback will
  214. /// also be executed.
  215. ///
  216. /// @param timer_info_iterator Iterator pointing to the timer
  217. /// configuration structure.
  218. /// @param run_callback Boolean value indicating if the callback
  219. /// should be executed for the socket being cleared (if true).
  220. ///
  221. /// @tparam Iterator Iterator pointing to the timer configuration
  222. /// structure.
  223. template<typename Iterator>
  224. void handleReadySocket(Iterator timer_info_iterator,
  225. const bool run_callback);
  226. //@}
  227. /// @brief Blocking wait for the socket to be cleared.
  228. void waitForSocketClearing(WatchSocket& watch_socket);
  229. /// @brief Signals that a watch socket has been cleared.
  230. void signalSocketClearing();
  231. /// @brief Pointer to the @c IfaceMgr.
  232. IfaceMgrPtr iface_mgr_;
  233. /// @brief Pointer to the io service.
  234. asiolink::IOServicePtr io_service_;
  235. /// @brief Pointer to the worker thread.
  236. ///
  237. /// This is initially set to NULL until the thread is started using the
  238. /// @c TimerMgr::startThread. The @c TimerMgr::stopThread sets it back
  239. /// to NULL.
  240. boost::shared_ptr<util::thread::Thread> thread_;
  241. /// @brief Mutex used to synchronize main thread and the worker thread.
  242. util::thread::Mutex mutex_;
  243. /// @brief Conditional variable used to synchronize main thread and
  244. /// worker thread.
  245. util::thread::CondVar cond_var_;
  246. /// @brief Boolean value indicating if the thread is being stopped.
  247. bool stopping_;
  248. /// @brief Holds mapping of the timer name to the watch socket, timer
  249. /// instance and other parameters pertaining to the timer.
  250. ///
  251. /// Each registered timer has a unique name which is used as a key to
  252. /// the map. The timer is associated with an instance of the @c WatchSocket
  253. /// which is marked ready when the interval for the particular elapses.
  254. TimerInfoMap registered_timers_;
  255. };
  256. TimerMgrImpl::TimerMgrImpl() :
  257. iface_mgr_(IfaceMgr::instancePtr()), io_service_(new IOService()), thread_(),
  258. mutex_(), cond_var_(), stopping_(false), registered_timers_() {
  259. }
  260. void
  261. TimerMgrImpl::registerTimer(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. // Must not register two timers under the same name.
  270. if (registered_timers_.find(timer_name) != registered_timers_.end()) {
  271. isc_throw(BadValue, "trying to register duplicate timer '"
  272. << timer_name << "'");
  273. }
  274. // Must not register new timer when the worker thread is running. Note
  275. // that worker thread is using IO service and trying to register a new
  276. // timer while IO service is being used would result in hang.
  277. if (thread_) {
  278. isc_throw(InvalidOperation, "unable to register new timer when the"
  279. " timer manager's worker thread is running");
  280. }
  281. // Create a structure holding the configuration for the timer. It will
  282. // create the instance if the IntervalTimer and WatchSocket. It will
  283. // also hold the callback, interval and scheduling mode parameters.
  284. // This may throw a WatchSocketError if the socket creation fails.
  285. TimerInfoPtr timer_info(new TimerInfo(getIOService(), callback,
  286. interval, scheduling_mode));
  287. // Register the WatchSocket in the IfaceMgr and register our own callback
  288. // to be executed when the data is received over this socket. The only time
  289. // this may fail is when the socket failed to open which would have caused
  290. // an exception in the previous call. So we should be safe here.
  291. iface_mgr_->addExternalSocket(timer_info->watch_socket_.getSelectFd(),
  292. boost::bind(&TimerMgrImpl::ifaceMgrCallback,
  293. this, timer_name));
  294. // Actually register the timer.
  295. registered_timers_.insert(std::pair<std::string, TimerInfoPtr>(timer_name,
  296. timer_info));
  297. }
  298. void
  299. TimerMgrImpl::unregisterTimer(const std::string& timer_name) {
  300. if (thread_) {
  301. isc_throw(InvalidOperation, "unable to unregister timer "
  302. << timer_name << " while worker thread is running");
  303. }
  304. // Find the timer with specified name.
  305. TimerInfoMap::iterator timer_info_it = registered_timers_.find(timer_name);
  306. // Check if the timer has been registered.
  307. if (timer_info_it == registered_timers_.end()) {
  308. isc_throw(BadValue, "unable to unregister non existing timer '"
  309. << timer_name << "'");
  310. }
  311. // Cancel any pending asynchronous operation and stop the timer.
  312. cancel(timer_name);
  313. const TimerInfoPtr& timer_info = timer_info_it->second;
  314. // Unregister the watch socket from the IfaceMgr.
  315. iface_mgr_->deleteExternalSocket(timer_info->watch_socket_.getSelectFd());
  316. // Remove the timer.
  317. registered_timers_.erase(timer_info_it);
  318. }
  319. void
  320. TimerMgrImpl::unregisterTimers() {
  321. // Copy the map holding timers configuration. This is required so as
  322. // we don't cut the branch which we're sitting on when we will be
  323. // erasing the timers. We're going to iterate over the register timers
  324. // and remove them with the call to unregisterTimer function. But this
  325. // function will remove them from the register_timers_ map. If we
  326. // didn't work on the copy here, our iterator would invalidate. The
  327. // TimerInfo structure is copyable and since it is using the shared
  328. // pointers the copy is not expensive. Also this function is called when
  329. // the process terminates so it is not critical for performance.
  330. TimerInfoMap registered_timers_copy(registered_timers_);
  331. // Iterate over the existing timers and unregister them.
  332. for (TimerInfoMap::iterator timer_info_it = registered_timers_copy.begin();
  333. timer_info_it != registered_timers_copy.end(); ++timer_info_it) {
  334. unregisterTimer(timer_info_it->first);
  335. }
  336. }
  337. size_t
  338. TimerMgrImpl::timersCount() const {
  339. return (registered_timers_.size());
  340. }
  341. void
  342. TimerMgrImpl::setup(const std::string& timer_name) {
  343. // Check if the specified timer exists.
  344. TimerInfoMap::const_iterator timer_info_it = registered_timers_.find(timer_name);
  345. if (timer_info_it == registered_timers_.end()) {
  346. isc_throw(BadValue, "unable to setup timer '" << timer_name << "': "
  347. "no such timer registered");
  348. }
  349. // Schedule the execution of the timer using the parameters supplied
  350. // during the registration.
  351. const TimerInfoPtr& timer_info = timer_info_it->second;
  352. IntervalTimer::Callback cb = boost::bind(&TimerMgrImpl::timerCallback, this,
  353. timer_name);
  354. timer_info->interval_timer_.setup(cb, timer_info->interval_,
  355. timer_info->scheduling_mode_);
  356. }
  357. void
  358. TimerMgrImpl::cancel(const std::string& timer_name) {
  359. // Find the timer of our interest.
  360. TimerInfoMap::const_iterator timer_info_it = registered_timers_.find(timer_name);
  361. if (timer_info_it == registered_timers_.end()) {
  362. isc_throw(BadValue, "unable to cancel timer '" << timer_name << "': "
  363. "no such timer registered");
  364. }
  365. // Cancel the timer.
  366. timer_info_it->second->interval_timer_.cancel();
  367. // Clear watch socket, if ready.
  368. timer_info_it->second->watch_socket_.clearReady();
  369. }
  370. bool
  371. TimerMgrImpl::threadRunning() const {
  372. return (static_cast<bool>(thread_));
  373. }
  374. void
  375. TimerMgrImpl::createThread() {
  376. thread_.reset(new Thread(boost::bind(&IOService::run, &getIOService())));
  377. }
  378. void
  379. TimerMgrImpl::stopThread(const bool run_pending_callbacks) {
  380. // Set the stopping flag to true while we're stopping. This will be
  381. // automatically reset to false when the function exits or exception
  382. // is thrown.
  383. ScopedTrue scoped_true(stopping_, mutex_);
  384. // Stop the IO Service. This will break the IOService::run executed in the
  385. // worker thread. The thread will now terminate.
  386. getIOService().stop();
  387. // Some of the watch sockets may be already marked as ready and
  388. // have some pending callbacks to be executed. If the caller
  389. // wants us to run the callbacks we clear the sockets and run
  390. // them. If pending callbacks shouldn't be executed, this will
  391. // only clear the sockets (which should be substantially faster).
  392. clearReadySockets(run_pending_callbacks);
  393. // Wait for the thread to terminate.
  394. thread_->wait();
  395. // Set the thread pointer to NULL to indicate that the thread is not running.
  396. thread_.reset();
  397. // IO Service has to be reset so as we can call run() on it again if we
  398. // desire (using the startThread()).
  399. getIOService().get_io_service().reset();
  400. }
  401. void
  402. TimerMgrImpl::timerCallback(const std::string& timer_name) {
  403. // Find the specified timer setup.
  404. TimerInfoMap::iterator timer_info_it = registered_timers_.find(timer_name);
  405. if (timer_info_it != registered_timers_.end()) {
  406. // We will mark watch socket ready - write data to a socket to
  407. // interrupt the execution of the select() function. This is
  408. // executed from the worker thread.
  409. const TimerInfoPtr& timer_info = timer_info_it->second;
  410. // This function is called from the worker thread and we don't want
  411. // the worker thread to get exceptions out of here. It is unlikely
  412. // that markReady() would cause any problems but theoretically
  413. // possible. Hence, we rather log an error and leave.
  414. try {
  415. timer_info->watch_socket_.markReady();
  416. } catch (const std::exception& ex) {
  417. LOG_ERROR(dhcpsrv_logger, DHCPSRV_TIMERMGR_SOCKET_MARK_FAILED)
  418. .arg(timer_name)
  419. .arg(ex.what());
  420. // Do not wait for clearing the socket because we were unable
  421. // to mark it ready anyway.
  422. return;
  423. }
  424. // Blocking wait for the socket to be cleared on the other
  425. // end. This may be interrupted both if the socket is cleared
  426. // or if the stopThread() has been called on the TimerMgr.
  427. waitForSocketClearing(timer_info->watch_socket_);
  428. }
  429. }
  430. void
  431. TimerMgrImpl::ifaceMgrCallback(const std::string& timer_name) {
  432. // Find the specified timer setup.
  433. TimerInfoMap::iterator timer_info_it = registered_timers_.find(timer_name);
  434. if (timer_info_it != registered_timers_.end()) {
  435. // We're executing a callback function from the Interface Manager.
  436. // This callback function is executed when the call to select() is
  437. // interrupted as a result of receiving some data over the watch
  438. // socket. We have to clear the socket which has been marked as
  439. // ready. Then execute the callback function supplied by the
  440. // TimerMgr user to perform custom actions on the expiration of
  441. // the given timer.
  442. handleReadySocket(timer_info_it, true);
  443. }
  444. }
  445. void
  446. TimerMgrImpl::clearReadySockets(const bool run_pending_callbacks) {
  447. for (TimerInfoMap::iterator timer_info_it = registered_timers_.begin();
  448. timer_info_it != registered_timers_.end(); ++timer_info_it) {
  449. handleReadySocket(timer_info_it, run_pending_callbacks);
  450. }
  451. }
  452. template<typename Iterator>
  453. void
  454. TimerMgrImpl::handleReadySocket(Iterator timer_info_iterator,
  455. const bool run_callback) {
  456. if (run_callback) {
  457. // Running user-defined operation for the timer. Logging it
  458. // on the slightly lower debug level as there may be many
  459. // such traces.
  460. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  461. DHCPSRV_TIMERMGR_RUN_TIMER_OPERATION)
  462. .arg(timer_info_iterator->first);
  463. std::string error_string;
  464. try {
  465. timer_info_iterator->second->user_callback_();
  466. } catch (const std::exception& ex){
  467. error_string = ex.what();
  468. } catch (...) {
  469. error_string = "unknown reason";
  470. }
  471. // Exception was thrown. Log an error.
  472. if (!error_string.empty()) {
  473. LOG_ERROR(dhcpsrv_logger, DHCPSRV_TIMERMGR_CALLBACK_FAILED)
  474. .arg(timer_info_iterator->first)
  475. .arg(error_string);
  476. }
  477. }
  478. try {
  479. // This shouldn't really fail, but if it does we want to log an
  480. // error and make sure that the thread is not stuck waiting for
  481. // the socket to clear.
  482. timer_info_iterator->second->watch_socket_.clearReady();
  483. } catch (const std::exception& ex) {
  484. LOG_ERROR(dhcpsrv_logger, DHCPSRV_TIMERMGR_SOCKET_CLEAR_FAILED)
  485. .arg(timer_info_iterator->first)
  486. .arg(ex.what());
  487. }
  488. // Whether it succeeded or not, clear the socket to make sure that
  489. // the worker thread is not stuck waiting for the main thread.
  490. signalSocketClearing();
  491. }
  492. void
  493. TimerMgrImpl::waitForSocketClearing(WatchSocket& watch_socket) {
  494. // Waiting for the specific socket to be cleared.
  495. while (watch_socket.isReady()) {
  496. Mutex::Locker lock(mutex_);
  497. // If stopThread has been called there is no sense to further
  498. // wait for the socket clearing. Leave from here to unblock the
  499. // worker thread.
  500. if (stopping_) {
  501. break;
  502. }
  503. cond_var_.wait(mutex_);
  504. }
  505. }
  506. void
  507. TimerMgrImpl::signalSocketClearing() {
  508. cond_var_.signal();
  509. }
  510. const TimerMgrPtr&
  511. TimerMgr::instance() {
  512. static TimerMgrPtr timer_mgr(new TimerMgr());
  513. return (timer_mgr);
  514. }
  515. TimerMgr::TimerMgr()
  516. : impl_(new TimerMgrImpl()) {
  517. }
  518. TimerMgr::~TimerMgr() {
  519. stopThread();
  520. unregisterTimers();
  521. delete impl_;
  522. }
  523. void
  524. TimerMgr::registerTimer(const std::string& timer_name,
  525. const IntervalTimer::Callback& callback,
  526. const long interval,
  527. const IntervalTimer::Mode& scheduling_mode) {
  528. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  529. DHCPSRV_TIMERMGR_REGISTER_TIMER)
  530. .arg(timer_name)
  531. .arg(interval);
  532. impl_->registerTimer(timer_name, callback, interval, scheduling_mode);
  533. }
  534. void
  535. TimerMgr::unregisterTimer(const std::string& timer_name) {
  536. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  537. DHCPSRV_TIMERMGR_UNREGISTER_TIMER)
  538. .arg(timer_name);
  539. impl_->unregisterTimer(timer_name);
  540. }
  541. void
  542. TimerMgr::unregisterTimers() {
  543. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  544. DHCPSRV_TIMERMGR_UNREGISTER_ALL_TIMERS);
  545. impl_->unregisterTimers();
  546. }
  547. size_t
  548. TimerMgr::timersCount() const {
  549. return (impl_->timersCount());
  550. }
  551. void
  552. TimerMgr::setup(const std::string& timer_name) {
  553. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  554. DHCPSRV_TIMERMGR_START_TIMER)
  555. .arg(timer_name);
  556. impl_->setup(timer_name);
  557. }
  558. void
  559. TimerMgr::cancel(const std::string& timer_name) {
  560. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  561. DHCPSRV_TIMERMGR_STOP_TIMER)
  562. .arg(timer_name);
  563. impl_->cancel(timer_name);
  564. }
  565. void
  566. TimerMgr::startThread() {
  567. // Do not start the thread if the thread is already there.
  568. if (!impl_->threadRunning()) {
  569. // Only log it if we really start the thread.
  570. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  571. DHCPSRV_TIMERMGR_START_THREAD);
  572. impl_->createThread();
  573. }
  574. }
  575. void
  576. TimerMgr::stopThread(const bool run_pending_callbacks) {
  577. // If thread is not running, this is no-op.
  578. if (impl_->threadRunning()) {
  579. // Only log it if we really have something to stop.
  580. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  581. DHCPSRV_TIMERMGR_STOP_THREAD);
  582. impl_->stopThread(run_pending_callbacks);
  583. }
  584. }
  585. IOService&
  586. TimerMgr::getIOService() const {
  587. return (impl_->getIOService());
  588. }
  589. } // end of namespace isc::dhcp
  590. } // end of namespace isc