~ubuntu-branches/ubuntu/breezy/ace/breezy

« back to all changes in this revision

Viewing changes to tests/Signal_Test.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad, Benjamin Montgomery, Adam Conrad
  • Date: 2005-09-18 22:51:38 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 sarge) (0.1.2 woody)
  • Revision ID: james.westby@ubuntu.com-20050918225138-seav22q6fyylb536
Tags: 5.4.7-3ubuntu1
[ Benjamin Montgomery ]
* Added a patch for amd64 and powerpc that disables the compiler
  option -fvisibility-inlines-hidden

[ Adam Conrad ]
* Added DPATCH_OPTION_CPP=1 to debian/patches/00options to make
  Benjamin's above changes work correctly with dpatch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Signal_Test.cpp,v 4.33 2003/12/26 21:59:35 shuston Exp
2
 
 
3
 
// ============================================================================
4
 
//
5
 
// = LIBRARY
6
 
//    tests
7
 
//
8
 
// = FILENAME
9
 
//    Signal_Test.cpp
10
 
//
11
 
// = DESCRIPTION
12
 
//      This program tests the signal handling capabilities of ACE on
13
 
//      various OS platforms that support sending signals between
14
 
//      processes.
15
 
//
16
 
// = AUTHOR
17
 
//    Douglas C. Schmidt <schmidt@cs.wustl.edu>
18
 
//
19
 
// ============================================================================
20
 
 
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"
26
 
#include "ace/ARGV.h"
27
 
#include "ace/ACE.h"
28
 
#include "ace/OS_NS_signal.h"
29
 
#include "ace/OS_NS_stdio.h"
30
 
 
31
 
ACE_RCSID(tests, Signal_Test, "Signal_Test.cpp,v 4.33 2003/12/26 21:59:35 shuston Exp")
32
 
 
33
 
#if !defined (ACE_LACKS_FORK) && !defined (ACE_LACKS_UNIX_SIGNALS)
34
 
 
35
 
// Global options.
36
 
static size_t n_iterations = 100000;
37
 
 
38
 
// Keeps track of whether we're the child or not.
39
 
static int child = 0;
40
 
 
41
 
// Keep track of the child pid.
42
 
static pid_t child_pid = 0;
43
 
 
44
 
// Keep track of the (original) parent pid.
45
 
static pid_t parent_pid = 0;
46
 
 
47
 
// Keep track of which test we're running.
48
 
static int test_number = 0;
49
 
 
50
 
// Coordinate the shutdown between threads.
51
 
static sig_atomic_t shut_down = 0;
52
 
 
53
 
static int
54
 
handle_signal (int signum)
55
 
{
56
 
  ACE_DEBUG ((LM_DEBUG,
57
 
              ACE_TEXT ("(%P|%t) received signal %S\n"),
58
 
              signum));
59
 
 
60
 
  switch (signum)
61
 
    {
62
 
    case SIGCHLD:
63
 
      // Signal to the main thread to shut down.
64
 
      shut_down = 1;
65
 
 
66
 
      // This should only occur for the asynchronous case, so we don't
67
 
      // need to return -1!
68
 
      return 0;
69
 
    case SIGINT:
70
 
      /* FALLTHRU */
71
 
    case SIGTERM:
72
 
      // Shut down our thread using <ACE_Thread_Manager::exit>.
73
 
      ACE_DEBUG ((LM_DEBUG,
74
 
                  ACE_TEXT ("(%P|%t) shutting down due to %S\n"),
75
 
                  signum));
76
 
 
77
 
      // Signal to the worker thread to shut down.
78
 
      shut_down = 1;
79
 
 
80
 
      // Bail out and close down.
81
 
      return -1;
82
 
      /* NOTREACHED */
83
 
 
84
 
    case SIGHUP:
85
 
      {
86
 
        // Shutdown the child.
87
 
 
88
 
        ACE_DEBUG ((LM_DEBUG,
89
 
                    ACE_TEXT ("(%P|%t) killing child pid %d \n"),
90
 
                    child_pid));
91
 
        int result = ACE_OS::kill (child_pid,
92
 
                                   SIGTERM);
93
 
        ACE_ASSERT (result != -1);
94
 
 
95
 
        return -1;
96
 
      }
97
 
      /* NOTREACHED */
98
 
    case -1:
99
 
      ACE_ERROR_RETURN ((LM_ERROR,
100
 
                         ACE_TEXT ("(%P|%t) %p\n"),
101
 
                         "sigwait"),
102
 
                        -1);
103
 
      /* NOTREACHED */
104
 
    default:
105
 
      ACE_ERROR_RETURN ((LM_ERROR,
106
 
                         ACE_TEXT ("(%P|%t) signal %S unexpected\n"),
107
 
                         signum),
108
 
                        -1);
109
 
      /* NOTREACHED */
110
 
    }
111
 
}
112
 
 
113
 
// This function handles signals synchronously.
114
 
 
115
 
static void *
116
 
synchronous_signal_handler (void *)
117
 
{
118
 
  ACE_Sig_Set sigset;
119
 
 
120
 
  // Register signal handlers.
121
 
  if (child)
122
 
    {
123
 
      sigset.sig_add (SIGINT);
124
 
      sigset.sig_add (SIGTERM);
125
 
    }
126
 
  else
127
 
    sigset.sig_add (SIGHUP);
128
 
 
129
 
  for (;;)
130
 
    {
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)
134
 
        break;
135
 
      ACE_DEBUG ((LM_DEBUG,
136
 
                  ACE_TEXT ("(%P|%t) handled signal\n")));
137
 
    }
138
 
 
139
 
  ACE_DEBUG ((LM_DEBUG,
140
 
              ACE_TEXT ("(%P|%t) synchronous signal handler done\n")));
141
 
 
142
 
  return 0;
143
 
}
144
 
 
145
 
// This function arranges to handle signals asynchronously, which is
146
 
// necessary if an OS platform lacks threads.
147
 
 
148
 
static void *
149
 
asynchronous_signal_handler (void *)
150
 
{
151
 
  ACE_Sig_Set sigset;
152
 
 
153
 
  // Register signal handlers.
154
 
  if (child)
155
 
    {
156
 
      sigset.sig_add (SIGINT);
157
 
      sigset.sig_add (SIGTERM);
158
 
    }
159
 
  else
160
 
    {
161
 
      sigset.sig_add (SIGCHLD);
162
 
      sigset.sig_add (SIGHUP);
163
 
    }
164
 
 
165
 
  // Register the <handle_signal> method to process all the signals in
166
 
  // <sigset>.
167
 
  ACE_Sig_Action sa (sigset,
168
 
                     (ACE_SignalHandler) handle_signal);
169
 
  ACE_UNUSED_ARG (sa);
170
 
 
171
 
  return 0;
172
 
}
173
 
 
174
 
// Function that runs in the child process in its own worker thread.
175
 
 
176
 
static void *
177
 
worker_child (void *arg)
178
 
{
179
 
  long handle_signals_synchronously =
180
 
    ACE_reinterpret_cast (long, arg);
181
 
 
182
 
  for (size_t i = 0; i < n_iterations; i++)
183
 
    {
184
 
      if (shut_down > 0)
185
 
        {
186
 
          ACE_DEBUG ((LM_DEBUG,
187
 
                      ACE_TEXT ("(%P|%t) we've been shutdown!\n")));
188
 
          break;
189
 
        }
190
 
 
191
 
      // Every 100 iterations sleep for 2 seconds.
192
 
      if ((i % 100) == 0)
193
 
        {
194
 
          ACE_DEBUG ((LM_DEBUG,
195
 
                      ACE_TEXT ("(%P|%t) sleeping for 2 seconds\n")));
196
 
          ACE_OS::sleep (2);
197
 
        }
198
 
 
199
 
      // After 1000 iterations sent a SIGHUP to our parent.
200
 
      if ((i % 1000) == 0)
201
 
        {
202
 
          ACE_DEBUG ((LM_DEBUG,
203
 
                      ACE_TEXT ("(%P|%t) sending SIGHUP to parent process %d\n"),
204
 
                      parent_pid));
205
 
          int result = ACE_OS::kill (parent_pid,
206
 
                                     SIGHUP);
207
 
          if (result == -1)
208
 
            {
209
 
              ACE_ERROR ((LM_ERROR,
210
 
                          ACE_TEXT ("(%P|%t) %p\n"),
211
 
                          ACE_TEXT ("kill")));
212
 
              ACE_ASSERT (result != -1);
213
 
            }
214
 
        }
215
 
    }
216
 
 
217
 
  if (handle_signals_synchronously)
218
 
    {
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 (),
224
 
                                 SIGINT);
225
 
      ACE_ASSERT (result != -1);
226
 
    }
227
 
  ACE_DEBUG ((LM_DEBUG,
228
 
              ACE_TEXT ("(%P|%t) finished running child\n")));
229
 
  return 0;
230
 
}
231
 
 
232
 
// This function runs the parent process in a separate worker thread.
233
 
 
234
 
static void *
235
 
worker_parent (void *arg)
236
 
{
237
 
  long handle_signals_synchronously =
238
 
    ACE_reinterpret_cast (long, arg);
239
 
  ACE_Process_Options options;
240
 
 
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,
246
 
                   "-p %ld -t %d",
247
 
                   ACE_static_cast (long, parent_pid),
248
 
                   test_number);
249
 
 
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
256
 
                       ACE_TEXT (" -c");
257
 
  l_argv[0] = ACE_const_cast (ACE_TCHAR *,
258
 
                              t);
259
 
  l_argv[1] = pid_str;
260
 
  l_argv[2] = 0;
261
 
 
262
 
  ACE_ARGV argv (l_argv);
263
 
 
264
 
  // Generate a command-line!
265
 
  options.command_line (argv.buf ());
266
 
  ACE_Process pm;
267
 
 
268
 
  child_pid = pm.spawn (options);
269
 
  ACE_DEBUG ((LM_DEBUG,
270
 
              ACE_TEXT ("(%P|%t) spawning child process %d\n"),
271
 
              child_pid));
272
 
 
273
 
  ACE_ASSERT (child_pid != -1);
274
 
 
275
 
  // Perform a <wait> until our child process has exited.
276
 
 
277
 
  if (handle_signals_synchronously)
278
 
    {
279
 
      int status;
280
 
      // Wait for the child process to exit.
281
 
      pm.wait (&status);
282
 
      ACE_DEBUG ((LM_DEBUG,
283
 
                  ACE_TEXT ("(%P|%t) reaped child with status %d\n"),
284
 
                  status));
285
 
    }
286
 
  else
287
 
    while (shut_down == 0)
288
 
      {
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")));
296
 
      }
297
 
 
298
 
  ACE_DEBUG ((LM_DEBUG,
299
 
              ACE_TEXT ("(%P|%t) parent worker done\n")));
300
 
  return 0;
301
 
}
302
 
 
303
 
// This is the driver function that spawns threads to run the test for
304
 
// the parent and the child process.
305
 
 
306
 
static void
307
 
run_test (ACE_THR_FUNC worker,
308
 
          long handle_signals_in_separate_thread,
309
 
          long handle_signals_synchronously)
310
 
{
311
 
#if defined (ACE_HAS_THREADS)
312
 
  if (handle_signals_synchronously)
313
 
    {
314
 
      int result;
315
 
      {
316
 
        // Block all signals before spawning the threads.  Then,
317
 
        // unblock these signals as the scope is exited.
318
 
        ACE_Sig_Guard guard;
319
 
 
320
 
        ACE_DEBUG ((LM_DEBUG,
321
 
                    ACE_TEXT ("(%P|%t) spawning worker thread\n")));
322
 
        result = ACE_Thread_Manager::instance ()->spawn
323
 
          (worker,
324
 
           ACE_reinterpret_cast (void *,
325
 
                                 handle_signals_synchronously),
326
 
           THR_DETACHED);
327
 
        ACE_ASSERT (result != -1);
328
 
 
329
 
        if (handle_signals_in_separate_thread)
330
 
          {
331
 
            ACE_DEBUG ((LM_DEBUG,
332
 
                        ACE_TEXT ("(%P|%t) spawning signal handler thread\n")));
333
 
 
334
 
            result = ACE_Thread_Manager::instance ()->spawn
335
 
              (synchronous_signal_handler,
336
 
               0,
337
 
               THR_DETACHED);
338
 
            ACE_ASSERT (result != -1);
339
 
 
340
 
            // Wait for the other threads to finish.
341
 
            result = ACE_Thread_Manager::instance ()->wait ();
342
 
            ACE_ASSERT (result != -1);
343
 
          }
344
 
      }
345
 
      if (handle_signals_in_separate_thread == 0)
346
 
        {
347
 
          synchronous_signal_handler (0);
348
 
 
349
 
          // Wait for the other thread to finish.
350
 
          result = ACE_Thread_Manager::instance ()->wait ();
351
 
          ACE_ASSERT (result != -1);
352
 
        }
353
 
    }
354
 
  else
355
 
#else
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 */
360
 
    {
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));
366
 
    }
367
 
}
368
 
 
369
 
// Parse the command-line arguments and set options.
370
 
 
371
 
static void
372
 
parse_args (int argc, char *argv[])
373
 
{
374
 
  ACE_Get_Opt get_opt (argc, argv, "i:chp:t:");
375
 
 
376
 
  int c;
377
 
 
378
 
  while ((c = get_opt ()) != -1)
379
 
    switch (c)
380
 
    {
381
 
    case 'i':
382
 
      n_iterations = ACE_OS::atoi (get_opt.opt_arg ());
383
 
      break;
384
 
    case 'c':
385
 
      child = 1;
386
 
      break;
387
 
    case 'p':
388
 
      parent_pid = ACE_OS::atoi (get_opt.opt_arg ());
389
 
      break;
390
 
    case 't':
391
 
      test_number = ACE_OS::atoi (get_opt.opt_arg ());
392
 
      break;
393
 
    case 'h':
394
 
    default:
395
 
      ACE_DEBUG ((LM_DEBUG,
396
 
                  "(%P|%t) usage:\n"
397
 
                  ACE_TEXT ("-i <iterations>\n")
398
 
                  ACE_TEXT ("-c\n")
399
 
                  ACE_TEXT ("-p <parent_pid>\n")
400
 
                  ACE_TEXT ("-t <test_number>\n")));
401
 
      break;
402
 
  }
403
 
}
404
 
 
405
 
int
406
 
run_main (int argc, ACE_TCHAR *argv[])
407
 
{
408
 
  if (argc > 1)
409
 
    {
410
 
      ACE_APPEND_LOG (ACE_TEXT ("Signal_Test-child"));
411
 
      parse_args (argc, argv);
412
 
 
413
 
      if (test_number == 1)
414
 
        {
415
 
          ACE_DEBUG ((LM_DEBUG,
416
 
                      ACE_TEXT ("(%P|%t) **** test 1: handle signals synchronously in separate thread\n")));
417
 
 
418
 
          // First, handle signals synchronously in separate thread.
419
 
          run_test (worker_child, 1, 1);
420
 
        }
421
 
      else if (test_number == 2)
422
 
        {
423
 
          ACE_DEBUG ((LM_DEBUG,
424
 
                      ACE_TEXT ("(%P|%t) **** test 2: handle signals synchronously in this thread\n")));
425
 
 
426
 
          // Next, handle signals synchronously in this thread.
427
 
          run_test (worker_child, 0, 1);
428
 
        }
429
 
      else if (test_number == 3)
430
 
        {
431
 
          ACE_DEBUG ((LM_DEBUG,
432
 
                      ACE_TEXT ("(%P|%t) **** test 3: handle signals asynchronously in this thread\n")));
433
 
 
434
 
          // Finally, handle signals asynchronously in this thread.
435
 
          run_test (worker_child, 0, 0);
436
 
        }
437
 
 
438
 
      ACE_END_LOG;
439
 
    }
440
 
  else
441
 
    {
442
 
      ACE_START_TEST (ACE_TEXT ("Signal_Test"));
443
 
      ACE_INIT_LOG (ACE_TEXT ("Signal_Test-child"));
444
 
 
445
 
      // We need to get the process id here to work around "features"
446
 
      // of Linux threads...
447
 
      parent_pid = ACE_OS::getpid ();
448
 
 
449
 
#if !defined (linux)
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")));
453
 
 
454
 
      test_number++;
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);
458
 
#else
459
 
      // Must increment anyhow.
460
 
      test_number++;
461
 
#endif /* linux */
462
 
 
463
 
      ACE_DEBUG ((LM_DEBUG,
464
 
                  ACE_TEXT ("(%P|%t) **** test 2: handle signals synchronously in this thread\n")));
465
 
 
466
 
      test_number++;
467
 
      // And next by handling synchronously signals in this thread.
468
 
      run_test (worker_parent, 0L, 1L);
469
 
 
470
 
      ACE_DEBUG ((LM_DEBUG,
471
 
                  ACE_TEXT ("(%P|%t) **** test 3: handle signals asynchronously in this thread\n")));
472
 
 
473
 
      test_number++;
474
 
      // And finally by handling asynchronously signals in this thread.
475
 
      run_test (worker_parent, 0L, 0L);
476
 
 
477
 
      ACE_END_TEST;
478
 
    }
479
 
  return 0;
480
 
}
481
 
 
482
 
#else
483
 
int
484
 
run_main (int, ACE_TCHAR *[])
485
 
{
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")));
489
 
  ACE_END_TEST;
490
 
  return 0;
491
 
}
492
 
#endif /* !ACE_LACKS_FORK && !defined (ACE_LACKS_UNIX_SIGNALS) */