GitHub Actions: Try MSVC builds with /std:c++17 and 20
[ACE_TAO.git] / ACE / ace / Timer_Queue_T.cpp
blobe5a5fbf1f91572ee2181efba4b40790b5a23967f
1 #ifndef ACE_TIMER_QUEUE_T_CPP
2 #define ACE_TIMER_QUEUE_T_CPP
4 #include "ace/config-all.h"
6 #if !defined (ACE_LACKS_PRAGMA_ONCE)
7 # pragma once
8 #endif /* ACE_LACKS_PRAGMA_ONCE */
11 * Hook to specialize to add includes
13 //@@ REACTOR_SPL_INCLUDE_FORWARD_DECL_ADD_HOOK
15 #include "ace/Timer_Queue_T.h"
16 #include "ace/Guard_T.h"
17 #include "ace/Reverse_Lock_T.h"
18 #include "ace/Log_Category.h"
19 #include "ace/Null_Mutex.h"
20 #include "ace/OS_NS_sys_time.h"
21 #include "ace/Functor.h"
23 #if !defined (__ACE_INLINE__)
24 #include "ace/Timer_Queue_T.inl"
25 #endif /* __ACE_INLINE__ */
27 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
29 // This fudge factor can be overriden for timers that need it, such as on
30 // Solaris, by defining the ACE_TIMER_SKEW symbol in the appropriate config
31 // header.
32 #if !defined (ACE_TIMER_SKEW)
33 # define ACE_TIMER_SKEW 0
34 #endif /* ACE_TIMER_SKEW */
36 template <class TYPE, class FUNCTOR> ACE_INLINE
37 ACE_Timer_Queue_Upcall_Base<TYPE, FUNCTOR>::ACE_Timer_Queue_Upcall_Base (FUNCTOR * upcall_functor)
38 : ACE_Abstract_Timer_Queue<TYPE>()
39 , ACE_Copy_Disabled()
40 , upcall_functor_(upcall_functor)
41 , delete_upcall_functor_ (upcall_functor == 0)
43 ACE_TRACE ("ACE_Timer_Queue_Upcall_Base::ACE_Timer_Queue_Upcall_Base");
45 if (upcall_functor != 0)
47 return;
50 ACE_NEW (upcall_functor_, FUNCTOR);
53 template <class TYPE, class FUNCTOR> ACE_INLINE
54 ACE_Timer_Queue_Upcall_Base<TYPE, FUNCTOR>::~ACE_Timer_Queue_Upcall_Base ()
56 ACE_TRACE ("ACE_Timer_Queue_Upcall_Base::~ACE_Timer_Queue_Upcall_Base");
57 if (this->delete_upcall_functor_)
59 delete this->upcall_functor_;
63 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Time_Value
64 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::gettimeofday()
66 return this->gettimeofday_static();
69 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
70 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::gettimeofday (ACE_Time_Value (*gettimeofday)(void))
72 this->time_policy_.set_gettimeofday (gettimeofday);
75 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Time_Value *
76 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::calculate_timeout (ACE_Time_Value *max_wait_time)
78 ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout");
79 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, max_wait_time));
81 if (this->is_empty ())
82 // Nothing on the Timer_Queue, so use whatever the caller gave us.
83 return max_wait_time;
84 else
86 ACE_Time_Value const cur_time = this->gettimeofday_static ();
88 if (this->earliest_time () > cur_time)
90 // The earliest item on the Timer_Queue is still in the
91 // future. Therefore, use the smaller of (1) caller's wait
92 // time or (2) the delta time between now and the earliest
93 // time on the Timer_Queue.
95 this->timeout_ = this->earliest_time () - cur_time;
96 if (max_wait_time == 0 || *max_wait_time > timeout_)
97 return &this->timeout_;
98 else
99 return max_wait_time;
101 else
103 // The earliest item on the Timer_Queue is now in the past.
104 // Therefore, we've got to "poll" the Reactor, i.e., it must
105 // just check the descriptors and then dispatch timers, etc.
106 this->timeout_ = ACE_Time_Value::zero;
107 return &this->timeout_;
112 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Time_Value *
113 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::calculate_timeout (ACE_Time_Value *max_wait_time,
114 ACE_Time_Value *the_timeout)
116 ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout");
118 if (the_timeout == 0)
119 return 0;
121 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, max_wait_time));
123 if (this->is_empty ())
125 // Nothing on the Timer_Queue, so use whatever the caller gave us.
126 if (max_wait_time)
127 *the_timeout = *max_wait_time;
128 else
129 return 0;
131 else
133 ACE_Time_Value cur_time = this->gettimeofday_static ();
135 if (this->earliest_time () > cur_time)
137 // The earliest item on the Timer_Queue is still in the
138 // future. Therefore, use the smaller of (1) caller's wait
139 // time or (2) the delta time between now and the earliest
140 // time on the Timer_Queue.
142 *the_timeout = this->earliest_time () - cur_time;
143 if (!(max_wait_time == 0 || *max_wait_time > *the_timeout))
144 *the_timeout = *max_wait_time;
146 else
148 // The earliest item on the Timer_Queue is now in the past.
149 // Therefore, we've got to "poll" the Reactor, i.e., it must
150 // just check the descriptors and then dispatch timers, etc.
151 *the_timeout = ACE_Time_Value::zero;
154 return the_timeout;
157 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Time_Value
158 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::current_time()
160 ACE_Time_Value tv = this->gettimeofday_static ();
161 tv += this->timer_skew();
162 return tv;
165 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
166 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::dump (void) const
168 #if defined (ACE_HAS_DUMP)
169 ACE_TRACE ("ACE_Timer_Queue_T::dump");
170 ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
171 this->timeout_.dump ();
172 this->timer_skew_.dump ();
173 ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
174 #endif /* ACE_HAS_DUMP */
177 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
178 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::ACE_Timer_Queue_T (FUNCTOR *upcall_functor,
179 ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist,
180 TIME_POLICY const & time_policy)
181 : ACE_Timer_Queue_Upcall_Base<TYPE,FUNCTOR>(upcall_functor),
182 time_policy_ (time_policy),
183 delete_free_list_ (freelist == 0),
184 timer_skew_ (0, ACE_TIMER_SKEW)
186 ACE_TRACE ("ACE_Timer_Queue_T::ACE_Timer_Queue_T");
188 if (!freelist)
189 ACE_NEW (free_list_,
190 (ACE_Locked_Free_List<ACE_Timer_Node_T<TYPE>,ACE_Null_Mutex>));
191 else
192 free_list_ = freelist;
195 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
196 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::~ACE_Timer_Queue_T (void)
198 ACE_TRACE ("ACE_Timer_Queue_T::~ACE_Timer_Queue_T");
200 // Cleanup the free_list on the way out
201 if (this->delete_free_list_)
202 delete this->free_list_;
205 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Timer_Node_T<TYPE> *
206 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::alloc_node (void)
208 return this->free_list_->remove ();
211 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
212 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::free_node (ACE_Timer_Node_T<TYPE> *node)
214 this->free_list_->add (node);
217 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_LOCK &
218 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::mutex (void)
220 return this->mutex_;
223 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> long
224 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::schedule (const TYPE &type,
225 const void *act,
226 const ACE_Time_Value &future_time,
227 const ACE_Time_Value &interval)
229 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
231 // Schedule the timer.
232 long const result =
233 this->schedule_i (type,
234 act,
235 future_time,
236 interval);
238 // Return on failure.
239 if (result == -1)
240 return result;
242 // Inform upcall functor of successful registration.
243 this->upcall_functor ().registration (*this,
244 type,
245 act);
247 // Return result;
248 return result;
251 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
252 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::expire (void)
254 // We can't check here is the timer queue is empty, in some
255 // implementations (like the timer heap) calling is_empty()
256 // would at that moment access member variables without having
257 // locked ourself for thread safety
258 return this->expire (this->gettimeofday_static () + timer_skew_);
261 // Run the <handle_timeout> method for all Timers whose values are <=
262 // <cur_time>.
263 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
264 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::expire (const ACE_Time_Value &cur_time)
266 ACE_TRACE ("ACE_Timer_Queue_T::expire");
267 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
269 // Keep looping while there are timers remaining and the earliest
270 // timer is <= the <cur_time> passed in to the method.
272 if (this->is_empty ())
273 return 0;
275 int number_of_timers_expired = 0;
276 int result = 0;
278 ACE_Timer_Node_Dispatch_Info_T<TYPE> info;
280 while ((result = this->dispatch_info_i (cur_time, info)) != 0)
282 ACE_MT (ACE_Reverse_Lock<ACE_LOCK> rev_lk(this->mutex_));
283 ACE_MT (ACE_GUARD_RETURN (ACE_Reverse_Lock<ACE_LOCK>, rmon, rev_lk, -1));
285 const void *upcall_act = 0;
287 this->preinvoke (info, cur_time, upcall_act);
289 this->upcall (info, cur_time);
291 this->postinvoke (info, cur_time, upcall_act);
293 ++number_of_timers_expired;
297 ACE_UNUSED_ARG (result);
298 return number_of_timers_expired;
301 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
302 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::recompute_next_abs_interval_time
303 (ACE_Timer_Node_T<TYPE> *expired,
304 const ACE_Time_Value &cur_time)
306 if ( expired->get_timer_value () <= cur_time )
309 * Somehow the current time is past when this time was
310 * supposed to expire (e.g., timer took too long,
311 * somebody changed system time, etc.). There used to
312 * be a simple loop here that skipped ahead one timer
313 * interval at a time, but that was horribly inefficient
314 * (an O(n) algorithm) when the timer duration was small
315 * relative to the amount of time skipped.
317 * So, we replace the loop with a simple computation,
318 * which also happens to be O(1). All times get
319 * normalized in the computation to microseconds.
321 * For reference, the loop looked like this:
323 * do
324 * expired->set_timer_value (expired->get_timer_value () +
325 * expired->get_interval ());
326 * while (expired->get_timer_value () <= cur_time);
330 // Compute the duration of the timer's interval
331 ACE_UINT64 interval_usec;
332 expired->get_interval ().to_usec (interval_usec);
334 // Compute the span between the current time and when
335 // the timer would have expired in the past (and
336 // normalize to microseconds).
337 ACE_Time_Value old_diff = cur_time - expired->get_timer_value ();
338 ACE_UINT64 old_diff_usec;
339 old_diff.to_usec (old_diff_usec);
341 // Compute the delta time in the future when the timer
342 // should fire as if it had advanced incrementally. The
343 // modulo arithmetic accomodates the likely case that
344 // the current time doesn't fall precisely on a timer
345 // firing interval.
346 ACE_UINT64 new_timer_usec =
347 interval_usec - (old_diff_usec % interval_usec);
349 // Compute the absolute time in the future when this
350 // interval timer should expire.
351 ACE_Time_Value new_timer_value
352 (cur_time.sec ()
353 + static_cast<time_t>(new_timer_usec / ACE_ONE_SECOND_IN_USECS),
354 cur_time.usec ()
355 + static_cast<suseconds_t>(new_timer_usec % ACE_ONE_SECOND_IN_USECS));
357 expired->set_timer_value (new_timer_value);
361 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
362 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::expire_single (
363 ACE_Command_Base & pre_dispatch_command)
365 ACE_TRACE ("ACE_Timer_Queue_T::expire_single");
366 ACE_Timer_Node_Dispatch_Info_T<TYPE> info;
367 ACE_Time_Value cur_time;
369 // Create a scope for the lock ...
370 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
372 if (this->is_empty ())
373 return 0;
375 // Get the current time
376 cur_time = this->gettimeofday_static () + this->timer_skew ();
378 // Look for a node in the timer queue whose timer <= the present
379 // time.
380 if (!this->dispatch_info_i (cur_time, info))
382 return 0;
385 // We do not need the lock anymore, all these operations take place
386 // with local variables.
387 const void *upcall_act = 0;
389 // Preinvoke (handles refcount if needed, etc.)
390 this->preinvoke (info, cur_time, upcall_act);
392 // Release the token before expiration upcall.
393 pre_dispatch_command.execute();
395 // call the functor
396 this->upcall (info, cur_time);
398 // Postinvoke (undo refcount if needed, etc.)
399 this->postinvoke (info, cur_time, upcall_act);
401 // We have dispatched a timer
402 return 1;
405 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
406 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::dispatch_info_i (const ACE_Time_Value &cur_time,
407 ACE_Timer_Node_Dispatch_Info_T<TYPE> &info)
409 ACE_TRACE ("ACE_Timer_Queue_T::dispatch_info_i");
411 if (this->is_empty ())
412 return 0;
414 if (this->earliest_time () <= cur_time)
416 ACE_Timer_Node_T<TYPE> *expired = this->remove_first ();
418 // Get the dispatch info
419 expired->get_dispatch_info (info);
421 // Check if this is an interval timer.
422 if (expired->get_interval () > ACE_Time_Value::zero)
424 // Make sure that we skip past values that have already
425 // "expired".
426 this->recompute_next_abs_interval_time (expired, cur_time);
428 // Since this is an interval timer, we need to reschedule
429 // it.
430 this->reschedule (expired);
432 else
434 // Call the factory method to free up the node.
435 this->free_node (expired);
438 return 1;
441 return 0;
444 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
445 ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::return_node (ACE_Timer_Node_T<TYPE> *node)
447 ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_));
448 this->free_node (node);
451 ACE_END_VERSIONED_NAMESPACE_DECL
453 #endif /* ACE_TIMER_QUEUE_T_CPP */