updated to use new modules (more independance to libi2ncommon)
[libasyncio] / asyncio / async_callout.cpp
1 /**
2  * @file
3  *
4  * @copyright © Copyright 2008 by Intra2net AG
5  * @license LGPL
6  * 
7  * info@intra2net.com
8  */
9
10 #include "async_callout.hpp"
11 #include <asyncio_config.hpp>
12
13 #ifdef HAVE_LIBI2NCOMMON
14 #include <tracefunc.hpp>
15 #include <logfunc.hpp>
16 #else
17 #define SCOPETRACKER(x) do{}while(false)
18 #endif
19
20 #include <map>
21
22
23 namespace AsyncIo
24 {
25
26 namespace
27 {
28
29 typedef boost::shared_ptr< Detail::Caller > CallerPtr;
30
31 typedef std::map< unsigned long, CallerPtr > CallMap;
32
33
34 unsigned long l_last_id=0;
35
36 CallMap 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  */
46 unsigned 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
53 void 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
62 bool 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
74 CallerPtr 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
85 bool 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
101 CallOutId::CallOutId()
102 : m_value(0)
103 {
104 } // eo CallOutId::CallOutId()
105
106
107 CallOutId::CallOutId(unsigned long value)
108 : m_value(value)
109 {
110 } // eo CallOutId::CallOutId(unsigned long)
111
112
113 bool 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
128 bool 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
140 bool 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  */
150 bool 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  */
167 MilliTime 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
183 namespace Detail
184 {
185
186 /*
187 ** implementation of class Caller
188 */
189
190 Caller::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
201 Caller::~Caller()
202 {
203    SCOPETRACKER();
204 } // eo Caller::~Caller()
205
206
207 void 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
223 bool 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
235 bool 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
247 bool 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  */
263 bool removeCallOut( CallOutId& id )
264 {
265    return id.remove();
266 } // eo removeCallOut(CallOutId&)
267
268
269
270 template<>
271 CallOutId 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
278 template<>
279 CallOutId 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
285 template<>
286 CallOutId 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
296 template<>
297 CallOutId 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
305 template<>
306 CallOutId 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
313 template<>
314 CallOutId 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
320 template<>
321 CallOutId 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
331 template<>
332 CallOutId 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
338 } // eo namespace AsyncIo