io_service_signal.cc 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright (C) 2014-2017 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 <asiolink/interval_timer.h>
  7. #include <process/d_log.h>
  8. #include <process/io_service_signal.h>
  9. namespace isc {
  10. namespace process {
  11. IOSignal::IOSignal (asiolink::IOService& io_service, int signum,
  12. IOSignalHandler handler)
  13. : sequence_id_(nextSequenceId()), signum_(signum),
  14. timer_(new asiolink::IntervalTimer(io_service)) {
  15. // Valid handler is essential.
  16. if (!handler) {
  17. isc_throw(IOSignalError,
  18. "IOSignal - handler cannot be null");
  19. }
  20. // Set up the timer as a one-shot which expires in 1 ms (intervals of 0
  21. // are invalid). This means that once control returns to IOService::run
  22. // the timer will have expired and its handler will be invoked.
  23. timer_->setup(TimerCallback(sequence_id_, handler), 1,
  24. asiolink::IntervalTimer::ONE_SHOT);
  25. }
  26. IOSignal::~IOSignal() {
  27. if (timer_) {
  28. // In the unlikely event that the timer hasn't expired cancel it.
  29. timer_->cancel();
  30. }
  31. }
  32. IOSignal::
  33. TimerCallback::TimerCallback(IOSignalId sequence_id, IOSignalHandler handler)
  34. : sequence_id_(sequence_id), handler_(handler) {
  35. if (!handler) {
  36. isc_throw(IOSignalError,
  37. "IOSignal::TimerCallback - handler cannot be null");
  38. }
  39. }
  40. void
  41. IOSignal::TimerCallback::operator()() {
  42. try {
  43. handler_(sequence_id_);
  44. } catch (const std::exception& ex) {
  45. // We log it and swallow it so we don't undermine IOService::run.
  46. LOG_ERROR(dctl_logger, DCTL_SIGNAL_ERROR)
  47. .arg(sequence_id_).arg(ex.what());
  48. }
  49. return;
  50. }
  51. IOSignalQueue::IOSignalQueue(asiolink::IOServicePtr& io_service)
  52. : io_service_(io_service), signals_() {
  53. if (!io_service_) {
  54. isc_throw(IOSignalError, "IOSignalQueue - io_service cannot be NULL");
  55. }
  56. }
  57. IOSignalQueue::~IOSignalQueue() {
  58. clear();
  59. }
  60. IOSignalId
  61. IOSignalQueue::pushSignal(int signum, IOSignalHandler handler) {
  62. // Create the new signal.
  63. IOSignalPtr signal(new IOSignal(*io_service_, signum, handler));
  64. // Make sure the sequence_id isn't already in the queue.
  65. IOSignalId sequence_id = signal->getSequenceId();
  66. IOSignalMap::iterator it = signals_.find(sequence_id);
  67. if (it != signals_.end()) {
  68. // This really shouldn't happen unless we are in the weeds.
  69. isc_throw (IOSignalError, "pushSignal - "
  70. "signal already exists for sequence_id: " << sequence_id);
  71. }
  72. // Add the signal to the queue.
  73. signals_[sequence_id] = signal;
  74. return (sequence_id);
  75. }
  76. IOSignalPtr
  77. IOSignalQueue::popSignal(IOSignalId sequence_id) {
  78. // Look for the signal in the queue.
  79. IOSignalMap::iterator it = signals_.find(sequence_id);
  80. if (it == signals_.end()) {
  81. // This really shouldn't happen unless we are in the weeds.
  82. isc_throw (IOSignalError, "popSignal - "
  83. "signal not found for sequence_id: " << sequence_id);
  84. }
  85. // Save the signal so we can return it.
  86. IOSignalPtr signal = ((*it).second);
  87. // Delete it from the queue.
  88. signals_.erase(it);
  89. // Return the signal.
  90. return (signal);
  91. }
  92. void
  93. IOSignalQueue::clear() {
  94. signals_.clear();
  95. }
  96. }; // end of isc::process namespace
  97. }; // end of isc namespace