Process. More...
#include <Process.h>


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 |
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.
| 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] |
| 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.
| 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.
| 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.
| 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.
| 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 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 }
friend class ACE_Process_Manager [friend] |
pid_t ACE_Process::child_id_ [protected] |
ACE_Handle_Set ACE_Process::dup_handles_ [protected] |
ACE_exitcode ACE_Process::exit_code_ [protected] |
ACE_Handle_Set ACE_Process::handles_passed_ [protected] |
PROCESS_INFORMATION ACE_Process::process_info_ [protected] |
1.6.1