#include <Process.h>
Inheritance diagram for ACE_Process:
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 |
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 447 of file Process.h.
ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_Process::ACE_Process | ( | void | ) |
Default construction. Must use <ACE_Process::spawn> to start.
Definition at line 45 of file Process.cpp.
References ACE_OS::memset().
00046 : 00047 #if !defined (ACE_WIN32) 00048 child_id_ (ACE_INVALID_PID), 00049 #endif /* !defined (ACE_WIN32) */ 00050 exit_code_ (0) 00051 { 00052 #if defined (ACE_WIN32) 00053 ACE_OS::memset ((void *) &this->process_info_, 00054 0, 00055 sizeof this->process_info_); 00056 #endif /* ACE_WIN32 */ 00057 }
ACE_Process::~ACE_Process | ( | void | ) | [virtual] |
Destructor.
Definition at line 59 of file Process.cpp.
References ACE_OS::close(), and close_dup_handles().
00060 { 00061 #if defined (ACE_WIN32) 00062 // Free resources allocated in kernel. 00063 ACE_OS::close (this->process_info_.hThread); 00064 ACE_OS::close (this->process_info_.hProcess); 00065 #endif /* ACE_WIN32 */ 00066 // If any handles were duplicated for the child process and 00067 // still not closed, get them now. 00068 this->close_dup_handles (); 00069 }
ACE_Process::ACE_Process | ( | const ACE_Process & | ) | [private] |
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 526 of file Process.cpp.
Referenced by spawn().
void ACE_Process::close_dup_handles | ( | void | ) |
Close all the handles in the set obtained from the
Definition at line 686 of file Process.cpp.
References ACE_OS::closesocket(), dup_handles_, and ACE_Handle_Set::reset().
Referenced by ~ACE_Process().
00687 { 00688 if (this->dup_handles_.num_set () > 0) 00689 { 00690 ACE_Handle_Set_Iterator h_iter (this->dup_handles_); 00691 for (ACE_HANDLE h = h_iter (); 00692 h != ACE_INVALID_HANDLE; 00693 h = h_iter ()) 00694 ACE_OS::closesocket (h); 00695 this->dup_handles_.reset (); 00696 } 00697 return; 00698 }
void ACE_Process::close_passed_handles | ( | void | ) |
Close all the handles in the set obtained from the
Definition at line 701 of file Process.cpp.
References ACE_OS::closesocket(), handles_passed_, and ACE_Handle_Set::reset().
00702 { 00703 if (this->handles_passed_.num_set () > 0) 00704 { 00705 ACE_Handle_Set_Iterator h_iter (this->handles_passed_); 00706 for (ACE_HANDLE h = h_iter (); 00707 h != ACE_INVALID_HANDLE; 00708 h = h_iter ()) 00709 ACE_OS::closesocket (h); 00710 this->handles_passed_.reset (); 00711 } 00712 return; 00713 }
ACE_INLINE 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 96 of file Process.inl.
References exit_code_.
00097 { 00098 this->exit_code_ = code; 00099 }
ACE_INLINE 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 90 of file Process.inl.
References exit_code_.
Referenced by ACE_Process_Manager::notify_proc_handler().
00091 { 00092 return this->exit_code_; 00093 }
ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_INLINE ACE_HANDLE ACE_Process::gethandle | ( | void | ) | const |
Return the handle of the process, if it has one.
Definition at line 23 of file Process.inl.
References child_id_.
Referenced by ACE_Process_Manager::append_proc(), and running().
00024 { 00025 #if defined (ACE_WIN32) 00026 return process_info_.hProcess; 00027 #else 00028 return ACE_HANDLE (child_id_); 00029 #endif /* ACE_WIN32 */ 00030 }
ACE_INLINE pid_t ACE_Process::getpid | ( | void | ) | const |
Return the process id of the new child process.
Definition at line 33 of file Process.inl.
References child_id_.
Referenced by ACE_Process_Manager::handle_signal(), ACE_Process_Manager::insert_proc(), spawn(), ACE_Process_Manager::wait(), and wait().
00035 { 00036 #if defined (ACE_WIN32) 00037 return process_info_.dwProcessId; 00038 #else /* ACE_WIN32 */ 00039 return child_id_; 00040 #endif /* ACE_WIN32 */ 00041 }
ACE_INLINE 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 62 of file Process.inl.
References ACE_OS::kill().
00063 { 00064 if (this->getpid () != -1) 00065 return ACE_OS::kill (this->getpid (), signum); 00066 else 00067 return -1; 00068 }
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 520 of file Process.cpp.
Referenced by spawn().
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 72 of file Process.cpp.
ACE_INLINE 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 80 of file Process.inl.
References exit_code_, and WEXITSTATUS.
00081 { 00082 #if defined (ACE_WIN32) 00083 return this->exit_code_; 00084 #else 00085 return WEXITSTATUS (this->exit_code_); 00086 #endif /* ACE_WIN32 */ 00087 }
int ACE_Process::running | ( | void | ) | const |
Return 1 if running; 0 otherwise.
Definition at line 538 of file Process.cpp.
References ACE_INVALID_PID, gethandle(), and ACE_OS::kill().
00539 { 00540 #if defined (ACE_WIN32) 00541 DWORD code; 00542 00543 BOOL result = ::GetExitCodeProcess (this->gethandle (), 00544 &code); 00545 return result && code == STILL_ACTIVE; 00546 #else 00547 if (ACE_INVALID_PID == this->getpid ()) 00548 return 0; 00549 else 00550 return ACE_OS::kill (this->getpid (), 00551 0) == 0 00552 || errno != ESRCH; 00553 #endif /* ACE_WIN32 */ 00554 }
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 78 of file Process.cpp.
References ACE_OS::_exit(), ACE_BIT_ENABLED, ACE_ERROR, ACE_INVALID_PID, ACE_NOTSUP_RETURN, ACE_STDERR, ACE_STDIN, ACE_STDOUT, ACE_TEXT, ACE_Process_Options::avoid_zombies(), ACE_OS::chdir(), child(), child_id_, ACE_OS::close(), ACE_Process_Options::command_line_argv(), ACE_Process_Options::command_line_buf(), ACE_Process_Options::creation_flags(), ACE_OS::dup(), ACE_OS::dup2(), ACE_Process_Options::dup_handles(), ACE_Process_Options::env_argv(), ACE_Process_Options::env_buf(), ACE_OS::execve(), ACE_OS::execvp(), ACE_OS::exit(), ACE::fork(), ACE_Process_Options::get_stderr(), ACE_Process_Options::get_stdin(), ACE_Process_Options::get_stdout(), ACE_Process_Options::getegid(), ACE_Process_Options::geteuid(), ACE_Process_Options::getgroup(), getpid(), ACE_OS::getppid(), ACE_Process_Options::getrgid(), ACE_Process_Options::getruid(), ACE_Process_Options::handle_inheritence(), ACE_Process_Options::inherit_environment(), LM_ERROR, ACE_Process_Options::NO_EXEC, parent(), ACE_Process_Options::passed_handles(), ACE_Process_Options::process_name(), ACE_OS::putenv(), ACE_OS::setpgid(), ACE_OS::setregid(), ACE_OS::setreuid(), ACE_OS::sprintf(), ACE_OS::strlen(), and ACE_Process_Options::working_directory().
Referenced by ACE_Process_Manager::spawn().
00079 { 00080 if (this->prepare (options) < 0) 00081 return ACE_INVALID_PID; 00082 00083 // Stash the passed/duped handle sets away in this object for later 00084 // closing if needed or requested. At the same time, figure out which 00085 // ones to include in command line options if that's needed below. 00086 ACE_Handle_Set *set_p = 0; 00087 if (options.dup_handles (this->dup_handles_)) 00088 set_p = &this->dup_handles_; 00089 else if (options.passed_handles (this->handles_passed_)) 00090 set_p = &this->handles_passed_; 00091 00092 // If we are going to end up running a new program (i.e. Win32, or 00093 // NO_EXEC option is set) then get any handles passed in the options, 00094 // and tack them onto the command line with +H <handle> options, 00095 // unless the command line runs out of space. 00096 // Note that we're using the knowledge that all the options, argvs, etc. 00097 // passed to the options are all sitting in the command_line_buf. Any 00098 // call to get the argv then splits them out. So, regardless of the 00099 // platform, tack them all onto the command line buf and take it 00100 // from there. 00101 if (set_p && !ACE_BIT_ENABLED (options.creation_flags (), 00102 ACE_Process_Options::NO_EXEC)) 00103 { 00104 int maxlen = 0; 00105 ACE_TCHAR *cmd_line_buf = options.command_line_buf (&maxlen); 00106 size_t max_len = static_cast<size_t> (maxlen); 00107 size_t curr_len = ACE_OS::strlen (cmd_line_buf); 00108 ACE_Handle_Set_Iterator h_iter (*set_p); 00109 // Because the length of the to-be-formatted +H option is not 00110 // known, and we don't have a snprintf, guess at the space 00111 // needed (20 chars), and use that as a limit. 00112 for (ACE_HANDLE h = h_iter (); 00113 h != ACE_INVALID_HANDLE && curr_len + 20 < max_len; 00114 h = h_iter ()) 00115 { 00116 #if defined (ACE_WIN32) 00117 # if defined (ACE_WIN64) 00118 curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len], 00119 ACE_TEXT (" +H %I64p"), 00120 h); 00121 # else 00122 curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len], 00123 ACE_TEXT (" +H %p"), 00124 h); 00125 # endif /* ACE_WIN64 */ 00126 #else 00127 curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len], 00128 ACE_TEXT (" +H %d"), 00129 h); 00130 #endif /* ACE_WIN32 */ 00131 } 00132 } 00133 00134 #if defined (ACE_HAS_WINCE) 00135 // Note that WinCE does not have process name included in the command line as argv[0] 00136 // like other OS environment. Therefore, it is user's whole responsibility to call 00137 // 'ACE_Process_Options::process_name(const ACE_TCHAR *name)' to set the proper 00138 // process name (the execution file name with path if needed). 00139 00140 BOOL fork_result = 00141 ACE_TEXT_CreateProcess (options.process_name(), 00142 options.command_line_buf(), 00143 options.get_process_attributes(), // must be NULL in CE 00144 options.get_thread_attributes(), // must be NULL in CE 00145 options.handle_inheritence(), // must be false in CE 00146 options.creation_flags(), // must be NULL in CE 00147 options.env_buf(), // environment variables, must be NULL in CE 00148 options.working_directory(), // must be NULL in CE 00149 options.startup_info(), // must be NULL in CE 00150 &this->process_info_); 00151 00152 if (fork_result) 00153 { 00154 parent (this->getpid ()); 00155 return this->getpid (); 00156 } 00157 return ACE_INVALID_PID; 00158 00159 #elif defined (ACE_WIN32) 00160 BOOL fork_result = 00161 ACE_TEXT_CreateProcess (0, 00162 options.command_line_buf (), 00163 options.get_process_attributes (), 00164 options.get_thread_attributes (), 00165 options.handle_inheritence (), 00166 options.creation_flags (), 00167 options.env_buf (), // environment variables 00168 options.working_directory (), 00169 options.startup_info (), 00170 &this->process_info_); 00171 00172 if (fork_result) 00173 { 00174 parent (this->getpid ()); 00175 return this->getpid (); 00176 } 00177 return ACE_INVALID_PID; 00178 00179 #elif defined(ACE_OPENVMS) 00180 if (ACE_BIT_ENABLED (options.creation_flags (), 00181 ACE_Process_Options::NO_EXEC)) 00182 ACE_NOTSUP_RETURN (ACE_INVALID_PID); 00183 00184 int saved_stdin = ACE_STDIN; 00185 int saved_stdout = ACE_STDOUT; 00186 int saved_stderr = ACE_STDERR; 00187 // Save STD file descriptors and redirect 00188 if (options.get_stdin () != ACE_INVALID_HANDLE) { 00189 if ((saved_stdin = ACE_OS::dup (ACE_STDIN)) == -1 && errno != EBADF) 00190 ACE_OS::exit (errno); 00191 if (ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1) 00192 ACE_OS::exit (errno); 00193 } 00194 if (options.get_stdout () != ACE_INVALID_HANDLE) { 00195 if ((saved_stdout = ACE_OS::dup (ACE_STDOUT)) == -1 && errno != EBADF) 00196 ACE_OS::exit (errno); 00197 if (ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1) 00198 ACE_OS::exit (errno); 00199 } 00200 if (options.get_stderr () != ACE_INVALID_HANDLE) { 00201 if ((saved_stderr = ACE_OS::dup (ACE_STDERR)) == -1 && errno != EBADF) 00202 ACE_OS::exit (errno); 00203 if (ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1) 00204 ACE_OS::exit (errno); 00205 } 00206 00207 if (options.working_directory () != 0) 00208 ACE_NOTSUP_RETURN (ACE_INVALID_PID); 00209 00210 this->child_id_ = vfork(); 00211 if (this->child_id_ == 0) { 00212 ACE_OS::execvp (options.process_name (), 00213 options.command_line_argv ()); 00214 // something went wrong 00215 this->child_id_ = ACE_INVALID_PID; 00216 } 00217 00218 // restore STD file descriptors (if necessary) 00219 if (options.get_stdin () != ACE_INVALID_HANDLE) { 00220 if (saved_stdin == -1) 00221 ACE_OS::close (ACE_STDIN); 00222 else 00223 ACE_OS::dup2 (saved_stdin, ACE_STDIN); 00224 } 00225 if (options.get_stdout () != ACE_INVALID_HANDLE) { 00226 if (saved_stdout == -1) 00227 ACE_OS::close (ACE_STDOUT); 00228 else 00229 ACE_OS::dup2 (saved_stdout, ACE_STDOUT); 00230 } 00231 if (options.get_stderr () != ACE_INVALID_HANDLE) { 00232 if (saved_stderr == -1) 00233 ACE_OS::close (ACE_STDERR); 00234 else 00235 ACE_OS::dup2 (saved_stderr, ACE_STDERR); 00236 } 00237 00238 return this->child_id_; 00239 #elif (defined (ACE_VXWORKS) && (ACE_VXWORKS > 0x600)) && defined (__RTP__) 00240 if (ACE_BIT_ENABLED (options.creation_flags (), 00241 ACE_Process_Options::NO_EXEC)) 00242 ACE_NOTSUP_RETURN (ACE_INVALID_PID); 00243 00244 if (options.working_directory () != 0) 00245 ACE_NOTSUP_RETURN (ACE_INVALID_PID); 00246 00247 int saved_stdin = ACE_STDIN; 00248 int saved_stdout = ACE_STDOUT; 00249 int saved_stderr = ACE_STDERR; 00250 // Save STD file descriptors and redirect 00251 if (options.get_stdin () != ACE_INVALID_HANDLE) { 00252 if ((saved_stdin = ACE_OS::dup (ACE_STDIN)) == -1 && errno != EBADF) 00253 ACE_OS::exit (errno); 00254 if (ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1) 00255 ACE_OS::exit (errno); 00256 } 00257 if (options.get_stdout () != ACE_INVALID_HANDLE) { 00258 if ((saved_stdout = ACE_OS::dup (ACE_STDOUT)) == -1 && errno != EBADF) 00259 ACE_OS::exit (errno); 00260 if (ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1) 00261 ACE_OS::exit (errno); 00262 } 00263 if (options.get_stderr () != ACE_INVALID_HANDLE) { 00264 if ((saved_stderr = ACE_OS::dup (ACE_STDERR)) == -1 && errno != EBADF) 00265 ACE_OS::exit (errno); 00266 if (ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1) 00267 ACE_OS::exit (errno); 00268 } 00269 00270 // Wide-char builds need narrow-char strings for commandline and 00271 // environment variables. 00272 # if defined (ACE_USES_WCHAR) 00273 wchar_t * const *wargv = options.command_line_argv (); 00274 size_t vcount, i; 00275 for (vcount = 0; wargv[vcount] != 0; ++vcount) 00276 ; 00277 char **procargv = new char *[vcount + 1]; // Need 0 at the end 00278 procargv[vcount] = 0; 00279 for (i = 0; i < vcount; ++i) 00280 procargv[i] = ACE_Wide_To_Ascii::convert (wargv[i]); 00281 00282 char **procenv = 0; 00283 if (options.inherit_environment ()) 00284 { 00285 wargv = options.env_argv (); 00286 for (vcount = 0; wargv[vcount] != 0; ++vcount) 00287 ; 00288 procenv = new char *[vcount + 1]; // Need 0 at the end 00289 procenv[vcount] = 0; 00290 for (i = 0; i < vcount; ++i) 00291 procenv[i] = ACE_Wide_To_Ascii::convert (wargv[i]); 00292 } 00293 # else 00294 const char **procargv = const_cast<const char**> (options.command_line_argv ()); 00295 const char **procenv = const_cast<const char**> (options.env_argv ()); 00296 # endif /* ACE_USES_WCHAR */ 00297 00298 this->child_id_ = ::rtpSpawn (procargv[0], 00299 procargv, 00300 procenv, 00301 200, // priority 00302 0x10000, // uStackSize 00303 0, // options 00304 VX_FP_TASK); // taskOptions 00305 int my_errno_ = errno; 00306 if (this->child_id_ == ERROR) { 00307 // something went wrong 00308 this->child_id_ = ACE_INVALID_PID; 00309 } 00310 00311 # if defined (ACE_USES_WCHAR) 00312 if (procenv) 00313 delete procenv; 00314 # endif /* ACE_USES_WCHAR */ 00315 00316 // restore STD file descriptors (if necessary) 00317 if (options.get_stdin () != ACE_INVALID_HANDLE) { 00318 if (saved_stdin == -1) 00319 ACE_OS::close (ACE_STDIN); 00320 else 00321 ACE_OS::dup2 (saved_stdin, ACE_STDIN); 00322 } 00323 if (options.get_stdout () != ACE_INVALID_HANDLE) { 00324 if (saved_stdout == -1) 00325 ACE_OS::close (ACE_STDOUT); 00326 else 00327 ACE_OS::dup2 (saved_stdout, ACE_STDOUT); 00328 } 00329 if (options.get_stderr () != ACE_INVALID_HANDLE) { 00330 if (saved_stderr == -1) 00331 ACE_OS::close (ACE_STDERR); 00332 else 00333 ACE_OS::dup2 (saved_stderr, ACE_STDERR); 00334 } 00335 00336 if (this->child_id_ == ACE_INVALID_PID) 00337 { 00338 errno = my_errno_; 00339 } 00340 00341 return this->child_id_; 00342 #else /* ACE_WIN32 */ 00343 // Fork the new process. 00344 this->child_id_ = ACE::fork (options.process_name (), 00345 options.avoid_zombies ()); 00346 00347 if (this->child_id_ == 0) 00348 { 00349 # if !defined (ACE_LACKS_SETPGID) 00350 // If we're the child and the options specified a non-default 00351 // process group, try to set our pgid to it. This allows the 00352 // <ACE_Process_Manager> to wait for processes by their 00353 // process-group. 00354 if (options.getgroup () != ACE_INVALID_PID 00355 && ACE_OS::setpgid (0, 00356 options.getgroup ()) < 0) 00357 { 00358 #if !defined (ACE_HAS_THREADS) 00359 // We can't emit this log message because ACE_ERROR(), etc. 00360 // will invoke async signal unsafe functions, which results 00361 // in undefined behavior in threaded programs. 00362 ACE_ERROR ((LM_ERROR, 00363 ACE_TEXT ("%p.\n"), 00364 ACE_TEXT ("ACE_Process::spawn: setpgid failed."))); 00365 #endif 00366 } 00367 # endif /* ACE_LACKS_SETPGID */ 00368 00369 # if !defined (ACE_LACKS_SETREGID) 00370 if (options.getrgid () != (uid_t) -1 00371 || options.getegid () != (uid_t) -1) 00372 if (ACE_OS::setregid (options.getrgid (), 00373 options.getegid ()) == -1) 00374 { 00375 #if !defined (ACE_HAS_THREADS) 00376 // We can't emit this log message because ACE_ERROR(), etc. 00377 // will invoke async signal unsafe functions, which results 00378 // in undefined behavior in threaded programs. 00379 ACE_ERROR ((LM_ERROR, 00380 ACE_TEXT ("%p.\n"), 00381 ACE_TEXT ("ACE_Process::spawn: setregid failed."))); 00382 #endif 00383 } 00384 # endif /* ACE_LACKS_SETREGID */ 00385 00386 # if !defined (ACE_LACKS_SETREUID) 00387 // Set user and group id's. 00388 if (options.getruid () != (uid_t) -1 00389 || options.geteuid () != (uid_t) -1) 00390 if (ACE_OS::setreuid (options.getruid (), 00391 options.geteuid ()) == -1) 00392 { 00393 #if !defined (ACE_HAS_THREADS) 00394 // We can't emit this log message because ACE_ERROR(), etc. 00395 // will invoke async signal unsafe functions, which results 00396 // in undefined behavior in threaded programs. 00397 ACE_ERROR ((LM_ERROR, 00398 ACE_TEXT ("%p.\n"), 00399 ACE_TEXT ("ACE_Process::spawn: setreuid failed."))); 00400 #endif 00401 } 00402 # endif /* ACE_LACKS_SETREUID */ 00403 00404 this->child (ACE_OS::getppid ()); 00405 } 00406 else if (this->child_id_ != -1) 00407 this->parent (this->child_id_); 00408 00409 // If we're not supposed to exec, return the process id. 00410 if (ACE_BIT_ENABLED (options.creation_flags (), 00411 ACE_Process_Options::NO_EXEC)) 00412 return this->child_id_; 00413 00414 switch (this->child_id_) 00415 { 00416 case -1: 00417 // Error. 00418 return ACE_INVALID_PID; 00419 case 0: 00420 // Child process...exec the 00421 { 00422 if (options.get_stdin () != ACE_INVALID_HANDLE 00423 && ACE_OS::dup2 (options.get_stdin (), 00424 ACE_STDIN) == -1) 00425 ACE_OS::exit (errno); 00426 else if (options.get_stdout () != ACE_INVALID_HANDLE 00427 && ACE_OS::dup2 (options.get_stdout (), 00428 ACE_STDOUT) == -1) 00429 ACE_OS::exit (errno); 00430 else if (options.get_stderr () != ACE_INVALID_HANDLE 00431 && ACE_OS::dup2 (options.get_stderr (), 00432 ACE_STDERR) == -1) 00433 ACE_OS::exit (errno); 00434 00435 // close down unneeded descriptors 00436 ACE_OS::close (options.get_stdin ()); 00437 ACE_OS::close (options.get_stdout ()); 00438 ACE_OS::close (options.get_stderr ()); 00439 00440 // If we must, set the working directory for the child 00441 // process. 00442 if (options.working_directory () != 0) 00443 ACE_OS::chdir (options.working_directory ()); 00444 // Should check for error here! 00445 00446 // Child process executes the command. 00447 int result = 0; 00448 00449 // Wide-char builds not on Windows need narrow-char strings for 00450 // exec() and environment variables. Don't need to worry about 00451 // releasing any of the converted string memory since this 00452 // process will either exec() or exit() shortly. 00453 # if defined (ACE_USES_WCHAR) 00454 ACE_Wide_To_Ascii n_procname (options.process_name ()); 00455 const char *procname = n_procname.char_rep (); 00456 00457 wchar_t * const *wargv = options.command_line_argv (); 00458 size_t vcount, i; 00459 for (vcount = 0; wargv[vcount] != 0; ++vcount) 00460 ; 00461 char **procargv = new char *[vcount + 1]; // Need 0 at the end 00462 procargv[vcount] = 0; 00463 for (i = 0; i < vcount; ++i) 00464 procargv[i] = ACE_Wide_To_Ascii::convert (wargv[i]); 00465 00466 wargv = options.env_argv (); 00467 for (vcount = 0; wargv[vcount] != 0; ++vcount) 00468 ; 00469 char **procenv = new char *[vcount + 1]; // Need 0 at the end 00470 procenv[vcount] = 0; 00471 for (i = 0; i < vcount; ++i) 00472 procenv[i] = ACE_Wide_To_Ascii::convert (wargv[i]); 00473 # else 00474 const char *procname = options.process_name (); 00475 char *const *procargv = options.command_line_argv (); 00476 char *const *procenv = options.env_argv (); 00477 # endif /* ACE_USES_WCHAR */ 00478 00479 if (options.inherit_environment ()) 00480 { 00481 // Add the new environment variables to the environment 00482 // context of the context before doing an <execvp>. 00483 for (size_t i = 0; procenv[i] != 0; i++) 00484 if (ACE_OS::putenv (procenv[i]) != 0) 00485 return ACE_INVALID_PID; 00486 00487 // Now the forked process has both inherited variables and 00488 // the user's supplied variables. 00489 result = ACE_OS::execvp (procname, procargv); 00490 } 00491 else 00492 { 00493 # if defined (ghs) 00494 // GreenHills 1.8.8 (for VxWorks 5.3.x) can't compile this 00495 // code. Processes aren't supported on VxWorks anyways. 00496 ACE_NOTSUP_RETURN (ACE_INVALID_PID); 00497 # else 00498 result = ACE_OS::execve (procname, procargv, procenv); 00499 # endif /* ghs */ 00500 } 00501 if (result == -1) 00502 { 00503 // If the execv fails, this child needs to exit. 00504 00505 // Exit with the errno so that the calling process can 00506 // catch this and figure out what went wrong. 00507 ACE_OS::_exit (errno); 00508 } 00509 // ... otherwise, this is never reached. 00510 return 0; 00511 } 00512 default: 00513 // Server process. The fork succeeded. 00514 return this->child_id_; 00515 } 00516 #endif /* ACE_WIN32 */ 00517 }
ACE_INLINE 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 71 of file Process.inl.
References ACE::terminate_process().
00072 { 00073 if (this->getpid () != -1) 00074 return ACE::terminate_process (this->getpid ()); 00075 else 00076 return -1; 00077 }
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 532 of file Process.cpp.
Referenced by ACE_Process_Manager::remove_proc().
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.
Definition at line 557 of file Process.cpp.
References ACE_INVALID_PID, exit_code_, getpid(), ACE_Time_Value::max_time, ACE_Time_Value::msec(), ACE_Sig_Action::register_action(), ACE_OS::set_errno_to_last_error(), SIGCHLD, sigchld_nop(), ACE_OS::sleep(), wait(), ACE_OS::waitpid(), WNOHANG, and ACE_Time_Value::zero.
00559 { 00560 #if defined (ACE_WIN32) 00561 // Don't try to get the process exit status if wait failed so we can 00562 // keep the original error code intact. 00563 switch (::WaitForSingleObject (process_info_.hProcess, 00564 tv.msec ())) 00565 { 00566 case WAIT_OBJECT_0: 00567 // The error status of <GetExitCodeProcess> is nonetheless not 00568 // tested because we don't know how to return the value. 00569 ::GetExitCodeProcess (process_info_.hProcess, 00570 &this->exit_code_); 00571 if (status != 0) 00572 *status = this->exit_code_; 00573 return this->getpid (); 00574 case WAIT_TIMEOUT: 00575 errno = ETIME; 00576 return 0; 00577 default: 00578 ACE_OS::set_errno_to_last_error (); 00579 return -1; 00580 } 00581 #elif defined(ACE_LACKS_UNIX_SIGNALS) 00582 if (tv == ACE_Time_Value::zero) 00583 { 00584 pid_t retv = 00585 ACE_OS::waitpid (this->child_id_, 00586 &this->exit_code_, 00587 WNOHANG); 00588 if (status != 0) 00589 *status = this->exit_code_; 00590 00591 return retv; 00592 } 00593 00594 if (tv == ACE_Time_Value::max_time) 00595 # if defined (ACE_VXWORKS) 00596 { 00597 pid_t retv; 00598 while ( (retv = this->wait (status)) == ACE_INVALID_PID && errno == EINTR ) ; 00599 return retv; 00600 } 00601 # else 00602 return this->wait (status); 00603 # endif 00604 00605 pid_t pid = 0; 00606 ACE_Time_Value sleeptm (1); // 1 msec 00607 if (sleeptm > tv) // if sleeptime > waittime 00608 sleeptm = tv; 00609 ACE_Time_Value tmo (tv); // Need one we can change 00610 for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ()) 00611 { 00612 pid = ACE_OS::waitpid (this->getpid (), 00613 &this->exit_code_, 00614 WNOHANG); 00615 if (status != 0) 00616 *status = this->exit_code_; 00617 00618 if (pid > 0 || pid == ACE_INVALID_PID) 00619 break; // Got a child or an error - all done 00620 00621 // pid 0, nothing is ready yet, so wait. 00622 // Do a (very) short sleep (only this thread sleeps). 00623 ACE_OS::sleep (sleeptm); 00624 } 00625 00626 return pid; 00627 #else /* !ACE_WIN32 && !ACE_LACKS_UNIX_SIGNALS */ 00628 if (tv == ACE_Time_Value::zero) 00629 { 00630 pid_t retv = 00631 ACE_OS::waitpid (this->child_id_, 00632 &this->exit_code_, 00633 WNOHANG); 00634 if (status != 0) 00635 *status = this->exit_code_; 00636 00637 return retv; 00638 } 00639 00640 if (tv == ACE_Time_Value::max_time) 00641 return this->wait (status); 00642 00643 // Need to wait but limited to specified time. 00644 // Force generation of SIGCHLD, even though we don't want to 00645 // catch it - just need it to interrupt the sleep below. 00646 // If this object has a reactor set, assume it was given at 00647 // open(), and there's already a SIGCHLD action set, so no 00648 // action is needed here. 00649 ACE_Sig_Action old_action; 00650 ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop); 00651 do_sigchld.register_action (SIGCHLD, &old_action); 00652 00653 pid_t pid; 00654 ACE_Time_Value tmo (tv); // Need one we can change 00655 for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ()) 00656 { 00657 pid = ACE_OS::waitpid (this->getpid (), 00658 &this->exit_code_, 00659 WNOHANG); 00660 if (status != 0) 00661 *status = this->exit_code_; 00662 00663 if (pid > 0 || pid == ACE_INVALID_PID) 00664 break; // Got a child or an error - all done 00665 00666 // pid 0, nothing is ready yet, so wait. 00667 // Do a sleep (only this thread sleeps) til something 00668 // happens. This relies on SIGCHLD interrupting the sleep. 00669 // If SIGCHLD isn't delivered, we'll need to do something 00670 // with sigaction to force it. 00671 if (-1 == ACE_OS::sleep (tmo) && errno == EINTR) 00672 continue; 00673 // Timed out 00674 pid = 0; 00675 break; 00676 } 00677 00678 // Restore the previous SIGCHLD action if it was changed. 00679 old_action.register_action (SIGCHLD); 00680 00681 return pid; 00682 #endif /* ACE_WIN32 */ 00683 }
ACE_INLINE 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 44 of file Process.inl.
References exit_code_, and ACE_OS::wait().
Referenced by ACE_Process_Manager::wait(), and wait().
00046 { 00047 pid_t retv = 00048 ACE_OS::wait (this->getpid (), 00049 &this->exit_code_, 00050 wait_options 00051 #if defined (ACE_WIN32) 00052 , process_info_.hProcess 00053 #endif /* ACE_WIN32 */ 00054 ); 00055 if (status != 0) 00056 *status = this->exit_code_; 00057 00058 return retv; 00059 }
friend class ACE_Process_Manager [friend] |
pid_t ACE_Process::child_id_ [protected] |
Process id of the child.
Definition at line 575 of file Process.h.
Referenced by gethandle(), getpid(), and spawn().
ACE_Handle_Set ACE_Process::dup_handles_ [protected] |
Handle duplicates made for the child process.
Definition at line 582 of file Process.h.
Referenced by close_dup_handles().
ACE_exitcode ACE_Process::exit_code_ [protected] |
ACE_Handle_Set ACE_Process::handles_passed_ [protected] |
Set of handles that were passed to the child process.
Definition at line 580 of file Process.h.
Referenced by close_passed_handles().