1
// Signal_Test.cpp,v 4.33 2003/12/26 21:59:35 shuston Exp
3
// ============================================================================
12
// This program tests the signal handling capabilities of ACE on
13
// various OS platforms that support sending signals between
17
// Douglas C. Schmidt <schmidt@cs.wustl.edu>
19
// ============================================================================
21
#include "test_config.h"
22
#include "ace/Thread_Manager.h"
23
#include "ace/Process.h"
24
#include "ace/Signal.h"
25
#include "ace/Get_Opt.h"
28
#include "ace/OS_NS_signal.h"
29
#include "ace/OS_NS_stdio.h"
31
ACE_RCSID(tests, Signal_Test, "Signal_Test.cpp,v 4.33 2003/12/26 21:59:35 shuston Exp")
33
#if !defined (ACE_LACKS_FORK) && !defined (ACE_LACKS_UNIX_SIGNALS)
36
static size_t n_iterations = 100000;
38
// Keeps track of whether we're the child or not.
41
// Keep track of the child pid.
42
static pid_t child_pid = 0;
44
// Keep track of the (original) parent pid.
45
static pid_t parent_pid = 0;
47
// Keep track of which test we're running.
48
static int test_number = 0;
50
// Coordinate the shutdown between threads.
51
static sig_atomic_t shut_down = 0;
54
handle_signal (int signum)
57
ACE_TEXT ("(%P|%t) received signal %S\n"),
63
// Signal to the main thread to shut down.
66
// This should only occur for the asynchronous case, so we don't
72
// Shut down our thread using <ACE_Thread_Manager::exit>.
74
ACE_TEXT ("(%P|%t) shutting down due to %S\n"),
77
// Signal to the worker thread to shut down.
80
// Bail out and close down.
86
// Shutdown the child.
89
ACE_TEXT ("(%P|%t) killing child pid %d \n"),
91
int result = ACE_OS::kill (child_pid,
93
ACE_ASSERT (result != -1);
99
ACE_ERROR_RETURN ((LM_ERROR,
100
ACE_TEXT ("(%P|%t) %p\n"),
105
ACE_ERROR_RETURN ((LM_ERROR,
106
ACE_TEXT ("(%P|%t) signal %S unexpected\n"),
113
// This function handles signals synchronously.
116
synchronous_signal_handler (void *)
120
// Register signal handlers.
123
sigset.sig_add (SIGINT);
124
sigset.sig_add (SIGTERM);
127
sigset.sig_add (SIGHUP);
131
// Block waiting for SIGINT, SIGTERM, or SIGHUP, depending on
132
// whether we're the parent or child process.
133
if (handle_signal (ACE_OS::sigwait (sigset)) == -1)
135
ACE_DEBUG ((LM_DEBUG,
136
ACE_TEXT ("(%P|%t) handled signal\n")));
139
ACE_DEBUG ((LM_DEBUG,
140
ACE_TEXT ("(%P|%t) synchronous signal handler done\n")));
145
// This function arranges to handle signals asynchronously, which is
146
// necessary if an OS platform lacks threads.
149
asynchronous_signal_handler (void *)
153
// Register signal handlers.
156
sigset.sig_add (SIGINT);
157
sigset.sig_add (SIGTERM);
161
sigset.sig_add (SIGCHLD);
162
sigset.sig_add (SIGHUP);
165
// Register the <handle_signal> method to process all the signals in
167
ACE_Sig_Action sa (sigset,
168
(ACE_SignalHandler) handle_signal);
174
// Function that runs in the child process in its own worker thread.
177
worker_child (void *arg)
179
long handle_signals_synchronously =
180
ACE_reinterpret_cast (long, arg);
182
for (size_t i = 0; i < n_iterations; i++)
186
ACE_DEBUG ((LM_DEBUG,
187
ACE_TEXT ("(%P|%t) we've been shutdown!\n")));
191
// Every 100 iterations sleep for 2 seconds.
194
ACE_DEBUG ((LM_DEBUG,
195
ACE_TEXT ("(%P|%t) sleeping for 2 seconds\n")));
199
// After 1000 iterations sent a SIGHUP to our parent.
202
ACE_DEBUG ((LM_DEBUG,
203
ACE_TEXT ("(%P|%t) sending SIGHUP to parent process %d\n"),
205
int result = ACE_OS::kill (parent_pid,
209
ACE_ERROR ((LM_ERROR,
210
ACE_TEXT ("(%P|%t) %p\n"),
212
ACE_ASSERT (result != -1);
217
if (handle_signals_synchronously)
219
ACE_DEBUG ((LM_DEBUG,
220
ACE_TEXT ("(%P|%t) sending SIGINT to ourselves\n")));
221
// We need to do this to dislodge the signal handling thread if
222
// it hasn't shut down on its own accord yet.
223
int result = ACE_OS::kill (ACE_OS::getpid (),
225
ACE_ASSERT (result != -1);
227
ACE_DEBUG ((LM_DEBUG,
228
ACE_TEXT ("(%P|%t) finished running child\n")));
232
// This function runs the parent process in a separate worker thread.
235
worker_parent (void *arg)
237
long handle_signals_synchronously =
238
ACE_reinterpret_cast (long, arg);
239
ACE_Process_Options options;
241
ACE_TCHAR *l_argv[3];
242
ACE_TCHAR pid_str[100];
243
// Store the parent's process id so we can pass it to the child
244
// portably. Also, pass the test number, as well.
245
ACE_OS::sprintf (pid_str,
247
ACE_static_cast (long, parent_pid),
250
// We're going to create a new process that runs this program again,
251
// so we need to indicate that it's the child.
252
const ACE_TCHAR *t = ACE_TEXT (".")
253
ACE_DIRECTORY_SEPARATOR_STR
254
ACE_TEXT ("Signal_Test")
255
ACE_PLATFORM_EXE_SUFFIX
257
l_argv[0] = ACE_const_cast (ACE_TCHAR *,
262
ACE_ARGV argv (l_argv);
264
// Generate a command-line!
265
options.command_line (argv.buf ());
268
child_pid = pm.spawn (options);
269
ACE_DEBUG ((LM_DEBUG,
270
ACE_TEXT ("(%P|%t) spawning child process %d\n"),
273
ACE_ASSERT (child_pid != -1);
275
// Perform a <wait> until our child process has exited.
277
if (handle_signals_synchronously)
280
// Wait for the child process to exit.
282
ACE_DEBUG ((LM_DEBUG,
283
ACE_TEXT ("(%P|%t) reaped child with status %d\n"),
287
while (shut_down == 0)
289
// Wait for a signal to arrive.
290
if (ACE_OS::sigsuspend (0) == -1)
291
ACE_ERROR ((LM_ERROR,
292
ACE_TEXT ("(%P|%t) %p\n"),
293
ACE_TEXT ("sigsuspend")));
294
ACE_DEBUG ((LM_DEBUG,
295
ACE_TEXT ("(%P|%t) got signal!\n")));
298
ACE_DEBUG ((LM_DEBUG,
299
ACE_TEXT ("(%P|%t) parent worker done\n")));
303
// This is the driver function that spawns threads to run the test for
304
// the parent and the child process.
307
run_test (ACE_THR_FUNC worker,
308
long handle_signals_in_separate_thread,
309
long handle_signals_synchronously)
311
#if defined (ACE_HAS_THREADS)
312
if (handle_signals_synchronously)
316
// Block all signals before spawning the threads. Then,
317
// unblock these signals as the scope is exited.
320
ACE_DEBUG ((LM_DEBUG,
321
ACE_TEXT ("(%P|%t) spawning worker thread\n")));
322
result = ACE_Thread_Manager::instance ()->spawn
324
ACE_reinterpret_cast (void *,
325
handle_signals_synchronously),
327
ACE_ASSERT (result != -1);
329
if (handle_signals_in_separate_thread)
331
ACE_DEBUG ((LM_DEBUG,
332
ACE_TEXT ("(%P|%t) spawning signal handler thread\n")));
334
result = ACE_Thread_Manager::instance ()->spawn
335
(synchronous_signal_handler,
338
ACE_ASSERT (result != -1);
340
// Wait for the other threads to finish.
341
result = ACE_Thread_Manager::instance ()->wait ();
342
ACE_ASSERT (result != -1);
345
if (handle_signals_in_separate_thread == 0)
347
synchronous_signal_handler (0);
349
// Wait for the other thread to finish.
350
result = ACE_Thread_Manager::instance ()->wait ();
351
ACE_ASSERT (result != -1);
356
// Don't remove this since otherwise some compilers give warnings
357
// when ACE_HAS_THREADS is disabled!
358
ACE_UNUSED_ARG (synchronous_signal_handler);
359
#endif /* ACE_HAS_THREADS */
361
ACE_UNUSED_ARG (handle_signals_in_separate_thread);
362
// Arrange to handle signals asynchronously.
363
asynchronous_signal_handler (0);
364
(*worker) (ACE_reinterpret_cast (void *,
365
handle_signals_synchronously));
369
// Parse the command-line arguments and set options.
372
parse_args (int argc, char *argv[])
374
ACE_Get_Opt get_opt (argc, argv, "i:chp:t:");
378
while ((c = get_opt ()) != -1)
382
n_iterations = ACE_OS::atoi (get_opt.opt_arg ());
388
parent_pid = ACE_OS::atoi (get_opt.opt_arg ());
391
test_number = ACE_OS::atoi (get_opt.opt_arg ());
395
ACE_DEBUG ((LM_DEBUG,
397
ACE_TEXT ("-i <iterations>\n")
399
ACE_TEXT ("-p <parent_pid>\n")
400
ACE_TEXT ("-t <test_number>\n")));
406
run_main (int argc, ACE_TCHAR *argv[])
410
ACE_APPEND_LOG (ACE_TEXT ("Signal_Test-child"));
411
parse_args (argc, argv);
413
if (test_number == 1)
415
ACE_DEBUG ((LM_DEBUG,
416
ACE_TEXT ("(%P|%t) **** test 1: handle signals synchronously in separate thread\n")));
418
// First, handle signals synchronously in separate thread.
419
run_test (worker_child, 1, 1);
421
else if (test_number == 2)
423
ACE_DEBUG ((LM_DEBUG,
424
ACE_TEXT ("(%P|%t) **** test 2: handle signals synchronously in this thread\n")));
426
// Next, handle signals synchronously in this thread.
427
run_test (worker_child, 0, 1);
429
else if (test_number == 3)
431
ACE_DEBUG ((LM_DEBUG,
432
ACE_TEXT ("(%P|%t) **** test 3: handle signals asynchronously in this thread\n")));
434
// Finally, handle signals asynchronously in this thread.
435
run_test (worker_child, 0, 0);
442
ACE_START_TEST (ACE_TEXT ("Signal_Test"));
443
ACE_INIT_LOG (ACE_TEXT ("Signal_Test-child"));
445
// We need to get the process id here to work around "features"
446
// of Linux threads...
447
parent_pid = ACE_OS::getpid ();
450
// Linux threads don't support this use-case very well.
451
ACE_DEBUG ((LM_DEBUG,
452
ACE_TEXT ("(%P|%t) **** test 1: handle signals synchronously in a separate thread\n")));
455
// Run the parent logic for the signal test, first by handling
456
// signals synchronously in a separate thread.
457
run_test (worker_parent, 1L, 1L);
459
// Must increment anyhow.
463
ACE_DEBUG ((LM_DEBUG,
464
ACE_TEXT ("(%P|%t) **** test 2: handle signals synchronously in this thread\n")));
467
// And next by handling synchronously signals in this thread.
468
run_test (worker_parent, 0L, 1L);
470
ACE_DEBUG ((LM_DEBUG,
471
ACE_TEXT ("(%P|%t) **** test 3: handle signals asynchronously in this thread\n")));
474
// And finally by handling asynchronously signals in this thread.
475
run_test (worker_parent, 0L, 0L);
484
run_main (int, ACE_TCHAR *[])
486
ACE_START_TEST (ACE_TEXT ("Signal_Test"));
487
ACE_ERROR ((LM_ERROR,
488
ACE_TEXT ("The ACE_Process capability is not supported on this platform\n")));
492
#endif /* !ACE_LACKS_FORK && !defined (ACE_LACKS_UNIX_SIGNALS) */