summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorschmidt <douglascraigschmidt@users.noreply.github.com>1999-08-30 21:26:48 +0000
committerschmidt <douglascraigschmidt@users.noreply.github.com>1999-08-30 21:26:48 +0000
commit82455c2029d9946c5ccfa12a1c3a38d3d15270e5 (patch)
tree263e2600bcc0702ebce60fcf5e53bdb630803b28
parent2df08d0bea3dda3312f99cf54ae31e138d97565e (diff)
downloadATCD-82455c2029d9946c5ccfa12a1c3a38d3d15270e5.tar.gz
ChangeLogTag:Mon Aug 30 16:12:36 1999 Douglas C. Schmidt <schmidt@tango.cs.wustl.edu>
-rw-r--r--ChangeLog-99b67
-rw-r--r--ace/Msg_WFMO_Reactor.h13
-rw-r--r--ace/OS.h9
-rw-r--r--ace/OS.i18
-rw-r--r--ace/Process.cpp134
-rw-r--r--ace/Process.h40
-rw-r--r--ace/Process.i59
-rw-r--r--ace/Process_Manager.cpp377
-rw-r--r--ace/Process_Manager.h139
-rw-r--r--ace/Signal.h3
-rw-r--r--ace/config-chorus.h1
-rw-r--r--ace/config-cray.h19
-rw-r--r--ace/config-cygwin32-common.h1
-rw-r--r--ace/config-freebsd-pthread.h1
-rw-r--r--ace/config-freebsd.h1
-rw-r--r--ace/config-hpux-9.x.h2
-rw-r--r--ace/config-lynxos.h1
-rw-r--r--ace/config-netbsd.h1
-rw-r--r--ace/config-sunos4-g++.h1
-rw-r--r--ace/config-sunos4-lucid3.2.h1
-rw-r--r--ace/config-sunos4-sun3.x.h1
-rw-r--r--ace/config-sunos4-sun4.1.4.h1
-rw-r--r--ace/config-sunos4-sun4.x-orbix.h1
-rw-r--r--ace/config-sunos4-sun4.x.h1
-rw-r--r--ace/config-win32-common.h1
-rw-r--r--examples/OS/Process/process.cpp218
26 files changed, 879 insertions, 232 deletions
diff --git a/ChangeLog-99b b/ChangeLog-99b
index fbe21bf797d..b81015ce43b 100644
--- a/ChangeLog-99b
+++ b/ChangeLog-99b
@@ -1,3 +1,12 @@
+Mon Aug 30 16:12:36 1999 Douglas C. Schmidt <schmidt@tango.cs.wustl.edu>
+
+ * ace/Process.i: Oops, the implementation of gethandle() was
+ in a Win32-specific part of the code...
+
+ * ace/Msg_WFMO_Reactor.h: Fixed a problem that was causing
+ ACE_Msg_WFMO_Reactor from being included in the documentation
+ windex files. Thanks to Jody Hagins for reporting this.
+
Mon Aug 30 16:16:46 1999 Ossama Othman <othman@cs.wustl.edu>
* PROBLEM-REPORT-FORM:
@@ -11,11 +20,59 @@ Mon Aug 30 14:27:26 1999 David L. Levine <levine@cs.wustl.edu>
use the explicit template instantiations even with
ACE_HAS_GNU_REPO. g++ 2.91.66 misses some of them with -frepo.
-Mon Aug 30 12:53:48 1999 Douglas C. Schmidt <schmidt@tango.cs.wustl.edu>
-
- * ace/Local_Tokens.h: Added a comment explaining that these locking
- classes aren't intended as general-purpose synchronization
- mechanisms. Thanks to Brian Wright <bwright@paladyne.com>
+Mon Aug 30 15:23:12 1999 Douglas C. Schmidt <schmidt@tango.cs.wustl.edu>
+
+ * ace/Process_Manager: Integrated the new features that make it
+ possible to notify a Reactor when a process exits. Thanks to
+ Dave Madden <dhm@mersenne.com> for contributing this.
+
+ * ace/Process: Added a more portable timed wait() operation for
+ UNIX platforms. However, this method has the following two
+ limitations: (1) on UNIX platforms this function uses <ualarm>,
+ i.e., it overwrites any existing alarm and (2) it steals all
+ SIGCHLDs during the timeout period, which will break another
+ ACE_Process_Manager in the same process that's expecting SIGCHLD
+ to kick off process reaping. If you know a good solution to
+ this please let us know. Thanks to Dave Madden
+ <dhm@mersenne.com> for contributing this.
+
+ * ace/Process: Added setgroup() and getgroup() methods to
+ ACE_Process_Options so that we can manage groups of processes.
+ Thanks to Dave Madden <dhm@mersenne.com> for contributing this.
+
+ * examples/OS/Process/process.cpp: Added a new version that
+ tests the various wait() methods on ACE_Process. Thanks to Dave
+ Madden <dhm@mersenne.com> for contributing this.
+
+ * config-chorus.h,
+ config-cray.h,
+ config-cygwin32-common.h,
+ config-freebsd-pthread.h,
+ config-freebsd.h,
+ config-hpux-9.x.h,
+ config-hpux-9.x.h,
+ config-lynxos.h,
+ config-netbsd.h,
+ config-sunos4-g++.h,
+ config-sunos4-lucid3.2.h,
+ config-sunos4-sun3.x.h,
+ config-sunos4-sun4.1.4.h,
+ config-sunos4-sun4.x-orbix.h,
+ config-sunos4-sun4.x.h,
+ config-win32-common.h:
+ Added ACE_LACKS_SETPGID on the assumption that platforms lacking
+ getpgid() won't have setpgid() either. If this turns out to be
+ incorrect, please let me know.
+
+ * ace/OS: Added a new wrapper facade method for setpgid(). Thanks to
+ Dave Madden <dhm@mersenne.com> for contributing this.
+
+ * ace/OS.h: Added a new macro called ACE_INVALID_PID. Thanks to
+ Dave Madden <dhm@mersenne.com> for contributing this.
+
+ * ace/Local_Tokens.h: Added a comment explaining that these locking
+ classes aren't intended as general-purpose synchronization
+ mechanisms. Thanks to Brian Wright <bwright@paladyne.com>
* examples/Misc/test_trace.cpp (main): Added a call to
ACE_OS::atexit() to make sure we test this someplace.
diff --git a/ace/Msg_WFMO_Reactor.h b/ace/Msg_WFMO_Reactor.h
index 0002c6f6c45..10fdc10b4ef 100644
--- a/ace/Msg_WFMO_Reactor.h
+++ b/ace/Msg_WFMO_Reactor.h
@@ -29,15 +29,14 @@
class ACE_Export ACE_Msg_WFMO_Reactor : public ACE_WFMO_Reactor
{
// = TITLE
- // An object oriented event demultiplexor and event handler
- // dispatcher for Win32 MsgWaitForMultipleObjects.
+ // An OO event demultiplexor and event handler dispatcher for
+ // Win32 <MsgWaitForMultipleObjects>.
//
// = DESCRIPTION
- // The ACE_Msg_WFMO_Reactor is an object-oriented event
- // demultiplexor and event handler Reactor. It differs from
- // WFMO_Reactor by its ability to react on Windows messages. It
- // is needed when the task should serve also as a COM/DCOM
- // server.
+ // The ACE_Msg_WFMO_Reactor is an OO event demultiplexor and
+ // event handler Reactor. It differs from <ACE_WFMO_Reactor> by
+ // its ability to react on Windows messages. It is needed when
+ // the task should serve also as a COM/DCOM server.
public:
// = Initialization and termination methods.
ACE_Msg_WFMO_Reactor (ACE_Sig_Handler * = 0,
diff --git a/ace/OS.h b/ace/OS.h
index 5b909b28519..fff3f3b5b5a 100644
--- a/ace/OS.h
+++ b/ace/OS.h
@@ -851,11 +851,12 @@ typedef int key_t;
# if defined (ACE_PSOS_DIAB_PPC)
typedef unsigned long pid_t;
+# define ACE_INVALID_PID ((pid_t) ~0)
# else /* !defined (ACE_PSOS_DIAB_PPC) */
typedef long pid_t;
+# define ACE_INVALID_PID ((pid_t) -1)
# endif /* defined (ACE_PSOS_DIAB_PPC) */
-
// typedef unsigned char wchar_t;
# endif
@@ -3250,6 +3251,7 @@ typedef OVERLAPPED ACE_OVERLAPPED;
typedef DWORD ACE_thread_t;
typedef HANDLE ACE_hthread_t;
typedef long pid_t;
+#define ACE_INVALID_PID ((pid_t) -1)
# if defined (ACE_HAS_TSS_EMULATION)
typedef DWORD ACE_OS_thread_key_t;
typedef u_int ACE_thread_key_t;
@@ -3492,6 +3494,10 @@ typedef char TCHAR;
# define ACE_SEH_EXCEPT(X) while (0)
# define ACE_SEH_FINALLY if (1)
+# if !defined (ACE_INVALID_PID)
+# define ACE_INVALID_PID ((pid_t) -1)
+# endif /* ACE_INVALID_PID */
+
// The "null" device on UNIX.
# define ACE_DEV_NULL "/dev/null"
@@ -5545,6 +5551,7 @@ public:
static uid_t getuid (void);
static int setuid (uid_t);
static pid_t setsid (void);
+ static int setpgid (pid_t pid, pid_t pgid);
static int system (const char *s);
static pid_t waitpid (pid_t,
int *status = 0,
diff --git a/ace/OS.i b/ace/OS.i
index 5c5e9d1473b..18b382dffd6 100644
--- a/ace/OS.i
+++ b/ace/OS.i
@@ -10125,6 +10125,24 @@ ACE_OS::getppid (void)
#endif /* ACE_WIN32 */
}
+ACE_INLINE int
+ACE_OS::setpgid (pid_t pid, pid_t pgid)
+{
+ ACE_TRACE ("ACE_OS::setpgid");
+#if defined (ACE_LACKS_SETPGID)
+ ACE_UNUSED_ARG (pid);
+ ACE_UNUSED_ARG (pgid);
+ ACE_NOTSUP_RETURN (-1);
+#elif defined (VXWORKS) || defined (ACE_PSOS)
+ // setpgid() is not supported, only one process anyway.
+ ACE_UNUSED_ARG (pid);
+ ACE_UNUSED_ARG (pgid);
+ return 0;
+#else
+ ACE_OSCALL_RETURN (::setpgid (pid, pgid), pid_t, -1);
+#endif /* ACE_WIN32 */
+}
+
ACE_INLINE off_t
ACE_OS::lseek (ACE_HANDLE handle, off_t offset, int whence)
{
diff --git a/ace/Process.cpp b/ace/Process.cpp
index a8d32cc33d8..c610e746f3d 100644
--- a/ace/Process.cpp
+++ b/ace/Process.cpp
@@ -1,6 +1,7 @@
// $Id$
#define ACE_BUILD_DLL
+#include "ace/OS.h"
#include "ace/Process.h"
#include "ace/ARGV.h"
#include "ace/SString.h"
@@ -9,16 +10,17 @@
#include "ace/Process.i"
#endif /* __ACE_INLINE__ */
-ACE_RCSID(ace, Process, "$Id$")
+ACE_RCSID (ace, Process, "$Id$")
ACE_Process::ACE_Process (void)
#if !defined (ACE_WIN32)
- : child_id_ (0)
+ : child_id_ (ACE_INVALID_PID)
#endif /* !defined (ACE_WIN32) */
{
#if defined (ACE_WIN32)
ACE_OS::memset ((void *) &this->process_info_,
- 0, sizeof this->process_info_);
+ 0,
+ sizeof this->process_info_);
#endif /* ACE_WIN32 */
}
@@ -47,27 +49,26 @@ ACE_Process::spawn (ACE_Process_Options &options)
options.startup_info (),
&this->process_info_);
- if (fork_result) // If success.
+ if (fork_result)
return this->getpid ();
else
- // CreateProcess failed.
- return -1;
+ return ACE_INVALID_PID;
#elif defined (CHORUS)
- // This only works if we <exec>. Chorus does not really support
- // <fork>.
+ // This only works if we exec. Chorus does not really support
+ // forking.
if (ACE_BIT_ENABLED (options.creation_flags (),
ACE_Process_Options::NO_EXEC))
- ACE_NOTSUP_RETURN (-1);
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
// These are all currently unsupported.
if (options.get_stdin () != ACE_INVALID_HANDLE)
- ACE_NOTSUP_RETURN (-1);
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
if (options.get_stdout () != ACE_INVALID_HANDLE)
- ACE_NOTSUP_RETURN (-1);
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
if (options.get_stderr () != ACE_INVALID_HANDLE)
- ACE_NOTSUP_RETURN (-1);
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
if (options.working_directory () != 0)
- ACE_NOTSUP_RETURN (-1);
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
if (options.env_argv ()[0] == 0)
// command-line args
@@ -81,7 +82,7 @@ ACE_Process::spawn (ACE_Process_Options &options)
*user_env != 0;
user_env++)
if (ACE_OS::putenv (*user_env) != 0)
- return -1;
+ return ACE_INVALID_PID;
// Now the forked process has both inherited variables and the
// user's supplied variables.
@@ -95,6 +96,14 @@ ACE_Process::spawn (ACE_Process_Options &options)
this->child_id_ = ACE::fork (options.command_line_argv ()[0],
options.avoid_zombies ());
+ // If we're the child and the options specified a non-default
+ // process group, try to set our pgid to it. (This will allow
+ // Process_Manager to wait for Processes by process-group.)
+ if (options.getgroup () != ACE_INVALID_PID
+ && this->child_id_ == 0)
+ ACE_OS::setpgid (0,
+ options.getgroup ());
+
// If we're not supposed to exec, return the process id.
if (ACE_BIT_ENABLED (options.creation_flags (),
ACE_Process_Options::NO_EXEC))
@@ -104,9 +113,9 @@ ACE_Process::spawn (ACE_Process_Options &options)
{
case -1:
// Error.
- return -1;
+ return ACE_INVALID_PID;
case 0:
- // Child process.
+ // Child process...exec the
{
if (options.get_stdin () != ACE_INVALID_HANDLE
&& ACE_OS::dup2 (options.get_stdin (),
@@ -130,6 +139,7 @@ ACE_Process::spawn (ACE_Process_Options &options)
// process.
if (options.working_directory () != 0)
ACE_OS::chdir (options.working_directory ());
+ // Should check for error here!
// Child process executes the command.
int result = 0;
@@ -140,10 +150,10 @@ ACE_Process::spawn (ACE_Process_Options &options)
options.command_line_argv ());
else
{
-#if defined( ghs )
+#if defined (ghs)
// GreenHills 1.8.8 (for VxWorks 5.3.x) can't compile this
// code. Processes aren't supported on VxWorks anyways.
- ACE_NOTSUP_RETURN (-1);
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
#else
// Add the new environment variables to the environment
// context of the context before doing an <execvp>.
@@ -151,7 +161,7 @@ ACE_Process::spawn (ACE_Process_Options &options)
*user_env != 0;
user_env++)
if (ACE_OS::putenv (*user_env) != 0)
- return -1;
+ return ACE_INVALID_PID;
// Now the forked process has both inherited variables and
// the user's supplied variables.
@@ -159,7 +169,6 @@ ACE_Process::spawn (ACE_Process_Options &options)
options.command_line_argv ());
#endif /* ghs */
}
-
if (result == -1)
{
// If the execv fails, this child needs to exit.
@@ -168,7 +177,7 @@ ACE_Process::spawn (ACE_Process_Options &options)
// catch this and figure out what went wrong.
ACE_OS::exit (errno);
}
-
+ // ... otherwise, this is never reached.
return 0;
}
default:
@@ -178,6 +187,71 @@ ACE_Process::spawn (ACE_Process_Options &options)
#endif /* ACE_WIN32 */
}
+pid_t
+ACE_Process::wait (const ACE_Time_Value &tv,
+ int *status)
+{
+#if defined (ACE_WIN32)
+ // Don't try to get the process exit status if wait failed so we can
+ // keep the original error code intact.
+ switch (::WaitForSingleObject (process_info_.hProcess,
+ tv.msec ()))
+ {
+ case WAIT_OBJECT_0:
+ if (status != 0)
+ // The error status of <GetExitCodeProcess> is nonetheless not
+ // tested because we don't know how to return the value.
+ ::GetExitCodeProcess (process_info_.hProcess,
+ (LPDWORD) status);
+ return 0;
+ case WAIT_TIMEOUT:
+ errno = ETIME;
+ return 0;
+ default:
+ ACE_OS::set_errno_to_last_error ();
+ return -1;
+ }
+#else /* ACE_WIN32 */
+ if (tv == ACE_Time_Value::zero)
+ ACE_OSCALL_RETURN (ACE_OS::waitpid (this->child_id_,
+ status,
+ WNOHANG),
+ int, ACE_INVALID_PID);
+
+ if (tv == ACE_Time_Value::max_time)
+ return this->wait (status);
+
+ ACE_Time_Value wait_until = ACE_OS::gettimeofday () + tv;
+
+ for (;;)
+ {
+ int result = ACE_OS::waitpid (this->getpid (),
+ status,
+ WNOHANG);
+ if (result != 0)
+ return result;
+
+ ACE_Sig_Set alarm_or_child;
+
+ alarm_or_child.sig_add (SIGALRM);
+ alarm_or_child.sig_add (SIGCHLD);
+
+ ACE_Time_Value time_left = wait_until - ACE_OS::gettimeofday ();
+
+ // If ACE_OS::ualarm doesn't have sub-second resolution:
+ time_left += ACE_Time_Value (0, 500000);
+ time_left.usec (0);
+
+ if (time_left <= ACE_Time_Value::zero)
+ return 0; // timeout
+
+ ACE_OS::ualarm (time_left);
+ if (ACE_OS::sigwait (alarm_or_child) == -1)
+ return ACE_INVALID_PID;
+ }
+#endif /* ACE_WIN32 */
+}
+
ACE_Process_Options::ACE_Process_Options (int ie,
int cobl,
int ebl,
@@ -208,7 +282,8 @@ ACE_Process_Options::ACE_Process_Options (int ie,
max_environ_argv_index_ (mea - 1),
#endif /* !ACE_HAS_WINCE */
command_line_argv_calculated_ (0),
- command_line_buf_ (0)
+ command_line_buf_ (0),
+ process_group_ (ACE_INVALID_PID)
{
ACE_NEW (command_line_buf_,
TCHAR[cobl]);
@@ -256,7 +331,8 @@ ACE_Process_Options::inherit_environment (void)
// Add the string to our env buffer.
if (this->setenv_i (existing_environment + slot, len) == -1)
{
- ACE_ERROR ((LM_ERROR, ASYS_TEXT ("%p.\n"),
+ ACE_ERROR ((LM_ERROR,
+ ASYS_TEXT ("%p.\n"),
ASYS_TEXT ("ACE_Process_Options::ACE_Process_Options")));
break;
}
@@ -434,27 +510,27 @@ ACE_Process_Options::set_handles (ACE_HANDLE std_in,
if (std_err == ACE_INVALID_HANDLE)
std_err = ACE_STDERR;
- if (!::DuplicateHandle (::GetCurrentProcess(),
+ if (!::DuplicateHandle (::GetCurrentProcess (),
std_in,
- ::GetCurrentProcess(),
+ ::GetCurrentProcess (),
&this->startup_info_.hStdInput,
NULL,
TRUE,
DUPLICATE_SAME_ACCESS))
return -1;
- if (!::DuplicateHandle (::GetCurrentProcess(),
+ if (!::DuplicateHandle (::GetCurrentProcess (),
std_out,
- ::GetCurrentProcess(),
+ ::GetCurrentProcess (),
&this->startup_info_.hStdOutput,
NULL,
TRUE,
DUPLICATE_SAME_ACCESS))
return -1;
- if (!::DuplicateHandle (::GetCurrentProcess(),
+ if (!::DuplicateHandle (::GetCurrentProcess (),
std_err,
- ::GetCurrentProcess(),
+ ::GetCurrentProcess (),
&this->startup_info_.hStdError,
NULL,
TRUE,
diff --git a/ace/Process.h b/ace/Process.h
index 9d272e2c0b7..045d38810cc 100644
--- a/ace/Process.h
+++ b/ace/Process.h
@@ -142,6 +142,12 @@ public:
// is an environment assignment "VARIABLE=value". This buffer
// should end with two null characters.
+ // = Get/set process group.
+ pid_t getgroup (void) const;
+ pid_t setgroup (pid_t pgrp);
+ // On UNIX, these methods are used by the <ACE_Process_Manager> to
+ // manage groups of processes.
+
#if defined (ACE_WIN32)
// = Non-portable accessors for when you "just have to use them."
@@ -277,6 +283,9 @@ protected:
LPTSTR command_line_argv_[MAX_COMMAND_LINE_OPTIONS];
// Argv-style command-line arguments.
+
+ pid_t process_group_;
+ // Process-group on Unix; unused on Win32.
};
class ACE_Export ACE_Process
@@ -295,7 +304,7 @@ class ACE_Export ACE_Process
// program file in the PATH variable.
public:
ACE_Process (void);
- // Default construction. Must use ACE_Process::start.
+ // Default construction. Must use <ACE_Process::spawn> to start.
virtual ~ACE_Process (void);
// Destructor.
@@ -307,18 +316,26 @@ public:
pid_t wait (int *status = 0,
int wait_options = 0);
- // Wait for the process we just created to exit. If <status> != 0,
- // it points to an integer where the function store the exit status
- // of child process to. If <wait_options> == <WNOHANG> then return
- // 0 and don't block if the child process hasn't exited yet. A
- // return value of -1 represents the <wait> operation failed,
- // otherwise, the child process id is returned.
+ // Wait for the process we've created to exit. If <status> != 0, it
+ // points to an integer where the function store the exit status of
+ // child process to. If <wait_options> == <WNOHANG> then return 0
+ // and don't block if the child process hasn't exited yet. A return
+ // value of -1 represents the <wait> operation failed, otherwise,
+ // the child process id is returned.
pid_t wait (const ACE_Time_Value &tv,
int *status = 0);
- // Timed wait for the process we just created to exit. This
- // operation is only supported on Win32 platforms because UNIX
- // platforms don't support a timed <wait> operation.
+ // Timed wait for the process we've created to exit. A return value
+ // of -1 indicates that the something failed; 0 indicates that a
+ // timeout occurred. Otherwise, the child's process id is returned.
+ // If <status> != 0, it points to an integer where the function
+ // stores the child's exit status.
+ //
+ // NOTE: on UNIX platforms this function uses <ualarm>, i.e., it
+ // overwrites any existing alarm. In addition, it steals all
+ // <SIGCHLD>s during the timeout period, which will break another
+ // <ACE_Process_Manager> in the same process that's expecting
+ // <SIGCHLD> to kick off process reaping.
int kill (int signum = SIGINT);
// Send the process a signal. This is only portable to operating
@@ -332,6 +349,9 @@ public:
pid_t getpid (void);
// Return the process id of the new child process.
+ ACE_HANDLE gethandle (void);
+ // Return the handle of the process, if it has one.
+
#if defined (ACE_WIN32)
PROCESS_INFORMATION process_info (void);
#endif /* ACE_WIN32 */
diff --git a/ace/Process.i b/ace/Process.i
index a89d87746a5..cdb3653a154 100644
--- a/ace/Process.i
+++ b/ace/Process.i
@@ -2,6 +2,7 @@
// $Id$
#if defined (ACE_WIN32)
+
ACE_INLINE PROCESS_INFORMATION
ACE_Process::process_info (void)
{
@@ -9,6 +10,15 @@ ACE_Process::process_info (void)
}
#endif /* ACE_WIN32 */
+ACE_INLINE ACE_HANDLE
+ACE_Process::gethandle (void)
+{
+#if defined (ACE_WIN32)
+ return process_info_.hProcess;
+#else
+ return ACE_HANDLE (child_id_);
+#endif /* ACE_WIN32 */
+}
ACE_INLINE pid_t
ACE_Process::getpid (void)
@@ -22,42 +32,11 @@ ACE_Process::getpid (void)
ACE_INLINE pid_t
ACE_Process::wait (int *status,
- int options)
+ int wait_options)
{
return ACE_OS::wait (this->getpid (),
status,
- options);
-}
-
-ACE_INLINE pid_t
-ACE_Process::wait (const ACE_Time_Value &tv,
- int *status)
-{
-#if defined (ACE_WIN32)
- // Don't try to get the process exit status if wait failed so we can
- // keep the original error code intact.
- switch (::WaitForSingleObject (process_info_.hProcess,
- tv.msec ()))
- {
- case WAIT_OBJECT_0:
- if (status != 0)
- // The error status of <GetExitCodeProcess> is nonetheless not
- // tested because we don't know how to return the value.
- ::GetExitCodeProcess (process_info_.hProcess,
- (LPDWORD) status);
- return 0;
- case WAIT_TIMEOUT:
- errno = ETIME;
- return 0;
- default:
- ACE_OS::set_errno_to_last_error ();
- return -1;
- }
-#else /* ACE_WIN32 */
- ACE_UNUSED_ARG (tv);
- ACE_UNUSED_ARG (status);
- ACE_NOTSUP_RETURN (-1);
-#endif /* ACE_WIN32 */
+ wait_options);
}
ACE_INLINE int
@@ -89,6 +68,20 @@ ACE_Process_Options::creation_flags (u_long cf)
creation_flags_ = cf;
}
+ACE_INLINE pid_t
+ACE_Process_Options::getgroup (void) const
+{
+ return process_group_;
+}
+
+ACE_INLINE pid_t
+ACE_Process_Options::setgroup (pid_t pgrp)
+{
+ pid_t old = process_group_;
+ process_group_ = pgrp;
+ return old;
+}
+
#if defined (ACE_WIN32)
ACE_INLINE STARTUPINFO *
diff --git a/ace/Process_Manager.cpp b/ace/Process_Manager.cpp
index 5cc8ca9f2a1..e18129d1e7a 100644
--- a/ace/Process_Manager.cpp
+++ b/ace/Process_Manager.cpp
@@ -11,9 +11,9 @@
#include "ace/Process_Manager.i"
#endif /* __ACE_INLINE__ */
-ACE_RCSID(ace, Process_Manager, "$Id$")
+ACE_RCSID (ace, Process_Manager, "$Id$")
-ACE_ALLOC_HOOK_DEFINE(ACE_Process_Manager)
+ACE_ALLOC_HOOK_DEFINE (ACE_Process_Manager)
// Singleton instance.
ACE_Process_Manager *ACE_Process_Manager::instance_ = 0;
@@ -29,16 +29,13 @@ ACE_Process_Descriptor::dump (void) const
ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
- ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\nproc_id_ = %d"), this->proc_id_));
- ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\ngrp_id_ = %d"), this->grp_id_));
+ ACE_DEBUG ((LM_DEBUG,
+ ASYS_TEXT ("\nproc_id_ = %d"),
+ this->process_->getpid()));
ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
}
-ACE_Process_Descriptor::~ACE_Process_Descriptor (void)
-{
-}
-
void
ACE_Process_Manager::dump (void) const
{
@@ -56,8 +53,9 @@ ACE_Process_Manager::dump (void) const
}
ACE_Process_Descriptor::ACE_Process_Descriptor (void)
- : proc_id_ (-1),
- grp_id_ (0)
+ : delete_process_ (0),
+ process_ (0),
+ exit_notify_ (0)
{
ACE_TRACE ("ACE_Process_Descriptor::ACE_Process_Descriptor");
}
@@ -105,7 +103,7 @@ ACE_Process_Manager::resize (size_t size)
{
ACE_TRACE ("ACE_Process_Manager::resize");
- ACE_Process_Descriptor *temp = 0;
+ ACE_Process_Descriptor *temp;
ACE_NEW_RETURN (temp,
ACE_Process_Descriptor[size],
@@ -128,31 +126,72 @@ ACE_Process_Manager::resize (size_t size)
// Create and initialize the table to keep track of the process pool.
int
-ACE_Process_Manager::open (size_t size)
+ACE_Process_Manager::open (size_t size,
+ ACE_Reactor *r)
{
ACE_TRACE ("ACE_Process_Manager::open");
+ if (r)
+ {
+ ACE_Event_Handler::reactor (r);
+#if !defined (ACE_WIN32)
+ // (No signals for child-exited on Win32) Assign the
+ // Process_Manager a dummy I/O descriptor. Note that even
+ // though we open this file "Write Only" we still need to use
+ // the ACE_Event_Handler::NULL_MASK when registering this with
+ // the ACE_Reactor (see below).
+ this->dummy_handle_ = ACE_OS::open (ACE_DEV_NULL,
+ O_WRONLY);
+ ACE_ASSERT (this->dummy_handle_ != ACE_INVALID_HANDLE);
+
+ // Register signal handler object. Note that NULL_MASK is used
+ // to keep the ACE_Reactor from calling us back on the
+ // "/dev/null" descriptor. NULL_MASK just reserves a "slot" in
+ // the Reactor's internal demuxing table, but doesn't cause it
+ // to dispatch the event handler directly. Instead, we use the
+ // signal handler to do this.
+ if (reactor ()->register_handler
+ (this,
+ ACE_Event_Handler::NULL_MASK) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n%a",
+ "register_handler",
+ 1));
+
+ if (reactor ()->register_handler
+ (SIGCHLD,
+ this) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n%a",
+ "register_handler",
+ 1));
+#endif // !defined (ACE_WIN32)
+ }
+
ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
if (this->max_process_table_size_ < size)
- return this->resize (size);
- else
- return 0;
+ this->resize (size);
+ return 0;
+
}
// Initialize the synchronization variables.
-ACE_Process_Manager::ACE_Process_Manager (size_t size)
- : process_table_ (0),
+ACE_Process_Manager::ACE_Process_Manager (size_t size,ACE_Reactor *r)
+ : ACE_Event_Handler(),
+ process_table_ (0),
max_process_table_size_ (0),
- current_count_ (0)
+ current_count_ (0),
+ dummy_handle_ (ACE_INVALID_HANDLE),
+ default_exit_handler_ (0)
#if defined (ACE_HAS_THREADS)
, zero_cond_ (lock_)
#endif /* ACE_HAS_THREADS */
{
ACE_TRACE ("ACE_Process_Manager::ACE_Process_Manager");
- if (this->open (size) == -1)
+ if (this->open (size,r) == -1)
ACE_ERROR ((LM_ERROR,
ASYS_TEXT ("%p\n"),
ASYS_TEXT ("ACE_Process_Manager")));
@@ -165,10 +204,22 @@ ACE_Process_Manager::close (void)
{
ACE_TRACE ("ACE_Process_Manager::close");
+ if (this->reactor ())
+ {
+ this->reactor ()->remove_handler (this, 0);
+ this->reactor (0);
+ }
+
ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
if (this->process_table_ != 0)
{
+ for (size_t i = 0; i < this->current_count_; ++i)
+ if (this->process_table_[i].exit_notify_ != 0)
+ this->process_table_[i].exit_notify_->handle_close
+ (this->process_table_[i].process_->gethandle (),
+ 0);
+
delete [] this->process_table_;
this->process_table_ = 0;
this->max_process_table_size_ = 0;
@@ -183,15 +234,151 @@ ACE_Process_Manager::~ACE_Process_Manager (void)
this->close ();
}
-// Create a new process. *Must* be called with the lock_ held...
+ACE_HANDLE
+ACE_Process_Manager::get_handle (void) const
+{
+ return this->dummy_handle_;
+}
+
+// This is called when the Reactor notices that a process has exited.
+// On Windoze, it knows which process it was, and passes the process'
+// handle. On Unix, what has actually happened is a SIGCHLD invoked
+// the handle_signal routine, which fooled the Reactor into thinking
+// that this routine needed to be called. (On Unix, we reap as many
+// children as are dead.)
+
+int
+ACE_Process_Manager::handle_input (ACE_HANDLE proc)
+{
+ ACE_TRACE ("ACE_Process_Manager::handle_input");
+
+#if defined (ACE_WIN32)
+ DWORD status = 0;
+ BOOL result = ::GetExitCodeProcess (proc, &status);
+
+ if (result)
+ {
+ if (status != STILL_ACTIVE)
+ {
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex,ace_mon,lock_,-1));
+ int i = find_proc ( proc );
+ pid_t pid = i != -1 ? process_table_[i].process_->getpid () : -1;
+ this->notify_proc_handler (proc, pid, status);
+ this->remove_proc (pid);
+ }
+ ACE_Reactor *r = reactor();
+ if (r)
+ r->remove_handler ( proc, 0 );
+ }
+ else
+ {
+ // Huh? Process still active -- shouldn't have been called yet!
+ }
+ }
+ else
+ {
+ // <GetExitCodeProcess> failed.
+ ACE_ERROR ((LM_ERROR,
+ "%p\n%a",
+ "handle_input: GetExitCodeProcess failed",
+ 0));
+ }
+#else // !defined (ACE_WIN32)
+ ACE_UNUSED_ARG (proc);
+ // <proc> is <dummy_handle_> on unix.
+ while (this->reap() > 0)
+ continue;
+#endif /* ACE_WIN32 */
+ return 0;
+}
+
+int
+ACE_Process_Manager::handle_signal (int signum, siginfo_t *, ucontext_t *)
+{
+ return reactor ()->ready_ops
+ (this->dummy_handle_,
+ ACE_Event_Handler::READ_MASK,
+ ACE_Reactor::ADD_MASK);
+}
+
+int
+ACE_Process_Manager::register_handler (ACE_Event_Handler *eh, pid_t pid)
+{
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (pid == -1)
+ {
+ if (this->default_exit_handler_ != 0)
+ this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE,
+ 0);
+ this->default_exit_handler_ = eh;
+ return 0;
+ }
+
+ int i = this->find_proc (pid);
+
+ if (i == -1)
+ return -1;
+ else
+ {
+ ACE_Process_Descriptor &proc_desc = this->process_table_[i];
+
+ if (proc_desc.exit_notify_ != 0)
+ proc_desc.exit_notify_->handle_close (ACE_INVALID_HANDLE, 0);
+ proc_desc.exit_notify_ = eh;
+ return 0;
+ }
+}
+
+int
+ACE_Process_Manager::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask)
+{
+ ACE_TRACE ("ACE_Process_Manager::handle_close");
+
+ ACE_ASSERT (handle==this->dummy_handle_ );
+
+ ACE_OS::close ( dummy_handle_ );
+
+ return 0;
+}
+
+// Create a new process.
pid_t
ACE_Process_Manager::spawn (ACE_Process_Options &options)
{
+ ACE_Process *process;
+ ACE_NEW_RETURN (process,
+ ACE_Process,
+ ACE_INVALID_PID);
+
+ pid_t pid = spawn (process,
+ options);
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ int i = ACE_INVALID_PID;
+
+ if (pid != -1)
+ i = this->find_proc (pid);
+
+ if (i != -1)
+ this->process_table_[i].delete_process_ = 1;
+
+ return pid;
+}
+
+// Create a new process.
+
+pid_t
+ACE_Process_Manager::spawn (ACE_Process *process,
+ ACE_Process_Options &options)
+{
ACE_TRACE ("ACE_Process_Manager::spawn");
- ACE_Process process;
- pid_t pid = process.spawn (options);
+ pid_t pid = process->spawn (options);
// Only include the pid in the parent's table.
if (pid == -1 || pid == 0)
@@ -200,10 +387,10 @@ ACE_Process_Manager::spawn (ACE_Process_Options &options)
{
ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
- if (this->append_proc (pid) == -1)
- return -1;
+ if (this->append_proc (process) == -1)
+ return ACE_INVALID_PID;
else
- return pid;
+ return pid;
}
}
@@ -234,7 +421,7 @@ ACE_Process_Manager::spawn_n (size_t n,
// Must be called with locks held.
int
-ACE_Process_Manager::append_proc (pid_t pid)
+ACE_Process_Manager::append_proc (ACE_Process *proc)
{
ACE_TRACE ("ACE_Process_Manager::append_proc");
@@ -248,8 +435,20 @@ ACE_Process_Manager::append_proc (pid_t pid)
ACE_Process_Descriptor &proc_desc =
this->process_table_[this->current_count_];
- proc_desc.proc_id_ = pid;
- proc_desc.grp_id_ = ACE_OS::getpgid (pid);
+ proc_desc.delete_process_ = 0; // pending better info from caller
+ proc_desc.process_ = proc;
+
+#if defined (ACE_WIN32)
+ // If we have a Reactor, then we're supposed to reap Processes
+ // automagically. Get a handle to this new Process and tell the
+ // Reactor we're interested in handling_input () on it.
+
+ ACE_Reactor *r = this->reactor ();
+ if (r != 0)
+ r->register_handler (proc->gethandle (),
+ this,
+ ACE_Event_Handler::READ_MASK);
+#endif /* ACE_WIN32 */
this->current_count_++;
return 0;
@@ -260,19 +459,19 @@ ACE_Process_Manager::append_proc (pid_t pid)
// allow them to be inserted twice).
int
-ACE_Process_Manager::insert_proc (pid_t pid)
+ACE_Process_Manager::insert_proc (ACE_Process *proc)
{
ACE_TRACE ("ACE_Process_Manager::insert_proc");
#if 0
// Check for duplicates and bail out if they're already
// registered...
- if (this->find_proc (pid) != -1)
+ if (this->find_proc (proc->getpid ()) != -1)
return -1;
- return this->append_proc (pid);
+ return this->append_proc (proc);
#else
- ACE_UNUSED_ARG (pid);
+ ACE_UNUSED_ARG (proc);
ACE_NOTSUP_RETURN (-1);
#endif
}
@@ -301,6 +500,9 @@ ACE_Process_Manager::remove_proc (pid_t pid)
return -1;
else
{
+ if (this->process_table_[i].delete_process_)
+ delete this->process_table_[i].process_;
+
this->current_count_--;
if (this->current_count_ > 0)
@@ -333,13 +535,13 @@ ACE_Process_Manager::terminate (pid_t pid)
return -1;
else
{
- int result = ACE::terminate_process (this->process_table_[i].proc_id_);
+ int result = ACE::terminate_process (this->process_table_[i].process_->getpid ());
if (result != -1)
{
// Save/restore errno.
ACE_Errno_Guard error (errno);
- this->remove (this->process_table_[i].proc_id_);
+ this->remove (this->process_table_[i].process_->getpid ());
return 0;
}
else
@@ -347,6 +549,23 @@ ACE_Process_Manager::terminate (pid_t pid)
}
}
+int
+ACE_Process_Manager::terminate (pid_t pid, int sig)
+{
+ ACE_TRACE ("ACE_Process_Manager::terminate");
+
+ // Check for duplicates and bail out if they're already
+ // registered...
+ int i = this->find_proc (pid);
+
+ if (i == -1)
+ return -1;
+ else
+ {
+ return ACE_OS::kill (this->process_table_[i].process_->getpid (), sig);
+ }
+}
+
// Locate the index in the table associated with <pid>. Must be
// called with the lock held.
@@ -356,12 +575,29 @@ ACE_Process_Manager::find_proc (pid_t pid)
ACE_TRACE ("ACE_Process_Manager::find_proc");
for (size_t i = 0; i < this->current_count_; i++)
- if (pid == this->process_table_[i].proc_id_)
+ if (pid == this->process_table_[i].process_->getpid ())
return i;
return -1;
}
+#if defined (ACE_WIN32)
+// Locate the index in the table associated with <h>. Must be called
+// with the lock held.
+
+int
+ACE_Process_Manager::find_proc (ACE_HANDLE h)
+{
+ ACE_TRACE ("ACE_Process_Manager::find_proc");
+
+ for (size_t i = 0; i < this->current_count_; i++)
+ if (h == this->process_table_[i].process_->gethandle ())
+ return i;
+
+ return -1;
+}
+#endif /* ACE_WIN32 */
+
// Wait for all the processs to exit. This implementation requires a
// cooperative signal handler or <ACE_OS::sigwait> thread, so it's not
// portable to Win32.
@@ -398,40 +634,83 @@ ACE_Process_Manager::wait (void)
ACE_Process_Descriptor &proc_desc =
this->process_table_[i];
- pid_t pid = ACE_OS::wait (proc_desc.proc_id_, 0);
+ pid_t pid = proc_desc.process_->wait ();
- if (pid == -1)
- return -1;
- else
+ if (pid != -1)
this->remove_proc (pid);
+ return pid;
}
return 0;
}
-// Reap a single child processes' exit status by calling
-// <ACE_OS::wait>.
+// Collect a single child processes' exit status by calling
+// <ACE_OS::wait>. Calls the appropriate exit_notify, if registered.
int
-ACE_Process_Manager::reap (pid_t pid,
+ACE_Process_Manager::wait (pid_t pid,
int *stat_loc,
int options)
{
- ACE_TRACE ("ACE_Process_Manager::reap");
+ ACE_TRACE ("ACE_Process_Manager::wait");
- pid = ACE_OS::wait (pid, stat_loc, options);
+ int local_stat = 0;
+
+ if (stat_loc == 0)
+ stat_loc = &local_stat;
+
+ pid = ACE_OS::waitpid (pid, stat_loc, options);
+
+ if (pid > 0)
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+ this->notify_proc_handler (ACE_HANDLE (pid),
+ pid,
+ *stat_loc);
+ }
- if (pid != -1)
- this->remove (pid);
return pid;
}
int
-ACE_Process_Manager::wait (pid_t pid,
+ACE_Process_Manager::reap (pid_t pid,
int *stat_loc,
int options)
{
- ACE_TRACE ("ACE_Process_Manager::wait");
+ ACE_TRACE ("ACE_Process_Manager::reap");
+
+ return this->wait (pid, stat_loc, options);
+}
+
+// Notify either the process-specific handler or the generic handler.
+// If process-specific, call handle_close on the handler. Returns 1
+// if process found, 0 if not. Must be called with locks held.
+
+int
+ACE_Process_Manager::notify_proc_handler (ACE_HANDLE h,
+ pid_t pid,
+ int status)
+{
+ int i = this->find_proc (pid);
+
+ if (i != -1)
+ {
+ ACE_Process_Descriptor &proc_desc = this->process_table_[i];
+
+ if (proc_desc.exit_notify_ != 0)
+ {
+ proc_desc.exit_notify_->handle_input (h);
+ proc_desc.exit_notify_->handle_close (h, 0);
+ proc_desc.exit_notify_ = 0;
+ }
+ else if (this->default_exit_handler_ != 0
+ && this->default_exit_handler_->handle_input (h) < 0)
+ this->register_handler (0);
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P:%t|%T) ACE_Process_Manager::notify_proc_handler: unknown process %d reaped\n",
+ pid));
- return this->reap (pid, stat_loc, options);
+ return i != -1;
}
diff --git a/ace/Process_Manager.h b/ace/Process_Manager.h
index b852ff4a5ec..8f970cebe5b 100644
--- a/ace/Process_Manager.h
+++ b/ace/Process_Manager.h
@@ -18,6 +18,8 @@
#define ACE_PROCESS_MANAGER_H
#include "ace/Synch.h"
+#include "ace/Reactor.h"
+#include "ace/Event_Handler.h"
#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
@@ -28,7 +30,7 @@
class ACE_Export ACE_Process_Descriptor
{
// = TITLE
- // Information describing each process that's controlled by the
+ // Information describing each process that's controlled by an
// <ACE_Process_Manager>.
private:
friend class ACE_Process_Manager;
@@ -37,17 +39,20 @@ private:
~ACE_Process_Descriptor (void);
// Default ctor/dtor.
- pid_t proc_id_;
- // Unique process ID.
+ int delete_process_;
+ // Do we need to delete the Process, or just close() it?
- gid_t grp_id_;
- // Unique group ID.
+ ACE_Process *process_;
+ // Describes the process itself.
+
+ ACE_Event_Handler *exit_notify_;
+ // function to call when process exits
void dump (void) const;
// Dump the state of an object.
};
-class ACE_Export ACE_Process_Manager
+class ACE_Export ACE_Process_Manager : protected ACE_Event_Handler
{
// = TITLE
// Manages a group of processes.
@@ -74,9 +79,32 @@ public:
};
// = Initialization and termination methods.
- ACE_Process_Manager (size_t size = ACE_Process_Manager::DEFAULT_SIZE);
+ ACE_Process_Manager (size_t size = ACE_Process_Manager::DEFAULT_SIZE,
+ ACE_Reactor *reactor = 0);
+ // Initialize an <ACE_Process_Manager> with a table containing up to
+ // <size> processes. This table resizes itself automatically as
+ // needed. If a non-NULL <reactor> is provided, this
+ // <ACE_Process_Manager> uses it to notify an application when a
+ // process it controls exits. By default, however, we don't use an
+ // <ACE_Reactor>.
+
+ int open (size_t size = DEFAULT_SIZE,
+ ACE_Reactor *r = ACE_Reactor::instance ());
+ // Initialize an <ACE_Process_Manager> with a table containing up to
+ // <size> processes. This table resizes itself automatically as
+ // needed. If a non-NULL <reactor> is provided, this
+ // <ACE_Process_Manager> uses it to notify an application when a
+ // process it controls exits. By default, however, we don't use an
+ // <ACE_Reactor>.
+
+ int close (void);
+ // Release all resources. Do not wait for processes to exit.
+
virtual ~ACE_Process_Manager (void);
+ // Destructor releases all resources and does not wait for processes
+ // to exit.
+ // = Singleton accessors.
static ACE_Process_Manager *instance (void);
// Get pointer to a process-wide <ACE_Process_Manager>.
@@ -84,13 +112,13 @@ public:
// Set pointer to a process-wide <ACE_Process_Manager> and return
// existing pointer.
- int open (size_t size = DEFAULT_SIZE);
- // Initialize an <ACE_Process_Manager> with a table containing up to
- // <size> processes. This table resizes itself automatically as
- // needed.
+ // = Process creation methods.
- int close (void);
- // Release all resources.
+ pid_t spawn (ACE_Process *proc,
+ ACE_Process_Options &options);
+ // Create a new process by passing <options> to <proc.spawn>. On
+ // success, returns the process id of the child that was created.
+ // On failure, returns -1.
pid_t spawn (ACE_Process_Options &options);
// Create a new process by passing <options> to
@@ -106,6 +134,8 @@ public:
// are filled in with the process ids of each newly created process.
// Returns 0 on success and -1 on failure.
+ // = Process synchronization operations.
+
int wait (void);
// Block until there are no more child processes running that were
// <spawn>ed by this <ACE_Process_Manager>. Unlike the <wait> call
@@ -113,23 +143,24 @@ public:
// <ACE_OS::sigwait> because it simply blocks synchronously waiting
// for all the children managed by this <ACE_Process_Manager> to
// exit. Note that this does not return any status information
- // about the success or failure of exiting child processes. Returns
+ // about the success or failure of exiting child processes, although
+ // any registered exit_handlers are called. Returns
// 0 on success (and <remove>s the corresponding
- // <ACE_Process_Descriptor> entry from the <Process_Manager>;
+ // <ACE_Process_Descriptor> entries from the <Process_Manager>;
// otherwise, returns -1 on failure.
int wait (ACE_Time_Value *timeout);
// Block until there are no more child processes running that were
- // <spawn>ed by this <ACE_Process_Manager> or <timeout> expires. In
- // order for this <wait> method to work you'll need to register a
- // signal handler or use <ACE_OS::sigwait> to call the <reap> or
- // <remove> method when a <SIGCHILD> signal occurs. Therefore, this
- // method is not portable to Win32... Returns 0 on success and -1
- // on failure.
-
- int wait (pid_t pid,
- int *stat_loc,
- int options);
+ // <spawn>ed by this <ACE_Process_Manager> or <timeout> expires.
+ // Returns 0 on success and -1 on failure.
+
+ int wait (pid_t pid, ACE_Time_Value *timeout);
+ // Block until pid exits or <timeout> expires.
+ // Returns 0 on success and -1 on failure.
+
+ int wait (pid_t pid = -(ACE_OS::getpid( )),
+ int *stat_loc = 0,
+ int options = WNOHANG );
// Reap the result of a single process by calling <ACE_OS::wait>.
// If the child is successfully reaped, <remove> is called
// automatically. Note that this method can be portably called
@@ -148,6 +179,13 @@ public:
// method does the same thing that the <wait> method directly above
// it does -- It's just here for backwards compatibility.
+ // = Utility methods.
+ int register_handler (ACE_Event_Handler *event_handler,
+ pid_t pid = ACE_INVALID_PID);
+ // Register an Event_Handler to be called back when the specified
+ // process exits. If pid == ACE_INVALID_PID this handler is called
+ // when any process with no specific handler exits.
+
int remove (pid_t pid);
// Remove process <pid> from the table. This is called
// automatically by the <reap> method after it successfully reaped a
@@ -162,26 +200,51 @@ public:
// may not have a chance to cleanup before it shuts down. Returns 0
// on success and -1 on failure.
+ int terminate (pid_t pid, int sig);
+ // On OSs that support signals, send the signal to the specified
+ // process. Returns 0 on success and -1 on failure.
+
void dump (void) const;
// Dump the state of an object.
ACE_ALLOC_HOOK_DECLARE;
// Declare the dynamic allocation hooks.
+protected:
+ // = These methods allow a <Process_Manager> to be an <Event_Handler>.
+
+ // @@ Dave, can you please add comments for these methods.
+ virtual ACE_HANDLE get_handle (void) const;
+ // Return the handle.
+
+ virtual int handle_input (ACE_HANDLE);
+ //
+ virtual int handle_signal (int signum, siginfo_t * = 0,
+ ucontext_t * = 0);
+ //
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+ //
+
private:
int resize (size_t);
// Resize the pool of Process_Descriptors.
int find_proc (pid_t process_id);
// Locate the index of the table slot occupied by <process_id>.
- // Returns -1 if <process_id> is not in the <process_table_> doesn't
- // contain <process_id>.
+ // Returns -1 if <process_id> is not in the <process_table_>
+
+#if defined (ACE_WIN32)
+ int find_proc (ACE_HANDLE process_handle);
+ // Locate the index of the table slot occupied by <process_handle>.
+ // Returns -1 if <process_handle> is not in the <process_table_>
+#endif /* ACE_WIN32 */
- int insert_proc (pid_t process_id);
- // Insert a process in the table (checks for duplicates).
- // Omitting the process handle won't work on Win32...
+ int insert_proc (ACE_Process *process);
+ // Insert a process in the table (checks for duplicates). Omitting
+ // the process handle won't work on Win32...
- int append_proc (pid_t process_id);
+ int append_proc (ACE_Process *process);
// Append information about a process, i.e., its <process_id> in the
// <process_table_>. Each entry is added at the end, growing the
// table if necessary.
@@ -190,6 +253,12 @@ private:
// Actually removes the process <pid> from the table. This method
// must be called with locks held.
+ int notify_proc_handler (ACE_HANDLE proc,
+ pid_t pid,
+ int status);
+ // If there's a specific handler for <pid>'s exit, or a default
+ // handler, call it.
+
ACE_Process_Descriptor *process_table_;
// Vector that describes process state within the Process_Manager.
@@ -200,6 +269,13 @@ private:
size_t current_count_;
// Current number of processes we are managing.
+ ACE_HANDLE dummy_handle_;
+ // Allows SIGCHLD to be handled synchronously.
+
+ ACE_Event_Handler *default_exit_handler_;
+ // This event handler is used to notify when a process we control
+ // exits.
+
static ACE_Process_Manager *instance_;
// Singleton pointer.
@@ -219,4 +295,3 @@ private:
#endif /* __ACE_INLINE__ */
#endif /* ACE_PROCESS_MANAGER_H */
-
diff --git a/ace/Signal.h b/ace/Signal.h
index 2d972a35039..3d5a67bd750 100644
--- a/ace/Signal.h
+++ b/ace/Signal.h
@@ -52,7 +52,8 @@ public:
// the set.
ACE_Sig_Set (int fill = 0);
- // If <fill> == 0 then initialize the <sigset_> empty, else full.
+ // If <fill> == 0 then initialize the <sigset_> to be empty, else
+ // full.
~ACE_Sig_Set (void);
diff --git a/ace/config-chorus.h b/ace/config-chorus.h
index ee92c196b12..5e10f2811c4 100644
--- a/ace/config-chorus.h
+++ b/ace/config-chorus.h
@@ -66,6 +66,7 @@
#define ACE_LACKS_FSYNC
#define ACE_LACKS_GETHOSTENT
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
#define ACE_LACKS_GETSERVBYNAME
#define ACE_LACKS_KEY_T
#define ACE_LACKS_LONGLONG_T
diff --git a/ace/config-cray.h b/ace/config-cray.h
index e9ab5630593..9bb277fc7a3 100644
--- a/ace/config-cray.h
+++ b/ace/config-cray.h
@@ -143,49 +143,32 @@
// working. Of course, all other Cray PVP and MPP systems do NOT support it,
// so it's probably good to just define like this for consistency
#define ACE_LACKS_SYSV_SHMEM
-
#define ACE_LACKS_MMAP
-
#define ACE_LACKS_CONST_TIMESPEC_PTR
-
#define ACE_LACKS_SYSCALL
-
#define ACE_LACKS_STRRECVFD
-
#define ACE_LACKS_MADVISE
-
#define ACE_LACKS_NETDB_REENTRANT_FUNCTIONS
-
#define ACE_LACKS_LINEBUFFERED_STREAMBUF
-
#define ACE_LACKS_PTHREAD_CLEANUP
-
#define ACE_LACKS_CONDATTR_PSHARED
-
#define ACE_LACKS_THREAD_PROCESS_SCOPING
#if !defined(_CRAYMPP)
#define ACE_LACKS_PTHREAD_CANCEL
-
#define ACE_LACKS_PTHREAD_KILL
#endif
#define ACE_LACKS_MUTEXATTR_PSHARED
-
#define ACE_LACKS_RWLOCK_T
-
#define ACE_LACKS_PRI_T
-
#define ACE_LACKS_GETPGID
-
+#define ACE_LACKS_SETPGID
#define ACE_LACKS_MPROTECT
-
#define ACE_LACKS_MSYNC
-
#define ACE_LACKS_READV
-
#define ACE_LACKS_RLIMIT
// we probably want to fake not having this, since Cray memory mgmt is different
diff --git a/ace/config-cygwin32-common.h b/ace/config-cygwin32-common.h
index 923f8952b79..01b1962adf1 100644
--- a/ace/config-cygwin32-common.h
+++ b/ace/config-cygwin32-common.h
@@ -59,6 +59,7 @@
// but that may depend on the version of glibc that is used.
# define ACE_HAS_DLFCN_H_BROKEN_EXTERN_C
# define ACE_HAS_VOIDPTR_SOCKOPT
+#define ACE_LACKS_SETPGID
# define ACE_LACKS_GETPGID
// The strtok_r declaration is protected in string.h.
extern "C" char *strtok_r __P ((char *__s, __const char *__delim,
diff --git a/ace/config-freebsd-pthread.h b/ace/config-freebsd-pthread.h
index 6758aee1db5..853a6eaab8e 100644
--- a/ace/config-freebsd-pthread.h
+++ b/ace/config-freebsd-pthread.h
@@ -36,6 +36,7 @@
#define ACE_HAS_RECURSIVE_THR_EXIT_SEMANTICS
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
#define ACE_LACKS_RWLOCK_T
#define ACE_LACKS_READDIR_R
#define ACE_HAS_SIG_MACROS
diff --git a/ace/config-freebsd.h b/ace/config-freebsd.h
index 1c82991a098..5ed3b1fe135 100644
--- a/ace/config-freebsd.h
+++ b/ace/config-freebsd.h
@@ -30,6 +30,7 @@
// Platform specific directives
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
#define ACE_LACKS_RWLOCK_T
#define ACE_LACKS_READDIR_R
#define ACE_HAS_SIG_MACROS
diff --git a/ace/config-hpux-9.x.h b/ace/config-hpux-9.x.h
index 21acfd86e55..c77788f0df7 100644
--- a/ace/config-hpux-9.x.h
+++ b/ace/config-hpux-9.x.h
@@ -18,6 +18,7 @@
#define ACE_HAS_IP_MULTICAST
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
#define ACE_HAS_BROKEN_CONVERSIONS
// Optimize ACE_Handle_Set for select().
#define ACE_HAS_HANDLE_SET_OPTIMIZED_FOR_SELECT
@@ -26,6 +27,7 @@
#define ACE_LACKS_CONST_TIMESPEC_PTR
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
#define ACE_HAS_IP_MULTICAST
#define ACE_LACKS_SYSCALL
#define ACE_LACKS_STRRECVFD
diff --git a/ace/config-lynxos.h b/ace/config-lynxos.h
index 3bd869b8848..0058523328e 100644
--- a/ace/config-lynxos.h
+++ b/ace/config-lynxos.h
@@ -90,6 +90,7 @@
#define ACE_LACKS_GETHOSTENT
#define ACE_LACKS_GETOPT_PROTO
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
#define ACE_LACKS_MADVISE
#define ACE_LACKS_MKTEMP
#define ACE_LACKS_RWLOCK_T
diff --git a/ace/config-netbsd.h b/ace/config-netbsd.h
index ff9f00717f8..4862af16990 100644
--- a/ace/config-netbsd.h
+++ b/ace/config-netbsd.h
@@ -29,6 +29,7 @@
// Platform specific directives
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
#define ACE_LACKS_RWLOCK_T
#define ACE_HAS_SIG_MACROS
#define ACE_HAS_CHARPTR_DL
diff --git a/ace/config-sunos4-g++.h b/ace/config-sunos4-g++.h
index 739e78174bc..65f5d2625d9 100644
--- a/ace/config-sunos4-g++.h
+++ b/ace/config-sunos4-g++.h
@@ -28,6 +28,7 @@
#define ACE_LACKS_SYSTIME_H
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
#define ACE_HAS_CHARPTR_SPRINTF
#define ACE_HAS_UNION_WAIT
diff --git a/ace/config-sunos4-lucid3.2.h b/ace/config-sunos4-lucid3.2.h
index 2c4317b8722..f30c8cde26d 100644
--- a/ace/config-sunos4-lucid3.2.h
+++ b/ace/config-sunos4-lucid3.2.h
@@ -8,6 +8,7 @@
#define ACE_CONFIG_H
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
// Maximum compensation (10 ms) for early return from timed ::select ().
#if !defined (ACE_TIMER_SKEW)
diff --git a/ace/config-sunos4-sun3.x.h b/ace/config-sunos4-sun3.x.h
index 4c91d18de30..9115692b70b 100644
--- a/ace/config-sunos4-sun3.x.h
+++ b/ace/config-sunos4-sun3.x.h
@@ -7,6 +7,7 @@
#ifndef ACE_CONFIG_H
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
// Maximum compensation (10 ms) for early return from timed ::select ().
#if !defined (ACE_TIMER_SKEW)
diff --git a/ace/config-sunos4-sun4.1.4.h b/ace/config-sunos4-sun4.1.4.h
index c9775e4fd9c..7275e63d648 100644
--- a/ace/config-sunos4-sun4.1.4.h
+++ b/ace/config-sunos4-sun4.1.4.h
@@ -8,6 +8,7 @@
#define ACE_CONFIG_H
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
// Maximum compensation (10 ms) for early return from timed ::select ().
#if !defined (ACE_TIMER_SKEW)
diff --git a/ace/config-sunos4-sun4.x-orbix.h b/ace/config-sunos4-sun4.x-orbix.h
index c429a951c72..b3baa967bd3 100644
--- a/ace/config-sunos4-sun4.x-orbix.h
+++ b/ace/config-sunos4-sun4.x-orbix.h
@@ -8,6 +8,7 @@
#define ACE_CONFIG_H
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
// Maximum compensation (10 ms) for early return from timed ::select ().
#if !defined (ACE_TIMER_SKEW)
diff --git a/ace/config-sunos4-sun4.x.h b/ace/config-sunos4-sun4.x.h
index 701599ab480..9fcb4025ba7 100644
--- a/ace/config-sunos4-sun4.x.h
+++ b/ace/config-sunos4-sun4.x.h
@@ -9,6 +9,7 @@
#define ACE_LACKS_SYSTIME_H
#define ACE_LACKS_GETPGID
+#define ACE_LACKS_SETPGID
#define ACE_HAS_CHARPTR_SPRINTF
#define ACE_LACKS_POSIX_PROTOTYPES
diff --git a/ace/config-win32-common.h b/ace/config-win32-common.h
index 4082f616051..ab4dc4dd8dd 100644
--- a/ace/config-win32-common.h
+++ b/ace/config-win32-common.h
@@ -28,6 +28,7 @@
#define ACE_HAS_SOCKADDR_MSG_NAME
#define ACE_LACKS_GETPGID
#define ACE_LACKS_GETPPID
+#define ACE_LACKS_SETPGID
#define ACE_HAS_THREAD_SAFE_ACCEPT
#define ACE_HAS_EXCEPTIONS
#define ACE_HAS_BROKEN_NAMESPACES
diff --git a/examples/OS/Process/process.cpp b/examples/OS/Process/process.cpp
index 6ba5d5454b2..0467c5fb7b3 100644
--- a/examples/OS/Process/process.cpp
+++ b/examples/OS/Process/process.cpp
@@ -1,6 +1,6 @@
-// ============================================================================
// $Id$
+// ============================================================================
//
// = LIBRARY
// examples
@@ -9,11 +9,11 @@
// process.cpp
//
// = DESCRIPTION
-// This example tests the ACE_Process. For more info, check the
+// This example tests the <ACE_Process>. For more info, check the
// README file in this directory.
//
// = AUTHOR
-// Tim Harrison.
+// Tim Harrison <harrison@cs.wustl.edu>.
//
// ============================================================================
@@ -27,10 +27,12 @@ ACE_RCSID(Process, process, "$Id$")
#define EXEC_NAME "MORE.COM"
const char *DATE_PATH = "date.exe";
const char *LS_PATH = "ls.exe";
+const char *SLEEP_PATH = "sleep.exe";
#else
#define EXEC_NAME "less"
const char *DATE_PATH = "date";
const char *LS_PATH = "ls";
+const char *SLEEP_PATH = "sleep";
#endif /* ACE_WIN32 */
static char *executable = EXEC_NAME;
@@ -42,12 +44,13 @@ 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, char **argv)
{
- ACE_Get_Opt get_opt (argc, argv, "dlx:p:e:gastu");
+ ACE_Get_Opt get_opt (argc, argv, "dlx:p:e:gastuw");
int c;
while ((c = get_opt ()) != -1)
@@ -81,6 +84,9 @@ parse_args (int argc, char **argv)
case 'g':
get_env = 1;
break;
+ case 'w':
+ run_wait = 1;
+ break;
case 'u':
default:
ACE_ERROR_RETURN ((LM_ERROR, "Usage:\n"
@@ -92,6 +98,7 @@ parse_args (int argc, char **argv)
"-s setenv ACE_PROCESS_ENV and spawn -g\n"
"-g get_env ACE_PROCESS_ENV\n"
"-t test tokenizer\n"
+ "-w test wait functions\n"
"-a run all (d,l,e \"running\")\n"), -1);
break;
}
@@ -120,19 +127,25 @@ test_more (void)
if (new_process.spawn (options) == -1)
{
int error = ACE_OS::last_error ();
- ACE_ERROR ((LM_ERROR, "%p errno = %d.\n",
- "test_more", error));
+ ACE_ERROR ((LM_ERROR,
+ "%p errno = %d.\n",
+ "test_more",
+ error));
}
int status;
new_process.wait (&status);
- ACE_DEBUG ((LM_DEBUG, "Process exit with status %d\n", status));
+ ACE_DEBUG ((LM_DEBUG,
+ "Process exit with status %d\n",
+ status));
ACE_OS::close (infile);
- ACE_DEBUG ((LM_DEBUG, "More succeeded.\n"));
+ ACE_DEBUG ((LM_DEBUG,
+ "More succeeded.\n"));
}
// This is a simple usage of ACE_Process.
+
static void
test_date (void)
{
@@ -144,15 +157,20 @@ test_date (void)
if (new_process.spawn (options) == -1)
{
int error = ACE_OS::last_error ();
- ACE_ERROR ((LM_ERROR, "%p errno = %d.\n",
- "test_date", error));
+ ACE_ERROR ((LM_ERROR,
+ "%p errno = %d.\n",
+ "test_date",
+ error));
return;
}
int status;
new_process.wait (&status);
- ACE_DEBUG ((LM_DEBUG, "Process exit with status %d\n", status));
- ACE_DEBUG ((LM_DEBUG, "date succeeded.\n"));
+ ACE_DEBUG ((LM_DEBUG,
+ "Process exit with status %d\n",
+ status));
+ ACE_DEBUG ((LM_DEBUG,
+ "date succeeded.\n"));
}
static void
@@ -165,13 +183,83 @@ test_ls (void)
if (new_process.spawn (options) == -1)
{
int error = ACE_OS::last_error ();
- ACE_ERROR ((LM_ERROR, "%p errno = %d.\n",
- "test_ls", error));
+ ACE_ERROR ((LM_ERROR,
+ "%p errno = %d.\n",
+ "test_ls",
+ error));
}
int status;
new_process.wait (&status);
- ACE_DEBUG ((LM_DEBUG, "Process exit with status %d\n", status));
+ ACE_DEBUG ((LM_DEBUG,
+ "Process exit with status %d\n",
+ status));
+}
+
+static void
+test_wait (void)
+{
+ ACE_Process_Options options;
+ options.command_line ("%s 10", SLEEP_PATH);
+
+ ACE_Process process1;
+ if (process1.spawn (options) == -1)
+ {
+ int error = ACE_OS::last_error ();
+ ACE_ERROR ((LM_ERROR,
+ "%p errno = %d.\n",
+ "test_ls",
+ error));
+ }
+
+ int result;
+ int status;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "[%T] New process sleeping 10; try wait(2)\n",
+ status));
+
+ result = process1.wait (ACE_Time_Value (2),
+ &status);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "[%T] wait(2) returns %d(%d)...now try regular wait\n",
+ result,
+ status));
+
+ result = process1.wait (&status);
+ ACE_DEBUG ((LM_DEBUG,
+ "[%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,
+ "%p errno = %d.\n",
+ "test_ls",
+ error));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ "[%T] New process sleeping 10; try wait(12)\n",
+ status));
+
+ result = process2.wait (ACE_Time_Value (12),
+ &status);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "[%T] wait(12) returns %d(%d)...now try regular wait\n",
+ result,
+ status));
+
+ result = process2.wait (&status);
+ ACE_DEBUG ((LM_DEBUG,
+ "[%T] wait returns %d(%d)\n",
+ result,
+ status));
}
#if defined (ACE_WIN32)
@@ -183,23 +271,27 @@ win32_test_ls (void)
PROCESS_INFORMATION process_info;
STARTUPINFO startup_info;
ACE_OS::memset ((void *) &startup_info,
- 0, sizeof startup_info);
+ 0,
+ sizeof startup_info);
ACE_OS::memset ((void *) &process_info,
- 0, sizeof process_info);
- startup_info.cb = sizeof (startup_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(),
+ if (!::DuplicateHandle (::GetCurrentProcess (),
std_out,
- ::GetCurrentProcess(),
+ ::GetCurrentProcess (),
&startup_info.hStdOutput,
NULL,
TRUE,
DUPLICATE_SAME_ACCESS))
{
- ACE_ERROR ((LM_ERROR, "%p duplicate failed.\n", "test_ls"));
+ ACE_ERROR ((LM_ERROR,
+ "%p duplicate failed.\n",
+ "test_ls"));
return;
}
@@ -218,11 +310,15 @@ win32_test_ls (void)
::CloseHandle (startup_info.hStdOutput);
if (fork_result == 0)
- ACE_ERROR ((LM_ERROR, "%p CreateProcess failed.\n", "test_ls"));
+ ACE_ERROR ((LM_ERROR,
+ "%p CreateProcess failed.\n",
+ "test_ls"));
else
{
- ::WaitForSingleObject (process_info.hProcess, INFINITE);
- ACE_DEBUG ((LM_ERROR, "ls succeeded.\n"));
+ ::WaitForSingleObject (process_info.hProcess,
+ INFINITE);
+ ACE_DEBUG ((LM_ERROR,
+ "ls succeeded.\n"));
}
}
@@ -230,15 +326,18 @@ win32_test_ls (void)
// 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;
STARTUPINFO startup_info;
ACE_OS::memset ((void *) &startup_info,
- 0, sizeof startup_info);
+ 0,
+ sizeof startup_info);
ACE_OS::memset ((void *) &process_info,
- 0, sizeof process_info);
+ 0,
+ sizeof process_info);
startup_info.cb = sizeof (startup_info);
startup_info.dwFlags = STARTF_USESTDHANDLES;
@@ -254,7 +353,8 @@ win32_spawn_environment_process (void)
TRUE,
DUPLICATE_SAME_ACCESS))
{
- ACE_ERROR ((LM_ERROR, "%p duplicate failed.\n", "spawn_environment_process"));
+ ACE_ERROR ((LM_ERROR,
+ "%p duplicate failed.\n", "spawn_environment_process"));
return;
}
@@ -266,7 +366,9 @@ win32_spawn_environment_process (void)
TRUE,
DUPLICATE_SAME_ACCESS))
{
- ACE_ERROR ((LM_ERROR, "%p duplicate failed.\n", "spawn_environment_process"));
+ ACE_ERROR ((LM_ERROR,
+ "%p duplicate failed.\n",
+ "spawn_environment_process"));
return;
}
@@ -278,13 +380,16 @@ win32_spawn_environment_process (void)
TRUE,
DUPLICATE_SAME_ACCESS))
{
- ACE_ERROR ((LM_ERROR, "%p duplicate failed.\n", "spawn_environment_process"));
+ ACE_ERROR ((LM_ERROR,
+ "%p duplicate failed.\n",
+ "spawn_environment_process"));
return;
}
char *existing_environment = ::GetEnvironmentStrings ();
char environment[10240];
- ACE_OS::sprintf (environment, "ACE_PROCESS_TEST=%s",
+ ACE_OS::sprintf (environment,
+ "ACE_PROCESS_TEST=%s",
environment_string);
int size = 0;
@@ -314,11 +419,15 @@ win32_spawn_environment_process (void)
::CloseHandle (startup_info.hStdError);
if (fork_result == 0)
- ACE_ERROR ((LM_ERROR, "%p.\n", "spawn_environment_process"));
+ ACE_ERROR ((LM_ERROR,
+ "%p.\n",
+ "spawn_environment_process"));
else
{
- ::WaitForSingleObject (process_info.hProcess, INFINITE);
- ACE_DEBUG ((LM_ERROR, "spawn_environment_process succeeded.\n"));
+ ::WaitForSingleObject (process_info.hProcess,
+ INFINITE);
+ ACE_DEBUG ((LM_ERROR,
+ "spawn_environment_process succeeded.\n"));
}
}
#endif
@@ -334,13 +443,17 @@ test_setenv (const char *argv0)
ACE_Process process;
if (process.spawn (options) == -1)
{
- ACE_ERROR ((LM_ERROR, "%p.\n", "test_setenv"));
+ ACE_ERROR ((LM_ERROR,
+ "%p.\n",
+ "test_setenv"));
return;
}
int status;
process.wait (&status);
- ACE_DEBUG ((LM_DEBUG, "Process exit with status %d\n", status));
+ ACE_DEBUG ((LM_DEBUG,
+ "Process exit with status %d\n",
+ status));
}
// Tests the ACE_Tokenizer.
@@ -354,15 +467,15 @@ tokenize (char *buffer)
parser.preserve_designators ('\"', '\"'); // " This quote is for emacs
parser.preserve_designators ('\'', '\'');
- const char *temp;
-
- while (1)
+ for (const char *temp; ;-)
{
temp = parser.next ();
if (temp == 0)
break;
- ACE_DEBUG ((LM_DEBUG, temp));
- ACE_DEBUG ((LM_DEBUG, "\n"));
+ ACE_DEBUG ((LM_DEBUG,
+ temp));
+ ACE_DEBUG ((LM_DEBUG,
+ "\n"));
}
}
@@ -370,9 +483,11 @@ int
main (int argc, char *argv[])
{
if (ACE_LOG_MSG->open (argv[0]) == -1)
- ACE_ERROR ((LM_ERROR, "cannot open logger!!!\n"));
+ ACE_ERROR ((LM_ERROR,
+ "cannot open logger!!!\n"));
- ACE_DEBUG ((LM_DEBUG, "starting...\n"));
+ ACE_DEBUG ((LM_DEBUG,
+ "starting...\n"));
if (::parse_args (argc, argv) == -1)
return -1;
@@ -380,14 +495,19 @@ main (int argc, char *argv[])
if (run_all)
{
ACE_Process_Options options;
- options.command_line ("%s -d -l -s", argv[0]);
+ options.command_line ("%s -d -l -s -w",
+ argv[0]);
ACE_Process process;
if (process.spawn (options) == -1)
- ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1);
-
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p.\n",
+ "main"),
+ -1);
int status;
process.wait (&status);
- ACE_DEBUG ((LM_DEBUG, "Process exit with status %d\n", status));
+ ACE_DEBUG ((LM_DEBUG,
+ "Process exit with status %d\n",
+ status));
}
if (run_date)
@@ -401,7 +521,8 @@ main (int argc, char *argv[])
ACE_DEBUG ((LM_DEBUG, "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 = %s.\n"
+ ACE_DEBUG ((LM_DEBUG,
+ "ACE_PROCESS_TEST = %s.\n"
"ACE_PROCESS_TEST2 = %s.\n",
value == 0 ? "no value" : value,
value2 == 0 ? "no value" : value2));
@@ -410,6 +531,9 @@ main (int argc, char *argv[])
if (run_ls)
::test_ls ();
+ if (run_wait)
+ ::test_wait ();
+
#if defined (ACE_WIN32)
if (environment_string != 0)
win32_spawn_environment_process ();