diff options
author | schmidt <douglascraigschmidt@users.noreply.github.com> | 1999-10-13 05:00:32 +0000 |
---|---|---|
committer | schmidt <douglascraigschmidt@users.noreply.github.com> | 1999-10-13 05:00:32 +0000 |
commit | 2af7b03ad7360895d84d811d20be0fa982895ddb (patch) | |
tree | b26c3f2be9d0144357f02d577f85c6e2a0066deb /tests | |
parent | 7ad4a3715227623cbfa68c01f1bb7386e366bf0d (diff) | |
download | ATCD-2af7b03ad7360895d84d811d20be0fa982895ddb.tar.gz |
*** empty log message ***
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Process_Manager_Test.cpp | 621 |
1 files changed, 161 insertions, 460 deletions
diff --git a/tests/Process_Manager_Test.cpp b/tests/Process_Manager_Test.cpp index 5e7cf69f7d6..b290dc77ee7 100644 --- a/tests/Process_Manager_Test.cpp +++ b/tests/Process_Manager_Test.cpp @@ -9,39 +9,27 @@ // Process_Manager_Test.cpp // // = DESCRIPTION -// This program tests the group management mechanisms provided by -// the <ACE_Process_Manager>. In particular, it illustrates the -// use of the following variants of the -// <ACE_Process_Manager::wait> method: -// -// 1. ACE_TEST_ONE_CHILD -- +// This program tests the various methods provided by +// <ACE_Process_Manager>. It illustrates both the explicit <wait> +// functions and the Reactor-style auto-reaping. There's an +// Exit_Handler class that can print out (in Debug mode) when a +// child has been reaped. // -// This test uses a version of <wait> requires the parent to -// use the signal handling mechanism in -// <one_child_sig_handler> to keep track of the counting of -// remaining processes. Therefore, this <wait> method is less -// portable than the version that's used in the -// <ACE_TEST_MULTIPLE_CHILDREN> test. -// -// 2. ACE_TEST_MULTIPLE_CHILDREN -- -// -// This test uses a version of <wait> that doesn't require any -// signal handling by the parent, i.e., it just uses one of -// the underlying <ACE_OS::wait> methods that's portable to -// all versions of UNIX, as well as Windows NT. +// The child processes spawned are simply this program itself, with +// an integer argument specifying how long to "process" (actually, +// the child just sleeps for the specified length of time). // // = AUTHOR -// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Dave Madden <dhm@mersenne.com> // // ============================================================================ #include "test_config.h" -#include "ace/Thread_Manager.h" #include "ace/Process_Manager.h" -#include "ace/Signal.h" #include "ace/Get_Opt.h" -ACE_RCSID(tests, Process_Manager_Test, "$Id$") +ACE_RCSID(tests, Process_Manager_Test, "Process_Manager_Test.cpp,v 4.11 1999/09/02 04:36:30 schmidt Exp") #if defined(__BORLANDC__) && __BORLANDC__ >= 0x0530 USELIB("..\ace\aced.lib"); @@ -50,482 +38,195 @@ USELIB("..\ace\aced.lib"); #if !defined (ACE_LACKS_FORK) && defined (ACE_HAS_THREADS) -// Global options. -static size_t n_iterations = 100000; +static bool debug_test = false; -enum +class Exit_Handler : public ACE_Event_Handler { - ACE_TEST_ONE_CHILD = 1, - ACE_TEST_MULTIPLE_CHILDREN = 2 -}; +public: + Exit_Handler (const char *msg): msg_ (msg) { } -// Keeps track of which of the child tests enumerated above that we're -// running. -static int child_test = 0; + virtual int handle_exit (ACE_Process *proc) + { + if (debug_test) + ACE_DEBUG ((LM_DEBUG, + ASYS_TEXT ("(%P|%t) Exit_Handler(%s) got %d: %d\n"), + msg_, + int (proc->getpid ()), + int (proc->exit_code ()) )); + return 0; + } +private: + const char *msg_; +}; -// Process ids of the children. -static pid_t child_pids[ACE_MAX_PROCESSES]; +static void +usage (const char *argv0) +{ + ACE_ERROR ((LM_ERROR, + ASYS_TEXT ("usage: %s [-d] [sleep-seconds]\n"), + argv0)); + ACE_OS::exit (0); +} -// Coordinate the shutdown between threads. -static ACE_Atomic_Op<ACE_Thread_Mutex, int> shut_down (0); +static pid_t +spawn_child (const char *argv0, + ACE_Process_Manager &mgr, + int sleep_time = 0) +{ + ACE_Process_Options opts; -// This function handles signals synchronously in a separate thread of -// control for the <ACE_TEST_ONE_CHILD> test. + opts.command_line ("%s %s %d", + argv0, + debug_test ? "-d" : "", + sleep_time); -static void * -one_child_sig_handler (void *) -{ - ACE_Sig_Set sigset; - - // Register ourselves as a "dummy" signal handler so that this - // processes' disposition isn't SIG_IGN (which is the default). - ACE_Sig_Action sa ((ACE_SignalHandler) one_child_sig_handler, SIGCHLD); - ACE_UNUSED_ARG (sa); - - // Register signal handlers. - if (child_test == ACE_TEST_ONE_CHILD) - { - sigset.sig_add (SIGINT); - sigset.sig_add (SIGTERM); - } - else - { - sigset.sig_add (SIGCHLD); - sigset.sig_add (SIGHUP); - } + pid_t result = mgr.spawn (opts); - for (int result;;) - { - // Block waiting for SIGINT, SIGCHLD, SIGTERM, or SIGHUP, - // depending on whether we're the parent or child process. - - int signum = ACE_OS::sigwait (sigset); - - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) received signal %S\n"), - signum)); - - switch (signum) - { - case SIGINT: - /* FALLTHRU */ - case SIGTERM: - // Shut_Down our thread using <ACE_Thread_Manager::exit>. - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) shutting down\n"))); - - // Signal to the main thread to shut_down. - shut_down = 1; - - // Bail out. - return 0; - /* NOTREACHED */ - - case SIGCHLD: - - for (;;) - { - int child_exit_status; - - // This method simply "reaps" the exit status of the - // child without blocking. Note that it also decrements - // the count of waiting children by one. - pid_t pid = - ACE_Process_Manager::instance ()->reap - (-1, - &child_exit_status, - WNOHANG); - // Check to see if there are anymore children to reap. - if (pid == -1) - break; - - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) reaped child pid %d with exit status %d\n"), - pid, - child_exit_status)); - } - - // Bail out. - return 0; - /* NOTREACHED */ - - case SIGHUP: - // Shutdown the child. - - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) killing child pid %d \n"), - child_pids[0])); - result = ACE_OS::kill (child_pids[0], - SIGTERM); - ACE_ASSERT (result != -1); - - // Continue looping on <sigwait> until the child process - // exits. - break; - /* NOTREACHED */ - case -1: - ACE_ERROR_RETURN ((LM_ERROR, - ASYS_TEXT ("(%P|%t) %p\n"), - "sigwait"), - 0); - /* NOTREACHED */ - default: - ACE_ERROR_RETURN ((LM_ERROR, - ASYS_TEXT ("(%P|%t) signal %S unexpected\n"), - signum), - 0); - /* NOTREACHED */ - } - } + if (debug_test) + ACE_DEBUG ((LM_DEBUG, + ASYS_TEXT ("(%P|%t) spawned child: %d\n"), + int (result))); + return result; } -// Function that runs in the child process in its own worker thread -// for the <ACE_TEST_ONE_CHILD> test. - -static void * -one_child_worker_child (void *) +int +main (int argc, ASYS_TCHAR *argv[]) { - for (size_t i = 0; i < n_iterations; i++) - { - if (shut_down > 0) - { - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) we've been shutdown!\n"))); - break; - } - - // Every 100 iterations sleep for 2 seconds. - if ((i % 100) == 0) - { - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) sleeping for 2 seconds\n"))); - ACE_OS::sleep (2); - } - - // After 1000 iterations sent a SIGHUP to our parent. - if ((i % 1000) == 0) - { - pid_t pid = ACE_OS::getppid (); - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) sending SIGHUP to parent process %d\n"), - pid)); - int result = ACE_OS::kill (pid, SIGHUP); - ACE_ASSERT (result != -1); - } - } + ACE_Get_Opt args (argc, argv, "d"); - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) finished running child\n"))); - return 0; -} - -// This function handles signals synchronously in a separate thread of -// control for the <ACE_TEST_MULTIPLE_CHILDREN> test. + for (int arg = args (); arg != EOF; arg = args ()) + switch (arg) + { + case 'd': + debug_test = true; + break; + default: + usage (argv[0]); + break; + } -static void * -multiple_children_sig_handler (void *) -{ - ACE_Sig_Set sigset; - - // Register signal handlers. - if (child_test == ACE_TEST_MULTIPLE_CHILDREN) - sigset.sig_add (SIGINT); - else - { - sigset.sig_add (SIGINT); - sigset.sig_add (SIGHUP); + if (args.optind == argc - 1) + { // child process: sleep & exit + int secs = atoi (argv[args.optind]); + ACE_OS::sleep (secs ? secs : 1); + if (debug_test) + ACE_DEBUG ((LM_DEBUG, + ASYS_TEXT ("(%P|%t) about to exit with code %d\n"), + secs)); + ACE_OS::exit (secs); } - for (;;) - { - // Block waiting for SIGINT or SIGHUP, depending on whether - // we're the parent or child process. - - int signum = ACE_OS::sigwait (sigset); - - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) received signal %S\n"), - signum)); - - switch (signum) - { - case SIGINT: - // Shut_Down our thread using <ACE_Thread_Manager::exit>. - if (shut_down > 0) - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) we've been shutdown!\n"))); - else - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) hum, something weird happened...\n"))); - - // Bail out. - return 0; - /* NOTREACHED */ - - case SIGHUP: - // Continue looping on <sigwait> until all child processes - // exit. - break; - /* NOTREACHED */ - - case -1: - ACE_ERROR_RETURN ((LM_ERROR, - ASYS_TEXT ("(%P|%t) %p\n"), - "sigwait"), - 0); - /* NOTREACHED */ - default: - ACE_ERROR_RETURN ((LM_ERROR, - ASYS_TEXT ("(%P|%t) signal %S unexpected\n"), - signum), - 0); - /* NOTREACHED */ - } - } + if (args.optind != argc) // incorrect usage + usage (argv[0]); - // @@ We never actually reach this code. Comment to fix warning. - // return 0; -} + // Try the explicit <ACE_Process_Manager::wait> functions -// Function that runs in the child process in its own worker thread -// for the <ACE_TEST_MULTIPLE_CHILDREN> test. + ACE_Process_Manager mgr; -static void * -multiple_children_worker_child (void *) -{ - for (size_t i = 0; i < n_iterations; i++) - { - // Every 10000 iterations sleep for 1 second. - if ((i % 10000) == 0) - { - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) sleeping for 1 second\n"))); - ACE_OS::sleep (1); - } - - // After 25000 iterations sent a SIGHUP to our parent. - if ((i % 25000) == 0) - { - pid_t pid = ACE_OS::getppid (); - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) sending SIGHUP to parent process %d\n"), - pid)); - int result = ACE_OS::kill (pid, SIGHUP); - ACE_ASSERT (result != -1); - } - } + mgr.register_handler (new Exit_Handler ("default")); + + ACE_exitcode exitcode; - // Signal to the <sig_wait> thread to shut_down. - shut_down = 1; + // wait for a specific PID + pid_t child1 = spawn_child (argv[0], + mgr, + 1); + pid_t result1 = mgr.wait (child1, + &exitcode); - // Send ourselves a signal to shut down the <sigwait> thread! - int result = ACE_OS::kill (ACE_OS::getpid (), - SIGINT); - ACE_ASSERT (result != -1); + if (debug_test) + ACE_DEBUG ((LM_DEBUG, + ASYS_TEXT ("(%P|%t) waited for child %d: %d\n"), + child1, + exitcode)); + + // wait for a specific PID; another should finish first + pid_t child2 = spawn_child (argv[0], + mgr, + 1); + pid_t child3 = spawn_child (argv[0], + mgr, + 4); + pid_t result2 = mgr.wait (child3, + &exitcode); + + if (debug_test) + ACE_DEBUG ((LM_DEBUG, + ASYS_TEXT ("(%P|%t) waited for child %d: %d\n"), + child3, + exitcode)); - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) finished running child\n"))); + // Now wait for any...should get the one that finished earlier. - return 0; -} + pid_t result3 = mgr.wait (0, + &exitcode); -// This is the driver function that spawns threads to run the various -// tests for the parent and the child process. + if (debug_test) + ACE_DEBUG ((LM_DEBUG, + ASYS_TEXT ("(%P|%t) waited for any child: %d\n"), + exitcode)); -static void -run_test (ACE_THR_FUNC handler, - ACE_THR_FUNC worker) -{ - // Block all signals. - ACE_Sig_Set sigset (1); - int result; - - result = ACE_OS::thr_sigsetmask (SIG_BLOCK, - sigset, - 0); - ACE_ASSERT (result != -1); - - result = ACE_Thread_Manager::instance ()->spawn - (handler, 0, THR_DETACHED); - ACE_ASSERT (result != -1); - - result = ACE_Thread_Manager::instance ()->spawn - (worker, 0, THR_DETACHED); - ACE_ASSERT (result != -1); - - // Wait for all threads to finish. - result = ACE_Thread_Manager::instance ()->wait (); - ACE_ASSERT (result != -1); -} + // Try the timed wait functions -// This function runs the child process in a separate worker thread -// for the <ACE_TEST_MULTIPLE_CHILDREN> test. + // This one shouldn't timeout: + pid_t child4 = spawn_child (argv[0], + mgr, + 1); + pid_t result4 = mgr.wait (0, + ACE_Time_Value (4), + &exitcode); -static void * -multiple_children_worker_parent (void *) -{ - ACE_Process_Options options; - - // We're going to create a new process that runs this program - // <ACE_MAX_PROCESSES> number of times, so we need to indicate that - // these processes are the childen. - options.command_line (ACE_TEXT (".") - ACE_DIRECTORY_SEPARATOR_STR - ACE_TEXT ("Process_Manager_Test") - ACE_PLATFORM_EXE_SUFFIX - ACE_TEXT (" -c 2")); - int result = - ACE_Process_Manager::instance ()->spawn_n (ACE_MAX_PROCESSES, - options, - child_pids); - ACE_ASSERT (result != -1); - - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) child pids =\n"))); - - for (size_t i = 0; i < ACE_MAX_PROCESSES; i++) + if (debug_test) ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("[%d]\n"), - child_pids[i])); - - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("\n"))); - - // Perform a barrier wait until all our child processes have exited. - // Note that this <wait> doesn't require any signal handling by the - // parent, i.e., it just uses one of the underlying <ACE_OS::wait> - // methods that's portable to all versions of UNIX, as well as - // Windows NT. - result = ACE_Process_Manager::instance ()->wait (); - ACE_ASSERT (result != -1); - - // Signal to the <sig_wait> thread to shut_down. - shut_down = 1; - - // Send ourselves a signal to shut down the <sigwait> thread! - result = ACE_OS::kill (ACE_OS::getpid (), - SIGINT); - ACE_ASSERT (result != -1); - - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) test multiple children done\n"))); - return 0; -} - -// This function runs the parent process in a separate worker thread -// for the <ACE_TEST_ONE_CHILDR> test. + ASYS_TEXT ("(%P|%t) waited for any child: %d\n"), + exitcode)); + + // This one should timeout: + pid_t child5 = spawn_child (argv[0], + mgr, + 4); + pid_t result5 = mgr.wait (0, + ACE_Time_Value (1), + &exitcode); + if (debug_test) + ACE_DEBUG ((LM_DEBUG, + ASYS_TEXT ("(%P|%t) waited for any child: %d\n"), + exitcode)); -static void * -one_child_worker_parent (void *) -{ - ACE_Process_Options options; - - // We're going to create a new process that runs this program again, - // so we need to indicate that it's the child. - options.command_line (ACE_TEXT (".") - ACE_DIRECTORY_SEPARATOR_STR - ACE_TEXT ("Process_Manager_Test") - ACE_PLATFORM_EXE_SUFFIX - ACE_TEXT (" -c 1")); - child_pids[0] = ACE_Process_Manager::instance ()->spawn (options); - - ACE_ASSERT (child_pids[0] != -1); - - // Perform a barrier wait until all our child processes have exited. - // Note that this <wait> requires the parent to use the signal - // handling mechanism in <one_child_sig_handler> to keep track of - // the counting of remaining processes. Therefore, this <wait> - // method is less portable than the version that's shown below in - // the <multiple_children_worker_parent> function. - int result = ACE_Process_Manager::instance ()->wait (); - ACE_ASSERT (result != -1); - - ACE_DEBUG ((LM_DEBUG, - ASYS_TEXT ("(%P|%t) test single child done\n"))); - return 0; -} + // Now wait indefinitely to clean up... + result5 = mgr.wait (0, + &exitcode); -// Parse the command-line arguments and set options. + if (debug_test) + ACE_DEBUG ((LM_DEBUG, + ASYS_TEXT ("(%P|%t) waited for child 5 again: %d\n"), + exitcode)); -static void -parse_args (int argc, char *argv[]) -{ - ACE_Get_Opt get_opt (argc, argv, "i:c:h"); + // Finally, try the reactor stuff... + mgr.open (ACE_Process_Manager::DEFAULT_SIZE, + ACE_Reactor::instance ()); - int c; + pid_t child6 = spawn_child (argv[0], + mgr, + 5); + pid_t child7 = spawn_child (argv[0], + mgr, + 6); - while ((c = get_opt ()) != -1) - switch (c) - { - case 'i': - n_iterations = ACE_OS::atoi (get_opt.optarg); - break; - case 'c': - { - int value = ACE_OS::atoi (get_opt.optarg); - if (value == 1) - child_test = ACE_TEST_ONE_CHILD; - else if (value == 2) - child_test = ACE_TEST_MULTIPLE_CHILDREN; - else - ACE_ERROR ((LM_ERROR, - ASYS_TEXT ("(%P|%t) unexpected child test %d\n"), - value)); - break; - } - case 'h': - default: - ACE_DEBUG ((LM_DEBUG, - "(%P|%t) usage:\n" - ASYS_TEXT ("-i <iterations>\n"))); - break; - } -} + mgr.register_handler (new Exit_Handler ("specific"), + child6); -int -main (int argc, ASYS_TCHAR *argv[]) -{ - if (argc > 1) - { - ACE_APPEND_LOG (ASYS_TEXT ("Process_Manager_Test-children")); - parse_args (argc, argv); + ACE_Time_Value how_long (10); - if (child_test == ACE_TEST_ONE_CHILD) - run_test (one_child_sig_handler, - one_child_worker_child); + ACE_Reactor::instance ()->run_event_loop (how_long); - else if (child_test == ACE_TEST_MULTIPLE_CHILDREN) - run_test (multiple_children_sig_handler, - multiple_children_worker_child); + if (debug_test) + ACE_DEBUG ((LM_DEBUG, + ASYS_TEXT ("(%P|%t) done!\n") )); - ACE_END_LOG; - } - else - { - ACE_START_TEST (ASYS_TEXT ("Process_Manager_Test")); - ACE_INIT_LOG (ASYS_TEXT ("Process_Manager_Test-children")); - - // Run the parent logic for the <ACE_TEST_ONE_CHILD> test. - run_test (one_child_sig_handler, - one_child_worker_parent); - - // Run the parent logic for the <ACE_TEST_MULTIPLE_CHILDREN> - // test. - run_test (multiple_children_sig_handler, - multiple_children_worker_parent); - - ACE_END_TEST; - return 0; - } return 0; } -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Atomic_Op<ACE_Thread_Mutex, int>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Atomic_Op<ACE_Thread_Mutex, int> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ - #else int main (int, ASYS_TCHAR *[]) |