updated to use new modules (more independance to libi2ncommon)
[libasyncio] / asyncio / async_callout.cpp
CommitLineData
5c8a3d40
RP
1/**
2 * @file
3 *
4 * @copyright © Copyright 2008 by Intra2net AG
42b7c46d 5 * @license LGPL
5c8a3d40
RP
6 *
7 * info@intra2net.com
8 */
9
42b7c46d 10#include "async_callout.hpp"
fd6ea89e 11#include <asyncio_config.hpp>
5c8a3d40 12
fd6ea89e 13#ifdef HAVE_LIBI2NCOMMON
5c8a3d40
RP
14#include <tracefunc.hpp>
15#include <logfunc.hpp>
fd6ea89e
RP
16#else
17#define SCOPETRACKER(x) do{}while(false)
18#endif
5c8a3d40
RP
19
20#include <map>
21
22
42b7c46d 23namespace AsyncIo
5c8a3d40
RP
24{
25
26namespace
27{
28
29typedef boost::shared_ptr< Detail::Caller > CallerPtr;
30
31typedef std::map< unsigned long, CallerPtr > CallMap;
32
33
34unsigned long l_last_id=0;
35
36CallMap l_call_map;
37
38
39/**
40 * @brief creates a new id value for a call out.
41 * @return the new id.
42 *
43 * The id value is basically just a counter.
44 * It is implemented in a way that it can not be 0 and can deal with wrap arounds.
45 */
46unsigned long create_call_out_id_value()
47{
48 while ( l_call_map.find(++l_last_id) != l_call_map.end() and l_last_id != 0);
49 return l_last_id;
50} // eo create_call_out_id_value
51
52
53void add_call( CallerPtr caller )
54{
55 if (caller->joinId())
56 {
57 l_call_map[ caller->getCallOutId().getValue() ] = caller;
58 }
59} // eo add_call
60
61
62bool remove_call( unsigned long id_value )
63{
64 CallMap::iterator it= l_call_map.find(id_value);
65 if (it != l_call_map.end())
66 {
67 l_call_map.erase(it);
68 return true;
69 }
70 return false;
71} // eo remove_call(unsigned long)
72
73
74CallerPtr get_call(unsigned long id_value)
75{
76 CallMap::iterator it= l_call_map.find(id_value);
77 if (it != l_call_map.end())
78 {
79 return it->second;
80 }
81 return CallerPtr();
82} // eo get_call(unsigned long)
83
84
85bool has_call( unsigned long id_value )
86{
87 CallMap::iterator it= l_call_map.find(id_value);
88 return (it != l_call_map.end() );
89} // eo has_call(unsigned long)
90
91
92
93} // eo namespace <anonymous>
94
95
96
97/*
98** implementation of class CallOutId
99*/
100
101CallOutId::CallOutId()
102: m_value(0)
103{
104} // eo CallOutId::CallOutId()
105
106
107CallOutId::CallOutId(unsigned long value)
108: m_value(value)
109{
110} // eo CallOutId::CallOutId(unsigned long)
111
112
113bool CallOutId::thaw() const
114{
115 if (m_caller_weak_ptr.expired())
116 {
117 return false;
118 }
119 CallerPtr call_ptr= get_call(m_value);
120 if (call_ptr)
121 {
122 return call_ptr->thaw();
123 }
124 return false;
125} // eo CallOutId::thaw() const
126
127
128bool CallOutId::remove()
129{
130 if (m_caller_weak_ptr.expired())
131 {
132 return false;
133 }
134 unsigned long value= m_value;
135 m_value= 0;
136 return remove_call(value);
137} // eo CallOutId::remove()
138
139
140bool CallOutId::active() const
141{
142 return m_value!=0 and not m_caller_weak_ptr.expired() and has_call(m_value);
143} // eo CallOutId::active() const
144
145
146/**
147 * @brief retruns if the call is frozen.
148 * @return @a true iff the call is frozen.
149 */
150bool CallOutId::frozen() const
151{
152 CallerPtr caller= m_caller_weak_ptr.lock();
153 if (not caller)
154 {
155 return false;
156 }
157 return caller->frozen();
158} // eo CallOutId::frozen() const
159
160
161/**
162 * @brief returns the remaining time until the call is done or thrown away (on frozen calls).
163 * @return the remaining time.
164 *
165 * The result only makes sense if the call is still active.
166 */
167MilliTime CallOutId::remaining_time()
168{
169 CallerPtr caller= m_caller_weak_ptr.lock();
170 if ( not active() or not caller )
171 {
172 return MilliTime();
173 }
174 MilliTime t;
175 get_current_monotonic_time(t);
176 MilliTime result= caller->getWhenTime();
177 result-= t;
178 MilliTime t_null;
179 return (result < t_null ? t_null : result);
180} // eo CallOutId::remaining_time()
181
182
183namespace Detail
184{
185
186/*
187** implementation of class Caller
188*/
189
190Caller::Caller( boost::function< void() > f, long delta_sec, long delta_msec, bool frozen)
191: TimerBase()
192, m_call_out_id( create_call_out_id_value() )
193, m_func(f)
194, m_waiting(frozen)
195{
196 SCOPETRACKER();
197 setDeltaWhenTime( delta_sec, delta_msec);
198} // eo Caller::Caller(boost::function< void() >,long)
199
200
201Caller::~Caller()
202{
203 SCOPETRACKER();
204} // eo Caller::~Caller()
205
206
207void Caller::execute()
208{
209 SCOPETRACKER();
210 // NOTE: since the func may throw an exception, we first get a shared pointer
211 // (to prevent early deletion) and then we remove us from the call map.
212 CallerPtr ptr= shared_from_this();
213 m_call_out_id.remove();
214
215 if (m_func and not m_waiting)
216 {
217 m_func(); // may throw..., but at this point it doesn't harm.
218 //( it may harm at other places,...)
219 }
220} // eo Caller::execute()
221
222
223bool Caller::thaw()
224{
225 if (m_waiting)
226 {
227 m_waiting= false;
228 setDeltaWhenTime( 0, 0 );
229 return true;
230 }
231 return false;
232} // eo Caller::thaw()
233
234
235bool Caller::joinId()
236{
237 if (m_call_out_id.m_caller_weak_ptr.expired())
238 {
239 m_call_out_id.m_caller_weak_ptr= shared_from_this();
240 activate();
241 return true;
242 }
243 return false;
244} // eo Caller::joinId()
245
246
247bool Caller::frozen() const
248{
249 return m_waiting;
250} // eo Caller::frozen() const
251
252
253} // eo namespace Detail
254
255
256
257/**
258 * @brief remove a pending call by id.
259 *
260 * @param id the call id which should be removed.
261 * @return @a true iff the call was removed, @a false if no call with the given id was found.
262 */
263bool removeCallOut( CallOutId& id )
264{
265 return id.remove();
266} // eo removeCallOut(CallOutId&)
267
268
269
270template<>
271CallOutId callOut( boost::function< void() > f, long delta_sec)
272{
273 CallerPtr caller( new Detail::Caller(f,delta_sec) );
274 add_call(caller);
275 return caller->getCallOutId();
276} // eo callOut(boost::function< void() >,long)
277
278template<>
279CallOutId callOut( boost::function< void() > f, int delta_sec)
280{
281 return callOut<long>(f,delta_sec);
282} // eo callOut(boost::function< void() >,int)
283
284
285template<>
286CallOutId callOut( boost::function< void() > f, double delta_sec )
287{
288 long delta_sec_i = (long)delta_sec;
289 long delta_sec_m = (long)((delta_sec - (double)delta_sec_i)*1000.0);
290 CallerPtr caller( new Detail::Caller(f,delta_sec_i, delta_sec_m) );
291 add_call(caller);
292 return caller->getCallOutId();
293} // eo callOut(boost::function< void() >,double)
294
295
296template<>
297CallOutId callOut( boost::function< void() > f, float delta_sec )
298{
299 return callOut<double>(f,delta_sec);
300} // eo callOut(boost::function< void() >,float)
301
302
303
304
305template<>
306CallOutId frozenCall( boost::function< void() > f, long delta_sec)
307{
308 CallerPtr caller( new Detail::Caller(f,delta_sec, 0, true) );
309 add_call(caller);
310 return caller->getCallOutId();
311} // eo frozenCall(boost::function< void() >,long)
312
313template<>
314CallOutId frozenCall( boost::function< void() > f, int delta_sec)
315{
316 return frozenCall<long>(f,delta_sec);
317} // eo frozenCall(boost::function< void() >,int)
318
319
320template<>
321CallOutId frozenCall( boost::function< void() > f, double delta_sec )
322{
323 long delta_sec_i = (long)delta_sec;
324 long delta_sec_m = (long)((delta_sec - (double)delta_sec_i)*1000.0);
325 CallerPtr caller( new Detail::Caller(f,delta_sec_i, delta_sec_m, true) );
326 add_call(caller);
327 return caller->getCallOutId();
328} // eo frozenCall(boost::function< void() >,double)
329
330
331template<>
332CallOutId frozenCall( boost::function< void() > f, float delta_sec )
333{
334 return frozenCall<double>(f,delta_sec);
335} // eo frozenCall(boost::function< void() >,float)
336
337
42b7c46d 338} // eo namespace AsyncIo