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)
PROCESS_INFORMATION process_info (void)

Protected Member Functions

void exit_code (ACE_exitcode code)

Protected Attributes

PROCESS_INFORMATION process_info_
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 &)
wchar_t * convert_env_buffer (const char *env) const

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 460 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.

00049   :
00050 #if !defined (ACE_WIN32)
00051   child_id_ (ACE_INVALID_PID),
00052 #endif /* !defined (ACE_WIN32) */
00053   exit_code_ (0)
00054 {
00055 #if defined (ACE_WIN32)
00056   ACE_OS::memset ((void *) &this->process_info_,
00057                   0,
00058                   sizeof this->process_info_);
00059 #endif /* ACE_WIN32 */
00060 }

ACE_Process::~ACE_Process ( void   )  [virtual]

Destructor.

Definition at line 62 of file Process.cpp.

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

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.

00556 {
00557   // nothing to do
00558 }

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.

00716 {
00717   if (this->dup_handles_.num_set () > 0)
00718     {
00719       ACE_Handle_Set_Iterator h_iter (this->dup_handles_);
00720       for (ACE_HANDLE h = h_iter ();
00721            h != ACE_INVALID_HANDLE;
00722            h = h_iter ())
00723         ACE_OS::closesocket (h);
00724       this->dup_handles_.reset ();
00725     }
00726   return;
00727 }

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.

00731 {
00732   if (this->handles_passed_.num_set () > 0)
00733     {
00734       ACE_Handle_Set_Iterator h_iter (this->handles_passed_);
00735       for (ACE_HANDLE h = h_iter ();
00736            h != ACE_INVALID_HANDLE;
00737            h = h_iter ())
00738         ACE_OS::closesocket (h);
00739       this->handles_passed_.reset ();
00740     }
00741   return;
00742 }

wchar_t* ACE_Process::convert_env_buffer ( const char *  env  )  const [private]
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.

00115 {
00116   this->exit_code_ = code;
00117 }

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.

00109 {
00110   return this->exit_code_;
00111 }

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.

00042 {
00043 #if defined (ACE_WIN32)
00044   return process_info_.hProcess;
00045 #else
00046   return ACE_HANDLE (child_id_);
00047 #endif /* ACE_WIN32 */
00048 }

pid_t ACE_Process::getpid ( void   )  const

Return the process id of the new child process.

Definition at line 51 of file Process.inl.

00053 {
00054 #if defined (ACE_WIN32)
00055   return process_info_.dwProcessId;
00056 #else /* ACE_WIN32 */
00057   return child_id_;
00058 #endif /* ACE_WIN32 */
00059 }

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.

00081 {
00082   if (this->getpid () != -1)
00083     return ACE_OS::kill (this->getpid (), signum);
00084   else
00085     return -1;
00086 }

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.

00550 {
00551   // nothing to do
00552 }

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.

00076 {
00077   return 0;
00078 }

PROCESS_INFORMATION ACE_Process::process_info ( void   ) 
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.

00099 {
00100 #if defined (ACE_WIN32)
00101   return this->exit_code_;
00102 #else
00103   return WEXITSTATUS (this->exit_code_);
00104 #endif /* ACE_WIN32 */
00105 }

int ACE_Process::running ( void   )  const

Return 1 if running; 0 otherwise.

Definition at line 567 of file Process.cpp.

00568 {
00569 #if defined (ACE_WIN32)
00570     DWORD code;
00571 
00572     BOOL result = ::GetExitCodeProcess (this->gethandle (),
00573                                         &code);
00574     return result && code == STILL_ACTIVE;
00575 #else
00576   if (ACE_INVALID_PID == this->getpid ())
00577     return 0;
00578   else
00579     return ACE_OS::kill (this->getpid (),
00580                          0) == 0
00581       || errno != ESRCH;
00582 #endif /* ACE_WIN32 */
00583 }

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.

00082 {
00083   if (this->prepare (options) < 0)
00084     return ACE_INVALID_PID;
00085 
00086   // Stash the passed/duped handle sets away in this object for later
00087   // closing if needed or requested. At the same time, figure out which
00088   // ones to include in command line options if that's needed below.
00089   ACE_Handle_Set *set_p = 0;
00090   if (options.dup_handles (this->dup_handles_))
00091     set_p = &this->dup_handles_;
00092   else if (options.passed_handles (this->handles_passed_))
00093     set_p = &this->handles_passed_;
00094 
00095   // If we are going to end up running a new program (i.e. Win32, or
00096   // NO_EXEC option is set) then get any handles passed in the options,
00097   // and tack them onto the command line with +H <handle> options,
00098   // unless the command line runs out of space.
00099   // Note that we're using the knowledge that all the options, argvs, etc.
00100   // passed to the options are all sitting in the command_line_buf. Any
00101   // call to get the argv then splits them out. So, regardless of the
00102   // platform, tack them all onto the command line buf and take it
00103   // from there.
00104   if (set_p && !ACE_BIT_ENABLED (options.creation_flags (),
00105                                  ACE_Process_Options::NO_EXEC))
00106     {
00107       int maxlen = 0;
00108       ACE_TCHAR *cmd_line_buf = options.command_line_buf (&maxlen);
00109       size_t max_len = static_cast<size_t> (maxlen);
00110       size_t curr_len = ACE_OS::strlen (cmd_line_buf);
00111       ACE_Handle_Set_Iterator h_iter (*set_p);
00112       // Because the length of the to-be-formatted +H option is not
00113       // known, and we don't have a snprintf, guess at the space
00114       // needed (20 chars), and use that as a limit.
00115       for (ACE_HANDLE h = h_iter ();
00116            h != ACE_INVALID_HANDLE && curr_len + 20 < max_len;
00117            h = h_iter ())
00118         {
00119 #if defined (ACE_WIN32)
00120 # if defined (ACE_WIN64)
00121           curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
00122                                        ACE_TEXT (" +H %I64p"),
00123                                        h);
00124 # else
00125           curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
00126                                        ACE_TEXT (" +H %p"),
00127                                        h);
00128 # endif  /* ACE_WIN64 */
00129 #else
00130           curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
00131                                        ACE_TEXT (" +H %d"),
00132                                        h);
00133 #endif /* ACE_WIN32 */
00134         }
00135     }
00136 
00137 #if defined (ACE_HAS_WINCE)
00138   // Note that WinCE does not have process name included in the command line as argv[0]
00139   // like other OS environment.  Therefore, it is user's whole responsibility to call
00140   // 'ACE_Process_Options::process_name(const ACE_TCHAR *name)' to set the proper
00141   // process name (the execution file name with path if needed).
00142   BOOL fork_result =
00143     ACE_TEXT_CreateProcess (options.process_name(),
00144                             options.command_line_buf(),
00145                             options.get_process_attributes(),  // must be NULL in CE
00146                             options.get_thread_attributes(),   // must be NULL in CE
00147                             options.handle_inheritance(),      // must be false in CE
00148                             options.creation_flags(),          // must be NULL in CE
00149                             options.env_buf(),                 // environment variables, must be NULL in CE
00150                             options.working_directory(),       // must be NULL in CE
00151                             options.startup_info(),            // must be NULL in CE
00152                             &this->process_info_);
00153 
00154   if (fork_result)
00155     {
00156       parent (this->getpid ());
00157       return this->getpid ();
00158     }
00159   return ACE_INVALID_PID;
00160 
00161 #elif defined (ACE_WIN32)
00162   void* env_buf = options.env_buf ();
00163   DWORD flags = options.creation_flags ();
00164 # if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
00165   wchar_t* wenv_buf = 0;
00166   if (options.use_unicode_environment ())
00167     {
00168       wenv_buf = this->convert_env_buffer (options.env_buf ());
00169       env_buf = wenv_buf;
00170       flags |= CREATE_UNICODE_ENVIRONMENT;
00171     }
00172 # endif
00173 
00174   BOOL fork_result =
00175     ACE_TEXT_CreateProcess (0,
00176                             options.command_line_buf (),
00177                             options.get_process_attributes (),
00178                             options.get_thread_attributes (),
00179                             options.handle_inheritance (),
00180                             flags,
00181                             env_buf, // environment variables
00182                             options.working_directory (),
00183                             options.startup_info (),
00184                             &this->process_info_);
00185 
00186 # if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
00187   if (options.use_unicode_environment ())
00188     delete wenv_buf;
00189 # endif
00190 
00191   if (fork_result)
00192     {
00193       parent (this->getpid ());
00194       return this->getpid ();
00195     }
00196   return ACE_INVALID_PID;
00197 
00198 #elif defined(ACE_OPENVMS)
00199   if (ACE_BIT_ENABLED (options.creation_flags (),
00200                        ACE_Process_Options::NO_EXEC))
00201     ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00202 
00203   int saved_stdin = ACE_STDIN;
00204   int saved_stdout = ACE_STDOUT;
00205   int saved_stderr = ACE_STDERR;
00206   // Save STD file descriptors and redirect
00207   if (options.get_stdin () != ACE_INVALID_HANDLE) {
00208     if ((saved_stdin = ACE_OS::dup (ACE_STDIN)) == -1 && errno != EBADF)
00209       ACE_OS::exit (errno);
00210     if (ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1)
00211       ACE_OS::exit (errno);
00212   }
00213   if (options.get_stdout () != ACE_INVALID_HANDLE) {
00214     if ((saved_stdout = ACE_OS::dup (ACE_STDOUT)) == -1 && errno != EBADF)
00215       ACE_OS::exit (errno);
00216     if (ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1)
00217       ACE_OS::exit (errno);
00218   }
00219   if (options.get_stderr () != ACE_INVALID_HANDLE) {
00220     if ((saved_stderr = ACE_OS::dup (ACE_STDERR)) == -1 && errno != EBADF)
00221       ACE_OS::exit (errno);
00222     if (ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1)
00223       ACE_OS::exit (errno);
00224   }
00225 
00226   if (options.working_directory () != 0)
00227     ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00228 
00229   this->child_id_ = vfork();
00230   if (this->child_id_ == 0) {
00231       ACE_OS::execvp (options.process_name (),
00232                 options.command_line_argv ());
00233       // something went wrong
00234       this->child_id_ = ACE_INVALID_PID;
00235   }
00236 
00237   // restore STD file descriptors (if necessary)
00238   if (options.get_stdin () != ACE_INVALID_HANDLE) {
00239     if (saved_stdin == -1)
00240       ACE_OS::close (ACE_STDIN);
00241     else
00242       ACE_OS::dup2 (saved_stdin, ACE_STDIN);
00243   }
00244   if (options.get_stdout () != ACE_INVALID_HANDLE) {
00245     if (saved_stdout == -1)
00246       ACE_OS::close (ACE_STDOUT);
00247     else
00248       ACE_OS::dup2 (saved_stdout, ACE_STDOUT);
00249   }
00250   if (options.get_stderr () != ACE_INVALID_HANDLE) {
00251     if (saved_stderr == -1)
00252       ACE_OS::close (ACE_STDERR);
00253     else
00254       ACE_OS::dup2 (saved_stderr, ACE_STDERR);
00255   }
00256 
00257   return this->child_id_;
00258 #elif (defined (ACE_VXWORKS) && (ACE_VXWORKS > 0x600)) && defined (__RTP__)
00259   if (ACE_BIT_ENABLED (options.creation_flags (),
00260                        ACE_Process_Options::NO_EXEC))
00261     ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00262 
00263   if (options.working_directory () != 0)
00264     ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00265 
00266   int saved_stdin = ACE_STDIN;
00267   int saved_stdout = ACE_STDOUT;
00268   int saved_stderr = ACE_STDERR;
00269   // Save STD file descriptors and redirect
00270   if (options.get_stdin () != ACE_INVALID_HANDLE) {
00271     if ((saved_stdin = ACE_OS::dup (ACE_STDIN)) == -1 && errno != EBADF)
00272       ACE_OS::exit (errno);
00273     if (ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1)
00274       ACE_OS::exit (errno);
00275   }
00276   if (options.get_stdout () != ACE_INVALID_HANDLE) {
00277     if ((saved_stdout = ACE_OS::dup (ACE_STDOUT)) == -1 && errno != EBADF)
00278       ACE_OS::exit (errno);
00279     if (ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1)
00280       ACE_OS::exit (errno);
00281   }
00282   if (options.get_stderr () != ACE_INVALID_HANDLE) {
00283     if ((saved_stderr = ACE_OS::dup (ACE_STDERR)) == -1 && errno != EBADF)
00284       ACE_OS::exit (errno);
00285     if (ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1)
00286       ACE_OS::exit (errno);
00287   }
00288 
00289   // Wide-char builds need narrow-char strings for commandline and
00290   // environment variables.
00291 # if defined (ACE_USES_WCHAR)
00292   wchar_t * const *wargv = options.command_line_argv ();
00293   size_t vcount, i;
00294   for (vcount = 0; wargv[vcount] != 0; ++vcount)
00295     ;
00296   char **procargv = new char *[vcount + 1];  // Need 0 at the end
00297   procargv[vcount] = 0;
00298   for (i = 0; i < vcount; ++i)
00299     procargv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);
00300 
00301   char **procenv = 0;
00302   if (options.inherit_environment ())
00303     {
00304       wargv = options.env_argv ();
00305       for (vcount = 0; wargv[vcount] != 0; ++vcount)
00306         ;
00307       procenv = new char *[vcount + 1];  // Need 0 at the end
00308       procenv[vcount] = 0;
00309       for (i = 0; i < vcount; ++i)
00310         procenv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);
00311     }
00312 # else
00313   const char **procargv = const_cast<const char**> (options.command_line_argv ());
00314   const char **procenv = const_cast<const char**> (options.env_argv ());
00315 # endif /* ACE_USES_WCHAR */
00316 
00317   this->child_id_ = ::rtpSpawn (procargv[0],
00318                                 procargv,
00319                                 procenv,
00320                                 200,          // priority
00321                                 0x10000,      // uStackSize
00322                                 0,            // options
00323                                 VX_FP_TASK);  // taskOptions
00324   int my_errno_ = errno;
00325   if (this->child_id_ == ERROR) {
00326       // something went wrong
00327       this->child_id_ = ACE_INVALID_PID;
00328   }
00329 
00330 # if defined (ACE_USES_WCHAR)
00331   if (procenv)
00332     delete procenv;
00333 # endif /* ACE_USES_WCHAR */
00334 
00335   // restore STD file descriptors (if necessary)
00336   if (options.get_stdin () != ACE_INVALID_HANDLE) {
00337     if (saved_stdin == -1)
00338       ACE_OS::close (ACE_STDIN);
00339     else
00340       ACE_OS::dup2 (saved_stdin, ACE_STDIN);
00341   }
00342   if (options.get_stdout () != ACE_INVALID_HANDLE) {
00343     if (saved_stdout == -1)
00344       ACE_OS::close (ACE_STDOUT);
00345     else
00346       ACE_OS::dup2 (saved_stdout, ACE_STDOUT);
00347   }
00348   if (options.get_stderr () != ACE_INVALID_HANDLE) {
00349     if (saved_stderr == -1)
00350       ACE_OS::close (ACE_STDERR);
00351     else
00352       ACE_OS::dup2 (saved_stderr, ACE_STDERR);
00353   }
00354 
00355   if (this->child_id_ == ACE_INVALID_PID)
00356     {
00357       errno = my_errno_;
00358     }
00359 
00360   return this->child_id_;
00361 #else /* ACE_WIN32 */
00362   // Fork the new process.
00363   this->child_id_ = ACE::fork (options.process_name (),
00364                                options.avoid_zombies ());
00365 
00366   if (this->child_id_ == 0)
00367     {
00368 # if !defined (ACE_LACKS_SETPGID)
00369       // If we're the child and the options specified a non-default
00370       // process group, try to set our pgid to it.  This allows the
00371       // <ACE_Process_Manager> to wait for processes by their
00372       // process-group.
00373       if (options.getgroup () != ACE_INVALID_PID
00374           && ACE_OS::setpgid (0,
00375                               options.getgroup ()) < 0)
00376         {
00377 #if !defined (ACE_HAS_THREADS)
00378           // We can't emit this log message because ACE_ERROR(), etc.
00379           // will invoke async signal unsafe functions, which results
00380           // in undefined behavior in threaded programs.
00381           ACE_ERROR ((LM_ERROR,
00382                       ACE_TEXT ("%p.\n"),
00383                       ACE_TEXT ("ACE_Process::spawn: setpgid failed.")));
00384 #endif
00385         }
00386 # endif /* ACE_LACKS_SETPGID */
00387 
00388 # if !defined (ACE_LACKS_SETREGID)
00389       if (options.getrgid () != (uid_t) -1
00390           || options.getegid () != (uid_t) -1)
00391         if (ACE_OS::setregid (options.getrgid (),
00392                               options.getegid ()) == -1)
00393           {
00394 #if !defined (ACE_HAS_THREADS)
00395             // We can't emit this log message because ACE_ERROR(), etc.
00396             // will invoke async signal unsafe functions, which results
00397             // in undefined behavior in threaded programs.
00398             ACE_ERROR ((LM_ERROR,
00399                         ACE_TEXT ("%p.\n"),
00400                         ACE_TEXT ("ACE_Process::spawn: setregid failed.")));
00401 #endif
00402           }
00403 # endif /* ACE_LACKS_SETREGID */
00404 
00405 # if !defined (ACE_LACKS_SETREUID)
00406       // Set user and group id's.
00407       if (options.getruid () != (uid_t) -1
00408           || options.geteuid () != (uid_t) -1)
00409         if (ACE_OS::setreuid (options.getruid (),
00410                               options.geteuid ()) == -1)
00411           {
00412 #if !defined (ACE_HAS_THREADS)
00413             // We can't emit this log message because ACE_ERROR(), etc.
00414             // will invoke async signal unsafe functions, which results
00415             // in undefined behavior in threaded programs.
00416             ACE_ERROR ((LM_ERROR,
00417                         ACE_TEXT ("%p.\n"),
00418                         ACE_TEXT ("ACE_Process::spawn: setreuid failed.")));
00419 #endif
00420           }
00421 # endif /* ACE_LACKS_SETREUID */
00422 
00423       this->child (ACE_OS::getppid ());
00424     }
00425   else if (this->child_id_ != -1)
00426     this->parent (this->child_id_);
00427 
00428   // If we're not supposed to exec, return the process id.
00429   if (ACE_BIT_ENABLED (options.creation_flags (),
00430                        ACE_Process_Options::NO_EXEC))
00431     return this->child_id_;
00432 
00433   switch (this->child_id_)
00434     {
00435     case -1:
00436       // Error.
00437       return ACE_INVALID_PID;
00438     case 0:
00439       // Child process...exec the
00440       {
00441         if (options.get_stdin () != ACE_INVALID_HANDLE
00442             && ACE_OS::dup2 (options.get_stdin (),
00443                              ACE_STDIN) == -1)
00444           ACE_OS::exit (errno);
00445         else if (options.get_stdout () != ACE_INVALID_HANDLE
00446                  && ACE_OS::dup2 (options.get_stdout (),
00447                                   ACE_STDOUT) == -1)
00448           ACE_OS::exit (errno);
00449         else if (options.get_stderr () != ACE_INVALID_HANDLE
00450                  && ACE_OS::dup2 (options.get_stderr (),
00451                                   ACE_STDERR) == -1)
00452           ACE_OS::exit (errno);
00453 
00454         // close down unneeded descriptors
00455         ACE_OS::close (options.get_stdin ());
00456         ACE_OS::close (options.get_stdout ());
00457         ACE_OS::close (options.get_stderr ());
00458         if (!options.handle_inheritance ())
00459           {
00460             // Set close-on-exec for all FDs except standard handles
00461             for (int i = ACE::max_handles () - 1; i >= 0; i--)
00462               {
00463                 if (i == ACE_STDIN || i == ACE_STDOUT || i == ACE_STDERR)
00464                   continue;
00465                 ACE_OS::fcntl (i, F_SETFD, FD_CLOEXEC);
00466               }
00467           }
00468 
00469         // If we must, set the working directory for the child
00470         // process.
00471         if (options.working_directory () != 0)
00472           ACE_OS::chdir (options.working_directory ());
00473         // Should check for error here!
00474 
00475         // Child process executes the command.
00476         int result = 0;
00477 
00478         // Wide-char builds not on Windows need narrow-char strings for
00479         // exec() and environment variables. Don't need to worry about
00480         // releasing any of the converted string memory since this
00481         // process will either exec() or exit() shortly.
00482 # if defined (ACE_USES_WCHAR)
00483         ACE_Wide_To_Ascii n_procname (options.process_name ());
00484         const char *procname = n_procname.char_rep ();
00485 
00486         wchar_t * const *wargv = options.command_line_argv ();
00487         size_t vcount, i;
00488         for (vcount = 0; wargv[vcount] != 0; ++vcount)
00489           ;
00490         char **procargv = new char *[vcount + 1];  // Need 0 at the end
00491         procargv[vcount] = 0;
00492         for (i = 0; i < vcount; ++i)
00493           procargv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);
00494 
00495         wargv = options.env_argv ();
00496         for (vcount = 0; wargv[vcount] != 0; ++vcount)
00497           ;
00498         char **procenv = new char *[vcount + 1];  // Need 0 at the end
00499         procenv[vcount] = 0;
00500         for (i = 0; i < vcount; ++i)
00501           procenv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);
00502 # else
00503         const char *procname = options.process_name ();
00504         char *const *procargv = options.command_line_argv ();
00505         char *const *procenv = options.env_argv ();
00506 # endif /* ACE_USES_WCHAR */
00507 
00508         if (options.inherit_environment ())
00509           {
00510             // Add the new environment variables to the environment
00511             // context of the context before doing an <execvp>.
00512             for (size_t i = 0; procenv[i] != 0; i++)
00513               if (ACE_OS::putenv (procenv[i]) != 0)
00514                 return ACE_INVALID_PID;
00515 
00516             // Now the forked process has both inherited variables and
00517             // the user's supplied variables.
00518             result = ACE_OS::execvp (procname, procargv);
00519           }
00520         else
00521           {
00522 # if defined (ghs)
00523             // GreenHills 1.8.8 (for VxWorks 5.3.x) can't compile this
00524             // code.  Processes aren't supported on VxWorks anyways.
00525             ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00526 # else
00527             result = ACE_OS::execve (procname, procargv, procenv);
00528 # endif /* ghs */
00529           }
00530         if (result == -1)
00531           {
00532             // If the execv fails, this child needs to exit.
00533 
00534             // Exit with the errno so that the calling process can
00535             // catch this and figure out what went wrong.
00536             ACE_OS::_exit (errno);
00537           }
00538         // ... otherwise, this is never reached.
00539         return 0;
00540       }
00541     default:
00542       // Server process.  The fork succeeded.
00543       return this->child_id_;
00544     }
00545 #endif /* ACE_WIN32 */
00546 }

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.

00090 {
00091   if (this->getpid () != -1)
00092     return ACE::terminate_process (this->getpid ());
00093   else
00094     return -1;
00095 }

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.

00562 {
00563   // nothing to do
00564 }

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.

00588 {
00589 #if defined (ACE_WIN32)
00590   // Don't try to get the process exit status if wait failed so we can
00591   // keep the original error code intact.
00592   switch (::WaitForSingleObject (process_info_.hProcess,
00593                                  tv.msec ()))
00594     {
00595     case WAIT_OBJECT_0:
00596         // The error status of <GetExitCodeProcess> is nonetheless not
00597         // tested because we don't know how to return the value.
00598         ::GetExitCodeProcess (process_info_.hProcess,
00599                               &this->exit_code_);
00600       if (status != 0)
00601         *status = this->exit_code_;
00602       return this->getpid ();
00603     case WAIT_TIMEOUT:
00604       errno = ETIME;
00605       return 0;
00606     default:
00607       ACE_OS::set_errno_to_last_error ();
00608       return -1;
00609     }
00610 #elif defined(ACE_LACKS_UNIX_SIGNALS)
00611   if (tv == ACE_Time_Value::zero)
00612     {
00613       pid_t retv =
00614         ACE_OS::waitpid (this->child_id_,
00615                          &this->exit_code_,
00616                          WNOHANG);
00617       if (status != 0)
00618         *status = this->exit_code_;
00619 
00620       return retv;
00621     }
00622 
00623   if (tv == ACE_Time_Value::max_time)
00624 # if defined (ACE_VXWORKS)
00625     {
00626       pid_t retv;
00627       while ( (retv = this->wait (status)) == ACE_INVALID_PID && errno == EINTR ) ;
00628       return retv;
00629     }
00630 # else
00631      return this->wait (status);
00632 # endif
00633 
00634   pid_t pid = 0;
00635   ACE_Time_Value sleeptm (1);    // 1 msec
00636   if (sleeptm > tv)              // if sleeptime > waittime
00637       sleeptm = tv;
00638   ACE_Time_Value tmo (tv);       // Need one we can change
00639   for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ())
00640     {
00641       pid = ACE_OS::waitpid (this->getpid (),
00642                              &this->exit_code_,
00643                              WNOHANG);
00644       if (status != 0)
00645         *status = this->exit_code_;
00646 
00647       if (pid > 0 || pid == ACE_INVALID_PID)
00648         break;          // Got a child or an error - all done
00649 
00650       // pid 0, nothing is ready yet, so wait.
00651       // Do a (very) short sleep (only this thread sleeps).
00652       ACE_OS::sleep (sleeptm);
00653     }
00654 
00655   return pid;
00656 #else /* !ACE_WIN32 && !ACE_LACKS_UNIX_SIGNALS */
00657   if (tv == ACE_Time_Value::zero)
00658     {
00659       pid_t retv =
00660         ACE_OS::waitpid (this->child_id_,
00661                          &this->exit_code_,
00662                          WNOHANG);
00663       if (status != 0)
00664         *status = this->exit_code_;
00665 
00666       return retv;
00667     }
00668 
00669   if (tv == ACE_Time_Value::max_time)
00670     return this->wait (status);
00671 
00672   // Need to wait but limited to specified time.
00673   // Force generation of SIGCHLD, even though we don't want to
00674   // catch it - just need it to interrupt the sleep below.
00675   // If this object has a reactor set, assume it was given at
00676   // open(), and there's already a SIGCHLD action set, so no
00677   // action is needed here.
00678   ACE_Sig_Action old_action;
00679   ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop);
00680   do_sigchld.register_action (SIGCHLD, &old_action);
00681 
00682   pid_t pid;
00683   ACE_Time_Value tmo (tv);       // Need one we can change
00684   for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ())
00685     {
00686       pid = ACE_OS::waitpid (this->getpid (),
00687                              &this->exit_code_,
00688                              WNOHANG);
00689       if (status != 0)
00690         *status = this->exit_code_;
00691 
00692       if (pid > 0 || pid == ACE_INVALID_PID)
00693         break;          // Got a child or an error - all done
00694 
00695       // pid 0, nothing is ready yet, so wait.
00696       // Do a sleep (only this thread sleeps) til something
00697       // happens. This relies on SIGCHLD interrupting the sleep.
00698       // If SIGCHLD isn't delivered, we'll need to do something
00699       // with sigaction to force it.
00700       if (-1 == ACE_OS::sleep (tmo) && errno == EINTR)
00701         continue;
00702       // Timed out
00703       pid = 0;
00704       break;
00705     }
00706 
00707   // Restore the previous SIGCHLD action if it was changed.
00708   old_action.register_action (SIGCHLD);
00709 
00710   return pid;
00711 #endif /* ACE_WIN32 */
00712 }

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.

00064 {
00065   pid_t retv =
00066     ACE_OS::wait (this->getpid (),
00067                   &this->exit_code_,
00068                   wait_options
00069 #if defined (ACE_WIN32)
00070                   , process_info_.hProcess
00071 #endif /* ACE_WIN32 */
00072                   );
00073   if (status != 0)
00074     *status = this->exit_code_;
00075 
00076   return retv;
00077 }


Friends And Related Function Documentation

friend class ACE_Process_Manager [friend]

Definition at line 463 of file Process.h.


Member Data Documentation

pid_t ACE_Process::child_id_ [protected]

Process id of the child.

Definition at line 588 of file Process.h.

Handle duplicates made for the child process.

Definition at line 596 of file Process.h.

Definition at line 590 of file Process.h.

Set of handles that were passed to the child process.

Definition at line 593 of file Process.h.

PROCESS_INFORMATION ACE_Process::process_info_ [protected]

Definition at line 585 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

Generated on Sun Nov 22 23:15:47 2009 for ACE by  doxygen 1.6.1