// Thread_Timer_Queue_Test.cpp,v 4.13 2004/01/05 22:57:06 shuston Exp // ============================================================================ // // = LIBRARY // examples // // = FILENAME // Thread_Timer_Queue_Test.cpp // // = DESCRIPTION // This test exercises the <ACE_Thread_Timer_Queue_Adapter> // using an <ACE_Timer_Heap>. // // = AUTHORS // Carlos O'Ryan <coryan@cs.wustl.edu> and // Douglas C. Schmidt <schmidt@cs.wustl.edu> // // ============================================================================ #include "ace/OS_NS_stdio.h" #include "ace/OS_NS_sys_time.h" #include "ace/Task.h" #include "ace/Timer_Heap_T.h" #include "ace/Timer_Queue_Adapters.h" #include "Thread_Timer_Queue_Test.h" #include "ace/Condition_T.h" #include "ace/Thread_Mutex.h" #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class ACE_Thread_Timer_Queue_Adapter<Timer_Heap>; template class Timer_Queue_Test_Driver<Thread_Timer_Queue, Input_Task, Input_Task::ACTION>; template class Command<Input_Task, Input_Task::ACTION>; #elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) #pragma instantiate ACE_Thread_Timer_Queue_Adapter<Timer_Heap> #pragma instantiate Timer_Queue_Test_Driver<Thread_Timer_Queue, \ Input_Task, \ Input_Task::ACTION> #pragma instantiate Command<Input_Task, Input_Task::ACTION> #endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) // These templates will specialized in libACE.* if the platforms does // not define ACE_MT_SAFE. #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class ACE_Thread_Condition<ACE_Thread_Mutex>; template class ACE_Condition<ACE_Thread_Mutex>; template class ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>; template class ACE_Timer_Queue_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>, ACE_Null_Mutex>; template class ACE_Timer_Heap_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>, ACE_Null_Mutex>; template class ACE_Timer_Heap_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>, ACE_Null_Mutex>; template class ACE_Timer_Queue_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>, ACE_Null_Mutex>; #elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) #pragma instantiate ACE_Thread_Condition<ACE_Thread_Mutex> #pragma instantiate ACE_Condition<ACE_Thread_Mutex> #pragma instantiate ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex> #pragma instantiate ACE_Timer_Queue_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>, ACE_Null_Mutex> #pragma instantiate ACE_Timer_Heap_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>, ACE_Null_Mutex> #pragma instantiate ACE_Timer_Heap_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>, ACE_Null_Mutex> #pragma instantiate ACE_Timer_Queue_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>, ACE_Null_Mutex> #endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ #endif /* ACE_MT_SAFE */ ACE_RCSID(Timer_Queue, Thread_Timer_Queue_Test, "Thread_Timer_Queue_Test.cpp,v 4.13 2004/01/05 22:57:06 shuston Exp") // Administrivia methods... Handler::Handler(const ACE_Time_Value &expiration_time) : expires_ (expiration_time), id_ (0) { } Handler::~Handler (void) { } void Handler::set_id (int id) { this->id_ = id; } // This is the method invoked when the Timer expires. int Handler::handle_timeout (const ACE_Time_Value ¤t_time, const void *) { ACE_Time_Value delay = current_time - this->expires_; // No need to protect this printf is always called from a Async safe // point. ACE_OS::printf ("\nexpiring timer %d at %lu.%7.7lu secs\n" "\tthere was a %lu.%7.7lu secs delay\n", this->id_, current_time.sec (), current_time.usec (), delay.sec (), delay.usec ()); // Notice this delete is protected. delete this; return 0; } Input_Task::Input_Task (Thread_Timer_Queue *queue, Thread_Timer_Queue_Test_Driver &timer_queue_driver) : ACE_Task_Base (ACE_Thread_Manager::instance ()), queue_ (queue), usecs_ (ACE_ONE_SECOND_IN_USECS), driver_ (timer_queue_driver) { } // Svc method is called from the thread library to read input from the // user. int Input_Task::svc (void) { for (;;) // call back to the driver's implementation on how to read and // parse input. if (this->driver_.get_next_request () == -1) break; // we are done. this->queue_->deactivate (); ACE_DEBUG ((LM_DEBUG, "terminating input thread\n")); return 0; } // schedule a new timer. This method will be called from inside the // <Timer_Queue_Test_Driver> class. (see Command pattern) int Input_Task::add_timer (void *argument) { u_long useconds = *ACE_reinterpret_cast (int *, argument); ACE_Time_Value interval (useconds / usecs_, useconds % usecs_); ACE_Time_Value expire_at = ACE_OS::gettimeofday () + interval; Handler *h; ACE_NEW_RETURN (h, Handler (expire_at), -1); int id = queue_->schedule (h, 0, expire_at); if (id == -1) ACE_ERROR_RETURN ((LM_ERROR, "schedule failed"), -1); // We store the id into the handler, this is only used to produce // nicer messages. h->set_id (id); ACE_OS::printf ("scheduling timer %d\n", id); return 0; } // Cancel a timer. This method will be called from inside the // <Timer_Queue_Test_Driver> class. (see Command pattern) int Input_Task::cancel_timer (void *argument) { return this->queue_->cancel (*ACE_reinterpret_cast (int *, argument)); } // Lists the timers in the queue. Ignores the argument. This method // will be called from inside the <Timer_Queue_Test_Driver> class. // (see Command pattern) int Input_Task::list_timer (void *argument) { // Macro to avoid "warning: unused parameter" type warning. ACE_UNUSED_ARG (argument); // Dump the timer queue contents. this->dump (); return 0; } // Shutdown the timer queue. Return -1 indicates to the // <Timer_Queue_Test_Driver> class that we are done. int Input_Task::shutdown_timer (void *argument) { // Macro to avoid "warning: unused parameter" type warning. ACE_UNUSED_ARG (argument); #if defined (ACE_LACKS_PTHREAD_CANCEL) // Cancel the thread timer queue task "voluntarily." this->queue_->deactivate (); #else // Cancel the thread timer queue task "preemptively." if (ACE_Thread::cancel (this->queue_->thr_id ()) == -1) ACE_ERROR ((LM_ERROR, "%p\n", "cancel")); #endif /* ACE_LACKS_PTHREAD_CANCEL */ // -1 indicates we are shutting down the application. return -1; } void Input_Task::dump (void) { ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->queue_->mutex ()); ACE_DEBUG ((LM_DEBUG, "begin dumping timer queue\n")); for (Timer_Heap_Iterator i (this->queue_->timer_queue ()); i.item () != 0; i.next ()) i.item ()->dump (); ACE_DEBUG ((LM_DEBUG, "end dumping timer queue\n")); } // constructor Thread_Timer_Queue_Test_Driver::Thread_Timer_Queue_Test_Driver (void) : input_task_ (&timer_queue_, *this) { } Thread_Timer_Queue_Test_Driver::~Thread_Timer_Queue_Test_Driver (void) { } int Thread_Timer_Queue_Test_Driver::run_test (void) { this->init (); return 0; } int Thread_Timer_Queue_Test_Driver::display_menu (void) { static char menu[] = "Usage:\n" "1 <microseconds>: setups a new timer\n" "2 <timerid>: removes a timer\n" "3 : prints timer queue\n" "4 : exit\n"; ACE_DEBUG ((LM_DEBUG, "%s", menu)); return 0; } int Thread_Timer_Queue_Test_Driver::init (void) { typedef Command<Input_Task, Input_Task::ACTION> CMD; // initialize the <Command> objects with their corresponding // methods from <Input_Task> ACE_NEW_RETURN (schedule_cmd_, CMD (input_task_, &Input_Task::add_timer), -1); ACE_NEW_RETURN (cancel_cmd_, CMD (input_task_, &Input_Task::cancel_timer), -1); ACE_NEW_RETURN (list_cmd_, CMD (input_task_, &Input_Task::list_timer), -1); ACE_NEW_RETURN (shutdown_cmd_, CMD (input_task_, &Input_Task::shutdown_timer), -1); if (this->input_task_.activate () == -1) ACE_ERROR_RETURN ((LM_ERROR, "cannot activate input task"), -1); else if (this->timer_queue_.activate () == -1) ACE_ERROR_RETURN ((LM_ERROR, "cannot activate timer queue"), -1); else if (ACE_Thread_Manager::instance ()->wait () == -1) ACE_ERROR_RETURN ((LM_ERROR, "wait on Thread_Manager failed"), -1); return 0; }