Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / TP_Reactor.h
blob24e0f3209c97f25acaed633936e55b773d8db775
1 // -*- C++ -*-
3 //=============================================================================
4 /**
5 * @file TP_Reactor.h
7 * The ACE_TP_Reactor (aka, Thread Pool Reactor) uses the
8 * Leader/Followers pattern to demultiplex events among a pool of
9 * threads. When using a thread pool reactor, an application
10 * pre-spawns a fixed number of threads. When these threads
11 * invoke the ACE_TP_Reactor's handle_events() method, one thread
12 * will become the leader and wait for an event. The other
13 * follower threads will queue up waiting for their turn to become
14 * the leader. When an event occurs, the leader will pick a
15 * follower to become the leader and go on to handle the event.
16 * The consequence of using ACE_TP_Reactor is the amortization of
17 * the costs used to create threads. The context switching cost
18 * will also reduce. Moreover, the total resources used by
19 * threads are bounded because there are a fixed number of threads.
21 * @author Irfan Pyarali <irfan@cs.wustl.edu>
22 * @author Nanbor Wang <nanbor@cs.wustl.edu>
24 //=============================================================================
27 #ifndef ACE_TP_REACTOR_H
28 #define ACE_TP_REACTOR_H
30 #include /**/ "ace/pre.h"
32 #include "ace/Select_Reactor.h"
33 #include "ace/Timer_Queue.h" /* Simple forward decl won't work... */
35 #if !defined (ACE_LACKS_PRAGMA_ONCE)
36 # pragma once
37 #endif /* ACE_LACKS_PRAGMA_ONCE */
39 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
41 /**
42 * @class ACE_EH_Dispatch_Info
44 * @brief This structure contains information of the activated event
45 * handler.
47 class ACE_EH_Dispatch_Info
49 public:
50 ACE_EH_Dispatch_Info ();
52 void set (ACE_HANDLE handle,
53 ACE_Event_Handler *event_handler,
54 ACE_Reactor_Mask mask,
55 ACE_EH_PTMF callback);
57 bool dispatch () const;
59 ACE_HANDLE handle_;
60 ACE_Event_Handler *event_handler_;
61 ACE_Reactor_Mask mask_;
62 ACE_EH_PTMF callback_;
63 int resume_flag_;
64 bool reference_counting_required_;
66 private:
67 bool dispatch_;
69 ACE_EH_Dispatch_Info (const ACE_EH_Dispatch_Info &) = delete;
70 ACE_EH_Dispatch_Info &operator= (const ACE_EH_Dispatch_Info &) = delete;
71 ACE_EH_Dispatch_Info (ACE_EH_Dispatch_Info &&) = delete;
72 ACE_EH_Dispatch_Info &operator= (ACE_EH_Dispatch_Info &&) = delete;
76 /**
77 * @class ACE_TP_Token_Guard
79 * @brief A helper class that helps grabbing, releasing and waiting
80 * on tokens for a thread that tries calling handle_events ().
82 * In short, this class will be owned by one thread by creating on the
83 * stack. This class gives the status of the ownership of the token
84 * and manages the ownership
87 class ACE_TP_Token_Guard
89 public:
90 /// Constructor that will grab the token for us
91 ACE_TP_Token_Guard (ACE_Select_Reactor_Token &token);
93 /// Destructor. This will release the token if it hasnt been
94 /// released till this point
95 ~ACE_TP_Token_Guard ();
97 /// Release the token ..
98 void release_token ();
100 /// Returns whether the thread that created this object ownes the
101 /// token or not.
102 bool is_owner ();
104 /// A helper method that grabs the token for us, after which the
105 /// thread that owns that can do some actual work.
106 int acquire_read_token (ACE_Time_Value *max_wait_time = 0);
109 * A helper method that grabs the token for us, after which the
110 * thread that owns that can do some actual work. This differs from
111 * acquire_read_token() as it uses acquire () to get the token instead of
112 * acquire_read ()
114 int acquire_token (ACE_Time_Value *max_wait_time = 0);
116 private:
117 ACE_TP_Token_Guard () = delete;
118 ACE_TP_Token_Guard (const ACE_TP_Token_Guard &) = delete;
119 ACE_TP_Token_Guard &operator= (const ACE_TP_Token_Guard &) = delete;
120 ACE_TP_Token_Guard (ACE_TP_Token_Guard &&) = delete;
121 ACE_TP_Token_Guard &operator= (ACE_TP_Token_Guard &&) = delete;
123 private:
124 /// The Select Reactor token.
125 ACE_Select_Reactor_Token &token_;
127 /// Flag that indicate whether the thread that created this object
128 /// owns the token or not. A value of false indicates that this class
129 /// hasn't got the token (and hence the thread) and a value of true
130 /// vice-versa.
131 bool owner_;
135 * @class ACE_TP_Reactor
137 * @brief Specialization of ACE_Select_Reactor to support thread-pool
138 * based event dispatching.
140 * One of the shortcomings of the ACE_Select_Reactor is that it
141 * does not support a thread pool-based event dispatching model,
142 * similar to the one in ACE_WFMO_Reactor. In ACE_Select_Reactor, only
143 * thread can call handle_events() at any given time. ACE_TP_Reactor
144 * removes this short-coming.
146 * ACE_TP_Reactor is a specialization of ACE_Select_Reactor to support
147 * thread pool-based event dispatching. This reactor takes advantage
148 * of the fact that events reported by @c select() are persistent if not
149 * acted upon immediately. It works by remembering the event handler
150 * which was just activated, suspending it for further I/O activities,
151 * releasing the internal lock (so that another thread can start waiting
152 * in the event loop) and then dispatching the event's handler outside the
153 * scope of the reactor lock. After the event handler has been dispatched
154 * the event handler is resumed for further I/O activity.
156 * This reactor implementation is best suited for situations when the
157 * callbacks to event handlers can take arbitrarily long and/or a number
158 * of threads are available to run the event loop. Note that I/O-processing
159 * callback code in event handlers (e.g. handle_input()) does not have to
160 * be modified or made thread-safe for this reactor. This is because
161 * before an I/O event is dispatched to an event handler, the handler is
162 * suspended; it is resumed by the reactor after the upcall completes.
163 * Therefore, multiple I/O events will not be made to one event handler
164 * multiple threads simultaneously. This suspend/resume protection does not
165 * apply to either timers scheduled with the reactor or to notifications
166 * requested via the reactor. When using timers and/or notifications you
167 * must provide proper protection for your class in the context of multiple
168 * threads.
170 class ACE_Export ACE_TP_Reactor : public ACE_Select_Reactor
172 public:
173 /// Initialize ACE_TP_Reactor with the default size.
174 ACE_TP_Reactor (ACE_Sig_Handler * = 0,
175 ACE_Timer_Queue * = 0,
176 bool mask_signals = true,
177 int s_queue = ACE_Select_Reactor_Token::FIFO);
180 * Initialize the ACE_TP_Reactor to manage
181 * @a max_number_of_handles. If @a restart is non-0 then the
182 * ACE_Reactor's @c handle_events() method will be restarted
183 * automatically when @c EINTR occurs. If @a sh or
184 * @a tq are non-0 they are used as the signal handler and
185 * timer queue, respectively.
187 ACE_TP_Reactor (size_t max_number_of_handles,
188 bool restart = false,
189 ACE_Sig_Handler *sh = 0,
190 ACE_Timer_Queue *tq = 0,
191 bool mask_signals = true,
192 int s_queue = ACE_Select_Reactor_Token::FIFO);
195 * This event loop driver that blocks for @a max_wait_time before
196 * returning. It will return earlier if timer events, I/O events,
197 * or signal events occur. Note that @a max_wait_time can be 0, in
198 * which case this method blocks indefinitely until events occur.
200 * @a max_wait_time is decremented to reflect how much time this call
201 * took. For instance, if a time value of 3 seconds is passed to
202 * handle_events and an event occurs after 2 seconds,
203 * @a max_wait_time will equal 1 second. This can be used if an
204 * application wishes to handle events for some fixed amount of
205 * time.
207 * @return The total number of events that were dispatched; 0 if the
208 * @a max_wait_time elapsed without dispatching any handlers, or -1
209 * if an error occurs (check @c errno for more information).
211 virtual int handle_events (ACE_Time_Value *max_wait_time = 0);
213 virtual int handle_events (ACE_Time_Value &max_wait_time);
215 /// Does the reactor allow the application to resume the handle on
216 /// its own ie. can it pass on the control of handle resumption to
217 /// the application. The TP reactor has can allow applications to
218 /// resume handles. So return a positive value.
219 virtual int resumable_handler ();
221 /// Called from handle events
222 static void no_op_sleep_hook (void *);
224 /// The ACE_TP_Reactor implementation does not have a single owner thread.
225 /// Attempts to set the owner explicitly are ignored. The reported owner
226 /// thread is the current Leader in the pattern.
227 virtual int owner (ACE_thread_t n_id, ACE_thread_t *o_id = 0);
229 /// Return the thread ID of the current Leader.
230 virtual int owner (ACE_thread_t *t_id);
232 /// Declare the dynamic allocation hooks.
233 ACE_ALLOC_HOOK_DECLARE;
235 protected:
236 // = Internal methods that do the actual work.
238 /// Template method from the base class.
239 virtual void clear_dispatch_mask (ACE_HANDLE handle,
240 ACE_Reactor_Mask mask);
242 /// Dispatch just 1 signal, timer, notification handlers
243 int dispatch_i (ACE_Time_Value *max_wait_time,
244 ACE_TP_Token_Guard &guard);
246 /// Get the event that needs dispatching. It could be either a
247 /// signal, timer, notification handlers or return possibly 1 I/O
248 /// handler for dispatching. In the most common use case, this would
249 /// return 1 I/O handler for dispatching
250 int get_event_for_dispatching (ACE_Time_Value *max_wait_time);
252 #if 0
253 // @Ciju
254 // signal handling isn't in a production state yet.
255 // Commenting it out for now.
257 /// Method to handle signals
258 /// @note It is just busted at this point in time.
259 int handle_signals (int &event_count,
260 ACE_TP_Token_Guard &g);
261 #endif // #if 0
263 /// Handle timer events
264 int handle_timer_events (int &event_count,
265 ACE_TP_Token_Guard &g);
267 /// Handle notify events
268 int handle_notify_events (int &event_count,
269 ACE_TP_Token_Guard &g);
271 /// handle socket events
272 int handle_socket_events (int &event_count,
273 ACE_TP_Token_Guard &g);
275 /// This method shouldn't get called.
276 virtual void notify_handle (ACE_HANDLE handle,
277 ACE_Reactor_Mask mask,
278 ACE_Handle_Set &,
279 ACE_Event_Handler *eh,
280 ACE_EH_PTMF callback);
281 private:
282 /// Get the handle of the notify pipe from the ready set if there is
283 /// an event in the notify pipe.
284 ACE_HANDLE get_notify_handle ();
286 /// Get socket event dispatch information.
287 int get_socket_event_info (ACE_EH_Dispatch_Info &info);
289 /// Notify the appropriate <callback> in the context of the <eh>
290 /// associated with <handle> that a particular event has occurred.
291 int dispatch_socket_event (ACE_EH_Dispatch_Info &dispatch_info);
293 /// Clear the @a handle from the read_set
294 void clear_handle_read_set (ACE_HANDLE handle);
296 int post_process_socket_event (ACE_EH_Dispatch_Info &dispatch_info,int status);
298 private:
299 ACE_TP_Reactor (const ACE_TP_Reactor &) = delete;
300 ACE_TP_Reactor &operator = (const ACE_TP_Reactor &) = delete;
303 ACE_END_VERSIONED_NAMESPACE_DECL
305 #if defined (__ACE_INLINE__)
306 #include "ace/TP_Reactor.inl"
307 #endif /* __ACE_INLINE__ */
309 #include /**/ "ace/post.h"
311 #endif /* ACE_TP_REACTOR_H */