timer_mgr.cc 25 KB

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