AgentXcpp  Revision:0.1.1
Internals Documentation
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Friends Pages
timeout_timer.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2012 Tanjeff-Nicolai Moos <tanjeff@cccmz.de>
3  *
4  * This file is part of the agentXcpp library.
5  *
6  * AgentXcpp is free software: you can redistribute it and/or modify
7  * it under the terms of the AgentXcpp library license, version 1, which
8  * consists of the GNU General Public License and some additional
9  * permissions.
10  *
11  * AgentXcpp is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * See the AgentXcpp library license in the LICENSE file of this package
17  * for more details.
18  */
19 #ifndef _TIMEOUT_TIMER_H_
20 #define _TIMEOUT_TIMER_H_
21 
22 
23 #include <set>
24 #include <boost/asio.hpp>
25 
26 namespace agentxcpp
27 {
28  /**
29  * \internal
30  *
31  * \brief A timer which can detect timeouts
32  *
33  * This timer can detect timeouts. A timeout_timer object starts in
34  * "standby" state. The timer can then be started using the expires_at()
35  * (giving an absolute time) or expires_from_now() (giving a time span)
36  * methods, which changes the status to "running". When the timer expires,
37  * the status changes to "expired". The timer can be disabled at any time
38  * using cancel(), which changes the status back to "standby" (this works
39  * also with an expired timer).
40  *
41  * This class uses the boost::asio library and therefore needs an
42  * io_service object. It never calls io_service::run() or
43  * io_service::run_one(). For the timeout_timer to work, the run() or
44  * run_one() method of the io_service object must be invoked by the user of
45  * timeout_timer. As long as neither of them are invoked, the timer will
46  * not report the status "expired".
47  *
48  * The object can break, e.g. when something with the interally used
49  * boost::asio::deadline_timer goes wrong. In this case the status changes
50  * to "broken". A broken timeout_timer cannot be used anymore: a call to
51  * any member function will do nothing (except for get_status(), which will
52  * report the status "broken") and the status will be "broken" forever.
53  *
54  * \par How it works
55  *
56  * For timeout detection, an asio deadline_timer is used together with the
57  * status member. While the timer is not in use, it's expiry time is set to
58  * "infinite" and status is set to "standby". When starting the timer, the
59  * deadline_timer's expiry is set to the according time, and status is set
60  * to "running". If the deadline_timer expires, it invokes the
61  * check_deadline() callback, which sets the expiry back to "infinite" and
62  * status to "expired". If cancel() is invoked before the deadline_timer
63  * expires, the expiry is set back to "infinite" and the status to
64  * "standby".
65  *
66  * The check_deadline() callback may be invoked errornously, e.g. when the
67  * deadline_timer's expiry time is reset after the timer expired, but
68  * before the callback actually is invoked. Therefore, check_deadline()
69  * compares the expiry date of the timer with the current timestamp to
70  * determine whether the timer really expired.
71  *
72  * Also, check_deadline() is called after the deadline_timer object is
73  * destroyed. This happens when a timeout_timer object is destroyed, which
74  * means that the callback function must not be a member function. Instead
75  * it is a static class function which takes a pointer to the timeout_timer
76  * object for which it is called. To identify calls for destroyed objects,
77  * the static mamber "available_timers" is used, which stores pointers to
78  * all timeout_timer objects currently in existence. This is handled by the
79  * constructors and destructor of the timeout_timer class.
80  */
82  {
83  public:
84 
85  /**
86  * \brief Constructor
87  *
88  * This constructor sets the timer status to "standby", the
89  * deadline_timer's expiry to "infinite" and add the new object to
90  * "available_timers". It also starts the deadline_timer.
91  *
92  * \note If something goes wrong, the status is set to "broken".
93  *
94  * \param io_service The io_service object which will be used by
95  * the timer.
96  *
97  * \exception None.
98  */
99  timeout_timer(boost::asio::io_service & io_service);
100 
101  /**
102  * \brief The timeout status type.
103  */
104  enum status_t
105  {
106  running, // timer is running
107  expired, // timer expired
108  standby, // timer currently not in use
109  broken // timer is broken
110  };
111 
112  /**
113  * \brief Time out at the given time.
114  *
115  * This function starts the timer and set its expiry time to
116  * 'time'. The status is set to 'running'.
117  *
118  * \note If something goes wrong, the status is set to "broken".
119  *
120  * \param time The time at which the timer shall expire.
121  *
122  * \exception None.
123  */
124  void expires_at(boost::asio::deadline_timer::time_type time);
125 
126  /**
127  * \brief Time out at (now + duration).
128  *
129  * This function starts the deadline_timer and sets its expiry time
130  * to (now + 'duration'). The status is set to 'running'.
131  *
132  * \note If something goes wrong, the status is set to "broken".
133  *
134  * \param duration The duration after which the timer elapses.
135  *
136  * \exception None.
137  */
138  void expires_from_now(boost::asio::deadline_timer::duration_type duration);
139 
140  /**
141  * \brief Stop the timer.
142  *
143  * This stops the timer. The status is set to "standby", and the
144  * deadline_timer's expiry time is set to "infinite".
145  *
146  * \note If something goes wrong, the status is set to "broken".
147  *
148  * \exception None.
149  */
150  void cancel();
151 
152  /**
153  * \brief Get the current timer status.
154  *
155  * \exception None.
156  */
158  {
159  return status;
160  }
161 
162  /**
163  * \brief Destructor
164  *
165  * The destructor removes the object from "available_timers".
166  */
167  ~timeout_timer();
168 
169  private:
170 
171  /**
172  * \brief Set of timeout_timer objects currently in existence.
173  */
174  static std::set<timeout_timer*> available_timers;
175 
176  /**
177  * \brief Hide default constructor.
178  *
179  * We need an io_service object to function properly.
180  */
181  timeout_timer();
182 
183  /**
184  * \brief The timeout status.
185  */
187 
188  /**
189  * \brief The boost::asio timer.
190  *
191  * This timer is used to detect timeout conditions.
192  */
193  boost::asio::deadline_timer timer;
194 
195  /**
196  * \brief The timeout handler.
197  *
198  * This function is used as callback handler for 'timer'. It
199  * compares the deadline_timer's expiry time with the current
200  * system time to detect errornous invokation. It also checks
201  * whether the timeout_timer object exists (and does nothing if
202  * not). If a real timeout is detected, the status is set to
203  * "expired" and the deadline_timer's expiry is set to
204  * "infinite".
205  *
206  * This callback also restarts the timer on each call to keep it
207  * running.
208  *
209  * If something goes wrong, the status is set to "broken".
210  *
211  * \param self The timeout_timer object which triggered the
212  * callback.
213  */
214  static void check_deadline(timeout_timer* self);
215  };
216 }
217 
218 #endif