1 // $Id: Timer_Queue_Adapters.cpp 80826 2008-03-04 14:51:23Z wotte $
3 #ifndef ACE_TIMER_QUEUE_ADAPTERS_CPP
4 #define ACE_TIMER_QUEUE_ADAPTERS_CPP
6 #include "ace/Timer_Queue_Adapters.h"
8 #if defined (ACE_HAS_DEFERRED_TIMER_COMMANDS)
9 #include "ace/Functor.h"
10 #endif /* ACE_HAS_DEFERRED_TIMER_COMMANDS */
12 #if !defined (ACE_LACKS_PRAGMA_ONCE)
14 #endif /* ACE_LACKS_PRAGMA_ONCE */
16 # if !defined (__ACE_INLINE__)
17 # include "ace/Timer_Queue_Adapters.inl"
18 # endif /* __ACE_INLINE__ */
20 #include "ace/Signal.h"
21 #include "ace/OS_NS_unistd.h"
22 #include "ace/OS_NS_sys_time.h"
24 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
26 template <class TQ
> TQ
&
27 ACE_Async_Timer_Queue_Adapter
<TQ
>::timer_queue (void)
29 return this->timer_queue_
;
32 template <class TQ
> int
33 ACE_Async_Timer_Queue_Adapter
<TQ
>::cancel (long timer_id
,
36 // Block designated signals.
37 ACE_Sig_Guard
sg (&this->mask_
);
40 return this->timer_queue_
.cancel (timer_id
, act
);
43 template <class TQ
> int
44 ACE_Async_Timer_Queue_Adapter
<TQ
>::expire (void)
46 // Block designated signals.
47 ACE_Sig_Guard
sg (&this->mask_
);
50 return this->timer_queue_
.expire ();
53 template <class TQ
> int
54 ACE_Async_Timer_Queue_Adapter
<TQ
>::schedule_ualarm (void)
56 ACE_Time_Value tv
= this->timer_queue_
.earliest_time ()
57 - this->timer_queue_
.gettimeofday ();
59 // Beware of negative times and zero times (which cause problems for
61 if (tv
< ACE_Time_Value::zero
)
62 tv
= ACE_Time_Value (0, 1);
64 // @@ This code should be clever enough to avoid updating the
65 // <ualarm> if we haven't actually changed the earliest time.
66 // Schedule a new timer.
71 template <class TQ
> long
72 ACE_Async_Timer_Queue_Adapter
<TQ
>::schedule (ACE_Event_Handler
*eh
,
74 const ACE_Time_Value
&future_time
,
75 const ACE_Time_Value
&interval
)
78 ACE_UNUSED_ARG (interval
);
80 // Block designated signals.
81 ACE_Sig_Guard
sg (&this->mask_
);
84 // @@ We still need to implement interval timers...
85 long tid
= this->timer_queue_
.schedule (eh
, act
, future_time
);
88 ACE_ERROR_RETURN ((LM_ERROR
,
90 ACE_TEXT ("schedule_timer")),
93 if (this->schedule_ualarm () == -1)
100 ACE_Async_Timer_Queue_Adapter
<TQ
>::ACE_Async_Timer_Queue_Adapter (ACE_Sig_Set
*mask
)
101 // If <mask> == 0, block *all* signals when the SIGARLM handler is
102 // running, else just block those in the mask.
105 // The following code is necessary to selectively "block" certain
106 // signals when SIGALRM is running. Also, we always restart system
107 // calls that are interrupted by the signals.
109 ACE_Sig_Action
sa ((ACE_SignalHandler
) 0,
113 if (this->sig_handler_
.register_handler (SIGALRM
, this, &sa
) == -1)
114 ACE_ERROR ((LM_ERROR
,
116 ACE_TEXT ("register_handler")));
119 // This is the signal handler function for the asynchronous timer
120 // list. It gets invoked asynchronously when the SIGALRM signal
123 template <class TQ
> int
124 ACE_Async_Timer_Queue_Adapter
<TQ
>::handle_signal (int signum
,
132 // Expire the pending timers.
134 // @@ We need to figure out how to implement interval
136 this->timer_queue_
.expire ();
138 // Only schedule a new timer if there is one in the list.
140 // @@ This code should also become smarter to avoid
141 // unnecessary calls to ualarm().
142 if (this->timer_queue_
.is_empty () == 0)
143 return this->schedule_ualarm ();
149 ACE_ERROR_RETURN ((LM_ERROR
,
150 "unexpected signal %S\n",
158 ACE_Thread_Timer_Queue_Adapter
<TQ
>::ACE_Thread_Timer_Queue_Adapter (ACE_Thread_Manager
*tm
,
160 : ACE_Task_Base (tm
),
161 timer_queue_(timer_queue
),
162 delete_timer_queue_(false),
164 active_ (true), // Assume that we start in active mode.
165 thr_id_ (ACE_OS::NULL_thread
)
167 if (timer_queue_
== 0)
169 ACE_NEW (this->timer_queue_
,
171 this->delete_timer_queue_
= true;
176 ACE_Thread_Timer_Queue_Adapter
<TQ
>::~ACE_Thread_Timer_Queue_Adapter (void)
178 if (this->delete_timer_queue_
)
180 delete this->timer_queue_
;
181 this->timer_queue_
= 0;
182 this->delete_timer_queue_
= false;
186 template<class TQ
> ACE_SYNCH_RECURSIVE_MUTEX
&
187 ACE_Thread_Timer_Queue_Adapter
<TQ
>::mutex (void)
192 template<class TQ
> long
193 ACE_Thread_Timer_Queue_Adapter
<TQ
>::schedule
194 (ACE_Event_Handler
* handler
,
196 const ACE_Time_Value
&future_time
,
197 const ACE_Time_Value
&interval
)
199 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX
, guard
, this->mutex_
, -1);
201 long result
= this->timer_queue_
->schedule (handler
, act
, future_time
, interval
);
202 this->condition_
.signal ();
206 template<class TQ
> int
207 ACE_Thread_Timer_Queue_Adapter
<TQ
>::cancel (long timer_id
,
210 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX
, guard
, this->mutex_
, -1);
212 int result
= this->timer_queue_
->cancel (timer_id
, act
);
213 condition_
.signal ();
217 template<class TQ
> void
218 ACE_Thread_Timer_Queue_Adapter
<TQ
>::deactivate (void)
220 ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX
, guard
, this->mutex_
);
222 this->active_
= false;
223 this->condition_
.signal ();
226 template<class TQ
> int
227 ACE_Thread_Timer_Queue_Adapter
<TQ
>::svc (void)
229 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX
, guard
, this->mutex_
, -1);
231 this->thr_id_
= ACE_Thread::self ();
233 // Thread cancellation point, if ACE supports it.
235 // Note: This call generates a warning under Solaris because the header
236 // file /usr/include/pthread.h redefines the routine argument. This
237 // is a bug in the Solaris header files and has nothing to do with
239 # if !defined (ACE_LACKS_PTHREAD_CANCEL)
240 ACE_PTHREAD_CLEANUP_PUSH (&this->condition_
.mutex ().get_nesting_mutex ());
241 # endif /* ACE_LACKS_PTHREAD_CANCEL */
243 while (this->active_
)
245 # if defined (ACE_HAS_DEFERRED_TIMER_COMMANDS)
246 // Temporarily suspend ownership of the timer queue mutex in
247 // order to dispatch deferred execution commands. These
248 // commands are to be treated as executing in a context
249 // "external" to the timer queue adapter, and thus must compete
250 // separately for this lock.
252 this->dispatch_commands ();
254 // Re-acquire ownership of the timer queue mutex in order to
255 // restore the "internal" timer queue adapter context
257 # endif /* ACE_HAS_DEFERRED_TIMER_COMMANDS */
259 // If the queue is empty, sleep until there is a change on it.
260 if (this->timer_queue_
->is_empty ())
261 this->condition_
.wait ();
264 // Compute the remaining time, being careful not to sleep
265 // for "negative" amounts of time.
266 ACE_Time_Value
const tv_curr
= this->timer_queue_
->gettimeofday ();
267 ACE_Time_Value
const tv_earl
= this->timer_queue_
->earliest_time ();
269 if (tv_earl
> tv_curr
)
271 // The earliest time on the Timer_Queue is in future, so
272 // use ACE_OS::gettimeofday() to convert the tv to the
274 ACE_Time_Value
const tv
= ACE_OS::gettimeofday () + (tv_earl
- tv_curr
);
275 // ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("waiting until %u.%3.3u secs\n"),
276 // tv.sec(), tv.msec()));
277 this->condition_
.wait (&tv
);
281 // Expire timers anyway, at worst this is a no-op.
282 this->timer_queue_
->expire ();
285 // Thread cancellation point, if ACE supports it.
286 # if !defined (ACE_LACKS_PTHREAD_CANCEL)
287 ACE_PTHREAD_CLEANUP_POP (0);
288 # endif /* ACE_LACKS_PTHREAD_CANCEL */
293 template<class TQ
> int
294 ACE_Thread_Timer_Queue_Adapter
<TQ
>::activate (long flags
,
303 ACE_thread_t thread_ids
[],
304 const char* thr_name
[])
306 // Make sure to set this flag in case we were deactivated earlier.
307 this->active_
= true;
309 // Make sure that we only allow a single thread to be spawned for
310 // our adapter. Otherwise, too many weird things can happen.
311 return ACE_Task_Base::activate (flags
, 1, 0, priority
, grp_id
, task
, 0,
312 stack
, stack_size
, thread_ids
, thr_name
);
315 # if defined (ACE_HAS_DEFERRED_TIMER_COMMANDS)
317 // Enqueues a command object for execution just before waiting on the next
318 // timer event. This allows deferred execution of commands that cannot
319 // be performed in the timer event handler context, such as registering
320 // or cancelling timers on platforms where the timer queue mutex is not
323 template<class TQ
> int
324 ACE_Thread_Timer_Queue_Adapter
<TQ
>::enqueue_command (ACE_Command_Base
*cmd
,
325 COMMAND_ENQUEUE_POSITION pos
)
327 // Serialize access to the command queue.
328 ACE_GUARD_RETURN (ACE_SYNCH_MUTEX
, guard
, this->command_mutex_
, -1);
330 if (pos
== ACE_Thread_Timer_Queue_Adapter
<TQ
>::TAIL
)
331 return command_queue_
.enqueue_tail (cmd
);
333 return command_queue_
.enqueue_head (cmd
);
336 // Dispatches all command objects enqueued in the most recent event
339 template<class TQ
> int
340 ACE_Thread_Timer_Queue_Adapter
<TQ
>::dispatch_commands (void)
342 // Serialize access to the command queue.
343 ACE_GUARD_RETURN (ACE_SYNCH_MUTEX
, guard
, this->command_mutex_
, -1);
345 // loop through the enqueued commands
346 ACE_Command_Base
*cmd
= 0;
347 while (command_queue_
.dequeue_head (cmd
) == 0)
357 # endif /* ACE_HAS_DEFERRED_TIMER_COMMANDS */
359 ACE_END_VERSIONED_NAMESPACE_DECL
361 #endif /* ACE_TIMER_QUEUE_ADAPTERS_CPP */