#include <Process_Manager.h>
Inheritance diagram for ACE_Process_Manager:
Public Types | |
enum | { DEFAULT_SIZE = 100 } |
Public Member Functions | |
ACE_Process_Manager (size_t size=ACE_Process_Manager::DEFAULT_SIZE, ACE_Reactor *reactor=0) | |
int | open (size_t size=DEFAULT_SIZE, ACE_Reactor *r=0) |
int | close (void) |
Release all resources. Do not wait for processes to exit. | |
virtual | ~ACE_Process_Manager (void) |
pid_t | spawn (ACE_Process *proc, ACE_Process_Options &options, ACE_Event_Handler *event_handler=0) |
pid_t | spawn (ACE_Process_Options &options, ACE_Event_Handler *event_handler=0) |
int | spawn_n (size_t n, ACE_Process_Options &options, pid_t *child_pids=0, ACE_Event_Handler *event_Handler=0) |
int | wait (const ACE_Time_Value &timeout=ACE_Time_Value::max_time) |
pid_t | wait (pid_t pid, const ACE_Time_Value &timeout, ACE_exitcode *status=0) |
pid_t | wait (pid_t pid, ACE_exitcode *status=0) |
int | reap (pid_t pid=-1, ACE_exitcode *stat_loc=0, int options=WNOHANG) |
int | register_handler (ACE_Event_Handler *event_handler, pid_t pid=ACE_INVALID_PID) |
int | remove (pid_t pid) |
int | terminate (pid_t pid) |
int | terminate (pid_t pid, int sig) |
size_t | managed (void) const |
Return the number of managed Processes. | |
int | set_scheduler (const ACE_Sched_Params ¶ms, pid_t pid) |
int | set_scheduler_all (const ACE_Sched_Params &) |
void | dump (void) const |
Dump the state of an object. | |
Static Public Member Functions | |
ACE_Process_Manager * | instance (void) |
Get pointer to a process-wide . | |
ACE_Process_Manager * | instance (ACE_Process_Manager *) |
void | close_singleton (void) |
Delete the dynamically allocated singleton. | |
void | cleanup (void *instance, void *arg) |
Public Attributes | |
ACE_ALLOC_HOOK_DECLARE | |
Declare the dynamic allocation hooks. | |
Protected Member Functions | |
virtual int | handle_signal (int signum, siginfo_t *=0, ucontext_t *=0) |
Private Member Functions | |
int | resize (size_t) |
Resize the pool of Process_Descriptors. | |
ssize_t | find_proc (pid_t process_id) |
ssize_t | find_proc (ACE_HANDLE process_handle) |
int | insert_proc (ACE_Process *process, ACE_Event_Handler *event_handler=0) |
int | append_proc (ACE_Process *process, ACE_Event_Handler *event_handler=0) |
int | remove_proc (size_t n) |
int | notify_proc_handler (size_t n, ACE_exitcode status) |
Private Attributes | |
ACE_Process_Descriptor * | process_table_ |
Vector that describes process state within the Process_Manager. | |
size_t | max_process_table_size_ |
size_t | current_count_ |
Current number of processes we are managing. | |
ACE_Event_Handler * | default_exit_handler_ |
ACE_Recursive_Thread_Mutex | lock_ |
This lock protects access/ops on . | |
Static Private Attributes | |
ACE_Process_Manager * | instance_ = 0 |
Singleton pointer. | |
int | delete_instance_ = 0 |
Friends | |
class | ACE_Process_Control |
This class allows applications to control groups of processes, similar to how the <ACE_Thread_Manager> controls groups of threads. Naturally, it doesn't work at all on platforms, such as VxWorks or pSoS, that don't support process. There are two (main) ways of using <ACE_Process_Manager>, depending on how involved you wish to be with the termination of managed es. If you just want es to go away when they're finished, simply register the with an <ACE_Reactor>: ACE_Process_Manager mgr( 100, some_reactor ) -or- ACE_Process_Manager mgr; ... mgr.open( 100, some_reactor ); Then, the will clean up after any es that it spawns. (On Unix, this means executing a wait(2) to collect the exit status -- and avoid zombie processes; on Win32, it means closing the process and thread HANDLEs that are created when CreateProcess is called.) If, on the other hand (and for some inexplicable reason) you want to explicitly invoke the terminated cleanup code, then *don't* register the with a Reactor, and be sure to call one of the <Process_Manager::wait> functions whenever there might be managed es that have exited. Note that in either case, allows you to register "<Event_Handlers>" to be called when a specific exits, or when any without a specific exits. When a exits, the appropriate 's is called; the ACE_HANDLE passed is either the Process' HANDLE (on Win32), or its pid cast to an ACE_HANDLE (on unix). It is also possible to call the <Process_Manager::wait> functions even though the is registered with a . Note also that the wait functions are "sloppy" on Unix, because there's no good way to wait for a subset of the children of a process. The wait functions may end up collecting the exit status of a process that's not managed by the whose you invoked. It's best to only use a single , and to create all subprocesses by calling that 's method. Incidentally, when you register your with a its notification pipe is used to help "reap" the available exit statuses. Therefore, you must not use a whose notify pipe has been disabled. Here's the sequence of steps used to reap the exit statuses in this case: + The registers a signal handler for SIGCHLD. + The SIGCHLD handler, when invoked, uses the 's method to inform the to wake up. + Next, the calls the 's , this happens synchronously, not in sighandler-space. + The method collects all available exit statuses.
Definition at line 124 of file Process_Manager.h.
|
Definition at line 129 of file Process_Manager.h.
00130 { 00131 DEFAULT_SIZE = 100 00132 }; |
|
Initialize an with a table containing up to processes. This table resizes itself automatically as needed. If a non-NULL is provided, this uses it to notify an application when a process it controls exits. By default, however, we don't use an ACE_Reactor. Definition at line 246 of file Process_Manager.cpp. References ACE_ERROR, ACE_LIB_TEXT, ACE_TRACE, LM_ERROR, and open().
00248 : ACE_Event_Handler (), 00249 process_table_ (0), 00250 max_process_table_size_ (0), 00251 current_count_ (0), 00252 default_exit_handler_ (0) 00253 #if defined (ACE_HAS_THREADS) 00254 , lock_ () 00255 #endif /* ACE_HAS_THREADS */ 00256 { 00257 ACE_TRACE ("ACE_Process_Manager::ACE_Process_Manager"); 00258 00259 if (this->open (size, 00260 r) == -1) 00261 ACE_ERROR ((LM_ERROR, 00262 ACE_LIB_TEXT ("%p\n"), 00263 ACE_LIB_TEXT ("ACE_Process_Manager"))); 00264 } |
|
Destructor releases all resources and does not wait for processes to exit. Definition at line 301 of file Process_Manager.cpp. References ACE_TRACE, and close().
|
|
Append information about a process, i.e., its in the . Each entry is added at the end, growing the table if necessary. Register to be called back when the process exits. Definition at line 497 of file Process_Manager.cpp. References ACE_TRACE, current_count_, DEFAULT_SIZE, ACE_Process_Descriptor::exit_notify_, ACE_Process::gethandle(), max_process_table_size_, ACE_Process_Descriptor::process_, process_table_, ACE_Event_Handler::reactor(), ACE_Reactor::register_handler(), and resize(). Referenced by insert_proc(), and spawn().
00499 { 00500 ACE_TRACE ("ACE_Process_Manager::append_proc"); 00501 00502 // Try to resize the array to twice its existing size (or the DEFAULT_SIZE, 00503 // if there are no array entries) if we run out of space... 00504 if (this->current_count_ >= this->max_process_table_size_) 00505 { 00506 size_t new_size = this->max_process_table_size_ * 2; 00507 if (new_size == 0) 00508 new_size = ACE_Process_Manager::DEFAULT_SIZE; 00509 if (this->resize (new_size) == -1) 00510 return -1; 00511 } 00512 00513 ACE_Process_Descriptor &proc_desc = 00514 this->process_table_[this->current_count_]; 00515 00516 proc_desc.process_ = proc; 00517 proc_desc.exit_notify_ = event_handler; 00518 00519 #if defined (ACE_WIN32) 00520 // If we have a Reactor, then we're supposed to reap Processes 00521 // automagically. Get a handle to this new Process and tell the 00522 // Reactor we're interested in <handling_input> on it. 00523 00524 ACE_Reactor * const r = this->reactor (); 00525 if (r != 0) 00526 r->register_handler (this, proc->gethandle ()); 00527 #endif /* ACE_WIN32 */ 00528 00529 ++this->current_count_; 00530 return 0; 00531 } |
|
Cleanup method, used by the to destroy the singleton. Definition at line 38 of file Process_Manager.cpp. References close_singleton(). Referenced by instance().
00039 { 00040 ACE_Process_Manager::close_singleton (); 00041 } |
|
Release all resources. Do not wait for processes to exit.
Definition at line 269 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_TRACE, current_count_, default_exit_handler_, ACE_Event_Handler::handle_close(), max_process_table_size_, process_table_, ACE_Event_Handler::reactor(), ACE_Reactor::remove_handler(), remove_proc(), and SIGCHLD. Referenced by ~ACE_Process_Manager().
00270 { 00271 ACE_TRACE ("ACE_Process_Manager::close"); 00272 00273 if (this->reactor () != 0) 00274 { 00275 #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS) 00276 this->reactor ()->remove_handler (SIGCHLD, (ACE_Sig_Action *) 0); 00277 #endif /* !ACE_WIN32 */ 00278 this->reactor (0); 00279 } 00280 00281 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00282 00283 if (this->process_table_ != 0) 00284 { 00285 while (this->current_count_ > 0) 00286 this->remove_proc (0); 00287 00288 delete [] this->process_table_; 00289 this->process_table_ = 0; 00290 this->max_process_table_size_ = 0; 00291 this->current_count_ = 0; 00292 } 00293 00294 if (this->default_exit_handler_ != 0) 00295 this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE,0); 00296 this->default_exit_handler_ = 0; 00297 00298 return 0; 00299 } |
|
Delete the dynamically allocated singleton.
Definition at line 176 of file Process_Manager.cpp. References ACE_GUARD, ACE_TRACE, delete_instance_, and instance_. Referenced by cleanup().
00177 { 00178 ACE_TRACE ("ACE_Process_Manager::close_singleton"); 00179 00180 ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, 00181 *ACE_Static_Object_Lock::instance ())); 00182 00183 if (ACE_Process_Manager::delete_instance_) 00184 { 00185 delete ACE_Process_Manager::instance_; 00186 ACE_Process_Manager::instance_ = 0; 00187 ACE_Process_Manager::delete_instance_ = 0; 00188 } 00189 } |
|
Dump the state of an object.
Definition at line 84 of file Process_Manager.cpp. References ACE_BEGIN_DUMP, ACE_DEBUG, ACE_END_DUMP, ACE_LIB_TEXT, ACE_TRACE, current_count_, ACE_Process_Descriptor::dump(), LM_DEBUG, and process_table_.
00085 { 00086 #if defined (ACE_HAS_DUMP) 00087 ACE_TRACE ("ACE_Process_Manager::dump"); 00088 00089 ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); 00090 00091 ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nmax_process_table_size_ = %d"), this->max_process_table_size_)); 00092 ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncurrent_count_ = %d"), this->current_count_)); 00093 00094 for (size_t i = 0; i < this->current_count_; i++) 00095 this->process_table_[i].dump (); 00096 00097 ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); 00098 #endif /* ACE_HAS_DUMP */ 00099 } |
|
Locate the index of the table slot occupied by . Returns ~0 if is not in the Definition at line 715 of file Process_Manager.cpp. References ACE_TRACE, current_count_, ACE_Process::gethandle(), ACE_Process_Descriptor::process_, and process_table_.
00716 { 00717 ACE_TRACE ("ACE_Process_Manager::find_proc"); 00718 00719 for (size_t i = 0; i < this->current_count_; ++i) 00720 if (h == this->process_table_[i].process_->gethandle ()) 00721 return i; 00722 00723 return -1; 00724 } |
|
Locate the index of the table slot occupied by . Returns -1 if is not in the Definition at line 699 of file Process_Manager.cpp. References ACE_TRACE, current_count_, ACE_Process::getpid(), pid_t, ACE_Process_Descriptor::process_, and process_table_. Referenced by handle_signal(), insert_proc(), register_handler(), remove(), set_scheduler(), terminate(), and wait().
00700 { 00701 ACE_TRACE ("ACE_Process_Manager::find_proc"); 00702 00703 for (size_t i = 0; i < this->current_count_; ++i) 00704 if (pid == this->process_table_[i].process_->getpid ()) 00705 return i; 00706 00707 return -1; 00708 } |
|
On Unix, this routine is called asynchronously when a SIGCHLD is received. We just tweak the reactor so that it'll call back our function, which allows us to handle Process exits synchronously. On Win32, this routine is called synchronously, and is passed the HANDLE of the Process that exited, so we can do all our work here Reimplemented from ACE_Event_Handler. Definition at line 341 of file Process_Manager.cpp. References ACE_ERROR_RETURN, ACE_exitcode, ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_LIB_TEXT, find_proc(), ACE_Process::getpid(), LM_ERROR, ACE_Reactor::notify(), notify_proc_handler(), pid_t, ACE_Process_Descriptor::process_, process_table_, ACE_Event_Handler::reactor(), remove_proc(), siginfo_t::si_handle_, ssize_t, and ucontext_t.
00344 { 00345 #if defined (ACE_WIN32) 00346 ACE_HANDLE proc = si->si_handle_; 00347 ACE_exitcode status = 0; 00348 BOOL result = ::GetExitCodeProcess (proc, 00349 &status); 00350 if (result) 00351 { 00352 if (status != STILL_ACTIVE) 00353 { 00354 { 00355 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, lock_, -1)); 00356 00357 ssize_t const i = this->find_proc (proc); 00358 if (i == -1) 00359 return -1; 00360 #if 0 00361 pid_t pid = i != -1 00362 ? process_table_[i].process_->getpid () 00363 : ACE_INVALID_PID; 00364 #endif 00365 this->notify_proc_handler (i, status); 00366 this->remove_proc (i); 00367 } 00368 return -1; // remove this HANDLE/Event_Handler combination 00369 } 00370 else 00371 ACE_ERROR_RETURN ((LM_ERROR, 00372 ACE_LIB_TEXT ("Process still active") 00373 ACE_LIB_TEXT (" -- shouldn't have been called yet!\n")), 00374 0); // return 0 : stay registered 00375 } 00376 else 00377 { 00378 // <GetExitCodeProcess> failed. 00379 ACE_ERROR_RETURN ((LM_ERROR, 00380 ACE_LIB_TEXT ("GetExitCodeProcess failed")), 00381 -1); // return -1: unregister 00382 } 00383 #else /* !ACE_WIN32 */ 00384 ACE_UNUSED_ARG (si); 00385 return reactor ()->notify (this, ACE_Event_Handler::READ_MASK); 00386 #endif /* !ACE_WIN32 */ 00387 } |
|
Insert a process in the table (checks for duplicates). Omitting the process handle won't work on Win32... Register to be called back when the process exits. Definition at line 537 of file Process_Manager.cpp. References ACE_TRACE, append_proc(), find_proc(), and ACE_Process::getpid().
00539 { 00540 ACE_TRACE ("ACE_Process_Manager::insert_proc"); 00541 00542 // Check for duplicates and bail out if they're already 00543 // registered... 00544 if (this->find_proc (proc->getpid ()) != -1) 00545 return -1; 00546 00547 return this->append_proc (proc, event_handler); 00548 } |
|
Set pointer to a process-wide and return existing pointer. Definition at line 147 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_TRACE, ACE_Object_Manager::at_exit(), cleanup(), delete_instance_, and instance_.
00148 { 00149 ACE_TRACE ("ACE_Process_Manager::instance"); 00150 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, 00151 *ACE_Static_Object_Lock::instance (), 0)); 00152 00153 ACE_Process_Manager *t = ACE_Process_Manager::instance_; 00154 // We can't safely delete it since we don't know who created it! 00155 ACE_Process_Manager::delete_instance_ = 0; 00156 00157 // Register with the Object_Manager so that the wrapper to 00158 // delete the proactor will be called when Object_Manager is 00159 // being terminated. 00160 00161 #if defined ACE_HAS_SIG_C_FUNC 00162 ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_, 00163 ACE_Process_Manager_cleanup, 00164 0); 00165 #else 00166 ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_, 00167 ACE_Process_Manager::cleanup, 00168 0); 00169 #endif /* ACE_HAS_SIG_C_FUNC */ 00170 00171 ACE_Process_Manager::instance_ = tm; 00172 return t; 00173 } |
|
Get pointer to a process-wide .
Definition at line 109 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_NEW_RETURN, ACE_TRACE, ACE_Object_Manager::at_exit(), cleanup(), delete_instance_, and instance_.
00110 { 00111 ACE_TRACE ("ACE_Process_Manager::instance"); 00112 00113 if (ACE_Process_Manager::instance_ == 0) 00114 { 00115 // Perform Double-Checked Locking Optimization. 00116 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, 00117 *ACE_Static_Object_Lock::instance (), 0)); 00118 00119 if (ACE_Process_Manager::instance_ == 0) 00120 { 00121 ACE_NEW_RETURN (ACE_Process_Manager::instance_, 00122 ACE_Process_Manager, 00123 0); 00124 ACE_Process_Manager::delete_instance_ = 1; 00125 00126 // Register with the Object_Manager so that the wrapper to 00127 // delete the proactor will be called when Object_Manager is 00128 // being terminated. 00129 00130 #if defined ACE_HAS_SIG_C_FUNC 00131 ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_, 00132 ACE_Process_Manager_cleanup, 00133 0); 00134 #else 00135 ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_, 00136 ACE_Process_Manager::cleanup, 00137 0); 00138 #endif /* ACE_HAS_SIG_C_FUNC */ 00139 00140 } 00141 } 00142 00143 return ACE_Process_Manager::instance_; 00144 } |
|
Return the number of managed Processes.
Definition at line 8 of file Process_Manager.inl. References current_count_.
00009 { 00010 return current_count_; 00011 } |
|
If there's a specific handler for the Process at index in the table, or there's a default handler, call it. Definition at line 1001 of file Process_Manager.cpp. References ACE_DEBUG, ACE_exitcode, ACE_LIB_TEXT, current_count_, default_exit_handler_, ACE_Process::exit_code(), ACE_Process_Descriptor::exit_notify_, ACE_Event_Handler::handle_close(), ACE_Event_Handler::handle_exit(), LM_DEBUG, ACE_Process_Descriptor::process_, and process_table_. Referenced by handle_signal(), and wait().
01003 { 01004 if (i < this->current_count_) 01005 { 01006 ACE_Process_Descriptor &proc_desc = 01007 this->process_table_[i]; 01008 01009 proc_desc.process_->exit_code (exit_code); 01010 01011 if (proc_desc.exit_notify_ != 0) 01012 proc_desc.exit_notify_->handle_exit (proc_desc.process_); 01013 else if (this->default_exit_handler_ != 0 01014 && this->default_exit_handler_->handle_exit (proc_desc.process_) < 0) 01015 { 01016 this->default_exit_handler_->handle_close 01017 (ACE_INVALID_HANDLE, 01018 0); 01019 this->default_exit_handler_ = 0; 01020 } 01021 return 1; 01022 } 01023 else 01024 { 01025 ACE_DEBUG ((LM_DEBUG, 01026 ACE_LIB_TEXT ("(%P:%t|%T) ACE_Process_Manager::notify_proc_handler:") 01027 ACE_LIB_TEXT (" unknown/unmanaged process reaped\n"))); 01028 return 0; 01029 } 01030 } |
|
Initialize an with a table containing up to processes. This table resizes itself automatically as needed. If a non-NULL is provided, this uses it to notify an application when a process it controls exits. By default, however, we don't use an ACE_Reactor. Definition at line 222 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_TRACE, max_process_table_size_, ACE_Event_Handler::reactor(), ACE_Reactor::register_handler(), resize(), and SIGCHLD. Referenced by ACE_Process_Manager().
00224 { 00225 ACE_TRACE ("ACE_Process_Manager::open"); 00226 00227 if (r) 00228 { 00229 this->reactor (r); 00230 #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS) 00231 // Register signal handler object. 00232 if (r->register_handler (SIGCHLD, this) == -1) 00233 return -1; 00234 #endif /* !defined(ACE_WIN32) */ 00235 } 00236 00237 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00238 00239 if (this->max_process_table_size_ < size) 00240 this->resize (size); 00241 return 0; 00242 } |
|
Definition at line 983 of file Process_Manager.cpp. References ACE_BIT_ENABLED, ACE_exitcode, ACE_TRACE, pid_t, wait(), and WNOHANG.
|
|
Register an Event_Handler to be called back when the specified process exits. If pid == ACE_INVALID_PID this handler is called when any process with no specific handler exits.
Definition at line 390 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_INVALID_PID, default_exit_handler_, ACE_Process_Descriptor::exit_notify_, find_proc(), ACE_Event_Handler::handle_close(), pid_t, process_table_, and ssize_t.
00392 { 00393 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00394 00395 if (pid == ACE_INVALID_PID) 00396 { 00397 if (this->default_exit_handler_ != 0) 00398 this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE, 0); 00399 this->default_exit_handler_ = eh; 00400 return 0; 00401 } 00402 00403 ssize_t const i = this->find_proc (pid); 00404 00405 if (i == -1) 00406 { 00407 errno = EINVAL; 00408 return -1; 00409 } 00410 00411 ACE_Process_Descriptor &proc_desc = this->process_table_[i]; 00412 00413 if (proc_desc.exit_notify_ != 0) 00414 proc_desc.exit_notify_->handle_close (ACE_INVALID_HANDLE, 0); 00415 proc_desc.exit_notify_ = eh; 00416 return 0; 00417 } |
|
Remove process from the table. This is called automatically by the method after it successfully reaped a signal. It's also possible to call this method directly from a signal handler, but don't call both and ! Definition at line 553 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_TRACE, find_proc(), pid_t, remove_proc(), and ssize_t. Referenced by wait().
00554 { 00555 ACE_TRACE ("ACE_Process_Manager::remove"); 00556 00557 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00558 00559 ssize_t const i = this->find_proc (pid); 00560 00561 if (i != -1) 00562 return this->remove_proc (i); 00563 00564 // set "process not found" error 00565 return -1; 00566 } |
|
Actually removes the process at index from the table. This method must be called with locks held. Definition at line 571 of file Process_Manager.cpp. References ACE_TRACE, current_count_, ACE_Process_Descriptor::exit_notify_, ACE_Process::gethandle(), ACE_Event_Handler::handle_close(), ACE_Process_Descriptor::process_, process_table_, ACE_Event_Handler::reactor(), ACE_Reactor::remove_handler(), and ACE_Process::unmanage(). Referenced by close(), handle_signal(), remove(), terminate(), and wait().
00572 { 00573 ACE_TRACE ("ACE_Process_Manager::remove_proc"); 00574 00575 // If there's an exit_notify_ <Event_Handler> for this pid, call its 00576 // <handle_close> method. 00577 00578 if (this->process_table_[i].exit_notify_ != 0) 00579 { 00580 this->process_table_[i].exit_notify_->handle_close 00581 (this->process_table_[i].process_->gethandle(), 00582 0); 00583 this->process_table_[i].exit_notify_ = 0; 00584 } 00585 00586 #if defined (ACE_WIN32) 00587 ACE_Reactor * const r = this->reactor (); 00588 if (r != 0) 00589 r->remove_handler (this->process_table_[i].process_->gethandle (), 00590 ACE_Event_Handler::DONT_CALL); 00591 #endif /* ACE_WIN32 */ 00592 00593 this->process_table_[i].process_->unmanage (); 00594 00595 this->process_table_[i].process_ = 0; 00596 00597 this->current_count_--; 00598 00599 if (this->current_count_ > 0) 00600 // Compact the table by moving the last item into the slot vacated 00601 // by the index being removed (this is a structure assignment). 00602 this->process_table_[i] = 00603 this->process_table_[this->current_count_]; 00604 00605 return 0; 00606 } |
|
Resize the pool of Process_Descriptors.
Definition at line 192 of file Process_Manager.cpp. References ACE_NEW_RETURN, ACE_TRACE, current_count_, max_process_table_size_, and process_table_. Referenced by append_proc(), and open().
00193 { 00194 ACE_TRACE ("ACE_Process_Manager::resize"); 00195 00196 if (size <= this->max_process_table_size_) 00197 return 0; 00198 00199 ACE_Process_Descriptor *temp = 0; 00200 00201 ACE_NEW_RETURN (temp, 00202 ACE_Process_Descriptor[size], 00203 -1); 00204 00205 for (size_t i = 0; 00206 i < this->current_count_; 00207 i++) 00208 // Structure assignment. 00209 temp[i] = this->process_table_[i]; 00210 00211 this->max_process_table_size_ = size; 00212 00213 delete [] this->process_table_; 00214 00215 this->process_table_ = temp; 00216 return 0; 00217 } |
|
Sets the scheduling parameters for the managed by identified by pid by passing , to <ACE_OS::sched_params>. Returns 0 on success, -1 on failure, and ACE_INVALID_PID when given pid is not managed by . Definition at line 657 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_TRACE, find_proc(), pid_t, ACE_OS::sched_params(), and ssize_t.
00659 { 00660 ACE_TRACE ("ACE_Process_Manager::set_scheduler"); 00661 00662 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, 00663 ace_mon, this->lock_, -1)); 00664 00665 // Check to see if the process identified by the given pid is managed by 00666 // this instance of ACE_Process_Manager. 00667 ssize_t const i = this->find_proc (pid); 00668 00669 if (i == -1) 00670 // set "no such process" error 00671 return ACE_INVALID_PID; 00672 00673 return ACE_OS::sched_params (params, pid); 00674 } |
|
Sets the scheduling parameters for all the es managed by by passing to <ACE_OS::sched_params>. Returns 0 on success, -1 on failure. Definition at line 677 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_TRACE, current_count_, ACE_Process::getpid(), pid_t, ACE_Process_Descriptor::process_, process_table_, and ACE_OS::sched_params().
00678 { 00679 ACE_TRACE ("ACE_Process_Manager::set_scheduler_all"); 00680 00681 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, 00682 ace_mon, this->lock_, -1)); 00683 00684 for (size_t i = 0; i < this->current_count_; ++i) 00685 { 00686 pid_t const pid = this->process_table_[i].process_->getpid (); 00687 if (ACE_OS::sched_params (params, pid) != 0) 00688 return -1; 00689 } 00690 return 0; 00691 00692 } |
|
Create a new process by passing to <ACE_Process::spawn>. Register to be called back when the process exits. On success, returns the process id of the child that was created. On failure, returns ACE_INVALID_PID. Definition at line 422 of file Process_Manager.cpp. References ACE_INVALID_PID, ACE_NEW_RETURN, pid_t, and spawn().
00424 { 00425 ACE_Process *process = 0; 00426 ACE_NEW_RETURN (process, 00427 ACE_Managed_Process, 00428 ACE_INVALID_PID); 00429 00430 pid_t const pid = spawn (process, options, event_handler); 00431 if (pid == ACE_INVALID_PID || pid == 0) 00432 delete process; 00433 00434 return pid; 00435 } |
|
Create a new process by passing to <proc.spawn>. Register to be called back when the process exits. On success, returns the process id of the child that was created. On failure, returns ACE_INVALID_PID. Definition at line 440 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_TRACE, append_proc(), pid_t, and ACE_Process::spawn(). Referenced by spawn(), and spawn_n().
00443 { 00444 ACE_TRACE ("ACE_Process_Manager::spawn"); 00445 00446 pid_t const pid = process->spawn (options); 00447 00448 // Only include the pid in the parent's table. 00449 if (pid == ACE_INVALID_PID || pid == 0) 00450 return pid; 00451 00452 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, 00453 ace_mon, this->lock_, -1)); 00454 00455 if (this->append_proc (process, event_handler) == -1) 00456 // bad news: spawned, but not registered in table. 00457 return ACE_INVALID_PID; 00458 00459 return pid; 00460 } |
|
Create new processes by passing to <ACE_Process::spawn>, which is called times. If is non-0 it is expected to be an array of 's, which are filled in with the process ids of each newly created process. Register to be called back when each process exits. Returns 0 on success and -1 on failure. Definition at line 465 of file Process_Manager.cpp. References ACE_INVALID_PID, ACE_TRACE, pid_t, and spawn().
00469 { 00470 ACE_TRACE ("ACE_Process_Manager::spawn_n"); 00471 00472 if (child_pids != 0) 00473 for (size_t i = 0; 00474 i < n; 00475 ++i) 00476 child_pids[i] = ACE_INVALID_PID; 00477 00478 for (size_t i = 0; 00479 i < n; 00480 i++) 00481 { 00482 pid_t const pid = this->spawn (options, event_handler); 00483 if (pid == ACE_INVALID_PID || pid == 0) 00484 // We're in the child or something's gone wrong. 00485 return pid; 00486 else if (child_pids != 0) 00487 child_pids[i] = pid; 00488 } 00489 00490 return 0; 00491 } |
|
On OSs that support signals, send the signal to the specified process. Returns 0 on success and -1 on failure. Definition at line 637 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_TRACE, find_proc(), ACE_OS::kill(), pid_t, and ssize_t.
00639 { 00640 ACE_TRACE ("ACE_Process_Manager::terminate"); 00641 00642 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00643 00644 // Check for duplicates and bail out if they're already 00645 // registered... 00646 ssize_t const i = this->find_proc (pid); 00647 00648 if (i == -1) 00649 // set "no such process" error 00650 return -1; 00651 00652 return ACE_OS::kill (pid, sig); 00653 } |
|
Abruptly terminate a single process with id using the <ACE::terminate_process> method. Note that this call is potentially dangerous to use since the process being terminated may not have a chance to cleanup before it shuts down. Returns 0 on success and -1 on failure. Definition at line 609 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_TRACE, find_proc(), pid_t, remove_proc(), ssize_t, and ACE::terminate_process().
00610 { 00611 ACE_TRACE ("ACE_Process_Manager::terminate"); 00612 00613 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00614 00615 // Check for duplicates and bail out if they're already 00616 // registered... 00617 ssize_t const i = this->find_proc (pid); 00618 00619 if (i == -1) 00620 // set "no such process" error 00621 return -1; 00622 00623 int const result = ACE::terminate_process (pid); 00624 00625 if (result != -1) 00626 { 00627 // Save/restore errno. 00628 ACE_Errno_Guard error (errno); 00629 this->remove_proc (i); 00630 return 0; 00631 } 00632 00633 return -1; 00634 } |
|
Wait indefinitely for a single process to terminate. If pid==0, waits for any of the managed es (but see the note in the class documentation for caveats about this -- "sloppy Process cleanup on unix") If pid != 0, waits for that only. Returns the pid of the process whose exit was handled, or ACE_INVALID_PID on error. Definition at line 770 of file Process_Manager.cpp. References ACE_exitcode, ACE_TRACE, pid_t, and wait().
|
|
Wait up to for a single process to terminate. If pid==0, waits for any of the managed es (but see the note in the class documentation above for caveats about this -- "sloppy process cleanup on unix") If pid != 0, waits for that only. Returns the pid of the Process whose exit was handled, 0 if a timeout occurred, or ACE_INVALID_PID on error. Definition at line 785 of file Process_Manager.cpp. References ACE_ASSERT, ACE_DEBUG, ACE_ERROR_RETURN, ACE_exitcode, ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_LIB_TEXT, ACE_NEW_RETURN, ACE_SignalHandler, ACE_TRACE, current_count_, find_proc(), ACE_Process::gethandle(), ACE_Process::getpid(), LM_DEBUG, LM_ERROR, ACE_Time_Value::msec(), notify_proc_handler(), pid_t, ACE_Process_Descriptor::process_, process_table_, ACE_Event_Handler::reactor(), ACE_Sig_Action::register_action(), remove(), remove_proc(), SIGCHLD, ACE_OS::sleep(), ssize_t, ACE_Countdown_Time::update(), ACE_Process::wait(), ACE_OS::waitpid(), and WNOHANG.
00788 { 00789 ACE_TRACE ("ACE_Process_Manager::wait"); 00790 00791 ACE_exitcode local_stat = 0; 00792 if (status == 0) 00793 status = &local_stat; 00794 00795 *status = 0; 00796 00797 ssize_t idx = -1; 00798 ACE_Process *proc = 0; 00799 00800 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00801 00802 if (pid != 0) 00803 { 00804 idx = this->find_proc (pid); 00805 if (idx == -1) 00806 return ACE_INVALID_PID; 00807 else 00808 proc = process_table_[idx].process_; 00809 } 00810 00811 if (proc != 0) 00812 pid = proc->wait (timeout, status); 00813 else 00814 { 00815 // Wait for any Process spawned by this Process_Manager. 00816 #if defined (ACE_WIN32) 00817 HANDLE *handles = 0; 00818 00819 ACE_NEW_RETURN (handles, 00820 HANDLE[this->current_count_], 00821 ACE_INVALID_PID); 00822 00823 for (size_t i = 0; 00824 i < this->current_count_; 00825 ++i) 00826 handles[i] = 00827 process_table_[i].process_->gethandle (); 00828 00829 DWORD handle_count = static_cast<DWORD> (this->current_count_); 00830 DWORD result = ::WaitForMultipleObjects (handle_count, 00831 handles, 00832 FALSE, 00833 timeout == ACE_Time_Value::max_time 00834 ? INFINITE 00835 : timeout.msec ()); 00836 if (result == WAIT_FAILED) 00837 pid = ACE_INVALID_PID; 00838 else if (result == WAIT_TIMEOUT) 00839 pid = 0; 00840 else 00841 { 00842 // Green Hills produces a warning that result >= WAIT_OBJECT_0 is 00843 // a pointless comparison because WAIT_OBJECT_0 is zero and DWORD is 00844 // unsigned long, so this test is skipped for Green Hills. 00845 // Same for mingw. 00846 # if defined (ghs) || defined (__MINGW32__) || (defined (_MSC_VER) && _MSC_VER >= 1300) 00847 ACE_ASSERT (result < WAIT_OBJECT_0 + this->current_count_); 00848 # else 00849 ACE_ASSERT (result >= WAIT_OBJECT_0 00850 && result < WAIT_OBJECT_0 + this->current_count_); 00851 # endif 00852 00853 idx = this->find_proc (handles[result - WAIT_OBJECT_0]); 00854 00855 if (idx != -1) 00856 { 00857 pid = process_table_[idx].process_->getpid (); 00858 result = ::GetExitCodeProcess (handles[result - WAIT_OBJECT_0], 00859 status); 00860 if (result == 0) 00861 { 00862 // <GetExitCodeProcess> failed! 00863 this->remove_proc (idx); 00864 pid = ACE_INVALID_PID; 00865 } 00866 } 00867 else 00868 { 00869 // uh oh...handle removed from process_table_, even though 00870 // we're holding a lock! 00871 delete [] handles; 00872 ACE_ERROR_RETURN ((LM_ERROR, 00873 ACE_LIB_TEXT ("Process removed") 00874 ACE_LIB_TEXT (" -- somebody's ignoring the lock!\n")), 00875 -1); 00876 } 00877 } 00878 00879 delete [] handles; 00880 #else /* !defined(ACE_WIN32) */ 00881 if (timeout == ACE_Time_Value::max_time) 00882 { 00883 pid = ACE_OS::waitpid (-1, status, 0); 00884 } 00885 else if (timeout == ACE_Time_Value::zero) 00886 { 00887 pid = ACE_OS::waitpid (-1, status, WNOHANG); 00888 } 00889 else 00890 { 00891 # if defined (ACE_LACKS_UNIX_SIGNALS) 00892 pid = 0; 00893 ACE_Time_Value sleeptm (1); // 1 msec 00894 if (sleeptm > timeout) // if sleeptime > waittime 00895 sleeptm = timeout; 00896 ACE_Time_Value tmo (timeout); // Need one we can change 00897 for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ()) 00898 { 00899 pid = ACE_OS::waitpid (-1, status, WNOHANG); 00900 if (pid > 0 || pid == ACE_INVALID_PID) 00901 break; // Got a child or an error - all done 00902 00903 // pid 0, nothing is ready yet, so wait. 00904 // Do a (very) short sleep (only this thread sleeps). 00905 ACE_OS::sleep (sleeptm); 00906 } 00907 # else 00908 // Force generation of SIGCHLD, even though we don't want to 00909 // catch it - just need it to interrupt the sleep below. 00910 // If this object has a reactor set, assume it was given at 00911 // open(), and there's already a SIGCHLD action set, so no 00912 // action is needed here. 00913 ACE_Sig_Action old_action; 00914 if (this->reactor () == 0) 00915 { 00916 ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop); 00917 do_sigchld.register_action (SIGCHLD, &old_action); 00918 } 00919 00920 ACE_Time_Value tmo (timeout); // Need one we can change 00921 for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ()) 00922 { 00923 pid = ACE_OS::waitpid (-1, status, WNOHANG); 00924 # if defined (ACE_VXWORKS) && (ACE_VXWORKS >= 0x600) 00925 if (pid > 0 || (pid == ACE_INVALID_PID && errno != EINTR)) 00926 # else 00927 if (pid > 0 || pid == ACE_INVALID_PID) 00928 # endif 00929 break; // Got a child or an error - all done 00930 00931 // pid 0, nothing is ready yet, so wait. 00932 // Do a sleep (only this thread sleeps) til something 00933 // happens. This relies on SIGCHLD interrupting the sleep. 00934 // If SIGCHLD isn't delivered, we'll need to do something 00935 // with sigaction to force it. 00936 if (-1 == ACE_OS::sleep (tmo) && errno == EINTR) 00937 continue; 00938 // Timed out 00939 pid = 0; 00940 break; 00941 } 00942 00943 // Restore the previous SIGCHLD action if it was changed. 00944 if (this->reactor () == 0) 00945 { 00946 old_action.register_action (SIGCHLD); 00947 } 00948 # endif /* !ACE_LACKS_UNIX_SIGNALS */ 00949 } 00950 #endif /* !defined (ACE_WIN32) */ 00951 } 00952 00953 if (pid != ACE_INVALID_PID && pid != 0) 00954 { 00955 if (proc == 0) 00956 { 00957 idx = this->find_proc (pid); 00958 if (idx == -1) 00959 { 00960 // oops, reaped an unmanaged process! 00961 ACE_DEBUG ((LM_DEBUG, 00962 ACE_LIB_TEXT ("(%P|%t) oops, reaped unmanaged %d\n"), 00963 pid)); 00964 return pid; 00965 } 00966 else 00967 proc = process_table_[idx].process_; 00968 } 00969 else 00970 ACE_ASSERT (pid == proc->getpid ()); 00971 00972 this->notify_proc_handler (idx, 00973 *status); 00974 this->remove (pid); 00975 } 00976 00977 return pid; 00978 } |
|
Block until there are no more child processes running that were ed by this . Unlike the call below, this method does not require a signal handler or <ACE_OS::sigwait> because it simply blocks synchronously waiting for all the children managed by this to exit. Note that this does not return any status information about the success or failure of exiting child processes, although any registered exit_handlers are called. Returns 0 on success (and s the corresponding entries from the ; otherwise, returns -1 on failure. Definition at line 731 of file Process_Manager.cpp. References ACE_INVALID_PID, ACE_TRACE, current_count_, ACE_OS::gettimeofday(), and pid_t. Referenced by reap(), and wait().
00732 { 00733 ACE_TRACE ("ACE_Process_Manager::wait"); 00734 00735 ACE_Time_Value until = timeout; 00736 ACE_Time_Value remaining = timeout; 00737 00738 if (until < ACE_Time_Value::max_time) 00739 until += ACE_OS::gettimeofday (); 00740 00741 while (this->current_count_ > 0) 00742 { 00743 pid_t const pid = this->wait (0, remaining); 00744 00745 if (pid == ACE_INVALID_PID) // wait() failed 00746 return -1; 00747 else if (pid == 0) // timeout 00748 break; 00749 00750 remaining = until < ACE_Time_Value::max_time 00751 ? until - ACE_OS::gettimeofday () 00752 : ACE_Time_Value::max_time; 00753 00754 if (remaining <= ACE_Time_Value::zero) 00755 break; 00756 00757 // else Process terminated...wait for more... 00758 } 00759 return static_cast<int> (this->current_count_); 00760 } |
|
Definition at line 127 of file Process_Manager.h. |
|
Declare the dynamic allocation hooks.
Definition at line 326 of file Process_Manager.h. |
|
Current number of processes we are managing.
Definition at line 416 of file Process_Manager.h. Referenced by append_proc(), close(), dump(), find_proc(), managed(), notify_proc_handler(), remove_proc(), resize(), set_scheduler_all(), and wait(). |
|
This event handler is used to notify when a process we control exits. Definition at line 420 of file Process_Manager.h. Referenced by close(), notify_proc_handler(), and register_handler(). |
|
Controls whether the is deleted when we shut down (we can only delete it safely if we created it!) Definition at line 62 of file Process_Manager.cpp. Referenced by close_singleton(), and instance(). |
|
Singleton pointer.
Definition at line 58 of file Process_Manager.cpp. Referenced by close_singleton(), and instance(). |
|
This lock protects access/ops on .
Definition at line 431 of file Process_Manager.h. |
|
Maximum number of processes we can manage (should be dynamically allocated). Definition at line 413 of file Process_Manager.h. Referenced by append_proc(), close(), open(), and resize(). |
|
Vector that describes process state within the Process_Manager.
Definition at line 409 of file Process_Manager.h. Referenced by append_proc(), close(), dump(), find_proc(), handle_signal(), notify_proc_handler(), register_handler(), remove_proc(), resize(), set_scheduler_all(), and wait(). |