added some more docs for callouts
[libasyncio] / asyncio / async_callout.cpp
CommitLineData
8c15b8c7
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
5c8a3d40
RP
20/**
21 * @file
22 *
d02bf926
RP
23 * @copyright © Copyright 2008-2009 by Intra2net AG
24 * @contact opensource@intra2net.com
25 *
5c8a3d40 26 */
42b7c46d 27#include "async_callout.hpp"
fd6ea89e 28#include <asyncio_config.hpp>
5c8a3d40 29
fd6ea89e 30#ifdef HAVE_LIBI2NCOMMON
5c8a3d40
RP
31#include <tracefunc.hpp>
32#include <logfunc.hpp>
fd6ea89e
RP
33#else
34#define SCOPETRACKER(x) do{}while(false)
35#endif
5c8a3d40
RP
36
37#include <map>
38
39
42b7c46d 40namespace AsyncIo
5c8a3d40
RP
41{
42
d02bf926 43// anonymous namespace for our secret details :-)
5c8a3d40
RP
44namespace
45{
46
47typedef boost::shared_ptr< Detail::Caller > CallerPtr;
48
49typedef std::map< unsigned long, CallerPtr > CallMap;
50
51
52unsigned long l_last_id=0;
53
54CallMap l_call_map;
55
56
57/**
58 * @brief creates a new id value for a call out.
59 * @return the new id.
60 *
61 * The id value is basically just a counter.
62 * It is implemented in a way that it can not be 0 and can deal with wrap arounds.
63 */
64unsigned long create_call_out_id_value()
65{
66 while ( l_call_map.find(++l_last_id) != l_call_map.end() and l_last_id != 0);
67 return l_last_id;
68} // eo create_call_out_id_value
69
70
d02bf926
RP
71/**
72 * @brief add a caller instance to the local call map.
73 * @param caller the caller instance.
74 */
5c8a3d40
RP
75void add_call( CallerPtr caller )
76{
77 if (caller->joinId())
78 {
79 l_call_map[ caller->getCallOutId().getValue() ] = caller;
80 }
81} // eo add_call
82
83
d02bf926
RP
84/**
85 * @brief removes an entry from the local call map
86 * @param id_value id to remove from the map.
87 * @return @a true if an entry was found and removed
88 * @a false if entry was not found in the map.
89 */
5c8a3d40
RP
90bool remove_call( unsigned long id_value )
91{
92 CallMap::iterator it= l_call_map.find(id_value);
93 if (it != l_call_map.end())
94 {
95 l_call_map.erase(it);
96 return true;
97 }
98 return false;
99} // eo remove_call(unsigned long)
100
101
d02bf926
RP
102/**
103 * @brief return the caller for an id.
104 * @param id_value the id to search the caller for.
105 * @return caller; empty pointer if not found.
106 */
5c8a3d40
RP
107CallerPtr get_call(unsigned long id_value)
108{
109 CallMap::iterator it= l_call_map.find(id_value);
110 if (it != l_call_map.end())
111 {
112 return it->second;
113 }
114 return CallerPtr();
115} // eo get_call(unsigned long)
116
117
d02bf926
RP
118/**
119 * @brief tests if an id can be found in the call map.
120 * @param id_value the id to search for.
121 * @return @a true if the id is found in the call map.
122 */
5c8a3d40
RP
123bool has_call( unsigned long id_value )
124{
125 CallMap::iterator it= l_call_map.find(id_value);
126 return (it != l_call_map.end() );
127} // eo has_call(unsigned long)
128
129
130
131} // eo namespace <anonymous>
132
133
134
135/*
136** implementation of class CallOutId
137*/
138
139CallOutId::CallOutId()
140: m_value(0)
141{
142} // eo CallOutId::CallOutId()
143
144
145CallOutId::CallOutId(unsigned long value)
146: m_value(value)
147{
148} // eo CallOutId::CallOutId(unsigned long)
149
150
d02bf926
RP
151/**
152 * @brief thaws (activate) the referenced (and frozen) call.
153 * @return @a true if the call was successfully thawed; @a false else.
154 *
155 * A call (referenced the id instance) can be successfully thawed if:
156 * - the call was a frozen call
157 * - the call is still existing; i.e. we are within the given time period
158 * for that call.
159 * .
160 */
5c8a3d40
RP
161bool CallOutId::thaw() const
162{
163 if (m_caller_weak_ptr.expired())
164 {
165 return false;
166 }
167 CallerPtr call_ptr= get_call(m_value);
168 if (call_ptr)
169 {
170 return call_ptr->thaw();
171 }
172 return false;
173} // eo CallOutId::thaw() const
174
175
d02bf926
RP
176/**
177 * @brief removes the referenced call.
178 * @return @a true if the call was removed; @a false else.
179 *
180 * @note after calling this method, the refernced call is not existing.
181 * Either it was removed or it was already removed earlier (explicit or implicit).
182 */
5c8a3d40
RP
183bool CallOutId::remove()
184{
185 if (m_caller_weak_ptr.expired())
186 {
187 return false;
188 }
189 unsigned long value= m_value;
190 m_value= 0;
191 return remove_call(value);
192} // eo CallOutId::remove()
193
194
d02bf926
RP
195/**
196 * @brief returns if the referenced call is still active.
197 * @return @a true if the referenced call is active.
198 *
199 * The referenced call is active if it is still waiting to be executed.
200 */
5c8a3d40
RP
201bool CallOutId::active() const
202{
203 return m_value!=0 and not m_caller_weak_ptr.expired() and has_call(m_value);
204} // eo CallOutId::active() const
205
206
207/**
d02bf926 208 * @brief returns if the call is frozen.
5c8a3d40
RP
209 * @return @a true iff the call is frozen.
210 */
211bool CallOutId::frozen() const
212{
213 CallerPtr caller= m_caller_weak_ptr.lock();
214 if (not caller)
215 {
216 return false;
217 }
218 return caller->frozen();
219} // eo CallOutId::frozen() const
220
221
222/**
223 * @brief returns the remaining time until the call is done or thrown away (on frozen calls).
224 * @return the remaining time.
225 *
226 * The result only makes sense if the call is still active.
d02bf926
RP
227 *
228 * If the references call is not active then the returned time is 0.
5c8a3d40
RP
229 */
230MilliTime CallOutId::remaining_time()
231{
232 CallerPtr caller= m_caller_weak_ptr.lock();
233 if ( not active() or not caller )
234 {
235 return MilliTime();
236 }
237 MilliTime t;
238 get_current_monotonic_time(t);
239 MilliTime result= caller->getWhenTime();
240 result-= t;
241 MilliTime t_null;
242 return (result < t_null ? t_null : result);
243} // eo CallOutId::remaining_time()
244
245
246namespace Detail
247{
248
249/*
250** implementation of class Caller
251*/
252
253Caller::Caller( boost::function< void() > f, long delta_sec, long delta_msec, bool frozen)
254: TimerBase()
255, m_call_out_id( create_call_out_id_value() )
256, m_func(f)
257, m_waiting(frozen)
258{
259 SCOPETRACKER();
260 setDeltaWhenTime( delta_sec, delta_msec);
261} // eo Caller::Caller(boost::function< void() >,long)
262
263
264Caller::~Caller()
265{
266 SCOPETRACKER();
267} // eo Caller::~Caller()
268
269
270void Caller::execute()
271{
272 SCOPETRACKER();
273 // NOTE: since the func may throw an exception, we first get a shared pointer
274 // (to prevent early deletion) and then we remove us from the call map.
275 CallerPtr ptr= shared_from_this();
276 m_call_out_id.remove();
277
278 if (m_func and not m_waiting)
279 {
280 m_func(); // may throw..., but at this point it doesn't harm.
281 //( it may harm at other places,...)
282 }
283} // eo Caller::execute()
284
285
286bool Caller::thaw()
287{
288 if (m_waiting)
289 {
290 m_waiting= false;
291 setDeltaWhenTime( 0, 0 );
292 return true;
293 }
294 return false;
295} // eo Caller::thaw()
296
297
298bool Caller::joinId()
299{
300 if (m_call_out_id.m_caller_weak_ptr.expired())
301 {
302 m_call_out_id.m_caller_weak_ptr= shared_from_this();
303 activate();
304 return true;
305 }
306 return false;
307} // eo Caller::joinId()
308
309
310bool Caller::frozen() const
311{
312 return m_waiting;
313} // eo Caller::frozen() const
314
315
316} // eo namespace Detail
317
318
319
320/**
321 * @brief remove a pending call by id.
322 *
323 * @param id the call id which should be removed.
324 * @return @a true iff the call was removed, @a false if no call with the given id was found.
325 */
326bool removeCallOut( CallOutId& id )
327{
328 return id.remove();
329} // eo removeCallOut(CallOutId&)
330
331
332
333template<>
334CallOutId callOut( boost::function< void() > f, long delta_sec)
335{
336 CallerPtr caller( new Detail::Caller(f,delta_sec) );
337 add_call(caller);
338 return caller->getCallOutId();
339} // eo callOut(boost::function< void() >,long)
340
341template<>
342CallOutId callOut( boost::function< void() > f, int delta_sec)
343{
344 return callOut<long>(f,delta_sec);
345} // eo callOut(boost::function< void() >,int)
346
347
348template<>
349CallOutId callOut( boost::function< void() > f, double delta_sec )
350{
351 long delta_sec_i = (long)delta_sec;
352 long delta_sec_m = (long)((delta_sec - (double)delta_sec_i)*1000.0);
353 CallerPtr caller( new Detail::Caller(f,delta_sec_i, delta_sec_m) );
354 add_call(caller);
355 return caller->getCallOutId();
356} // eo callOut(boost::function< void() >,double)
357
358
359template<>
360CallOutId callOut( boost::function< void() > f, float delta_sec )
361{
362 return callOut<double>(f,delta_sec);
363} // eo callOut(boost::function< void() >,float)
364
365
366
367
368template<>
369CallOutId frozenCall( boost::function< void() > f, long delta_sec)
370{
371 CallerPtr caller( new Detail::Caller(f,delta_sec, 0, true) );
372 add_call(caller);
373 return caller->getCallOutId();
374} // eo frozenCall(boost::function< void() >,long)
375
376template<>
377CallOutId frozenCall( boost::function< void() > f, int delta_sec)
378{
379 return frozenCall<long>(f,delta_sec);
380} // eo frozenCall(boost::function< void() >,int)
381
382
383template<>
384CallOutId frozenCall( boost::function< void() > f, double delta_sec )
385{
386 long delta_sec_i = (long)delta_sec;
387 long delta_sec_m = (long)((delta_sec - (double)delta_sec_i)*1000.0);
388 CallerPtr caller( new Detail::Caller(f,delta_sec_i, delta_sec_m, true) );
389 add_call(caller);
390 return caller->getCallOutId();
391} // eo frozenCall(boost::function< void() >,double)
392
393
394template<>
395CallOutId frozenCall( boost::function< void() > f, float delta_sec )
396{
397 return frozenCall<double>(f,delta_sec);
398} // eo frozenCall(boost::function< void() >,float)
399
400
42b7c46d 401} // eo namespace AsyncIo