2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
23 * @copyright © Copyright 2008-2009 by Intra2net AG
24 * @contact opensource@intra2net.com
27 #include "async_callout.hpp"
28 #include <asyncio_config.hpp>
30 #ifdef HAVE_LIBI2NCOMMON
31 #include <tracefunc.hpp>
32 #include <logfunc.hpp>
34 #define SCOPETRACKER(x) do{}while(false)
43 // anonymous namespace for our secret details :-)
47 typedef boost::shared_ptr< Detail::Caller > CallerPtr;
49 typedef std::map< unsigned long, CallerPtr > CallMap;
52 unsigned long l_last_id=0;
58 * @brief creates a new id value for a call out.
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.
64 unsigned long create_call_out_id_value()
66 while ( l_call_map.find(++l_last_id) != l_call_map.end() and l_last_id != 0);
68 } // eo create_call_out_id_value
72 * @brief add a caller instance to the local call map.
73 * @param caller the caller instance.
75 void add_call( CallerPtr caller )
79 l_call_map[ caller->getCallOutId().getValue() ] = caller;
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.
90 bool remove_call( unsigned long id_value )
92 CallMap::iterator it= l_call_map.find(id_value);
93 if (it != l_call_map.end())
99 } // eo remove_call(unsigned long)
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.
107 CallerPtr get_call(unsigned long id_value)
109 CallMap::iterator it= l_call_map.find(id_value);
110 if (it != l_call_map.end())
115 } // eo get_call(unsigned long)
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.
123 bool has_call( unsigned long id_value )
125 CallMap::iterator it= l_call_map.find(id_value);
126 return (it != l_call_map.end() );
127 } // eo has_call(unsigned long)
131 } // eo namespace <anonymous>
136 ** implementation of class CallOutId
139 CallOutId::CallOutId()
142 } // eo CallOutId::CallOutId()
145 CallOutId::CallOutId(unsigned long value)
148 } // eo CallOutId::CallOutId(unsigned long)
152 * @brief thaws (activate) the referenced (and frozen) call.
153 * @return @a true if the call was successfully thawed; @a false else.
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
161 bool CallOutId::thaw() const
163 if (m_caller_weak_ptr.expired())
167 CallerPtr call_ptr= get_call(m_value);
170 return call_ptr->thaw();
173 } // eo CallOutId::thaw() const
177 * @brief removes the referenced call.
178 * @return @a true if the call was removed; @a false else.
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).
183 bool CallOutId::remove()
185 if (m_caller_weak_ptr.expired())
189 unsigned long value= m_value;
191 return remove_call(value);
192 } // eo CallOutId::remove()
196 * @brief returns if the referenced call is still active.
197 * @return @a true if the referenced call is active.
199 * The referenced call is active if it is still waiting to be executed.
201 bool CallOutId::active() const
203 return m_value!=0 and not m_caller_weak_ptr.expired() and has_call(m_value);
204 } // eo CallOutId::active() const
208 * @brief returns if the call is frozen.
209 * @return @a true iff the call is frozen.
211 bool CallOutId::frozen() const
213 CallerPtr caller= m_caller_weak_ptr.lock();
218 return caller->frozen();
219 } // eo CallOutId::frozen() const
223 * @brief returns the remaining time until the call is done or thrown away (on frozen calls).
224 * @return the remaining time.
226 * The result only makes sense if the call is still active.
228 * If the references call is not active then the returned time is 0.
230 MilliTime CallOutId::remaining_time()
232 CallerPtr caller= m_caller_weak_ptr.lock();
233 if ( not active() or not caller )
238 get_current_monotonic_time(t);
239 MilliTime result= caller->getWhenTime();
242 return (result < t_null ? t_null : result);
243 } // eo CallOutId::remaining_time()
250 ** implementation of class Caller
253 Caller::Caller( boost::function< void() > f, long delta_sec, long delta_msec, bool frozen)
255 , m_call_out_id( create_call_out_id_value() )
260 setDeltaWhenTime( delta_sec, delta_msec);
261 } // eo Caller::Caller(boost::function< void() >,long)
267 } // eo Caller::~Caller()
270 void Caller::execute()
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();
278 if (m_func and not m_waiting)
280 m_func(); // may throw..., but at this point it doesn't harm.
281 //( it may harm at other places,...)
283 } // eo Caller::execute()
291 setDeltaWhenTime( 0, 0 );
295 } // eo Caller::thaw()
298 bool Caller::joinId()
300 if (m_call_out_id.m_caller_weak_ptr.expired())
302 m_call_out_id.m_caller_weak_ptr= shared_from_this();
307 } // eo Caller::joinId()
310 bool Caller::frozen() const
313 } // eo Caller::frozen() const
316 } // eo namespace Detail
321 * @brief remove a pending call by id.
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.
326 bool removeCallOut( CallOutId& id )
329 } // eo removeCallOut(CallOutId&)
334 CallOutId callOut( boost::function< void() > f, long delta_sec)
336 CallerPtr caller( new Detail::Caller(f,delta_sec) );
338 return caller->getCallOutId();
339 } // eo callOut(boost::function< void() >,long)
342 CallOutId callOut( boost::function< void() > f, int delta_sec)
344 return callOut<long>(f,delta_sec);
345 } // eo callOut(boost::function< void() >,int)
349 CallOutId callOut( boost::function< void() > f, double delta_sec )
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) );
355 return caller->getCallOutId();
356 } // eo callOut(boost::function< void() >,double)
360 CallOutId callOut( boost::function< void() > f, float delta_sec )
362 return callOut<double>(f,delta_sec);
363 } // eo callOut(boost::function< void() >,float)
369 CallOutId frozenCall( boost::function< void() > f, long delta_sec)
371 CallerPtr caller( new Detail::Caller(f,delta_sec, 0, true) );
373 return caller->getCallOutId();
374 } // eo frozenCall(boost::function< void() >,long)
377 CallOutId frozenCall( boost::function< void() > f, int delta_sec)
379 return frozenCall<long>(f,delta_sec);
380 } // eo frozenCall(boost::function< void() >,int)
384 CallOutId frozenCall( boost::function< void() > f, double delta_sec )
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) );
390 return caller->getCallOutId();
391 } // eo frozenCall(boost::function< void() >,double)
395 CallOutId frozenCall( boost::function< void() > f, float delta_sec )
397 return frozenCall<double>(f,delta_sec);
398 } // eo frozenCall(boost::function< void() >,float)
401 } // eo namespace AsyncIo