3 //=============================================================================
5 * @file Leader_Follower.h
7 * @author Carlos O'Ryan (coryan@cs.wustl.edu)
9 //=============================================================================
12 #ifndef TAO_LEADER_FOLLOWER_H
13 #define TAO_LEADER_FOLLOWER_H
15 #include /**/ "ace/pre.h"
16 #include "ace/os_include/os_errno.h"
18 #if !defined (ACE_LACKS_PRAGMA_ONCE)
20 #endif /* ACE_LACKS_PRAGMA_ONCE */
22 #include "tao/New_Leader_Generator.h"
23 #include "tao/LF_Follower.h"
24 #include "ace/Reverse_Lock_T.h"
25 #include "ace/Intrusive_List.h"
26 #include "ace/Intrusive_List_Node.h"
27 #include "ace/OS_NS_Thread.h"
28 #include "ace/Event_Handler.h"
30 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
32 ACE_END_VERSIONED_NAMESPACE_DECL
34 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
39 class TAO_ORB_Core_TSS_Resources
;
42 * @class TAO_Leader_Follower
44 * @brief TAO_Leader_Follower
48 class TAO_Export TAO_Leader_Follower
52 TAO_Leader_Follower (TAO_ORB_Core
*orb_core
,
53 TAO_New_Leader_Generator
*new_leader_generator
= 0);
56 ~TAO_Leader_Follower ();
58 /// The current thread has become a server thread (i.e. called
59 /// ORB::run), update any flags and counters.
60 int set_event_loop_thread (ACE_Time_Value
*max_wait_time
);
62 /// The current thread is not a server thread anymore, reset any
63 /// flags and counters.
64 void reset_event_loop_thread ();
66 /// This thread is going to perform an upcall, it will no longer be
67 /// an event loop thread.
68 void set_upcall_thread ();
70 /// Is there any thread running as a leader?
71 bool leader_available () const;
73 /// A server thread is making a request.
74 void set_client_thread ();
76 /// A server thread has finished is making a request.
77 void reset_client_thread ();
79 /// Wait on the Leader/Followers loop until one event happens.
81 * @param event The event we wait for, the loop iterates until the
82 * event is successful, or it fails due to timeout, and error or a
84 * @param transport The transport attached to the event
85 * @param max_wait_time Limit the time spent on the loop
86 * @return Returns -1 on error, 0 or non-zero value
89 * @todo Document this better, split the Follower code to the
90 * TAO_LF_Follower class, we probably don't need the transport
93 int wait_for_event (TAO_LF_Event
*event
,
94 TAO_Transport
*transport
,
95 ACE_Time_Value
*max_wait_time
);
97 /// The current thread has become the leader thread in the
98 /// client side leader-follower set.
99 void set_client_leader_thread ();
101 /// The current thread is no longer the leader thread in the client
102 /// side leader-follower set.
103 void reset_client_leader_thread ();
105 /// Sets the thread ID of the leader thread in the leader-follower
107 void set_client_leader_thread (ACE_thread_t thread_ID
);
109 /// Checks if we are a leader thread
110 bool is_client_leader_thread () const;
112 /// Sets the client leader avoidance flag true. This is used with the
113 /// noupcall wait strategy to allow the creation of dynamic threads
115 void set_avoid_client_leader ();
118 * A leader thread is relinquishing its role, unless there are more
119 * leader threads running pick up a follower (if there is any) to
120 * play the leader role.
122 int elect_new_leader ();
124 /** @name Follower creation/destruction
126 * The Leader/Followers set acts as a factory for the Follower
127 * objects. Followers are used to represent a thread blocked
128 * waiting in the Follower set.
130 * The Leader/Followers abstraction keeps a list of the waiting
131 * followers, so it can wake up one when the leader thread stops
134 * For performance reasons the Leader/Followers set uses a pool (or
135 * free-list) to keep Follower objects unattached to any thread. It
136 * could be tempting to use TSS to keep such followers, after all a
137 * thread can only need one such Follower object, however, that does
138 * not work with multiple Leader/Followers sets, consult this bug
139 * report for more details:
141 * http://bugzilla.dre.vanderbilt.edu/show_bug.cgi?id=296
145 /// Allocate a new follower to the caller.
146 TAO_LF_Follower
*allocate_follower ();
148 /// The caller has finished using a follower.
149 void release_follower (TAO_LF_Follower
*);
152 /** @name Follower Set Operations
156 /// Add a new follower to the set
157 void add_follower (TAO_LF_Follower
*follower
);
159 /// Removes a follower from the leader-follower set
160 void remove_follower (TAO_LF_Follower
*follower
);
162 /// Checks if there are any followers available
164 * @return true if there follower set is not empty
166 bool follower_available () const;
170 /// Get a reference to the underlying mutex
171 TAO_SYNCH_MUTEX
&lock ();
173 /// Provide a pre-initialized reverse lock for the Leader/Followers
176 * The Leader/Followers set mutex must be release during some long
177 * running operations. This helper class simplifies the process of
178 * releasing and reacquiring said mutex.
180 ACE_Reverse_Lock
<TAO_SYNCH_MUTEX
> &reverse_lock ();
182 /// Check if there are any client threads running
183 bool has_clients () const;
185 /// Accessor to the reactor
186 ACE_Reactor
*reactor ();
188 /// Called when we are out of leaders.
189 bool no_leaders_available ();
191 /// Set the new leader generator.
192 void set_new_leader_generator(TAO_New_Leader_Generator
*new_leader_generator
);
194 /// Method to support deferring an event till later (f.i. in
195 /// cases where transport()->wait_strategy()->can_process_upcalls()
197 int defer_event (ACE_Event_Handler
*);
200 /// Shortcut to obtain the TSS resources of the orb core.
201 TAO_ORB_Core_TSS_Resources
*get_tss_resources () const;
203 /// Wait for the client leader to complete.
204 int wait_for_client_leader_to_complete (ACE_Time_Value
*max_wait_time
);
207 * Implement the reset_event_loop_thread() method, once the TSS
208 * resources have been acquired.
209 * Also used in the set_upcall_thread.
211 void reset_event_loop_thread_i (TAO_ORB_Core_TSS_Resources
*tss
);
213 /** @name Follower Set Operations
217 /// Remove a follower from the Followers set and promote it to the
220 * This is a helper routine for elect_new_leader(), after verifying
221 * that all the pre-conditions are satisfied the Follower set is
222 * changed and the promoted Follower is signaled.
224 int elect_new_leader_i ();
228 /// Method to allow the Leader_Follower to resume deferred events
229 /// when it is opportune to do so.
230 void resume_events ();
234 TAO_ORB_Core
*orb_core_
;
236 /// To synchronize access to the members.
237 TAO_SYNCH_MUTEX lock_
;
239 /// Do protect the access to the following three members
240 ACE_Reverse_Lock
<TAO_SYNCH_MUTEX
> reverse_lock_
;
242 /// Implement the Leader/Followers set using an intrusive list
243 typedef ACE_Intrusive_List
<TAO_LF_Follower
> Follower_Set
;
244 Follower_Set follower_set_
;
246 /// Use a free list to allocate and release Follower objects
247 Follower_Set follower_free_list_
;
250 * Count the number of active leaders.
251 * There could be many leaders in the thread pool (i.e. calling
252 * ORB::run), and the same leader could show up multiple times as it
253 * receives nested upcalls and sends more requests.
257 /// Count the number of active clients, this is useful to know when
258 /// to deactivate the reactor
262 ACE_Reactor
*reactor_
;
264 /// Flag to indicate that it is preferable to start a new thread, if possible
265 /// rather than become a client leader. In particular when using the no-upcall
266 /// wait strategy along with the dynamic thread pool, this is the case. It is
267 /// still possible for a client leader to emerge in the case when no additional
268 /// threads may be generated.
269 bool avoid_client_leader_
;
271 /// Is a client thread the current leader?
272 int client_thread_is_leader_
;
274 /// Are server threads waiting for the client leader to complete?
275 int event_loop_threads_waiting_
;
277 /// Condition variable for server threads waiting for the client
278 /// leader to complete.
279 TAO_SYNCH_CONDITION event_loop_threads_condition_
;
281 /// Leader/Follower class uses this method to notify the system that
282 /// we are out of leaders.
283 TAO_New_Leader_Generator
*new_leader_generator_
;
285 /// Class used to register deferred event handlers.
287 : public ACE_Intrusive_List_Node
<Deferred_Event
>
290 Deferred_Event (ACE_Event_Handler
* h
);
292 ACE_Event_Handler
* handler () const;
294 ACE_Event_Handler_var eh_
;
297 /// The set of deferred event handlers.
298 typedef ACE_Intrusive_List
<Deferred_Event
> Deferred_Event_Set
;
299 Deferred_Event_Set deferred_event_set_
;
302 class TAO_Export TAO_LF_Client_Thread_Helper
306 TAO_LF_Client_Thread_Helper (TAO_Leader_Follower
&leader_follower
);
309 ~TAO_LF_Client_Thread_Helper ();
312 /// Reference to leader/followers object.
313 TAO_Leader_Follower
&leader_follower_
;
316 class TAO_Export TAO_LF_Client_Leader_Thread_Helper
320 TAO_LF_Client_Leader_Thread_Helper (TAO_Leader_Follower
&leader_follower
);
323 ~TAO_LF_Client_Leader_Thread_Helper ();
326 /// Reference to leader/followers object.
327 TAO_Leader_Follower
&leader_follower_
;
330 TAO_END_VERSIONED_NAMESPACE_DECL
332 #if defined (__ACE_INLINE__)
333 # include "tao/Leader_Follower.inl"
334 #endif /* __ACE_INLINE__ */
336 #include /**/ "ace/post.h"
338 #endif /* TAO_LEADER_FOLLOWER_H */