Public Member Functions | Protected Member Functions | Protected Attributes | Private Member Functions | Friends

ACE_Process Class Reference

Process. More...

#include <Process.h>

Inheritance diagram for ACE_Process:
Inheritance graph
[legend]
Collaboration diagram for ACE_Process:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 ACE_Process (void)
 Default construction. Must use <ACE_Process::spawn> to start.
virtual ~ACE_Process (void)
 Destructor.
virtual int prepare (ACE_Process_Options &options)
virtual pid_t spawn (ACE_Process_Options &options)
virtual void parent (pid_t child)
virtual void child (pid_t parent)
virtual void unmanage (void)
pid_t wait (ACE_exitcode *status=0, int wait_options=0)
pid_t wait (const ACE_Time_Value &tv, ACE_exitcode *status=0)
int kill (int signum=SIGINT)
int terminate (void)
pid_t getpid (void) const
 Return the process id of the new child process.
ACE_HANDLE gethandle (void) const
 Return the handle of the process, if it has one.
int running (void) const
 Return 1 if running; 0 otherwise.
ACE_exitcode exit_code (void) const
int return_value (void) const
void close_dup_handles (void)
void close_passed_handles (void)

Protected Member Functions

void exit_code (ACE_exitcode code)

Protected Attributes

pid_t child_id_
 Process id of the child.
ACE_exitcode exit_code_
ACE_Handle_Set handles_passed_
 Set of handles that were passed to the child process.
ACE_Handle_Set dup_handles_
 Handle duplicates made for the child process.

Private Member Functions

 ACE_Process (const ACE_Process &)
void operator= (const ACE_Process &)

Friends

class ACE_Process_Manager

Detailed Description

Process.

A Portable encapsulation for creating new processes. Notice that on UNIX platforms, if the <setenv> is used, the <spawn> is using the <execve> system call. It means that the <command_line> should include a full path to the program file (<execve> does not search the PATH). If <setenv> is not used then, the <spawn> is using the <execvp> which searches for the program file in the PATH variable.

Definition at line 466 of file Process.h.


Constructor & Destructor Documentation

ACE_Process::ACE_Process ( void   ) 

Default construction. Must use <ACE_Process::spawn> to start.

Definition at line 48 of file Process.cpp.

  :
#if !defined (ACE_WIN32)
  child_id_ (ACE_INVALID_PID),
#endif /* !defined (ACE_WIN32) */
  exit_code_ (0)
{
#if defined (ACE_WIN32)
  ACE_OS::memset ((void *) &this->process_info_,
                  0,
                  sizeof this->process_info_);
#endif /* ACE_WIN32 */
}

ACE_Process::~ACE_Process ( void   )  [virtual]

Destructor.

Definition at line 62 of file Process.cpp.

{
#if defined (ACE_WIN32)
  // Free resources allocated in kernel.
  ACE_OS::close (this->process_info_.hThread);
  ACE_OS::close (this->process_info_.hProcess);
#endif /* ACE_WIN32 */
  // If any handles were duplicated for the child process and
  // still not closed, get them now.
  this->close_dup_handles ();
}

ACE_Process::ACE_Process ( const ACE_Process  )  [private]

Member Function Documentation

void ACE_Process::child ( pid_t  parent  )  [virtual]

Called just after <ACE_OS::fork> in the child's context. The default does nothing. This function is *not* called on Win32 because the process-creation scheme does not allow it.

Definition at line 555 of file Process.cpp.

{
  // nothing to do
}

void ACE_Process::close_dup_handles ( void   ) 

Close all the handles in the set obtained from the

Definition at line 715 of file Process.cpp.

{
  if (this->dup_handles_.num_set () > 0)
    {
      ACE_Handle_Set_Iterator h_iter (this->dup_handles_);
      for (ACE_HANDLE h = h_iter ();
           h != ACE_INVALID_HANDLE;
           h = h_iter ())
        ACE_OS::closesocket (h);
      this->dup_handles_.reset ();
    }
  return;
}

void ACE_Process::close_passed_handles ( void   ) 

Close all the handles in the set obtained from the

Definition at line 730 of file Process.cpp.

{
  if (this->handles_passed_.num_set () > 0)
    {
      ACE_Handle_Set_Iterator h_iter (this->handles_passed_);
      for (ACE_HANDLE h = h_iter ();
           h != ACE_INVALID_HANDLE;
           h = h_iter ())
        ACE_OS::closesocket (h);
      this->handles_passed_.reset ();
    }
  return;
}

void ACE_Process::exit_code ( ACE_exitcode  code  )  [protected]

Set this process' <exit_code_>. ACE_Process_Manager uses this method to set the <exit_code_> after successfully waiting for this process to exit.

Definition at line 114 of file Process.inl.

{
  this->exit_code_ = code;
}

ACE_exitcode ACE_Process::exit_code ( void   )  const

Return the Process' exit code. This method returns the raw exit status returned from system APIs (such as <wait> or <waitpid>). This value is system dependent.

Definition at line 108 of file Process.inl.

{
  return this->exit_code_;
}

ACE_HANDLE ACE_Process::gethandle ( void   )  const

Return the handle of the process, if it has one.

Definition at line 41 of file Process.inl.

{
#if defined (ACE_WIN32)
  return process_info_.hProcess;
#else
  return ACE_HANDLE (child_id_);
#endif /* ACE_WIN32 */
}

pid_t ACE_Process::getpid ( void   )  const

Return the process id of the new child process.

Definition at line 51 of file Process.inl.

{
#if defined (ACE_WIN32)
  return process_info_.dwProcessId;
#else /* ACE_WIN32 */
  return child_id_;
#endif /* ACE_WIN32 */
}

int ACE_Process::kill ( int  signum = SIGINT  ) 

Send the process a signal. This is only portable to operating systems that support signals, such as UNIX/POSIX.

Definition at line 80 of file Process.inl.

{
  if (this->getpid () != -1)
    return ACE_OS::kill (this->getpid (), signum);
  else
    return -1;
}

void ACE_Process::operator= ( const ACE_Process  )  [private]
void ACE_Process::parent ( pid_t  child  )  [virtual]

Called just after <ACE_OS::fork> in the parent's context, if the <fork> succeeds. The default is to do nothing.

Definition at line 549 of file Process.cpp.

{
  // nothing to do
}

int ACE_Process::prepare ( ACE_Process_Options options  )  [virtual]

Called just before <ACE_OS::fork> in the <spawn>. If this returns non-zero, the <spawn> is aborted (and returns ACE_INVALID_PID). The default simply returns zero.

Definition at line 75 of file Process.cpp.

{
  return 0;
}

int ACE_Process::return_value ( void   )  const

Return the Process' return value. This method returns the actual return value that a child process returns or <exit>s.

Definition at line 98 of file Process.inl.

{
#if defined (ACE_WIN32)
  return this->exit_code_;
#else
  return WEXITSTATUS (this->exit_code_);
#endif /* ACE_WIN32 */
}

int ACE_Process::running ( void   )  const

Return 1 if running; 0 otherwise.

Definition at line 567 of file Process.cpp.

{
#if defined (ACE_WIN32)
    DWORD code;

    BOOL result = ::GetExitCodeProcess (this->gethandle (),
                                        &code);
    return result && code == STILL_ACTIVE;
#else
  if (ACE_INVALID_PID == this->getpid ())
    return 0;
  else
    return ACE_OS::kill (this->getpid (),
                         0) == 0
      || errno != ESRCH;
#endif /* ACE_WIN32 */
}

pid_t ACE_Process::spawn ( ACE_Process_Options options  )  [virtual]

Launch a new process as described by options. On success, returns 1 if the option avoid_zombies is set, else returns the process id of the newly spawned child. Returns -1 on failure. This will be fixed in the future versions of ACE when the process id of the child will be returned regardless of the option.

Definition at line 81 of file Process.cpp.

{
  if (this->prepare (options) < 0)
    return ACE_INVALID_PID;

  // Stash the passed/duped handle sets away in this object for later
  // closing if needed or requested. At the same time, figure out which
  // ones to include in command line options if that's needed below.
  ACE_Handle_Set *set_p = 0;
  if (options.dup_handles (this->dup_handles_))
    set_p = &this->dup_handles_;
  else if (options.passed_handles (this->handles_passed_))
    set_p = &this->handles_passed_;

  // If we are going to end up running a new program (i.e. Win32, or
  // NO_EXEC option is set) then get any handles passed in the options,
  // and tack them onto the command line with +H <handle> options,
  // unless the command line runs out of space.
  // Note that we're using the knowledge that all the options, argvs, etc.
  // passed to the options are all sitting in the command_line_buf. Any
  // call to get the argv then splits them out. So, regardless of the
  // platform, tack them all onto the command line buf and take it
  // from there.
  if (set_p && !ACE_BIT_ENABLED (options.creation_flags (),
                                 ACE_Process_Options::NO_EXEC))
    {
      int maxlen = 0;
      ACE_TCHAR *cmd_line_buf = options.command_line_buf (&maxlen);
      size_t max_len = static_cast<size_t> (maxlen);
      size_t curr_len = ACE_OS::strlen (cmd_line_buf);
      ACE_Handle_Set_Iterator h_iter (*set_p);
      // Because the length of the to-be-formatted +H option is not
      // known, and we don't have a snprintf, guess at the space
      // needed (20 chars), and use that as a limit.
      for (ACE_HANDLE h = h_iter ();
           h != ACE_INVALID_HANDLE && curr_len + 20 < max_len;
           h = h_iter ())
        {
#if defined (ACE_WIN32)
# if defined (ACE_WIN64)
          curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
                                       ACE_TEXT (" +H %I64p"),
                                       h);
# else
          curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
                                       ACE_TEXT (" +H %p"),
                                       h);
# endif  /* ACE_WIN64 */
#else
          curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
                                       ACE_TEXT (" +H %d"),
                                       h);
#endif /* ACE_WIN32 */
        }
    }

#if defined (ACE_HAS_WINCE)
  // Note that WinCE does not have process name included in the command line as argv[0]
  // like other OS environment.  Therefore, it is user's whole responsibility to call
  // 'ACE_Process_Options::process_name(const ACE_TCHAR *name)' to set the proper
  // process name (the execution file name with path if needed).
  BOOL fork_result =
    ACE_TEXT_CreateProcess (options.process_name(),
                            options.command_line_buf(),
                            options.get_process_attributes(),  // must be NULL in CE
                            options.get_thread_attributes(),   // must be NULL in CE
                            options.handle_inheritance(),      // must be false in CE
                            options.creation_flags(),          // must be NULL in CE
                            options.env_buf(),                 // environment variables, must be NULL in CE
                            options.working_directory(),       // must be NULL in CE
                            options.startup_info(),            // must be NULL in CE
                            &this->process_info_);

  if (fork_result)
    {
      parent (this->getpid ());
      return this->getpid ();
    }
  return ACE_INVALID_PID;

#elif defined (ACE_WIN32)
  void* env_buf = options.env_buf ();
  DWORD flags = options.creation_flags ();
# if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
  wchar_t* wenv_buf = 0;
  if (options.use_unicode_environment ())
    {
      wenv_buf = this->convert_env_buffer (options.env_buf ());
      env_buf = wenv_buf;
      flags |= CREATE_UNICODE_ENVIRONMENT;
    }
# endif

  BOOL fork_result =
    ACE_TEXT_CreateProcess (0,
                            options.command_line_buf (),
                            options.get_process_attributes (),
                            options.get_thread_attributes (),
                            options.handle_inheritance (),
                            flags,
                            env_buf, // environment variables
                            options.working_directory (),
                            options.startup_info (),
                            &this->process_info_);

# if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
  if (options.use_unicode_environment ())
    delete wenv_buf;
# endif

  if (fork_result)
    {
      parent (this->getpid ());
      return this->getpid ();
    }
  return ACE_INVALID_PID;

#elif defined(ACE_OPENVMS)
  if (ACE_BIT_ENABLED (options.creation_flags (),
                       ACE_Process_Options::NO_EXEC))
    ACE_NOTSUP_RETURN (ACE_INVALID_PID);

  int saved_stdin = ACE_STDIN;
  int saved_stdout = ACE_STDOUT;
  int saved_stderr = ACE_STDERR;
  // Save STD file descriptors and redirect
  if (options.get_stdin () != ACE_INVALID_HANDLE) {
    if ((saved_stdin = ACE_OS::dup (ACE_STDIN)) == -1 && errno != EBADF)
      ACE_OS::exit (errno);
    if (ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1)
      ACE_OS::exit (errno);
  }
  if (options.get_stdout () != ACE_INVALID_HANDLE) {
    if ((saved_stdout = ACE_OS::dup (ACE_STDOUT)) == -1 && errno != EBADF)
      ACE_OS::exit (errno);
    if (ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1)
      ACE_OS::exit (errno);
  }
  if (options.get_stderr () != ACE_INVALID_HANDLE) {
    if ((saved_stderr = ACE_OS::dup (ACE_STDERR)) == -1 && errno != EBADF)
      ACE_OS::exit (errno);
    if (ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1)
      ACE_OS::exit (errno);
  }

  if (options.working_directory () != 0)
    ACE_NOTSUP_RETURN (ACE_INVALID_PID);

  this->child_id_ = vfork();
  if (this->child_id_ == 0) {
      ACE_OS::execvp (options.process_name (),
                options.command_line_argv ());
      // something went wrong
      this->child_id_ = ACE_INVALID_PID;
  }

  // restore STD file descriptors (if necessary)
  if (options.get_stdin () != ACE_INVALID_HANDLE) {
    if (saved_stdin == -1)
      ACE_OS::close (ACE_STDIN);
    else
      ACE_OS::dup2 (saved_stdin, ACE_STDIN);
  }
  if (options.get_stdout () != ACE_INVALID_HANDLE) {
    if (saved_stdout == -1)
      ACE_OS::close (ACE_STDOUT);
    else
      ACE_OS::dup2 (saved_stdout, ACE_STDOUT);
  }
  if (options.get_stderr () != ACE_INVALID_HANDLE) {
    if (saved_stderr == -1)
      ACE_OS::close (ACE_STDERR);
    else
      ACE_OS::dup2 (saved_stderr, ACE_STDERR);
  }

  return this->child_id_;
#elif (defined (ACE_VXWORKS) && (ACE_VXWORKS > 0x600)) && defined (__RTP__)
  if (ACE_BIT_ENABLED (options.creation_flags (),
                       ACE_Process_Options::NO_EXEC))
    ACE_NOTSUP_RETURN (ACE_INVALID_PID);

  if (options.working_directory () != 0)
    ACE_NOTSUP_RETURN (ACE_INVALID_PID);

  int saved_stdin = ACE_STDIN;
  int saved_stdout = ACE_STDOUT;
  int saved_stderr = ACE_STDERR;
  // Save STD file descriptors and redirect
  if (options.get_stdin () != ACE_INVALID_HANDLE) {
    if ((saved_stdin = ACE_OS::dup (ACE_STDIN)) == -1 && errno != EBADF)
      ACE_OS::exit (errno);
    if (ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1)
      ACE_OS::exit (errno);
  }
  if (options.get_stdout () != ACE_INVALID_HANDLE) {
    if ((saved_stdout = ACE_OS::dup (ACE_STDOUT)) == -1 && errno != EBADF)
      ACE_OS::exit (errno);
    if (ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1)
      ACE_OS::exit (errno);
  }
  if (options.get_stderr () != ACE_INVALID_HANDLE) {
    if ((saved_stderr = ACE_OS::dup (ACE_STDERR)) == -1 && errno != EBADF)
      ACE_OS::exit (errno);
    if (ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1)
      ACE_OS::exit (errno);
  }

  // Wide-char builds need narrow-char strings for commandline and
  // environment variables.
# if defined (ACE_USES_WCHAR)
  wchar_t * const *wargv = options.command_line_argv ();
  size_t vcount, i;
  for (vcount = 0; wargv[vcount] != 0; ++vcount)
    ;
  char **procargv = new char *[vcount + 1];  // Need 0 at the end
  procargv[vcount] = 0;
  for (i = 0; i < vcount; ++i)
    procargv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);

  char **procenv = 0;
  if (options.inherit_environment ())
    {
      wargv = options.env_argv ();
      for (vcount = 0; wargv[vcount] != 0; ++vcount)
        ;
      procenv = new char *[vcount + 1];  // Need 0 at the end
      procenv[vcount] = 0;
      for (i = 0; i < vcount; ++i)
        procenv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);
    }
# else
  const char **procargv = const_cast<const char**> (options.command_line_argv ());
  const char **procenv = const_cast<const char**> (options.env_argv ());
# endif /* ACE_USES_WCHAR */

  this->child_id_ = ::rtpSpawn (procargv[0],
                                procargv,
                                procenv,
                                200,          // priority
                                0x10000,      // uStackSize
                                0,            // options
                                VX_FP_TASK);  // taskOptions
  int my_errno_ = errno;
  if (this->child_id_ == ERROR) {
      // something went wrong
      this->child_id_ = ACE_INVALID_PID;
  }

# if defined (ACE_USES_WCHAR)
  if (procenv)
    delete procenv;
# endif /* ACE_USES_WCHAR */

  // restore STD file descriptors (if necessary)
  if (options.get_stdin () != ACE_INVALID_HANDLE) {
    if (saved_stdin == -1)
      ACE_OS::close (ACE_STDIN);
    else
      ACE_OS::dup2 (saved_stdin, ACE_STDIN);
  }
  if (options.get_stdout () != ACE_INVALID_HANDLE) {
    if (saved_stdout == -1)
      ACE_OS::close (ACE_STDOUT);
    else
      ACE_OS::dup2 (saved_stdout, ACE_STDOUT);
  }
  if (options.get_stderr () != ACE_INVALID_HANDLE) {
    if (saved_stderr == -1)
      ACE_OS::close (ACE_STDERR);
    else
      ACE_OS::dup2 (saved_stderr, ACE_STDERR);
  }

  if (this->child_id_ == ACE_INVALID_PID)
    {
      errno = my_errno_;
    }

  return this->child_id_;
#else /* ACE_WIN32 */
  // Fork the new process.
  this->child_id_ = ACE::fork (options.process_name (),
                               options.avoid_zombies ());

  if (this->child_id_ == 0)
    {
# if !defined (ACE_LACKS_SETPGID)
      // If we're the child and the options specified a non-default
      // process group, try to set our pgid to it.  This allows the
      // <ACE_Process_Manager> to wait for processes by their
      // process-group.
      if (options.getgroup () != ACE_INVALID_PID
          && ACE_OS::setpgid (0,
                              options.getgroup ()) < 0)
        {
#if !defined (ACE_HAS_THREADS)
          // We can't emit this log message because ACE_ERROR(), etc.
          // will invoke async signal unsafe functions, which results
          // in undefined behavior in threaded programs.
          ACE_ERROR ((LM_ERROR,
                      ACE_TEXT ("%p.\n"),
                      ACE_TEXT ("ACE_Process::spawn: setpgid failed.")));
#endif
        }
# endif /* ACE_LACKS_SETPGID */

# if !defined (ACE_LACKS_SETREGID)
      if (options.getrgid () != (uid_t) -1
          || options.getegid () != (uid_t) -1)
        if (ACE_OS::setregid (options.getrgid (),
                              options.getegid ()) == -1)
          {
#if !defined (ACE_HAS_THREADS)
            // We can't emit this log message because ACE_ERROR(), etc.
            // will invoke async signal unsafe functions, which results
            // in undefined behavior in threaded programs.
            ACE_ERROR ((LM_ERROR,
                        ACE_TEXT ("%p.\n"),
                        ACE_TEXT ("ACE_Process::spawn: setregid failed.")));
#endif
          }
# endif /* ACE_LACKS_SETREGID */

# if !defined (ACE_LACKS_SETREUID)
      // Set user and group id's.
      if (options.getruid () != (uid_t) -1
          || options.geteuid () != (uid_t) -1)
        if (ACE_OS::setreuid (options.getruid (),
                              options.geteuid ()) == -1)
          {
#if !defined (ACE_HAS_THREADS)
            // We can't emit this log message because ACE_ERROR(), etc.
            // will invoke async signal unsafe functions, which results
            // in undefined behavior in threaded programs.
            ACE_ERROR ((LM_ERROR,
                        ACE_TEXT ("%p.\n"),
                        ACE_TEXT ("ACE_Process::spawn: setreuid failed.")));
#endif
          }
# endif /* ACE_LACKS_SETREUID */

      this->child (ACE_OS::getppid ());
    }
  else if (this->child_id_ != -1)
    this->parent (this->child_id_);

  // If we're not supposed to exec, return the process id.
  if (ACE_BIT_ENABLED (options.creation_flags (),
                       ACE_Process_Options::NO_EXEC))
    return this->child_id_;

  switch (this->child_id_)
    {
    case -1:
      // Error.
      return ACE_INVALID_PID;
    case 0:
      // Child process...exec the
      {
        if (options.get_stdin () != ACE_INVALID_HANDLE
            && ACE_OS::dup2 (options.get_stdin (),
                             ACE_STDIN) == -1)
          ACE_OS::exit (errno);
        else if (options.get_stdout () != ACE_INVALID_HANDLE
                 && ACE_OS::dup2 (options.get_stdout (),
                                  ACE_STDOUT) == -1)
          ACE_OS::exit (errno);
        else if (options.get_stderr () != ACE_INVALID_HANDLE
                 && ACE_OS::dup2 (options.get_stderr (),
                                  ACE_STDERR) == -1)
          ACE_OS::exit (errno);

        // close down unneeded descriptors
        ACE_OS::close (options.get_stdin ());
        ACE_OS::close (options.get_stdout ());
        ACE_OS::close (options.get_stderr ());
        if (!options.handle_inheritance ())
          {
            // Set close-on-exec for all FDs except standard handles
            for (int i = ACE::max_handles () - 1; i >= 0; i--)
              {
                if (i == ACE_STDIN || i == ACE_STDOUT || i == ACE_STDERR)
                  continue;
                ACE_OS::fcntl (i, F_SETFD, FD_CLOEXEC);
              }
          }

        // If we must, set the working directory for the child
        // 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;

        // Wide-char builds not on Windows need narrow-char strings for
        // exec() and environment variables. Don't need to worry about
        // releasing any of the converted string memory since this
        // process will either exec() or exit() shortly.
# if defined (ACE_USES_WCHAR)
        ACE_Wide_To_Ascii n_procname (options.process_name ());
        const char *procname = n_procname.char_rep ();

        wchar_t * const *wargv = options.command_line_argv ();
        size_t vcount, i;
        for (vcount = 0; wargv[vcount] != 0; ++vcount)
          ;
        char **procargv = new char *[vcount + 1];  // Need 0 at the end
        procargv[vcount] = 0;
        for (i = 0; i < vcount; ++i)
          procargv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);

        wargv = options.env_argv ();
        for (vcount = 0; wargv[vcount] != 0; ++vcount)
          ;
        char **procenv = new char *[vcount + 1];  // Need 0 at the end
        procenv[vcount] = 0;
        for (i = 0; i < vcount; ++i)
          procenv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);
# else
        const char *procname = options.process_name ();
        char *const *procargv = options.command_line_argv ();
        char *const *procenv = options.env_argv ();
# endif /* ACE_USES_WCHAR */

        if (options.inherit_environment ())
          {
            // Add the new environment variables to the environment
            // context of the context before doing an <execvp>.
            for (size_t i = 0; procenv[i] != 0; i++)
              if (ACE_OS::putenv (procenv[i]) != 0)
                return ACE_INVALID_PID;

            // Now the forked process has both inherited variables and
            // the user's supplied variables.
            result = ACE_OS::execvp (procname, procargv);
          }
        else
          {
# 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 (ACE_INVALID_PID);
# else
            result = ACE_OS::execve (procname, procargv, procenv);
# endif /* ghs */
          }
        if (result == -1)
          {
            // If the execv fails, this child needs to exit.

            // Exit with the errno so that the calling process can
            // catch this and figure out what went wrong.
            ACE_OS::_exit (errno);
          }
        // ... otherwise, this is never reached.
        return 0;
      }
    default:
      // Server process.  The fork succeeded.
      return this->child_id_;
    }
#endif /* ACE_WIN32 */
}

int ACE_Process::terminate ( void   ) 

Terminate the process abruptly using ACE::terminate_process(). This call doesn't give the process a chance to cleanup, so use it with caution...

Definition at line 89 of file Process.inl.

{
  if (this->getpid () != -1)
    return ACE::terminate_process (this->getpid ());
  else
    return -1;
}

void ACE_Process::unmanage ( void   )  [virtual]

Called by a Process_Manager that is removing this Process from its table of managed Processes. Default is to do nothing.

Reimplemented in ACE_Managed_Process.

Definition at line 561 of file Process.cpp.

{
  // nothing to do
}

pid_t ACE_Process::wait ( ACE_exitcode status = 0,
int  wait_options = 0 
)

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.

Definition at line 62 of file Process.inl.

{
  pid_t retv =
    ACE_OS::wait (this->getpid (),
                  &this->exit_code_,
                  wait_options
#if defined (ACE_WIN32)
                  , process_info_.hProcess
#endif /* ACE_WIN32 */
                  );
  if (status != 0)
    *status = this->exit_code_;

  return retv;
}

pid_t ACE_Process::wait ( const ACE_Time_Value tv,
ACE_exitcode status = 0 
)

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.

Definition at line 586 of file Process.cpp.

{
#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:
        // The error status of <GetExitCodeProcess> is nonetheless not
        // tested because we don't know how to return the value.
        ::GetExitCodeProcess (process_info_.hProcess,
                              &this->exit_code_);
      if (status != 0)
        *status = this->exit_code_;
      return this->getpid ();
    case WAIT_TIMEOUT:
      errno = ETIME;
      return 0;
    default:
      ACE_OS::set_errno_to_last_error ();
      return -1;
    }
#elif defined(ACE_LACKS_UNIX_SIGNALS)
  if (tv == ACE_Time_Value::zero)
    {
      pid_t retv =
        ACE_OS::waitpid (this->child_id_,
                         &this->exit_code_,
                         WNOHANG);
      if (status != 0)
        *status = this->exit_code_;

      return retv;
    }

  if (tv == ACE_Time_Value::max_time)
# if defined (ACE_VXWORKS)
    {
      pid_t retv;
      while ( (retv = this->wait (status)) == ACE_INVALID_PID && errno == EINTR ) ;
      return retv;
    }
# else
     return this->wait (status);
# endif

  pid_t pid = 0;
  ACE_Time_Value sleeptm (1);    // 1 msec
  if (sleeptm > tv)              // if sleeptime > waittime
      sleeptm = tv;
  ACE_Time_Value tmo (tv);       // Need one we can change
  for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ())
    {
      pid = ACE_OS::waitpid (this->getpid (),
                             &this->exit_code_,
                             WNOHANG);
      if (status != 0)
        *status = this->exit_code_;

      if (pid > 0 || pid == ACE_INVALID_PID)
        break;          // Got a child or an error - all done

      // pid 0, nothing is ready yet, so wait.
      // Do a (very) short sleep (only this thread sleeps).
      ACE_OS::sleep (sleeptm);
    }

  return pid;
#else /* !ACE_WIN32 && !ACE_LACKS_UNIX_SIGNALS */
  if (tv == ACE_Time_Value::zero)
    {
      pid_t retv =
        ACE_OS::waitpid (this->child_id_,
                         &this->exit_code_,
                         WNOHANG);
      if (status != 0)
        *status = this->exit_code_;

      return retv;
    }

  if (tv == ACE_Time_Value::max_time)
    return this->wait (status);

  // Need to wait but limited to specified time.
  // Force generation of SIGCHLD, even though we don't want to
  // catch it - just need it to interrupt the sleep below.
  // If this object has a reactor set, assume it was given at
  // open(), and there's already a SIGCHLD action set, so no
  // action is needed here.
  ACE_Sig_Action old_action;
  ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop);
  do_sigchld.register_action (SIGCHLD, &old_action);

  pid_t pid;
  ACE_Time_Value tmo (tv);       // Need one we can change
  for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ())
    {
      pid = ACE_OS::waitpid (this->getpid (),
                             &this->exit_code_,
                             WNOHANG);
      if (status != 0)
        *status = this->exit_code_;

      if (pid > 0 || pid == ACE_INVALID_PID)
        break;          // Got a child or an error - all done

      // pid 0, nothing is ready yet, so wait.
      // Do a sleep (only this thread sleeps) til something
      // happens. This relies on SIGCHLD interrupting the sleep.
      // If SIGCHLD isn't delivered, we'll need to do something
      // with sigaction to force it.
      if (-1 == ACE_OS::sleep (tmo) && errno == EINTR)
        continue;
      // Timed out
      pid = 0;
      break;
    }

  // Restore the previous SIGCHLD action if it was changed.
  old_action.register_action (SIGCHLD);

  return pid;
#endif /* ACE_WIN32 */
}


Friends And Related Function Documentation

friend class ACE_Process_Manager [friend]

Definition at line 469 of file Process.h.


Member Data Documentation

pid_t ACE_Process::child_id_ [protected]

Process id of the child.

Definition at line 594 of file Process.h.

Handle duplicates made for the child process.

Definition at line 602 of file Process.h.

Definition at line 596 of file Process.h.

Set of handles that were passed to the child process.

Definition at line 599 of file Process.h.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines