summaryrefslogtreecommitdiff
path: root/ACE/examples/OS/Process/process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/examples/OS/Process/process.cpp')
-rw-r--r--ACE/examples/OS/Process/process.cpp577
1 files changed, 577 insertions, 0 deletions
diff --git a/ACE/examples/OS/Process/process.cpp b/ACE/examples/OS/Process/process.cpp
new file mode 100644
index 00000000000..de0f2db0d57
--- /dev/null
+++ b/ACE/examples/OS/Process/process.cpp
@@ -0,0 +1,577 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// process.cpp
+//
+// = DESCRIPTION
+// This example tests the <ACE_Process>. For more info, check the
+// README file in this directory.
+//
+// = AUTHOR
+// Tim Harrison <harrison@cs.wustl.edu>.
+//
+// ============================================================================
+
+#include "ace/OS_NS_errno.h"
+#include "ace/OS_NS_fcntl.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Get_Opt.h"
+#include "ace/Process.h"
+#include "ace/Log_Msg.h"
+#include "ace/Time_Value.h"
+#include "ace/SString.h"
+
+ACE_RCSID(Process, process, "$Id$")
+
+#if defined (ACE_WIN32)
+#define EXEC_NAME ACE_TEXT ("MORE.COM")
+const ACE_TCHAR *DATE_PATH = ACE_TEXT ("date.exe");
+const ACE_TCHAR *LS_PATH = ACE_TEXT ("ls.exe");
+const ACE_TCHAR *SLEEP_PATH = ACE_TEXT ("sleep.exe");
+#else
+#define EXEC_NAME ACE_TEXT ("less")
+const ACE_TCHAR *DATE_PATH = ACE_TEXT ("date");
+const ACE_TCHAR *LS_PATH = ACE_TEXT ("ls");
+const ACE_TCHAR *SLEEP_PATH = ACE_TEXT ("sleep");
+#endif /* ACE_WIN32 */
+
+static const ACE_TCHAR *executable = EXEC_NAME;
+static ACE_TCHAR *print_file = 0;
+static ACE_TCHAR *environment_string = 0;
+static int get_env = 0;
+static int run_date = 0;
+static int run_ls = 0;
+static int run_all = 0;
+static int run_setenv = 0;
+static int run_tokenizer = 0;
+static int run_wait = 0;
+
+// Parse the command-line arguments and set options.
+static int
+parse_args (int argc, ACE_TCHAR **argv)
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("dlx:p:e:gastuw"));
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ {
+ switch (c)
+ {
+ case 't':
+ run_tokenizer = 1;
+ break;
+ case 's':
+ run_setenv = 1;
+ break;
+ case 'a':
+ run_all = 1;
+ break;
+ case 'd':
+ run_date = 1;
+ break;
+ case 'l':
+ run_ls = 1;
+ break;
+ case 'x':
+ executable = get_opt.opt_arg ();
+ break;
+ case 'p':
+ print_file = get_opt.opt_arg ();
+ break;
+ case 'e':
+ environment_string = get_opt.opt_arg ();
+ break;
+ case 'g':
+ get_env = 1;
+ break;
+ case 'w':
+ run_wait = 1;
+ break;
+ case 'u':
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Usage:\n")
+ ACE_TEXT ("-d print date\n")
+ ACE_TEXT ("-l run ls\n")
+ ACE_TEXT ("-x <executable=more.com>\n")
+ ACE_TEXT ("-p print <file_name>\n")
+ ACE_TEXT ("-e <env variable message>\n")
+ ACE_TEXT ("-s setenv ACE_PROCESS_ENV and spawn -g\n")
+ ACE_TEXT ("-g get_env ACE_PROCESS_ENV\n")
+ ACE_TEXT ("-t test tokenizer\n")
+ ACE_TEXT ("-w test wait functions\n")
+ ACE_TEXT ("-a run all (d,l,e \"running\")\n")),
+ -1);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+// This shows how to set handles.
+static void
+test_more (void)
+{
+ ACE_HANDLE infile = ACE_OS::open (print_file, O_RDONLY);
+
+ if (infile == ACE_INVALID_HANDLE)
+ {
+ ACE_ERROR ((LM_DEBUG, ACE_TEXT ("%p\n"), print_file));
+ return;
+ }
+
+ ACE_Process new_process;
+ ACE_Process_Options options;
+ options.command_line (executable);
+ options.set_handles (infile);
+
+ if (new_process.spawn (options) == -1)
+ {
+ int error = ACE_OS::last_error ();
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p errno = %d.\n"),
+ ACE_TEXT ("test_more"),
+ error));
+ }
+
+ ACE_exitcode status;
+ new_process.wait (&status);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Process exit with status %d\n"),
+ status));
+ ACE_OS::close (infile);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("More succeeded.\n")));
+}
+
+// This is a simple usage of ACE_Process.
+
+static void
+test_date (void)
+{
+ ACE_Process_Options options;
+ options.command_line (DATE_PATH);
+
+ // Try to create a new process running date.
+ ACE_Process new_process;
+ if (new_process.spawn (options) == -1)
+ {
+ int error = ACE_OS::last_error ();
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p errno = %d.\n"),
+ ACE_TEXT ("test_date"),
+ error));
+ return;
+ }
+
+ ACE_exitcode status;
+ new_process.wait (&status);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Process exit with status %d\n"),
+ status));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("date succeeded.\n")));
+}
+
+static void
+test_ls (void)
+{
+ ACE_Process_Options options;
+#if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR)
+ options.command_line (ACE_TEXT ("%s -al"), LS_PATH);
+#else
+ options.command_line (ACE_TEXT ("%ls -al"), LS_PATH);
+#endif
+ ACE_Process new_process;
+ if (new_process.spawn (options) == -1)
+ {
+ int error = ACE_OS::last_error ();
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p errno = %d.\n"),
+ ACE_TEXT ("test_ls"),
+ error));
+ }
+
+ ACE_exitcode status;
+ new_process.wait (&status);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Process exit with status %d\n"),
+ status));
+}
+
+static void
+test_wait (void)
+{
+ ACE_Process_Options options;
+#if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR)
+ options.command_line (ACE_TEXT ("%s 10"), SLEEP_PATH);
+#else
+ options.command_line (ACE_TEXT ("%ls 10"), SLEEP_PATH);
+#endif
+ ACE_Process process1;
+ if (process1.spawn (options) == -1)
+ {
+ int error = ACE_OS::last_error ();
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p errno = %d.\n"),
+ ACE_TEXT ("test_ls"),
+ error));
+ }
+
+ int result;
+ ACE_exitcode status;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("[%T] New process sleeping 10; try wait(2)\n")));
+
+ result = process1.wait (ACE_Time_Value (2), &status);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("[%T] wait(2) returns %d(%d)...now try regular wait\n"),
+ result,
+ status));
+
+ result = process1.wait (&status);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("[%T] wait() returns %d(%d)\n"),
+ result,
+ status));
+
+ ACE_Process process2;
+ if (process2.spawn (options) == -1)
+ {
+ int error = ACE_OS::last_error ();
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p errno = %d.\n"),
+ ACE_TEXT ("test_ls"),
+ error));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("[%T] New process sleeping 10; try wait(12)\n"),
+ status));
+
+ result = process2.wait (ACE_Time_Value (12), &status);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("[%T] wait(12) returns %d(%d)...now try regular wait\n"),
+ result,
+ status));
+
+ result = process2.wait (&status);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("[%T] wait returns %d(%d)\n"),
+ result,
+ status));
+}
+
+#if defined (ACE_WIN32)
+// This is just to test the direct usage of CreateProcess. I use this
+// occasionally as a sanity check when ACE_Process breaks.
+static void
+win32_test_ls (void)
+{
+ PROCESS_INFORMATION process_info;
+ ACE_TEXT_STARTUPINFO startup_info;
+ ACE_OS::memset ((void *) &startup_info,
+ 0,
+ sizeof startup_info);
+ ACE_OS::memset ((void *) &process_info,
+ 0,
+ sizeof process_info);
+ startup_info.cb = sizeof startup_info;
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+
+ ACE_HANDLE std_out = ACE_STDOUT;
+
+ if (!::DuplicateHandle (::GetCurrentProcess (),
+ std_out,
+ ::GetCurrentProcess (),
+ &startup_info.hStdOutput,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p duplicate failed.\n"),
+ ACE_TEXT ("test_ls")));
+ return;
+ }
+
+ BOOL fork_result =
+ ACE_TEXT_CreateProcess (ACE_TEXT ("c:\\Utils\\bin\\ls.exe"),
+ ACE_TEXT ("-a"),
+ NULL, // No process attributes.
+ NULL, // No thread attributes.
+ TRUE, // Allow handle inheritance.
+ 0, // CREATE_NEW_CONSOLE, // Create a new console window.
+ NULL,
+ 0, // Current directory to start in.
+ &startup_info,
+ &process_info);
+
+ ::CloseHandle (startup_info.hStdOutput);
+
+ if (fork_result == 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p CreateProcess failed.\n"),
+ ACE_TEXT ("test_ls")));
+ else
+ {
+ ::WaitForSingleObject (process_info.hProcess,
+ INFINITE);
+ ACE_DEBUG ((LM_ERROR, ACE_TEXT ("ls succeeded.\n")));
+ }
+}
+
+// This code spawns a new process. The new process inherits our
+// existing environment, plus one more. This has to be done by hand
+// since CreateProcess does not allow us to inherit AND add
+// environment variables.
+
+static void
+win32_spawn_environment_process (void)
+{
+ PROCESS_INFORMATION process_info;
+ ACE_TEXT_STARTUPINFO startup_info;
+ ACE_OS::memset ((void *) &startup_info,
+ 0,
+ sizeof startup_info);
+ ACE_OS::memset ((void *) &process_info,
+ 0,
+ sizeof process_info);
+ startup_info.cb = sizeof (startup_info);
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+
+ ACE_HANDLE std_in = ACE_STDIN;
+ ACE_HANDLE std_out = ACE_STDOUT;
+ ACE_HANDLE std_err = ACE_STDERR;
+
+ if (!::DuplicateHandle (::GetCurrentProcess(),
+ std_out,
+ ::GetCurrentProcess(),
+ &startup_info.hStdOutput,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p duplicate failed.\n"),
+ ACE_TEXT ("spawn_environment_process")));
+ return;
+ }
+
+ if (!::DuplicateHandle (::GetCurrentProcess(),
+ std_err,
+ ::GetCurrentProcess(),
+ &startup_info.hStdError,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p duplicate failed.\n"),
+ ACE_TEXT ("spawn_environment_process")));
+ return;
+ }
+
+ if (!::DuplicateHandle (::GetCurrentProcess(),
+ std_in,
+ ::GetCurrentProcess(),
+ &startup_info.hStdInput,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p duplicate failed.\n"),
+ ACE_TEXT ("spawn_environment_process")));
+ return;
+ }
+
+ // Normally, this would be just GetEnvironmentStrings, but it
+ // doesn't follow the same rules as the rest of the Win32 API
+ ACE_TCHAR *existing_environment = ACE_OS::getenvstrings ();
+ ACE_TCHAR environment[10240];
+ ACE_OS::sprintf (environment,
+ ACE_TEXT("ACE_PROCESS_TEST=%s"),
+ environment_string);
+
+ int size = 0;
+ while (existing_environment[size] != '\0')
+ size += ACE_OS::strlen (existing_environment + size) + 1;
+
+ ACE_OS::memcpy (environment + (ACE_OS::strlen (environment) + 1),
+ existing_environment,
+ size);
+
+ ACE_TEXT_FreeEnvironmentStrings (existing_environment);
+
+ BOOL fork_result =
+ ACE_TEXT_CreateProcess (ACE_TEXT ("d:\\harrison\\ACE_wrappers\\examples\\OS\\Process\\process.exe"),
+ ACE_TEXT ("process -g"),
+ NULL, // No process attributes.
+ NULL, // No thread attributes.
+ TRUE, // Allow handle inheritance.
+ 0, // CREATE_NEW_CONSOLE, // Create a new console window.
+ environment, // Environment.
+ //"d:\\harrison\\ACE_wrappers\\examples\\OS\\Process\\",
+ 0,
+ &startup_info,
+ &process_info);
+
+ ::CloseHandle (startup_info.hStdOutput);
+ ::CloseHandle (startup_info.hStdError);
+
+ if (fork_result == 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("spawn_environment_process")));
+ else
+ {
+ ::WaitForSingleObject (process_info.hProcess,
+ INFINITE);
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("spawn_environment_process succeeded.\n")));
+ }
+}
+#endif
+
+static void
+test_setenv (const ACE_TCHAR *argv0)
+{
+ ACE_Process_Options options;
+ // options.setenv ("ACE_PROCESS_TEST", "here's a really large number: %u", 0 - 1);
+ options.setenv (ACE_TEXT ("ACE_PROCESS_TEST= here's a large number %u"),
+ 0 - 1);
+ options.setenv (ACE_TEXT ("ACE_PROCESS_TEST2"), ACE_TEXT ("ophilli"));
+#if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR)
+ options.command_line ("%s -g", argv0);
+#else
+ options.command_line ("%ls -g", argv0);
+#endif
+ ACE_Process process;
+ if (process.spawn (options) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("test_setenv")));
+ return;
+ }
+
+ ACE_exitcode status;
+ process.wait (&status);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Process exit with status %d\n"),
+ status));
+}
+
+// Tests the ACE_Tokenizer.
+static void
+tokenize (ACE_TCHAR *buffer)
+{
+ // This tokenizer will replace all spaces with end-of-string
+ // characters and will preserve text between "" and '' pairs.
+ ACE_Tokenizer parser (buffer);
+ parser.delimiter_replace (' ', '\0');
+ parser.preserve_designators ('\"', '\"'); // " This quote is for emacs
+ parser.preserve_designators ('\'', '\'');
+
+ for (const ACE_TCHAR *temp; ;)
+ {
+ temp = parser.next ();
+ if (temp == 0)
+ break;
+ ACE_DEBUG ((LM_DEBUG, temp));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+ }
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ if (ACE_LOG_MSG->open (argv[0]) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("cannot open logger!!!\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("starting...\n")));
+
+ if (::parse_args (argc, argv) == -1)
+ return -1;
+
+ if (run_all)
+ {
+#if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR)
+ const ACE_TCHAR *cmdline = ACE_TEXT ("%s -d -l -s -w");
+#else
+ const ACE_TCHAR *cmdline = ACE_TEXT ("%ls -d -l -s -w");
+#endif
+ ACE_Process_Options options;
+ options.command_line (cmdline, argv[0]);
+ ACE_Process process;
+ if (process.spawn (options) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("main")),
+ -1);
+ ACE_exitcode status;
+ process.wait (&status);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Process exit with status %d\n"),
+ status));
+ }
+
+ if (run_date)
+ ::test_date ();
+
+ if (run_setenv)
+ ::test_setenv (argv[0]);
+
+ if (get_env)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("checking ACE_PROCESS_TEST\n")));
+ char *value = ACE_OS::getenv ("ACE_PROCESS_TEST");
+ char *value2 = ACE_OS::getenv ("ACE_PROCESS_TEST2");
+ ACE_DEBUG ((LM_DEBUG,
+ "ACE_PROCESS_TEST = %C.\n"
+ "ACE_PROCESS_TEST2 = %C.\n",
+ value == 0 ? "no value" : value,
+ value2 == 0 ? "no value" : value2));
+ }
+
+ if (run_ls)
+ ::test_ls ();
+
+ if (run_wait)
+ ::test_wait ();
+
+#if defined (ACE_WIN32)
+ if (environment_string != 0)
+ win32_spawn_environment_process ();
+#endif /* ACE_WIN32 */
+
+ if (print_file != 0)
+ test_more ();
+
+ ACE_TCHAR buf1[30];
+ ACE_TCHAR buf2[30];
+ ACE_OS::strcpy(buf1, ACE_TEXT (" -f hi honey -g \"I\'m home\""));
+ ACE_OS::strcpy(buf2, ACE_TEXT ("\"token 1\"\'token 2\'\"token 3\" "));
+
+ if (run_tokenizer)
+ {
+ tokenize (buf1);
+ tokenize (buf2);
+ }
+
+ return 0;
+}