diff options
-rw-r--r-- | ChangeLog-97a | 42 | ||||
-rw-r--r-- | ace/Asynch_IO.cpp | 11 | ||||
-rw-r--r-- | ace/Asynch_IO.h | 12 | ||||
-rw-r--r-- | ace/Proactor.cpp | 312 | ||||
-rw-r--r-- | ace/Proactor.h | 96 | ||||
-rw-r--r-- | ace/Strategies.cpp | 8 | ||||
-rw-r--r-- | ace/Strategies.h | 18 | ||||
-rw-r--r-- | ace/Timer_Heap.cpp | 25 | ||||
-rw-r--r-- | ace/Timer_Heap.h | 6 | ||||
-rw-r--r-- | ace/Timer_List.cpp | 6 | ||||
-rw-r--r-- | ace/Timer_List.h | 5 | ||||
-rw-r--r-- | ace/Timer_Queue.cpp | 37 | ||||
-rw-r--r-- | ace/Timer_Queue.h | 24 | ||||
-rw-r--r-- | examples/Reactor/Proactor/test_proactor.mak | 247 | ||||
-rw-r--r-- | examples/Reactor/Proactor/test_proactor.mdp | bin | 46592 -> 54784 bytes | |||
-rw-r--r-- | examples/Reactor/Proactor/test_timeout.cpp | 92 |
16 files changed, 855 insertions, 86 deletions
diff --git a/ChangeLog-97a b/ChangeLog-97a index a456477d6dc..0c151ef6bb9 100644 --- a/ChangeLog-97a +++ b/ChangeLog-97a @@ -1,3 +1,45 @@ +Tue Apr 22 01:38:14 1997 <irfan@TWOSTEP> + + * ace/Timer_Queue: Added ACE_Upcall_Strategy as a parameter to the + constructor. <expire> will call <upcall_strategy->upcall> if + <upcall_strategy> is not 0. Else it will call <handle_timeout> + on the <Event_Handler>. Thus ACE_Upcall_Strategy becomes a + vehicle for extending the behavior of ACE_Timer_Queue wrt the + upcall (callback) *without subclassing*. Hence, it's an example + of the Bridge/Strategy patterns. + + This also affected ACE_Timer_List and ACE_Timer_Heap + + * ace/Strategies: Added ACE_Upcall_Strategy. + + * ace/Proactor: Added timing support to the <handle_event> calls. + + * ace/Asynch_IO: ACE_Handler now supports handle_timeout. + + * ace/Proactor: Added timer support for the new Proactor. This + new scheme allows any of the threads in the "thread pool" + waiting on the completion port of the Proactor to execute the + callback routine of the handler. + + The implementation included adding ACE_Proactor_Timer_Handler + class that has a thread that will wait on the earliest time in a + timer queue and an event. When a timer expires, the thread will + post a completion event on the port and go back to waiting on + the timer queue and event. If the event is signaled, the thread + will refresh the time it is currently waiting on (in case the + earliest time has changed). + + The ACE_Proactor::Asynch_Timer class is posted to the completion + port when a timer expires. When the <complete> method of this + object is called, the <handler>'s handle_timeout method will be + called. + + * examples/Reactor/Proactor/test_timeout: This example illustrates + the new timer features in the Proactor + + * examples/Reactor/Proactor/test_proactor.{mdp,mak}: Added new + example. + Tue Apr 22 00:21:03 1997 Douglas C. Schmidt <schmidt@tango.cs.wustl.edu> * examples/OS/Process/process.cpp (main): Replaced the use of diff --git a/ace/Asynch_IO.cpp b/ace/Asynch_IO.cpp index 067810f139e..1e0cb04ba4e 100644 --- a/ace/Asynch_IO.cpp +++ b/ace/Asynch_IO.cpp @@ -35,6 +35,10 @@ ACE_Asynch_Result::ACE_Asynch_Result (ACE_Handler &handler, this->hEvent = event; } +ACE_Asynch_Result::~ACE_Asynch_Result (void) +{ +} + u_long ACE_Asynch_Result::bytes_transferred (void) const { @@ -945,12 +949,13 @@ void ACE_Handler::handle_notify (const ACE_Asynch_Notify::Result &result) { } +*/ -void -ACE_Handler::handle_timeout (const ACE_Asynch_Timeout::Result &result) +void +ACE_Handler::handle_timeout (const ACE_Time_Value &tv, + const void *act) { } -*/ ACE_Proactor * ACE_Handler::proactor (void) diff --git a/ace/Asynch_IO.h b/ace/Asynch_IO.h index b0fcd522070..3145d3104c1 100644 --- a/ace/Asynch_IO.h +++ b/ace/Asynch_IO.h @@ -87,6 +87,9 @@ public: u_long offset_high = 0); // Constructor + virtual ~ACE_Asynch_Result (void); + // Destructor + protected: virtual void complete (u_long bytes_transferred, int success, @@ -814,8 +817,13 @@ public: /* virtual void handle_notify (const ACE_Asynch_Notify::Result &result); - virtual void handle_timeout (const ACE_Asynch_Timeout::Result &result); - */ + */ + + virtual void handle_timeout (const ACE_Time_Value &tv, + const void *act = 0); + // Called when timer expires. + // <tv> was the requested time value and + // <act> is the ACT passed when scheduling the timer ACE_Proactor *proactor (void); // Get the proactor associated with this handler. diff --git a/ace/Proactor.cpp b/ace/Proactor.cpp index 7a76cfa55f8..c7bf5f60089 100644 --- a/ace/Proactor.cpp +++ b/ace/Proactor.cpp @@ -7,10 +7,68 @@ #if defined (ACE_WIN32) // This only works on Win32 platforms +#include "ace/Task.h" #include "ace/Timer_Queue.h" +#include "ace/Timer_List.h" #include "ace/Log_Msg.h" -#include "ace/Asynch_IO.h" +class ACE_Export ACE_Proactor_Timer_Handler : public ACE_Task <ACE_NULL_SYNCH> + // + // = TITLE + // + // A Handler for timer. It helps in the management of timers + // registered with the Proactor. + // + // = DESCRIPTION + // + // This object has a thread that will wait on the earliest + // time in a list of timers and an event. When a timer + // expires, the thread will post a completion event on the + // port and go back to waiting on the timer queue and + // event. If the event is signaled, the thread will refresh + // the time it is currently waiting on (in case the earliest + // time has changed) + // +{ + friend class ACE_Proactor; + // Proactor has special privileges + +public: + ACE_Proactor_Timer_Handler (ACE_Proactor &proactor); + +protected: + virtual int svc (void); + // Run by a daemon thread to handle deferred processing. In other + // words, this method will do the waiting on the earliest timer + // and event + + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *arg = 0); + // Framework calls this when a timer expires + + ACE_Auto_Event timer_event_; + // Event to wait on + + ACE_Proactor &proactor_; + // Proactor + +public: + class ACE_Export ACT + // + // = TITLE + // + // A new ACT that combines the old ACT and Handler + // + { + public: + ACT (ACE_Handler &handler, + const void *act); + + ACE_Handler &handler_; + const void *act_; + }; +}; + #if !defined (__ACE_INLINE__) #include "ace/Proactor.i" #endif /* __ACE_INLINE__ */ @@ -18,14 +76,27 @@ ACE_Proactor::ACE_Proactor (size_t number_of_threads, ACE_Timer_Queue *tq) : completion_port_ (0), // This *MUST* be 0, *NOT* ACE_INVALID_HANDLE!!!! - number_of_threads_ (number_of_threads) + number_of_threads_ (number_of_threads), + timer_queue_ (0), + delete_timer_queue_ (0), + timer_handler_ (0) { + ACE_NEW (this->timer_handler_, ACE_Proactor_Timer_Handler (*this)); + + // set the timer queue + this->timer_queue (tq); + + // create the completion port this->completion_port_ = ::CreateIoCompletionPort (INVALID_HANDLE_VALUE, this->completion_port_, 0, this->number_of_threads_); if (this->completion_port_ == 0) ACE_ERROR ((LM_ERROR, "%p\n", "CreateIoCompletionPort")); + + // activate <timer_handler> + if (this->timer_handler_->activate () == -1) + ACE_ERROR ((LM_ERROR, "%p Could not create thread\n", "Task::activate")); } ACE_Proactor::~ACE_Proactor (void) @@ -36,6 +107,21 @@ ACE_Proactor::~ACE_Proactor (void) int ACE_Proactor::close (void) { + // Take care of the timer handler + if (this->timer_handler_) + { + delete this->timer_handler_; + this->timer_handler_ = 0; + } + + // Take care of the timer queue + if (this->delete_timer_queue_) + { + delete this->timer_queue_; + this->timer_queue_ = 0; + this->delete_timer_queue_ = 0; + } + // Close the completion port if (this->completion_port_ != 0) { @@ -68,14 +154,87 @@ ACE_Proactor::register_handle (ACE_HANDLE handle, } int +ACE_Proactor::schedule_timer (ACE_Handler &handler, + const void *act, + const ACE_Time_Value &time) +{ + return this->schedule_timer (handler, act, time, ACE_Time_Value::zero); +} + +int +ACE_Proactor::schedule_repeating_timer (ACE_Handler &handler, + const void *act, + const ACE_Time_Value &interval) +{ + return this->schedule_timer (handler, act, interval, interval); +} + +int +ACE_Proactor::schedule_timer (ACE_Handler &handler, + const void *act, + const ACE_Time_Value &time, + const ACE_Time_Value &interval) +{ + // Create a new ACT + ACE_Proactor_Timer_Handler::ACT *new_act = 0; + ACE_NEW_RETURN (new_act, ACE_Proactor_Timer_Handler::ACT (handler, act), -1); + + // Only one guy goes in here at a time + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->timer_queue_->lock (), -1); + + // absolute time + ACE_Time_Value absolute_time = this->timer_queue_->gettimeofday () + time; + + // Schedule the timer + int result = this->timer_queue_->schedule (this->timer_handler_, + new_act, + absolute_time, + interval); + // Failure of schedule + if (result == -1) + // cleanup + delete new_act; + + // no failures: check to see if we are the earliest time + else if (this->timer_queue_->earliest_time () == absolute_time) + // wake up the timer thread + if (this->timer_handler_->timer_event_.signal () == -1) + { + // failure: cleanup + delete new_act; + // Cancel timer + this->timer_queue_->cancel (result); + result = -1; + } + return result; +} + +int +ACE_Proactor::cancel_timer (int timer_id, + const void **arg) +{ + // No need to singal timer event here. Even if the cancel timer was + // the earliest, we will have an extra wakeup. + return this->timer_queue_->cancel (timer_id, arg); +} + +int ACE_Proactor::handle_events (ACE_Time_Value &wait_time) { - return 0; + // Decrement <wait_time> with the amount of time spent in the method + ACE_Countdown_Time countdown (&wait_time); + return this->handle_events (wait_time.msec ()); } int ACE_Proactor::handle_events (void) { + return this->handle_events (INFINITE); +} + +int +ACE_Proactor::handle_events (unsigned long milli_seconds) +{ OVERLAPPED *overlapped = 0; u_long bytes_transferred = 0; u_long completion_key = 0; @@ -85,11 +244,20 @@ ACE_Proactor::handle_events (void) &bytes_transferred, &completion_key, &overlapped, - INFINITE); - + milli_seconds); if (result == FALSE && overlapped == 0) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "GetQueuedCompletionStatus"), -1); + { + errno = ::GetLastError (); + // @@ What's the WIN32 constant for timeout (258)?!?!?! + if (errno == 258) + { + errno = ETIMEDOUT; + return 0; + } + else + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "GetQueuedCompletionStatus"), -1); + } else { // Narrow result @@ -177,4 +345,136 @@ ACE_Proactor::number_of_threads (size_t threads) this->number_of_threads_ = threads; } +ACE_Timer_Queue * +ACE_Proactor::timer_queue (void) const +{ + return this->timer_queue_; +} + +void +ACE_Proactor::timer_queue (ACE_Timer_Queue *tq) +{ + // cleanup old timer queue + if (this->delete_timer_queue_) + { + delete this->timer_queue_; + this->delete_timer_queue_ = 0; + } + + // new timer queue + if (tq == 0) + { + this->timer_queue_ = new ACE_Timer_List; + this->delete_timer_queue_ = 1; + } + else + { + this->timer_queue_ = tq; + this->delete_timer_queue_ = 0; + } +} + +ACE_Proactor_Timer_Handler::ACE_Proactor_Timer_Handler (ACE_Proactor &proactor) + : proactor_ (proactor), + ACE_Task <ACE_NULL_SYNCH> (&proactor.thr_mgr_) +{ +} + +int +ACE_Proactor_Timer_Handler::svc (void) +{ + u_long time; + ACE_Time_Value absolute_time; + + for (;;) + { + // default value + time = INFINITE; + + // If the timer queue is not empty + if (!this->proactor_.timer_queue_->is_empty ()) + { + // Get the earliest absolute time + absolute_time + = this->proactor_.timer_queue_->earliest_time () + - this->proactor_.timer_queue_->gettimeofday (); + + // time to wait + time = absolute_time.msec (); + + // Make sure the time is positive + if (time < 0) + time = 0; + } + + // Wait for event upto <time> milli seconds + int result = ::WaitForSingleObject (this->timer_event_.handle (), + time); + switch (result) + { + case WAIT_TIMEOUT: + // timeout: expire timers + this->proactor_.timer_queue_->expire (); + break; + case WAIT_FAILED: + // error + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "WaitForSingleObject"), -1); + } + } + + return 0; +} + +int +ACE_Proactor_Timer_Handler::handle_timeout (const ACE_Time_Value &tv, + const void *arg) +{ + ACE_Proactor_Timer_Handler::ACT *new_act + = (ACE_Proactor_Timer_Handler::ACT *) arg; + + // Create the Asynch_Timer + ACE_Proactor::Asynch_Timer *asynch_timer + = new ACE_Proactor::Asynch_Timer (new_act->handler_, + new_act->act_, + tv); + + // Post a completion + if (::PostQueuedCompletionStatus (this->proactor_.completion_port_, // completion port + 0, // number of bytes tranferred + 0, // completion key + asynch_timer // overlapped + ) == FALSE) + { + ACE_ERROR ((LM_ERROR, "Failure in dealing with timers: PostQueuedCompletionStatus failed")); + delete asynch_timer; + } + + return 0; +} + +ACE_Proactor::Asynch_Timer::Asynch_Timer (ACE_Handler &handler, + const void *act, + const ACE_Time_Value &tv) + : ACE_Asynch_Result (handler, + act), + time_ (tv) +{ +} + +void +ACE_Proactor::Asynch_Timer::complete (u_long bytes_transferred, + int success, + const void *completion_key, + u_long error) +{ + this->handler_.handle_timeout (this->time_, this->act ()); +} + +ACE_Proactor_Timer_Handler::ACT::ACT (ACE_Handler &handler, + const void *act) + : act_ (act), + handler_ (handler) +{ +} + #endif /* ACE_WIN32 */ diff --git a/ace/Proactor.h b/ace/Proactor.h index 79a0d8d8600..205844e6260 100644 --- a/ace/Proactor.h +++ b/ace/Proactor.h @@ -18,13 +18,15 @@ #if !defined (ACE_PROACTOR_H) #define ACE_PROACTOR_H -#include "ace/OS.h" +#include "ace/Asynch_IO.h" +#include "ace/Thread_Manager.h" #if defined (ACE_WIN32) // This only works on Win32 platforms class ACE_Timer_Queue; class ACE_Asynch_Result; +class ACE_Proactor_Timer_Handler; class ACE_Export ACE_Proactor // @@ -36,6 +38,9 @@ class ACE_Export ACE_Proactor // // A manager for the I/O completion port. { + friend class ACE_Proactor_Timer_Handler; + // Timer Handler has special privileges + public: ACE_Proactor (size_t number_of_threads = 0, ACE_Timer_Queue *tq = 0); @@ -51,6 +56,44 @@ public: const void *completion_key); // This method adds the <handle> to the I/O completion port + // = Timer management. + virtual int schedule_timer (ACE_Handler &handler, + const void *act, + const ACE_Time_Value &time); + // Schedule a <handler> that will expire after <time>. If it + // expires then <act> is passed in as the value to the <handler>'s + // <handle_timeout> callback method. This method returns a + // <timer_id>. This <timer_id> can be used to cancel a timer before + // it expires. The cancellation ensures that <timer_ids> are unique + // up to values of greater than 2 billion timers. As long as timers + // don't stay around longer than this there should be no problems + // with accidentally deleting the wrong timer. Returns -1 on + // failure (which is guaranteed never to be a valid <timer_id>. + + virtual int schedule_repeating_timer (ACE_Handler &handler, + const void *act, + const ACE_Time_Value &interval); + + // Same as above except <interval> it is used to reschedule the + // <handler> automatically. + + int schedule_timer (ACE_Handler &handler, + const void *act, + const ACE_Time_Value &time, + const ACE_Time_Value &interval); + // This combines the above two methods into one. Mostly for backward + // compatibility. + + virtual int cancel_timer (int timer_id, + const void **act = 0); + // Cancel the single <ACE_Handler> that matches the <timer_id> value + // (which was returned from the <schedule> method). If <act> is + // non-NULL then it will be set to point to the ``magic cookie'' + // argument passed in when the <Handler> was registered. This makes + // it possible to free up the memory and avoid memory leaks. + // Returns 1 if cancellation succeeded and 0 if the <timer_id> + // wasn't found. + virtual int handle_events (ACE_Time_Value &wait_time); // Dispatch a single set of events. If <wait_time> elapses before // any events occur, return. @@ -83,6 +126,10 @@ public: void number_of_threads (size_t threads); // Number of thread used as a parameter to CreatIoCompletionPort + ACE_Timer_Queue *timer_queue (void) const; + void timer_queue (ACE_Timer_Queue *); + // Get/Set timer queue + protected: void application_specific_code (ACE_Asynch_Result *asynch_result, @@ -93,8 +140,55 @@ protected: // Protect against structured exceptions caused by user code when // dispatching handles + virtual int handle_events (unsigned long milli_seconds); + // Dispatch a single set of events. If <milli_seconds> elapses + // before any events occur, return. + + class ACE_Export Asynch_Timer : protected ACE_Asynch_Result + // + // = TITLE + // + // This class is posted to the completion port when a timer + // expires. When the complete method of this object is called, + // the <handler>'s handle_timeout method will be called. + // + { + friend class ACE_Proactor_Timer_Handler; + // Timer Handler has special privileges + + public: + Asynch_Timer (ACE_Handler &handler, + const void *act, + const ACE_Time_Value &tv); + + protected: + virtual void complete (u_long bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); + // This method calls the <handler>'s handle_timeout method + + ACE_Time_Value time_; + // Time value requested by caller + }; + ACE_HANDLE completion_port_; + // Handle for the completion port + size_t number_of_threads_; + // This number is passed to the CreatIOCompletionPort() system call + + ACE_Timer_Queue *timer_queue_; + // Timer Queue + + int delete_timer_queue_; + // Flag on whether to delete the timer queue + + ACE_Proactor_Timer_Handler *timer_handler_; + // Handles timeouts events + + ACE_Thread_Manager thr_mgr_; + // This will manage the thread in the Timer_Handler }; #if defined (__ACE_INLINE__) diff --git a/ace/Strategies.cpp b/ace/Strategies.cpp index 0943d560b2c..bce6dfc329c 100644 --- a/ace/Strategies.cpp +++ b/ace/Strategies.cpp @@ -62,4 +62,12 @@ ACE_ReactorEx_Notification_Strategy::notify (ACE_Event_Handler *eh, return this->reactorex_->notify (eh, mask); } +ACE_Upcall_Strategy::ACE_Upcall_Strategy (void) +{ +} + +ACE_Upcall_Strategy::~ACE_Upcall_Strategy (void) +{ +} + #endif /* ACE_STRATEGIES_C */ diff --git a/ace/Strategies.h b/ace/Strategies.h index 07fc604be90..087a2e516f6 100644 --- a/ace/Strategies.h +++ b/ace/Strategies.h @@ -91,6 +91,24 @@ private: ACE_ReactorEx *reactorex_; }; +class ACE_Export ACE_Upcall_Strategy + // = TITLE + // Abstract class used for defining an upcall (callback) + // + // = DESCRIPTION + // A vehicle for extending the behavior of ACE_Timer_Queue wrt + // the upcall (callback) *without subclassing*. Thus, it's an + // example of the Bridge/Strategy patterns. +{ +public: + ACE_Upcall_Strategy (void); + virtual ~ACE_Upcall_Strategy (void); + + virtual void upcall (ACE_Event_Handler *handler, + const void *arg, + const ACE_Time_Value &cur_time) = 0; +}; + // This needs to come here to avoid circular dependencies. #include "ace/Strategies_T.h" diff --git a/ace/Timer_Heap.cpp b/ace/Timer_Heap.cpp index 97d971d3713..e29ac76565b 100644 --- a/ace/Timer_Heap.cpp +++ b/ace/Timer_Heap.cpp @@ -3,6 +3,7 @@ #define ACE_BUILD_DLL #include "ace/Timer_Heap.h" +#include "ace/Strategies.h" ACE_Timer_Heap_Iterator::ACE_Timer_Heap_Iterator (ACE_Timer_Heap &heap) : timer_heap_ (heap) @@ -29,8 +30,10 @@ ACE_Timer_Heap_Iterator::next (ACE_Timer_Node *&node, } ACE_Timer_Heap::ACE_Timer_Heap (size_t size, - int preallocate) - : max_size_ (size), + int preallocate, + ACE_Upcall_Strategy *upcall_strategy) + : ACE_Timer_Queue (upcall_strategy), + max_size_ (size), cur_size_ (0), iterator_ (*this), timer_ids_freelist_ (0), @@ -248,29 +251,27 @@ ACE_Timer_Heap::grow_heap (void) ACE_NEW (new_timer_ids, int[new_size]); - ACE_OS::memcpy (new_timer_ids, - this->timer_ids_, - max_size_ * sizeof *this->timer_ids_); + ACE_OS::memcpy (new_timer_ids, this->timer_ids_, max_size_ * sizeof (int)); delete [] timer_ids_; this->timer_ids_ = new_timer_ids; - // Add the new elements to the end of the "freelist" + // and add the new elements to the end of the "freelist" for (size_t i = this->max_size_; i < new_size; i++) this->timer_ids_[i] = -((int) (i + 1)); // Grow the preallocation array (if using preallocation) if (this->preallocated_nodes_ != 0) { - // Create a new array with max_size elements to link in to - // existing list. + // Create a new array with max_size elements to link in + // to existing list. ACE_NEW (this->preallocated_nodes_, ACE_Timer_Node[this->max_size_]); - // Add it to the set for later deletion + // add it to the set for later deletion this->preallocated_node_set_.insert (this->preallocated_nodes_); - // Link new nodes together (as for original list). + // link new nodes together (as for original list) for (size_t k = 1; k < this->max_size_; k++) this->preallocated_nodes_[k - 1].next_ = &this->preallocated_nodes_[k]; @@ -278,7 +279,7 @@ ACE_Timer_Heap::grow_heap (void) // NULL-terminate the new list. this->preallocated_nodes_[this->max_size_ - 1].next_ = 0; - // Link new array to the end of the existling list. + // link new array to the end of the existling list if (this->preallocated_nodes_freelist_ == 0) this->preallocated_nodes_freelist_ = &preallocated_nodes_[0]; else @@ -287,7 +288,7 @@ ACE_Timer_Heap::grow_heap (void) for (ACE_Timer_Node* current = this->preallocated_nodes_freelist_->next_; current != 0; - current = current->next_) + current = current->next_) previous = current; previous->next_ = &this->preallocated_nodes_[0]; diff --git a/ace/Timer_Heap.h b/ace/Timer_Heap.h index b52d7b0fadd..04c9bb11dd3 100644 --- a/ace/Timer_Heap.h +++ b/ace/Timer_Heap.h @@ -47,6 +47,9 @@ protected: // Pointer to the <ACE_Timer_Heap> that we are iterating over. }; +// Forward declaration. +class ACE_Upcall_Strategy; + class ACE_Export ACE_Timer_Heap : public ACE_Timer_Queue // = TITLE // Provides a very fast and predictable timer implementation. @@ -65,7 +68,8 @@ class ACE_Export ACE_Timer_Heap : public ACE_Timer_Queue public: // = Initialization and termination methods. ACE_Timer_Heap (size_t size = ACE_DEFAULT_TIMERS, - int preallocated = 0); + int preallocated = 0, + ACE_Upcall_Strategy *upcall_strategy = 0); // The Constructor creates a heap with <size> elements. If // <preallocated> is non-0 then we'll pre-allocate all the memory // for the <ACE_Timer_Nodes>. This saves time and is more diff --git a/ace/Timer_List.cpp b/ace/Timer_List.cpp index 02773ef5019..75d107d7173 100644 --- a/ace/Timer_List.cpp +++ b/ace/Timer_List.cpp @@ -3,6 +3,7 @@ #define ACE_BUILD_DLL #include "ace/Timer_List.h" +#include "ace/Strategies.h" ACE_Timer_List_Iterator::ACE_Timer_List_Iterator (ACE_Timer_List &list) : timer_list_ (list) @@ -34,8 +35,9 @@ ACE_Timer_List::iter (void) // Create an empty list. -ACE_Timer_List::ACE_Timer_List (void) - : head_ (0), +ACE_Timer_List::ACE_Timer_List (ACE_Upcall_Strategy *upcall_strategy) + : ACE_Timer_Queue (upcall_strategy), + head_ (0), iterator_ (*this), timer_id_ (0) { diff --git a/ace/Timer_List.h b/ace/Timer_List.h index 95b4157d215..d4411080746 100644 --- a/ace/Timer_List.h +++ b/ace/Timer_List.h @@ -46,6 +46,9 @@ protected: // Pointer to the <ACE_Timer_List> that we are iterating over. }; +// Forward declaration. +class ACE_Upcall_Strategy; + class ACE_Export ACE_Timer_List : public ACE_Timer_Queue // = TITLE // Provides a simple implementation of timers. @@ -68,7 +71,7 @@ class ACE_Export ACE_Timer_List : public ACE_Timer_Queue friend class ACE_Timer_List_Iterator; public: // = Initialization and termination methods. - ACE_Timer_List (void); + ACE_Timer_List (ACE_Upcall_Strategy *upcall_strategy = 0); // Default constructor. virtual ~ACE_Timer_List (void); diff --git a/ace/Timer_Queue.cpp b/ace/Timer_Queue.cpp index b5c9c964d12..e7342315f4d 100644 --- a/ace/Timer_Queue.cpp +++ b/ace/Timer_Queue.cpp @@ -3,6 +3,7 @@ #define ACE_BUILD_DLL #include "ace/Timer_Queue.h" +#include "ace/Strategies.h" #if !defined (__ACE_INLINE__) #include "ace/Timer_Queue.i" @@ -108,9 +109,10 @@ ACE_Timer_Queue::dump (void) const ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } -ACE_Timer_Queue::ACE_Timer_Queue (void) +ACE_Timer_Queue::ACE_Timer_Queue (ACE_Upcall_Strategy *upcall_strategy) : gettimeofday_ (ACE_OS::gettimeofday), - timer_skew_ (0, ACE_TIMER_SKEW) + timer_skew_ (0, ACE_TIMER_SKEW), + upcall_strategy_ (upcall_strategy) { ACE_TRACE ("ACE_Timer_Queue::ACE_Timer_Queue"); } @@ -160,9 +162,7 @@ ACE_Timer_Queue::expire (const ACE_Time_Value &cur_time) reclaim = 0; } - // Perform the callback. - if (handler->handle_timeout (cur_time, arg) == -1) - this->cancel (handler, 0); // 0 means "call handle_close()". + this->upcall (handler, arg, cur_time); if (reclaim) // Call the factory method to free up the node. @@ -174,6 +174,23 @@ ACE_Timer_Queue::expire (const ACE_Time_Value &cur_time) return number_of_timers_expired; } +void +ACE_Timer_Queue::upcall (ACE_Event_Handler *handler, + const void *arg, + const ACE_Time_Value &cur_time) +{ + if (this->upcall_strategy_ == 0) + { + // Perform the callback. + if (handler->handle_timeout (cur_time, arg) == -1) + this->cancel (handler, 0); // 0 means "call handle_close()". + } + else + // Pass the information along to the strategy + this->upcall_strategy_->upcall (handler, arg, cur_time); +} + + ACE_Time_Value ACE_Timer_Queue::gettimeofday (void) { @@ -187,3 +204,13 @@ ACE_Timer_Queue::gettimeofday (ACE_Time_Value (*gettimeofday)(void)) gettimeofday_ = gettimeofday; } +#if defined (ACE_MT_SAFE) + +ACE_Recursive_Thread_Mutex & +ACE_Timer_Queue::lock (void) +{ + return this->lock_; +} + +#endif /* ACE_MT_SAFE */ + diff --git a/ace/Timer_Queue.h b/ace/Timer_Queue.h index cdf0ee9ef9d..6c5fa062020 100644 --- a/ace/Timer_Queue.h +++ b/ace/Timer_Queue.h @@ -97,6 +97,9 @@ public: // seen, else 1. }; +// Forward declaration. +class ACE_Upcall_Strategy; + class ACE_Export ACE_Timer_Queue // = TITLE // Provides an interface to timers. @@ -108,8 +111,10 @@ class ACE_Export ACE_Timer_Queue { public: // = Initialization and termination methods. - ACE_Timer_Queue (void); - // Default constructor. + ACE_Timer_Queue (ACE_Upcall_Strategy *upcall_strategy = 0); + // Default constructor. <expire> will call <upcall_strategy->upcall> + // if <upcall_strategy> is not 0. Else it will call <handle_timeout> + // on the <Event_Handler> virtual ~ACE_Timer_Queue (void); // Destructor - make virtual for proper destruction of inherited @@ -187,6 +192,11 @@ public: void timer_skew (const ACE_Time_Value &skew); const ACE_Time_Value &timer_skew (void) const; +#if defined (ACE_MT_SAFE) + ACE_Recursive_Thread_Mutex &lock (void); + // Synchronization variable used by the queue +#endif /* ACE_MT_SAFE */ + virtual void dump (void) const; // Dump the state of an object. @@ -194,6 +204,13 @@ public: // Declare the dynamic allocation hooks. protected: + + virtual void upcall (ACE_Event_Handler *handler, + const void *arg, + const ACE_Time_Value &cur_time); + // This method will call <handle_timeout> on the <handler> or will + // forward the parameters to an upcall strategy (if one is present) + virtual void reschedule (ACE_Timer_Node *) = 0; // Reschedule an "interval" <ACE_Timer_Node>. @@ -214,6 +231,9 @@ protected: ACE_Time_Value (*gettimeofday_)(void); // Pointer to function that returns the current time of day. + ACE_Upcall_Strategy *upcall_strategy_; + // Upcall Strategy for callbacks + private: ACE_Time_Value timeout_; // Returned by <calculate_timeout>. diff --git a/examples/Reactor/Proactor/test_proactor.mak b/examples/Reactor/Proactor/test_proactor.mak index 2579cccae78..ee0650f7bdb 100644 --- a/examples/Reactor/Proactor/test_proactor.mak +++ b/examples/Reactor/Proactor/test_proactor.mak @@ -4,25 +4,24 @@ # TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
-CFG=test_proactor - Win32 Debug
-!MESSAGE No configuration specified. Defaulting to test_proactor - Win32\
- Debug.
+CFG=test_timeout - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to test_timeout - Win32 Debug.
!ENDIF
-!IF "$(CFG)" != "test_proactor - Win32 Release" && "$(CFG)" !=\
- "test_proactor - Win32 Debug"
+!IF "$(CFG)" != "test_proactor - Win32 Debug" && "$(CFG)" !=\
+ "test_timeout - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
-!MESSAGE NMAKE /f "test_proactor.mak" CFG="test_proactor - Win32 Debug"
+!MESSAGE NMAKE /f "test_proactor.mak" CFG="test_timeout - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
-!MESSAGE "test_proactor - Win32 Release" (based on\
- "Win32 (x86) Console Application")
!MESSAGE "test_proactor - Win32 Debug" (based on\
"Win32 (x86) Console Application")
+!MESSAGE "test_timeout - Win32 Debug" (based on\
+ "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
@@ -34,30 +33,45 @@ NULL=nul !ENDIF
################################################################################
# Begin Project
+# PROP Target_Last_Scanned "test_proactor - Win32 Debug"
RSC=rc.exe
CPP=cl.exe
-!IF "$(CFG)" == "test_proactor - Win32 Release"
+!IF "$(CFG)" == "test_proactor - Win32 Debug"
# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Use_Debug_Libraries 1
# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-OUTDIR=.
-INTDIR=.
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "."
+# PROP Intermediate_Dir "debug"
+OUTDIR=.\.
+INTDIR=.\debug
ALL : "$(OUTDIR)\test_proactor.exe"
CLEAN :
-@erase "$(INTDIR)\test_proactor.obj"
+ -@erase "$(INTDIR)\vc40.idb"
+ -@erase "$(INTDIR)\vc40.pdb"
-@erase "$(OUTDIR)\test_proactor.exe"
+ -@erase "$(OUTDIR)\test_proactor.ilk"
+ -@erase "$(OUTDIR)\test_proactor.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
-# ADD CPP /nologo /MDd /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
-CPP_PROJ=/nologo /MDd /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
- /Fp"test_proactor.pch" /YX /c
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
+ /Fp"$(INTDIR)/test_proactor.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\debug/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
@@ -65,12 +79,12 @@ BSC32_FLAGS=/nologo /o"$(OUTDIR)/test_proactor.bsc" BSC32_SBRS= \
LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 ace.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 ace.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
LINK32_FLAGS=ace.lib kernel32.lib user32.lib gdi32.lib winspool.lib\
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\
- odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no\
- /pdb:"$(OUTDIR)/test_proactor.pdb" /machine:I386\
+ odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:yes\
+ /pdb:"$(OUTDIR)/test_proactor.pdb" /debug /machine:I386\
/out:"$(OUTDIR)/test_proactor.exe"
LINK32_OBJS= \
"$(INTDIR)\test_proactor.obj"
@@ -80,35 +94,49 @@ LINK32_OBJS= \ $(LINK32_FLAGS) $(LINK32_OBJS)
<<
-!ELSEIF "$(CFG)" == "test_proactor - Win32 Debug"
+!ELSEIF "$(CFG)" == "test_timeout - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "test_timeout\Debug"
+# PROP BASE Intermediate_Dir "test_timeout\Debug"
+# PROP BASE Target_Dir "test_timeout"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
-OUTDIR=.
-INTDIR=.
+# PROP Output_Dir "."
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir "test_timeout"
+OUTDIR=.\.
+INTDIR=.\Debug
-ALL : "$(OUTDIR)\test_proactor.exe"
+ALL : "$(OUTDIR)\test_timeout.exe"
CLEAN :
- -@erase "$(INTDIR)\test_proactor.obj"
+ -@erase "$(INTDIR)\test_timeout.obj"
-@erase "$(INTDIR)\vc40.idb"
-@erase "$(INTDIR)\vc40.pdb"
- -@erase "$(OUTDIR)\test_proactor.exe"
- -@erase "$(OUTDIR)\test_proactor.ilk"
- -@erase "$(OUTDIR)\test_proactor.pdb"
+ -@erase "$(OUTDIR)\test_timeout.exe"
+ -@erase "$(OUTDIR)\test_timeout.ilk"
+ -@erase "$(OUTDIR)\test_timeout.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
- /Fp"test_proactor.pch" /YX /c
+ /Fp"$(INTDIR)/test_timeout.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=.\.
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/test_proactor.bsc"
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/test_timeout.bsc"
BSC32_SBRS= \
LINK32=link.exe
@@ -117,48 +145,40 @@ LINK32=link.exe LINK32_FLAGS=ace.lib kernel32.lib user32.lib gdi32.lib winspool.lib\
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\
odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:yes\
- /pdb:"$(OUTDIR)/test_proactor.pdb" /debug /machine:I386\
- /out:"$(OUTDIR)/test_proactor.exe"
+ /pdb:"$(OUTDIR)/test_timeout.pdb" /debug /machine:I386\
+ /out:"$(OUTDIR)/test_timeout.exe"
LINK32_OBJS= \
- "$(INTDIR)\test_proactor.obj"
+ "$(INTDIR)\test_timeout.obj"
-"$(OUTDIR)\test_proactor.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+"$(OUTDIR)\test_timeout.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
-.c.obj:
+.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
-.cpp.obj:
+.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
-.cxx.obj:
+.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
-.c.sbr:
+.c{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
-.cpp.sbr:
+.cpp{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
-.cxx.sbr:
+.cxx{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Target
-# Name "test_proactor - Win32 Release"
# Name "test_proactor - Win32 Debug"
-
-!IF "$(CFG)" == "test_proactor - Win32 Release"
-
-!ELSEIF "$(CFG)" == "test_proactor - Win32 Debug"
-
-!ENDIF
-
################################################################################
# Begin Source File
@@ -278,5 +298,130 @@ DEP_CPP_TEST_=\ # End Source File
# End Target
+################################################################################
+# Begin Target
+
+# Name "test_timeout - Win32 Debug"
+################################################################################
+# Begin Source File
+
+SOURCE=.\test_timeout.cpp
+DEP_CPP_TEST_T=\
+ {$(INCLUDE)}"\ace\ACE.h"\
+ {$(INCLUDE)}"\ace\ACE.i"\
+ {$(INCLUDE)}"\ace\Addr.h"\
+ {$(INCLUDE)}"\ace\Addr.i"\
+ {$(INCLUDE)}"\ace\Asynch_IO.h"\
+ {$(INCLUDE)}"\ace\Asynch_IO.i"\
+ {$(INCLUDE)}"\ace\config-win32-common.h"\
+ {$(INCLUDE)}"\ace\config.h"\
+ {$(INCLUDE)}"\ace\Event_Handler.h"\
+ {$(INCLUDE)}"\ace\Event_Handler.i"\
+ {$(INCLUDE)}"\ace\Handle_Set.h"\
+ {$(INCLUDE)}"\ace\Handle_Set.i"\
+ {$(INCLUDE)}"\ace\INET_Addr.h"\
+ {$(INCLUDE)}"\ace\INET_Addr.i"\
+ {$(INCLUDE)}"\ace\IO_Cntl_Msg.h"\
+ {$(INCLUDE)}"\ace\IPC_SAP.h"\
+ {$(INCLUDE)}"\ace\IPC_SAP.i"\
+ {$(INCLUDE)}"\ace\Local_Tokens.h"\
+ {$(INCLUDE)}"\ace\Local_Tokens.i"\
+ {$(INCLUDE)}"\ace\Log_Msg.h"\
+ {$(INCLUDE)}"\ace\Log_Priority.h"\
+ {$(INCLUDE)}"\ace\Log_Record.h"\
+ {$(INCLUDE)}"\ace\Log_Record.i"\
+ {$(INCLUDE)}"\ace\Malloc.h"\
+ {$(INCLUDE)}"\ace\Malloc.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.cpp"\
+ {$(INCLUDE)}"\ace\Malloc_T.h"\
+ {$(INCLUDE)}"\ace\Malloc_T.i"\
+ {$(INCLUDE)}"\ace\Map_Manager.cpp"\
+ {$(INCLUDE)}"\ace\Map_Manager.h"\
+ {$(INCLUDE)}"\ace\Map_Manager.i"\
+ {$(INCLUDE)}"\ace\Mem_Map.h"\
+ {$(INCLUDE)}"\ace\Mem_Map.i"\
+ {$(INCLUDE)}"\ace\Memory_Pool.h"\
+ {$(INCLUDE)}"\ace\Memory_Pool.i"\
+ {$(INCLUDE)}"\ace\Message_Block.h"\
+ {$(INCLUDE)}"\ace\Message_Block.i"\
+ {$(INCLUDE)}"\ace\Message_Queue.cpp"\
+ {$(INCLUDE)}"\ace\Message_Queue.h"\
+ {$(INCLUDE)}"\ace\Message_Queue.i"\
+ {$(INCLUDE)}"\ace\Module.cpp"\
+ {$(INCLUDE)}"\ace\Module.h"\
+ {$(INCLUDE)}"\ace\Module.i"\
+ {$(INCLUDE)}"\ace\OS.h"\
+ {$(INCLUDE)}"\ace\OS.i"\
+ {$(INCLUDE)}"\ace\Pipe.h"\
+ {$(INCLUDE)}"\ace\Pipe.i"\
+ {$(INCLUDE)}"\ace\Proactor.h"\
+ {$(INCLUDE)}"\ace\Proactor.i"\
+ {$(INCLUDE)}"\ace\Reactor.h"\
+ {$(INCLUDE)}"\ace\Reactor.i"\
+ {$(INCLUDE)}"\ace\ReactorEx.h"\
+ {$(INCLUDE)}"\ace\ReactorEx.i"\
+ {$(INCLUDE)}"\ace\Service_Config.h"\
+ {$(INCLUDE)}"\ace\Service_Config.i"\
+ {$(INCLUDE)}"\ace\Service_Object.h"\
+ {$(INCLUDE)}"\ace\Service_Object.i"\
+ {$(INCLUDE)}"\ace\Set.cpp"\
+ {$(INCLUDE)}"\ace\Set.h"\
+ {$(INCLUDE)}"\ace\Set.i"\
+ {$(INCLUDE)}"\ace\Shared_Object.h"\
+ {$(INCLUDE)}"\ace\Shared_Object.i"\
+ {$(INCLUDE)}"\ace\Signal.h"\
+ {$(INCLUDE)}"\ace\Signal.i"\
+ {$(INCLUDE)}"\ace\SOCK.h"\
+ {$(INCLUDE)}"\ace\SOCK.i"\
+ {$(INCLUDE)}"\ace\SOCK_IO.h"\
+ {$(INCLUDE)}"\ace\SOCK_IO.i"\
+ {$(INCLUDE)}"\ace\SOCK_Stream.h"\
+ {$(INCLUDE)}"\ace\SOCK_Stream.i"\
+ {$(INCLUDE)}"\ace\SString.h"\
+ {$(INCLUDE)}"\ace\SString.i"\
+ {$(INCLUDE)}"\ace\Stack.cpp"\
+ {$(INCLUDE)}"\ace\Stack.h"\
+ {$(INCLUDE)}"\ace\Stack.i"\
+ {$(INCLUDE)}"\ace\stdcpp.h"\
+ {$(INCLUDE)}"\ace\Strategies.h"\
+ {$(INCLUDE)}"\ace\Strategies_T.cpp"\
+ {$(INCLUDE)}"\ace\Strategies_T.h"\
+ {$(INCLUDE)}"\ace\Stream_Modules.cpp"\
+ {$(INCLUDE)}"\ace\Stream_Modules.h"\
+ {$(INCLUDE)}"\ace\Stream_Modules.i"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Complex.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Complex.i"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Simple.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Simple.i"\
+ {$(INCLUDE)}"\ace\Svc_Conf_Tokens.h"\
+ {$(INCLUDE)}"\ace\Synch.h"\
+ {$(INCLUDE)}"\ace\Synch.i"\
+ {$(INCLUDE)}"\ace\Synch_Options.h"\
+ {$(INCLUDE)}"\ace\Synch_T.cpp"\
+ {$(INCLUDE)}"\ace\Synch_T.h"\
+ {$(INCLUDE)}"\ace\Synch_T.i"\
+ {$(INCLUDE)}"\ace\Task.h"\
+ {$(INCLUDE)}"\ace\Task.i"\
+ {$(INCLUDE)}"\ace\Task_T.cpp"\
+ {$(INCLUDE)}"\ace\Task_T.h"\
+ {$(INCLUDE)}"\ace\Task_T.i"\
+ {$(INCLUDE)}"\ace\Thread.h"\
+ {$(INCLUDE)}"\ace\Thread.i"\
+ {$(INCLUDE)}"\ace\Thread_Manager.h"\
+ {$(INCLUDE)}"\ace\Thread_Manager.i"\
+ {$(INCLUDE)}"\ace\Time_Value.h"\
+ {$(INCLUDE)}"\ace\Timer_Queue.h"\
+ {$(INCLUDE)}"\ace\Timer_Queue.i"\
+ {$(INCLUDE)}"\ace\Token.h"\
+ {$(INCLUDE)}"\ace\Token.i"\
+ {$(INCLUDE)}"\ace\Trace.h"\
+ {$(INCLUDE)}"\ace\ws2tcpip.h"\
+
+
+"$(INTDIR)\test_timeout.obj" : $(SOURCE) $(DEP_CPP_TEST_T) "$(INTDIR)"
+
+
+# End Source File
+# End Target
# End Project
################################################################################
diff --git a/examples/Reactor/Proactor/test_proactor.mdp b/examples/Reactor/Proactor/test_proactor.mdp Binary files differindex d03e368531f..14d0497de94 100644 --- a/examples/Reactor/Proactor/test_proactor.mdp +++ b/examples/Reactor/Proactor/test_proactor.mdp diff --git a/examples/Reactor/Proactor/test_timeout.cpp b/examples/Reactor/Proactor/test_timeout.cpp new file mode 100644 index 00000000000..55a36ccc93d --- /dev/null +++ b/examples/Reactor/Proactor/test_timeout.cpp @@ -0,0 +1,92 @@ +// $Id: test_timeout.cpp + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// test_timeout.cpp +// +// = DESCRIPTION +// +// This example application shows how to write event loops that +// handle events for some fixed amount of time. Note that any +// thread in the Proactor thread pool can call back the handler +// +// = AUTHOR +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/Proactor.h" +#include "ace/Synch.h" +#include "ace/Task.h" + +class Timeout_Handler : public ACE_Handler +// = TITLE +// Generic timeout handler. +{ +public: + Timeout_Handler (void) + { + } + + virtual void handle_timeout (const ACE_Time_Value &tv, + const void *arg) + // Print out when timeouts occur. + { + ACE_DEBUG ((LM_DEBUG, "(%t) %d timeout occurred for %s @ %d.\n", + ++count_, + (char *) arg, + tv.sec ())); + // Sleep for a while + ACE_OS::sleep (4); + } + +private: + ACE_Atomic_Op <ACE_Thread_Mutex, int> count_; +}; + +class Worker : public ACE_Task <ACE_NULL_SYNCH> +{ +public: + int svc (void) + { + // Handle events for 13 seconds. + ACE_Time_Value run_time (13); + + if (ACE_Service_Config::run_proactor_event_loop (run_time) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "Worker::svc"), -1); + else + ACE_DEBUG ((LM_DEBUG, "(%t) work complete\n")); + + return 0; + } +}; + +int +main () +{ + Timeout_Handler handler; + + // Register a 2 second timer. + ACE_Time_Value foo_tv (2); + ACE_Service_Config::proactor ()->schedule_timer (handler, + (void *) "Foo", + ACE_Time_Value::zero, + foo_tv); + // Register a 3 second timer. + ACE_Time_Value bar_tv (3); + ACE_Service_Config::proactor ()->schedule_timer (handler, + (void *) "Bar", + ACE_Time_Value::zero, + bar_tv); + + Worker worker; + if (worker.activate (THR_NEW_LWP, 10) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1); + + ACE_Service_Config::thr_mgr ()->wait (); + return 0; +} |