00001 // -*- C++ -*- 00002 00003 //============================================================================= 00004 /** 00005 * @file Leader_Follower.h 00006 * 00007 * $Id: Leader_Follower.h 81570 2008-05-01 18:30:01Z johnnyw $ 00008 * 00009 * @author Carlos O'Ryan (coryan@cs.wustl.edu) 00010 */ 00011 //============================================================================= 00012 00013 00014 #ifndef TAO_LEADER_FOLLOWER_H 00015 #define TAO_LEADER_FOLLOWER_H 00016 00017 #include /**/ "ace/pre.h" 00018 #include "ace/os_include/os_errno.h" 00019 00020 #if !defined (ACE_LACKS_PRAGMA_ONCE) 00021 # pragma once 00022 #endif /* ACE_LACKS_PRAGMA_ONCE */ 00023 00024 #include "tao/New_Leader_Generator.h" 00025 #include "tao/LF_Follower.h" 00026 #include "ace/Reverse_Lock_T.h" 00027 #include "ace/Intrusive_List.h" 00028 #include "ace/Intrusive_List_Node.h" 00029 #include "ace/OS_NS_Thread.h" 00030 00031 ACE_BEGIN_VERSIONED_NAMESPACE_DECL 00032 class ACE_Reactor; 00033 ACE_END_VERSIONED_NAMESPACE_DECL 00034 00035 TAO_BEGIN_VERSIONED_NAMESPACE_DECL 00036 00037 class TAO_LF_Event; 00038 class TAO_Transport; 00039 class TAO_ORB_Core; 00040 class TAO_ORB_Core_TSS_Resources; 00041 00042 /** 00043 * @class TAO_Leader_Follower 00044 * 00045 * @brief TAO_Leader_Follower 00046 * 00047 * TAO_Leader_Follower 00048 */ 00049 class TAO_Export TAO_Leader_Follower 00050 { 00051 public: 00052 /// Constructor 00053 TAO_Leader_Follower (TAO_ORB_Core *orb_core, 00054 TAO_New_Leader_Generator *new_leader_generator = 0); 00055 00056 /// Destructor 00057 ~TAO_Leader_Follower (void); 00058 00059 /// The current thread has become a server thread (i.e. called 00060 /// ORB::run), update any flags and counters. 00061 int set_event_loop_thread (ACE_Time_Value *max_wait_time); 00062 00063 /// The current thread is not a server thread anymore, reset any 00064 /// flags and counters. 00065 void reset_event_loop_thread (void); 00066 00067 /// This thread is going to perform an upcall, it will no longer be 00068 /// an event loop thread. 00069 void set_upcall_thread (void); 00070 00071 /// Is there any thread running as a leader? 00072 int leader_available (void) const; 00073 00074 /// A server thread is making a request. 00075 void set_client_thread (void); 00076 00077 /// A server thread has finished is making a request. 00078 void reset_client_thread (void); 00079 00080 /// Wait on the Leader/Followers loop until one event happens. 00081 /** 00082 * @param event The event we wait for, the loop iterates until the 00083 * event is sucessful, or it fails due to timeout, and error or a 00084 * connection closed. 00085 * @param transport The transport attached to the event 00086 * @param max_wait_time Limit the time spent on the loop 00087 * @param return Returns -1 on error, 0 or non-zero value 00088 * otherwise. 00089 * 00090 * @todo Document this better, split the Follower code to the 00091 * TAO_LF_Follower class, we probably don't need the transport 00092 * object. 00093 */ 00094 int wait_for_event (TAO_LF_Event *event, 00095 TAO_Transport *transport, 00096 ACE_Time_Value *max_wait_time); 00097 00098 /// The current thread has become the leader thread in the 00099 /// client side leader-follower set. 00100 void set_client_leader_thread (void) ; 00101 00102 /// The current thread is no longer the leader thread in the client 00103 /// side leader-follower set. 00104 void reset_client_leader_thread (void) ; 00105 00106 /// sets the thread ID of the leader thread in the leader-follower 00107 /// model 00108 void set_client_leader_thread (ACE_thread_t thread_ID); 00109 00110 /// checks if we are a leader thread 00111 int is_client_leader_thread (void) const; 00112 00113 /** 00114 * A leader thread is relinquishing its role, unless there are more 00115 * leader threads running pick up a follower (if there is any) to 00116 * play the leader role. 00117 */ 00118 int elect_new_leader (void); 00119 00120 /** @name Follower creation/destructions 00121 * 00122 * The Leader/Followers set acts as a factory for the Follower 00123 * objects. Followers are used to represent a thread blocked 00124 * waiting in the Follower set. 00125 * 00126 * The Leader/Followers abstraction keeps a list of the waiting 00127 * followers, so it can wake up one when the leader thread stops 00128 * handling events. 00129 * 00130 * For performance reasons the Leader/Followers set uses a pool (or 00131 * free-list) to keep Follower objects unattached to any thread. It 00132 * could be tempting to use TSS to keep such followers, after all a 00133 * thread can only need one such Follower object, however, that does 00134 * not work with multiple Leader/Followers sets, consult this bug 00135 * report for more details: 00136 * 00137 * http://ace.cs.wustl.edu/bugzilla/show_bug.cgi?id=296 00138 * 00139 */ 00140 //@{ 00141 /// Allocate a new follower to the caller. 00142 TAO_LF_Follower *allocate_follower (void); 00143 00144 /// The caller has finished using a follower. 00145 void release_follower (TAO_LF_Follower *); 00146 //@} 00147 00148 /** @name Follower Set Operations 00149 * 00150 */ 00151 //@{ 00152 /// Add a new follower to the set 00153 void add_follower (TAO_LF_Follower *follower); 00154 00155 /// Removes a follower from the leader-follower set 00156 void remove_follower (TAO_LF_Follower *follower); 00157 00158 /// Checks if there are any followers available 00159 /** 00160 * @return 1 if there follower set is not empty 00161 */ 00162 int follower_available (void) const; 00163 00164 //@} 00165 00166 /// Get a reference to the underlying mutex 00167 TAO_SYNCH_MUTEX &lock (void); 00168 00169 /// Provide a pre-initialized reverse lock for the Leader/Followers 00170 /// set. 00171 /** 00172 * The Leader/Followers set mutex must be release during some long 00173 * running operations. This helper class simplifies the process of 00174 * releasing and reacquiring said mutex. 00175 */ 00176 ACE_Reverse_Lock<TAO_SYNCH_MUTEX> &reverse_lock (void); 00177 00178 /// Check if there are any client threads running 00179 int has_clients (void) const; 00180 00181 /// Accesor to the reactor 00182 ACE_Reactor *reactor (void); 00183 00184 /// Called when we are out of leaders. 00185 void no_leaders_available (void); 00186 00187 private: 00188 /// Shortcut to obtain the TSS resources of the orb core. 00189 TAO_ORB_Core_TSS_Resources *get_tss_resources (void) const; 00190 00191 /// Wait for the client leader to complete. 00192 int wait_for_client_leader_to_complete (ACE_Time_Value *max_wait_time); 00193 00194 /** 00195 * Implement the reset_event_loop_thread() method, once the TSS 00196 * resources have been acquired. 00197 * Also used in the set_upcall_thread. 00198 */ 00199 void reset_event_loop_thread_i (TAO_ORB_Core_TSS_Resources *tss); 00200 00201 /** @name Follower Set Operations 00202 * 00203 */ 00204 //@{ 00205 /// Remote a follower from the Followers set and promote it to the 00206 /// leader role. 00207 /** 00208 * This is a helper routine for elect_new_leader(), after verifying 00209 * that all the pre-conditions are satisfied the Follower set is 00210 * changed and the promoted Follower is signaled. 00211 */ 00212 int elect_new_leader_i (void); 00213 00214 //@} 00215 00216 private: 00217 /// The orb core 00218 TAO_ORB_Core *orb_core_; 00219 00220 /// To synchronize access to the members. 00221 TAO_SYNCH_MUTEX lock_; 00222 00223 /// Do protect the access to the following three members 00224 ACE_Reverse_Lock<TAO_SYNCH_MUTEX> reverse_lock_; 00225 00226 /// Implement the Leader/Followers set using an intrusive list 00227 typedef ACE_Intrusive_List<TAO_LF_Follower> Follower_Set; 00228 Follower_Set follower_set_; 00229 00230 /// Use a free list to allocate and release Follower objects 00231 Follower_Set follower_free_list_; 00232 00233 /** 00234 * Count the number of active leaders. 00235 * There could be many leaders in the thread pool (i.e. calling 00236 * ORB::run), and the same leader could show up multiple times as it 00237 * receives nested upcalls and sends more requests. 00238 */ 00239 int leaders_; 00240 00241 /// Count the number of active clients, this is useful to know when 00242 /// to deactivate the reactor 00243 int clients_; 00244 00245 /// The reactor 00246 ACE_Reactor *reactor_; 00247 00248 /// Is a client thread the current leader? 00249 int client_thread_is_leader_; 00250 00251 /// Are server threads waiting for the client leader to complete? 00252 int event_loop_threads_waiting_; 00253 00254 /// Condition variable for server threads waiting for the client 00255 /// leader to complete. 00256 TAO_SYNCH_CONDITION event_loop_threads_condition_; 00257 00258 /// Leader/Follower class uses this method to notify the system that 00259 /// we are out of leaders. 00260 TAO_New_Leader_Generator *new_leader_generator_; 00261 }; 00262 00263 class TAO_Export TAO_LF_Client_Thread_Helper 00264 { 00265 public: 00266 /// Constructor 00267 TAO_LF_Client_Thread_Helper (TAO_Leader_Follower &leader_follower); 00268 00269 /// Destructor 00270 ~TAO_LF_Client_Thread_Helper (void); 00271 00272 private: 00273 /// Reference to leader/followers object. 00274 TAO_Leader_Follower &leader_follower_; 00275 }; 00276 00277 class TAO_Export TAO_LF_Client_Leader_Thread_Helper 00278 { 00279 public: 00280 /// Constructor 00281 TAO_LF_Client_Leader_Thread_Helper (TAO_Leader_Follower &leader_follower); 00282 00283 /// Destructor 00284 ~TAO_LF_Client_Leader_Thread_Helper (void); 00285 00286 private: 00287 /// Reference to leader/followers object. 00288 TAO_Leader_Follower &leader_follower_; 00289 }; 00290 00291 TAO_END_VERSIONED_NAMESPACE_DECL 00292 00293 #if defined (__ACE_INLINE__) 00294 # include "tao/Leader_Follower.inl" 00295 #endif /* __ACE_INLINE__ */ 00296 00297 #include /**/ "ace/post.h" 00298 00299 #endif /* TAO_LEADER_FOLLOWER_H */