1 #include "ace/OS_NS_unistd.h"
2 #include "ace/Service_Config.h"
3 #include "ace/Reactor.h"
4 #include "ace/Thread_Manager.h"
5 #include "ace/Thread.h"
6 #include "ace/Signal.h"
7 #include "ace/Truncate.h"
10 #if defined (ACE_HAS_THREADS)
11 #define MAX_ITERATIONS 10000
13 class Thread_Handler
: public ACE_Event_Handler
16 // Illustrate how the ACE_Reactor's thread-safe event notification
20 // Handle timeouts in the main thread via the ACE_Reactor and I/O
21 // events in a separate thread. Just before the separate I/O
22 // thread exits it notifies the ACE_Reactor in the main thread
23 // using the ACE_Reactor's notification mechanism.
25 Thread_Handler (long delay
,
28 size_t max_iterations
);
31 Thread_Handler (size_t id
,
32 size_t max_iterations
);
37 virtual int handle_signal (int signum
, siginfo_t
* = 0, ucontext_t
* = 0);
40 virtual int handle_exception (ACE_HANDLE
);
41 // Print data from main thread.
43 virtual int handle_output (ACE_HANDLE
);
44 // Print data from main thread.
46 virtual int handle_timeout (const ACE_Time_Value
&,
48 // Handle timeout events in the main thread.
50 virtual int handle_input (ACE_HANDLE
);
51 // General notification messages to the Reactor.
53 virtual int notify (ACE_Time_Value
*tv
= 0);
54 // Perform notifications.
57 // Handle I/O events in a separate threads.
60 static void *svc_run (void *);
61 // Glues C++ to C thread library functions.
64 // ID passed in by Thread_Handler constructor.
68 static sig_atomic_t shutdown_
;
71 // = Timing variables.
72 // Delay factor for timer-driven I/O.
73 static ACE_Time_Value delay_
;
75 // Interval factor for Event_Handler timer.
76 static ACE_Time_Value interval_
;
80 sig_atomic_t Thread_Handler::shutdown_
= 0;
82 // Delay factor for timer-driven I/O.
83 ACE_Time_Value
Thread_Handler::delay_
;
85 // Interval factor for Event_Handler timer.
86 ACE_Time_Value
Thread_Handler::interval_
;
88 Thread_Handler::Thread_Handler (size_t id
,
89 size_t max_iterations
)
91 iterations_ (max_iterations
)
95 Thread_Handler::~Thread_Handler ()
97 // Cleanup resources so that we don't crash and burn when shutdown.
98 ACE_Event_Handler::remove_stdin_handler (ACE_Reactor::instance (),
99 ACE_Thread_Manager::instance ());
100 ACE_Reactor::instance ()->cancel_timer (this);
103 Thread_Handler::Thread_Handler (
107 size_t max_iterations
)
108 : iterations_ (max_iterations
)
112 sig_set
.sig_add (SIGQUIT
);
113 sig_set
.sig_add (SIGINT
);
116 interval_
.set (interval
);
119 if (ACE_Event_Handler::register_stdin_handler (this,
120 ACE_Reactor::instance (),
121 ACE_Thread_Manager::instance ()) == -1)
122 ACE_ERROR ((LM_ERROR
,
124 "register_stdin_handler"));
125 else if (ACE_Reactor::instance ()->register_handler (sig_set
,
127 ACE_ERROR ((LM_ERROR
,
129 "register_handler"));
130 else if (ACE_Reactor::instance ()->schedule_timer
133 Thread_Handler::delay_
,
134 Thread_Handler::interval_
) == -1)
135 ACE_ERROR ((LM_ERROR
,
139 // Set up this thread's signal mask to block all the signal in the
140 // <sig_set>, which is inherited by the threads it spawns.
141 ACE_Sig_Guard
guard (&sig_set
);
143 // Create N new threads of control Thread_Handlers.
145 for (size_t i
= 0; i
< n_threads
; i
++)
150 Thread_Handler (i
+ 1,
153 if (ACE_Thread::spawn (reinterpret_cast<ACE_THR_FUNC
> (&Thread_Handler::svc_run
),
154 reinterpret_cast<void *> (th
),
155 THR_NEW_LWP
| THR_DETACHED
) != 0)
156 ACE_ERROR ((LM_ERROR
,
158 "ACE_Thread::spawn"));
161 // The destructor of <guard> unblocks the signal set so that only
162 // this thread receives them!
166 Thread_Handler::notify (ACE_Time_Value
*timeout
)
168 // Just do something to test the ACE_Reactor's multi-thread
171 if (ACE_Reactor::instance ()->notify
173 ACE_Event_Handler::EXCEPT_MASK
,
175 ACE_ERROR_RETURN ((LM_ERROR
,
177 "notification::notify:exception"),
179 else if (ACE_Reactor::instance ()->notify
181 ACE_Event_Handler::WRITE_MASK
,
183 ACE_ERROR_RETURN ((LM_ERROR
,
185 "notification::notify:write"),
190 // Test stdin handling that uses <select> to demultiplex HANDLEs.
191 // Input is only handled by the main thread.
194 Thread_Handler::handle_input (ACE_HANDLE handle
)
197 ssize_t n
= ACE_OS::read (handle
, buf
, sizeof buf
);
201 ACE_DEBUG ((LM_DEBUG
,
206 ACE_DEBUG ((LM_DEBUG
,
207 "%d more input to kill\n",
210 // Only wait up to 10 milliseconds to notify the Reactor.
211 ACE_Time_Value
timeout (0,
214 if (this->notify (&timeout
) == -1)
215 ACE_ERROR ((LM_DEBUG
,
217 "notification::handle_input:notify"));
224 // Perform a task that will test the ACE_Reactor's multi-threading
225 // capabilities in separate threads.
228 Thread_Handler::svc ()
230 ACE_Time_Value
sleep_timeout (Thread_Handler::interval_
.sec () / 2);
232 for (int i
= ACE_Utils::truncate_cast
<int> (this->iterations_
);
236 if (this->shutdown_
!= 0)
239 // Block for delay_.secs () / 2, then notify the Reactor.
240 ACE_OS::sleep (sleep_timeout
);
242 // Wait up to 10 milliseconds to notify the Reactor.
243 ACE_Time_Value
timeout (0,
245 if (this->notify (&timeout
) == -1)
246 ACE_ERROR ((LM_ERROR
,
251 ACE_Reactor::instance ()->remove_handler (this,
253 ACE_DEBUG ((LM_DEBUG
,
254 "(%t) exiting svc\n"));
258 // Test signal handling.
261 Thread_Handler::handle_signal (int signum
, siginfo_t
*, ucontext_t
*)
263 // @@ Note that this code is not portable to all OS platforms since
264 // it uses print statements within signal handler context.
265 ACE_DEBUG ((LM_DEBUG
,
266 "(%t) received signal %S\n",
272 // This is coded thusly to avoid problems if SIGQUIT is a legit
273 // value but is not a preprocessor macro.
274 #if !defined (SIGQUIT) || (SIGQUIT != 0)
277 ACE_ERROR ((LM_ERROR
,
278 "(%t) ******************** shutting down %n on signal %S\n",
281 ACE_Reactor::end_event_loop();
287 Thread_Handler::handle_timeout (const ACE_Time_Value
&time
, const void *)
289 ACE_DEBUG ((LM_DEBUG
,
290 "(%t) received timeout at (%u, %u), iterations = %d\n",
295 if (--this->iterations_
<= 0
296 || Thread_Handler::interval_
.sec () == 0)
297 ACE_Reactor::end_event_loop ();
302 // Called by the ACE_Reactor when it receives a notification.
305 Thread_Handler::handle_exception (ACE_HANDLE
)
307 ACE_DEBUG ((LM_DEBUG
,
308 "(%t) exception to id %d, iteration = %d\n",
314 // Called by the ACE_Reactor when it receives a notification.
317 Thread_Handler::handle_output (ACE_HANDLE
)
319 ACE_DEBUG ((LM_DEBUG
,
320 "(%t) output to id %d, iteration = %d\n",
322 // This decrement must come last since
323 // <handle_exception> is called before <handle_output>!
324 this->iterations_
--));
328 // "Shim" function that integrates C thread API with C++.
331 Thread_Handler::svc_run (void *eh
)
333 Thread_Handler
*this_handler
=
334 reinterpret_cast<Thread_Handler
*> (eh
);
336 if (this_handler
->svc () == 0)
339 return reinterpret_cast<void *> (-1);
343 ACE_TMAIN (int argc
, ACE_TCHAR
*argv
[])
345 ACE_LOG_MSG
->open (argv
[0]);
349 ACE_ERROR ((LM_ERROR
,
350 ACE_TEXT ("usage: %s delay interval n_threads [iterations]\n"),
355 int delay
= ACE_OS::atoi (argv
[1]);
356 int interval
= ACE_OS::atoi (argv
[2]);
357 size_t n_threads
= ACE_OS::atoi (argv
[3]);
358 size_t max_iterations
= argc
> 4 ? ACE_OS::atoi (argv
[4]) : MAX_ITERATIONS
;
360 Thread_Handler
thr_handler (delay
,
365 ACE_Reactor::instance ()->run_reactor_event_loop ();
367 ACE_DEBUG ((LM_DEBUG
,
368 ACE_TEXT ("exiting from main\n")));
373 ACE_TMAIN (int, ACE_TCHAR
*[])
375 ACE_ERROR_RETURN ((LM_ERROR
,
376 "threads must be supported to run this application\n"), -1);
378 #endif /* ACE_HAS_THREADS */