Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

TP_Reactor.h

Go to the documentation of this file.
00001 /* -*- C++ -*- */
00002 
00003 //=============================================================================
00004 /**
00005  *  @file    TP_Reactor.h
00006  *
00007  *  $Id: TP_Reactor.h,v 1.1.1.4 2003/02/21 18:36:32 chad Exp $
00008  *
00009  *  The <ACE_TP_Reactor> (aka, Thread Pool Reactor) uses the
00010  *  Leader/Followers pattern to demultiplex events among a pool of
00011  *  threads.  When using a thread pool reactor, an application
00012  *  pre-spawns a _fixed_ number of threads.  When these threads
00013  *  invoke the <ACE_TP_Reactor>'s <handle_events> method, one thread
00014  *  will become the leader and wait for an event.  The other
00015  *  follower threads will queue up waiting for their turn to become
00016  *  the leader.  When an event occurs, the leader will pick a
00017  *  follower to become the leader and go on to handle the event.
00018  *  The consequence of using <ACE_TP_Reactor> is the amortization of
00019  *  the costs used to creating threads.  The context switching cost
00020  *  will also reduce.  More over, the total resources used by
00021  *  threads are bounded because there are a fixed number of threads.
00022  *
00023  *
00024  *  @author Irfan Pyarali <irfan@cs.wustl.edu>
00025  *  @author Nanbor Wang <nanbor@cs.wustl.edu>
00026  */
00027 //=============================================================================
00028 
00029 
00030 #ifndef ACE_TP_REACTOR_H
00031 #define ACE_TP_REACTOR_H
00032 #include "ace/pre.h"
00033 
00034 #include "ace/Select_Reactor.h"
00035 #include "ace/Log_Msg.h"
00036 
00037 #if !defined (ACE_LACKS_PRAGMA_ONCE)
00038 # pragma once
00039 #endif /* ACE_LACKS_PRAGMA_ONCE */
00040 
00041 /**
00042  * @class ACE_EH_Dispatch_Info
00043  *
00044  * @brief This structure contains information of the activated event
00045  * handler.
00046  */
00047 class ACE_Export ACE_EH_Dispatch_Info
00048 {
00049 public:
00050 
00051   ACE_EH_Dispatch_Info (void);
00052 
00053   void set (ACE_HANDLE handle,
00054             ACE_Event_Handler *event_handler,
00055             ACE_Reactor_Mask mask,
00056             ACE_EH_PTMF callback);
00057 
00058   void reset (void);
00059 
00060   int dispatch (void) const;
00061 
00062   ACE_HANDLE handle_;
00063   ACE_Event_Handler *event_handler_;
00064   ACE_Reactor_Mask mask_;
00065   ACE_EH_PTMF callback_;
00066 
00067   int dispatch_;
00068 
00069 private:
00070   ACE_UNIMPLEMENTED_FUNC (ACE_EH_Dispatch_Info (const ACE_EH_Dispatch_Info &))
00071   ACE_UNIMPLEMENTED_FUNC (ACE_EH_Dispatch_Info &operator= (const ACE_EH_Dispatch_Info &))
00072 };
00073 
00074 
00075 /**
00076  * @class ACE_TP_Token_Guard
00077  *
00078  * @brief A helper class that helps grabbing, releasing and waiting
00079  * on tokens for a thread that tries calling handle_events ().
00080  *
00081  * In short, this class will be owned by one thread by creating on the
00082  * stack. This class gives the status of the ownership of the token
00083  * and manages the ownership
00084  */
00085 
00086 class ACE_Export ACE_TP_Token_Guard
00087 {
00088 public:
00089 
00090   /// Constructor that will grab the token for us
00091   ACE_TP_Token_Guard (ACE_Select_Reactor_Token &token);
00092 
00093   /// Destructor. This will release the token if it hasnt been
00094   /// released till this point
00095   ~ACE_TP_Token_Guard (void);
00096 
00097   /// Release the token ..
00098   void release_token (void);
00099 
00100   /// Returns whether the thread that created this object ownes the
00101   /// token or not.
00102   int is_owner (void);
00103 
00104   /// A helper method that grabs the token for us, after which the
00105   /// thread that owns that can do some actual work.
00106   /// @todo Should probably be called acquire_read_token ()
00107   int grab_token (ACE_Time_Value *max_wait_time = 0);
00108 
00109   /**
00110    * A helper method that grabs the token for us, after which the
00111    * thread that owns that can do some actual work. This differs from
00112    * grab_token () as it uses acquire () to get the token instead of
00113    * acquire_read ()
00114    */
00115   int acquire_token (ACE_Time_Value *max_wait_time = 0);
00116 
00117 private:
00118 
00119   /// The Select Reactor token.
00120   ACE_Select_Reactor_Token &token_;
00121 
00122   /// Flag that indicate whether the thread that created this object
00123   /// owns the token or not. A value of 0 indicates that this class
00124   /// hasnt got the token (and hence the thread) and a value of 1
00125   /// vice-versa.
00126   int owner_;
00127 
00128 private:
00129 
00130   ACE_UNIMPLEMENTED_FUNC (ACE_TP_Token_Guard (void))
00131 };
00132 
00133 /**
00134  * @class ACE_TP_Reactor
00135  *
00136  * @brief Specialization of Select Reactor to support thread-pool based
00137  * event dispatching.
00138  *
00139  * One of the short comings of the Select_Reactor in ACE is that
00140  * it did not support a thread pool based event dispatching
00141  * model, similar to the one in WFMO_Reactor.  In
00142  * Select_Reactor, only thread can be blocked in <handle_events>
00143  * at any given time.
00144  * A new Reactor has been added to ACE that removes this
00145  * short-coming.  TP_Reactor is a specialization of Select
00146  * Reactor to support thread-pool based event dispatching. This
00147  * Reactor takes advantage of the fact that events reported by
00148  * <select> are persistent if not acted upon immediately.  It
00149  * works by remembering the event handler that just got
00150  * activated, releasing the internal lock (so that some other
00151  * thread can start waiting in the event loop) and then
00152  * dispatching the event handler outside the context of the
00153  * Reactor lock.
00154  * This Reactor is best suited for situations when the callbacks
00155  * to event handlers can take arbitrarily long and/or a number
00156  * of threads are available to run the event loops.
00157  * Note that callback code in Event Handlers
00158  * (e.g. Event_Handler::handle_input) does not have to be
00159  * modified or made thread-safe for this Reactor.  This is
00160  * because an activated Event Handler is suspended in the
00161  * Reactor before the upcall is made and resumed after the
00162  * upcall completes.  Therefore, one Event Handler cannot be
00163  * called by multiple threads simultaneously.
00164  */
00165 class ACE_Export ACE_TP_Reactor : public ACE_Select_Reactor
00166 {
00167 public:
00168 
00169   // = Initialization and termination methods.
00170 
00171   /// Initialize <ACE_TP_Reactor> with the default size.
00172   ACE_TP_Reactor (ACE_Sig_Handler * = 0,
00173                   ACE_Timer_Queue * = 0,
00174                   int mask_signals = 1,
00175                   int s_queue = ACE_Select_Reactor_Token::FIFO);
00176 
00177   /**
00178    * Initialize the <ACE_TP_Reactor> to manage
00179    * <max_number_of_handles>.  If <restart> is non-0 then the
00180    * <ACE_Reactor>'s <handle_events> method will be restarted
00181    * automatically when <EINTR> occurs.  If <signal_handler> or
00182    * <timer_queue> are non-0 they are used as the signal handler and
00183    * timer queue, respectively.
00184    */
00185   ACE_TP_Reactor (size_t max_number_of_handles,
00186                   int restart = 0,
00187                   ACE_Sig_Handler * = 0,
00188                   ACE_Timer_Queue * = 0,
00189                   int mask_signals = 1,
00190                   int s_queue = ACE_Select_Reactor_Token::FIFO);
00191 
00192   // = Event loop drivers.
00193 
00194   /**
00195    * This event loop driver that blocks for <max_wait_time> before
00196    * returning.  It will return earlier if timer events, I/O events,
00197    * or signal events occur.  Note that <max_wait_time> can be 0, in
00198    * which case this method blocks indefinitely until events occur.
00199    *
00200    * <max_wait_time> is decremented to reflect how much time this call
00201    * took.  For instance, if a time value of 3 seconds is passed to
00202    * handle_events and an event occurs after 2 seconds,
00203    * <max_wait_time> will equal 1 second.  This can be used if an
00204    * application wishes to handle events for some fixed amount of
00205    * time.
00206    *
00207    * Returns the total number of <ACE_Event_Handler>s that were
00208    * dispatched, 0 if the <max_wait_time> elapsed without dispatching
00209    * any handlers, or -1 if something goes wrong.
00210    */
00211   virtual int handle_events (ACE_Time_Value *max_wait_time = 0);
00212 
00213   virtual int handle_events (ACE_Time_Value &max_wait_time);
00214 
00215 
00216   /// The following two overloaded methods are necessary as we dont
00217   /// want the TP_Reactor to call handle_close () with the token
00218   /// held.
00219   /**
00220    * Removes the <mask> binding of <eh> from the Select_Reactor.  If
00221    * there are no more bindings for this <eh> then it is removed from
00222    * the Select_Reactor.  Note that the Select_Reactor will call
00223    * <ACE_Event_Handler::get_handle> to extract the underlying I/O
00224    * handle.
00225    */
00226   virtual int remove_handler (ACE_Event_Handler *eh,
00227                               ACE_Reactor_Mask mask);
00228 
00229   /**
00230    * Removes the <mask> bind of <Event_Handler> whose handle is
00231    * <handle> from the Select_Reactor.  If there are no more bindings
00232    * for this <eh> then it is removed from the Select_Reactor.
00233    */
00234   virtual int remove_handler (ACE_HANDLE handle,
00235                               ACE_Reactor_Mask);
00236 
00237   /**
00238    * Removes all the <mask> bindings for handles in the <handle_set>
00239    * bind of <Event_Handler>.  If there are no more bindings for any
00240    * of these handlers then they are removed from the Select_Reactor.
00241    */
00242   virtual int remove_handler (const ACE_Handle_Set &handle_set,
00243                               ACE_Reactor_Mask);
00244 
00245   /* @todo The following methods are not supported. Support for
00246    * signals is not available in the TP_Reactor. These methods will be
00247    * supported once signal handling is supported. We have to include
00248    * these two methods in the  TP_Reactor to keep some compilers
00249    * silent.
00250    */
00251   /**
00252    * Remove the ACE_Event_Handler currently associated with <signum>.
00253    * <sigkey> is ignored in this implementation since there is only
00254    * one instance of a signal handler.  Install the new disposition
00255    * (if given) and return the previous disposition (if desired by the
00256    * caller).  Returns 0 on success and -1 if <signum> is invalid.
00257    */
00258   virtual int remove_handler (int signum,
00259                               ACE_Sig_Action *new_disp,
00260                               ACE_Sig_Action *old_disp = 0,
00261                               int sigkey = -1);
00262 
00263   /// Calls <remove_handler> for every signal in <sigset>.
00264   virtual int remove_handler (const ACE_Sig_Set &sigset);
00265 
00266   /// Does the reactor allow the application to resume the handle on
00267   /// its own ie. can it pass on the control of handle resumption to
00268   /// the application.  The TP reactor has can allow applications to
00269   /// resume handles.  So return a +ve value.
00270   virtual int resumable_handler (void);
00271 
00272   /// GET/SET/ADD/CLR the dispatch mask "bit" bound with the <eh> and
00273   /// <mask>.
00274   virtual int mask_ops (ACE_Event_Handler *eh,
00275                         ACE_Reactor_Mask mask,
00276                         int ops);
00277 
00278   /// GET/SET/ADD/CLR the dispatch mask "bit" bound with the <handle>
00279   /// and <mask>.
00280   virtual int mask_ops (ACE_HANDLE handle,
00281                         ACE_Reactor_Mask mask,
00282                         int ops);
00283 
00284   /// Called from handle events
00285   static void no_op_sleep_hook (void *);
00286 
00287   // = Any thread can perform a <handle_events>, override the owner()
00288   //   methods to avoid the overhead of setting the owner thread.
00289 
00290   /// Set the new owner of the thread and return the old owner.
00291   virtual int owner (ACE_thread_t n_id, ACE_thread_t *o_id = 0);
00292 
00293   /// Return the current owner of the thread.
00294   virtual int owner (ACE_thread_t *);
00295 
00296   /// Declare the dynamic allocation hooks.
00297   ACE_ALLOC_HOOK_DECLARE;
00298 
00299 protected:
00300   // = Internal methods that do the actual work.
00301 
00302 
00303   /// Dispatch just 1 signal, timer, notification handlers
00304   int dispatch_i (ACE_Time_Value *max_wait_time,
00305                   ACE_TP_Token_Guard &guard);
00306 
00307   /// Get the event that needs dispatching.It could be either a
00308   /// signal, timer, notification handlers or return possibly 1 I/O
00309   /// handler for dispatching. In the most common use case, this would
00310   /// return 1 I/O handler for dispatching
00311   int get_event_for_dispatching (ACE_Time_Value *max_wait_time);
00312 
00313   /// Method to handle signals
00314   /// NOTE: It is just busted at this point in time.
00315   int handle_signals (int &event_count,
00316                       ACE_TP_Token_Guard &g);
00317 
00318   /// Handle timer events
00319   int handle_timer_events (int &event_count,
00320                            ACE_TP_Token_Guard &g);
00321 
00322   /// Handle notify events
00323   int handle_notify_events (int &event_count,
00324                             ACE_TP_Token_Guard &g);
00325 
00326   /// handle socket events
00327   int handle_socket_events (int &event_count,
00328                             ACE_TP_Token_Guard &g);
00329 
00330   /// This method shouldn't get called.
00331   virtual void notify_handle (ACE_HANDLE handle,
00332                               ACE_Reactor_Mask mask,
00333                               ACE_Handle_Set &,
00334                               ACE_Event_Handler *eh,
00335                               ACE_EH_PTMF callback);
00336 private:
00337 
00338   /// Get the handle of the notify pipe from the ready set if there is
00339   /// an event  in the notify pipe.
00340   ACE_HANDLE get_notify_handle (void);
00341 
00342   /// Get socket event dispatch information.
00343   int get_socket_event_info (ACE_EH_Dispatch_Info &info);
00344 
00345   /// Notify the appropriate <callback> in the context of the <eh>
00346   /// associated with <handle> that a particular event has occurred.
00347   int dispatch_socket_event (ACE_EH_Dispatch_Info &dispatch_info);
00348 
00349   /// Clear the <handle> from the read_set
00350   void clear_handle_read_set (ACE_HANDLE handle);
00351 
00352 private:
00353   /// Deny access since member-wise won't work...
00354   ACE_TP_Reactor (const ACE_TP_Reactor &);
00355   ACE_TP_Reactor &operator = (const ACE_TP_Reactor &);
00356 };
00357 
00358 #if defined (__ACE_INLINE__)
00359 #include "ace/TP_Reactor.i"
00360 #endif /* __ACE_INLINE__ */
00361 
00362 #include "ace/post.h"
00363 #endif /* ACE_TP_REACTOR_H */

Generated on Mon Jun 16 11:21:59 2003 for ACE by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002