Branch data Line data Source code
1 : : // Copyright (C) 2011 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 : :
15 : : #include <config.h>
16 : :
17 : : #include <boost/bind.hpp>
18 : : #include <boost/enable_shared_from_this.hpp>
19 : : #include <boost/shared_ptr.hpp>
20 : :
21 : : #include <exceptions/exceptions.h>
22 : :
23 : : #include <asio.hpp>
24 : : #include <asiolink/interval_timer.h>
25 : : #include <asiolink/io_service.h>
26 : :
27 : : namespace isc {
28 : : namespace asiolink {
29 : :
30 : : /// This class holds a call back function of asynchronous operations.
31 : : /// To ensure the object is alive while an asynchronous operation refers
32 : : /// to it, we use shared_ptr and enable_shared_from_this.
33 : : /// The object will be destructed in case IntervalTimer has been destructed
34 : : /// and no asynchronous operation refers to it.
35 : : /// Please follow the link to get an example:
36 : : /// http://think-async.com/asio/asio-1.4.8/doc/asio/tutorial/tutdaytime3.html#asio.tutorial.tutdaytime3.the_tcp_connection_class
37 : : class IntervalTimerImpl :
38 : : public boost::enable_shared_from_this<IntervalTimerImpl>
39 : : {
40 : : private:
41 : : // prohibit copy
42 : : IntervalTimerImpl(const IntervalTimerImpl& source);
43 : : IntervalTimerImpl& operator=(const IntervalTimerImpl& source);
44 : : public:
45 : : IntervalTimerImpl(IOService& io_service);
46 : : ~IntervalTimerImpl();
47 : : void setup(const IntervalTimer::Callback& cbfunc, const long interval);
48 : : void callback(const asio::error_code& error);
49 : : void cancel() {
50 : 120 : timer_.cancel();
51 : 120 : interval_ = 0;
52 : : }
53 : 0 : long getInterval() const { return (interval_); }
54 : : private:
55 : : // a function to update timer_ when it expires
56 : : void update();
57 : : // a function to call back when timer_ expires
58 : : IntervalTimer::Callback cbfunc_;
59 : : // interval in milliseconds
60 : : long interval_;
61 : : // asio timer
62 : : asio::deadline_timer timer_;
63 : : // interval_ will be set to this value in destructor in order to detect
64 : : // use-after-free type of bugs.
65 : : static const long INVALIDATED_INTERVAL = -1;
66 : : };
67 : :
68 : 115 : IntervalTimerImpl::IntervalTimerImpl(IOService& io_service) :
69 [ + - ]: 115 : interval_(0), timer_(io_service.get_io_service())
70 : 115 : {}
71 : :
72 : 345 : IntervalTimerImpl::~IntervalTimerImpl() {
73 : 115 : interval_ = INVALIDATED_INTERVAL;
74 : 115 : }
75 : :
76 : : void
77 : 19 : IntervalTimerImpl::setup(const IntervalTimer::Callback& cbfunc,
78 : : const long interval)
79 : : {
80 : : // Interval should not be less than or equal to 0.
81 [ + + ]: 19 : if (interval <= 0) {
82 [ + - ]: 4 : isc_throw(isc::BadValue, "Interval should not be less than or "
83 : : "equal to 0");
84 : : }
85 : : // Call back function should not be empty.
86 [ + + ]: 17 : if (cbfunc.empty()) {
87 [ + - ]: 2 : isc_throw(isc::InvalidParameter, "Callback function is empty");
88 : : }
89 : 16 : cbfunc_ = cbfunc;
90 : 16 : interval_ = interval;
91 : : // Set initial expire time.
92 : : // At this point the timer is not running yet and will not expire.
93 : : // After calling IOService::run(), the timer will expire.
94 : 16 : update();
95 : 16 : }
96 : :
97 : : void
98 : 31 : IntervalTimerImpl::update() {
99 : : try {
100 : : // Update expire time to (current time + interval_).
101 : 31 : timer_.expires_from_now(boost::posix_time::millisec(interval_));
102 : : // Reset timer.
103 : : // Pass a function bound with a shared_ptr to this.
104 : : timer_.async_wait(boost::bind(&IntervalTimerImpl::callback,
105 : : shared_from_this(),
106 [ + - ][ + - ]: 31 : asio::placeholders::error));
107 [ # # # ]: 0 : } catch (const asio::system_error& e) {
108 [ # # ][ # # ]: 0 : isc_throw(isc::Unexpected, "Failed to update timer: " << e.what());
[ # # ]
109 : 0 : } catch (const boost::bad_weak_ptr&) {
110 : : // Can't happen. It means a severe internal bug.
111 : 0 : assert(0);
112 : : }
113 : 31 : }
114 : :
115 : : void
116 : 20 : IntervalTimerImpl::callback(const asio::error_code& ec) {
117 [ - + ]: 20 : assert(interval_ != INVALIDATED_INTERVAL);
118 [ + + ][ + + ]: 38 : if (interval_ == 0 || ec) {
[ + + ]
119 : : // timer has been canceled. Do nothing.
120 : : } else {
121 : : // Set next expire time.
122 : 15 : update();
123 : : // Invoke the call back function.
124 : 15 : cbfunc_();
125 : : }
126 : 20 : }
127 : :
128 : 115 : IntervalTimer::IntervalTimer(IOService& io_service) :
129 [ + - ]: 115 : impl_(new IntervalTimerImpl(io_service))
130 : 115 : {}
131 : :
132 : 230 : IntervalTimer::~IntervalTimer() {
133 : : // Cancel the timer to make sure cbfunc_() will not be called any more.
134 [ + - ]: 115 : cancel();
135 : 115 : }
136 : :
137 : : void
138 : 19 : IntervalTimer::setup(const Callback& cbfunc, const long interval) {
139 : 19 : return (impl_->setup(cbfunc, interval));
140 : : }
141 : :
142 : : void
143 : 120 : IntervalTimer::cancel() {
144 : 120 : impl_->cancel();
145 : 120 : }
146 : :
147 : : long
148 : 10 : IntervalTimer::getInterval() const {
149 : 10 : return (impl_->getInterval());
150 : : }
151 : :
152 : : } // namespace asiolink
153 [ + - ][ + - ]: 30 : } // namespace isc
|