Revert "Minor modernization of DynamicAny code"
[ACE_TAO.git] / TAO / tao / Leader_Follower.h
blobe7555173d323f055fc504a97785c0ee3f8d949df
1 // -*- C++ -*-
3 //=============================================================================
4 /**
5 * @file Leader_Follower.h
7 * @author Carlos O'Ryan (coryan@cs.wustl.edu)
8 */
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)
19 # 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
31 class ACE_Reactor;
32 ACE_END_VERSIONED_NAMESPACE_DECL
34 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
36 class TAO_LF_Event;
37 class TAO_Transport;
38 class TAO_ORB_Core;
39 class TAO_ORB_Core_TSS_Resources;
41 /**
42 * @class TAO_Leader_Follower
44 * @brief TAO_Leader_Follower
46 * TAO_Leader_Follower
48 class TAO_Export TAO_Leader_Follower
50 public:
51 /// Constructor
52 TAO_Leader_Follower (TAO_ORB_Core *orb_core,
53 TAO_New_Leader_Generator *new_leader_generator = 0);
55 /// Destructor
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.
80 /**
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
83 * connection closed.
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
87 * otherwise.
89 * @todo Document this better, split the Follower code to the
90 * TAO_LF_Follower class, we probably don't need the transport
91 * object.
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
106 /// model
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
114 /// when possible
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
132 * handling events.
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
144 //@{
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 *);
150 //@}
152 /** @name Follower Set Operations
155 //@{
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;
168 //@}
170 /// Get a reference to the underlying mutex
171 TAO_SYNCH_MUTEX &lock ();
173 /// Provide a pre-initialized reverse lock for the Leader/Followers
174 /// set.
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()
196 /// returns false).
197 int defer_event (ACE_Event_Handler*);
199 private:
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
216 //@{
217 /// Remove a follower from the Followers set and promote it to the
218 /// leader role.
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 ();
226 //@}
228 /// Method to allow the Leader_Follower to resume deferred events
229 /// when it is opportune to do so.
230 void resume_events ();
232 private:
233 /// The orb core
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.
255 int leaders_;
257 /// Count the number of active clients, this is useful to know when
258 /// to deactivate the reactor
259 int clients_;
261 /// 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.
286 class Deferred_Event
287 : public ACE_Intrusive_List_Node<Deferred_Event>
289 public:
290 Deferred_Event (ACE_Event_Handler* h);
292 ACE_Event_Handler* handler () const;
293 private:
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
304 public:
305 /// Constructor
306 TAO_LF_Client_Thread_Helper (TAO_Leader_Follower &leader_follower);
308 /// Destructor
309 ~TAO_LF_Client_Thread_Helper ();
311 private:
312 /// Reference to leader/followers object.
313 TAO_Leader_Follower &leader_follower_;
316 class TAO_Export TAO_LF_Client_Leader_Thread_Helper
318 public:
319 /// Constructor
320 TAO_LF_Client_Leader_Thread_Helper (TAO_Leader_Follower &leader_follower);
322 /// Destructor
323 ~TAO_LF_Client_Leader_Thread_Helper ();
325 private:
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 */