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