#include <Process_Manager.h>
Inheritance diagram for ACE_Process_Manager:
Utility methods | |
int | register_handler (ACE_Event_Handler *event_handler, pid_t pid=ACE_INVALID_PID) |
int | remove (pid_t pid) |
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. | |
ACE_ALLOC_HOOK_DECLARE | |
Declare the dynamic allocation hooks. | |
Public Types | |
enum | { DEFAULT_SIZE = 100 } |
Public Member Functions | |
Initialization and termination methods | |
ACE_Process_Manager (size_t size=ACE_Process_Manager::DEFAULT_SIZE, ACE_Reactor *reactor=0) | |
int | open (size_t size=ACE_Process_Manager::DEFAULT_SIZE, ACE_Reactor *r=0) |
int | close (void) |
Release all resources. Do not wait for processes to exit. | |
virtual | ~ACE_Process_Manager (void) |
Process creation methods | |
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) |
Process synchronization operations | |
int | terminate (pid_t pid) |
int | terminate (pid_t pid, int sig) |
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) |
Static Public Member Functions | |
Singleton access and control | |
ACE_Process_Manager * | instance (void) |
Get pointer to a process-wide ACE_Process_Manager. | |
ACE_Process_Manager * | instance (ACE_Process_Manager *) |
void | close_singleton (void) |
Delete the dynamically allocated singleton. | |
void | cleanup (void *instance, void *arg) |
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 | |
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 processes. If you want processes to simply go away when they're finished, register the ACE_Process_Manager with an ACE_Reactor that can handle notifications of child process exit:
In this usage scenario, the ACE_Process_Manager will clean up after any processes 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.)
Note that in either case, ACE_Process_Manager allows you to register an ACE_Event_Handler to be called when a specific spawned process exits, or when any process without a specific ACE_Event_Handler exits. When a process exits, the appropriate ACE_Event_Handler's handle_input() method is called; the ACE_HANDLE passed is either the process's HANDLE (on Win32), or its pid cast to an ACE_HANDLE (on POSIX). It is also possible to call the wait() functions even when the ACE_Process_Manager is registered with a reactor.
Definition at line 98 of file Process_Manager.h.
|
Definition at line 103 of file Process_Manager.h.
00104 { 00105 DEFAULT_SIZE = 100 00106 }; |
|
Initialize an ACE_Process_Manager with a table containing up to size processes. This table resizes itself automatically as needed. If a reactor is provided, this ACE_Process_Manager 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_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_TEXT ("%p\n"), 00263 ACE_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 event_handler 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_Manager::Process_Descriptor::exit_notify_, ACE_Process::gethandle(), max_process_table_size_, ACE_Process_Manager::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 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 ACE_Object_Manager 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_TEXT, ACE_TRACE, current_count_, ACE_Process_Manager::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_TEXT ("\nmax_process_table_size_ = %d"), this->max_process_table_size_)); 00092 ACE_DEBUG ((LM_DEBUG, ACE_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 process_handle. Returns ~0 if process_handle is not in the Definition at line 704 of file Process_Manager.cpp. References ACE_TRACE, current_count_, ACE_Process::gethandle(), ACE_Process_Manager::Process_Descriptor::process_, and process_table_.
00705 { 00706 ACE_TRACE ("ACE_Process_Manager::find_proc"); 00707 00708 for (size_t i = 0; i < this->current_count_; ++i) 00709 if (h == this->process_table_[i].process_->gethandle ()) 00710 return i; 00711 00712 return -1; 00713 } |
|
Locate the index of the table slot occupied by . Returns -1 if is not in the Definition at line 688 of file Process_Manager.cpp. References ACE_TRACE, current_count_, ACE_Process::getpid(), pid_t, ACE_Process_Manager::Process_Descriptor::process_, and process_table_. Referenced by handle_signal(), insert_proc(), register_handler(), remove(), set_scheduler(), terminate(), and wait().
00689 { 00690 ACE_TRACE ("ACE_Process_Manager::find_proc"); 00691 00692 for (size_t i = 0; i < this->current_count_; ++i) 00693 if (pid == this->process_table_[i].process_->getpid ()) 00694 return i; 00695 00696 return -1; 00697 } |
|
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_TEXT, find_proc(), ACE_Process::getpid(), LM_ERROR, ACE_Reactor::notify(), notify_proc_handler(), pid_t, ACE_Process_Manager::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_TEXT ("Process still active") 00373 ACE_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_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 event_handler 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 ACE_Process_Manager 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 ACE_Process_Manager.
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 n in the table, or there's a default handler, call it. Definition at line 990 of file Process_Manager.cpp. References ACE_DEBUG, ACE_exitcode, ACE_TEXT, current_count_, default_exit_handler_, ACE_Process::exit_code(), ACE_Process_Manager::Process_Descriptor::exit_notify_, ACE_Event_Handler::handle_close(), ACE_Event_Handler::handle_exit(), LM_DEBUG, ACE_Process_Manager::Process_Descriptor::process_, and process_table_. Referenced by handle_signal(), and wait().
00992 { 00993 if (i < this->current_count_) 00994 { 00995 Process_Descriptor &proc_desc = 00996 this->process_table_[i]; 00997 00998 proc_desc.process_->exit_code (exit_code); 00999 01000 if (proc_desc.exit_notify_ != 0) 01001 proc_desc.exit_notify_->handle_exit (proc_desc.process_); 01002 else if (this->default_exit_handler_ != 0 01003 && this->default_exit_handler_->handle_exit (proc_desc.process_) < 0) 01004 { 01005 this->default_exit_handler_->handle_close 01006 (ACE_INVALID_HANDLE, 01007 0); 01008 this->default_exit_handler_ = 0; 01009 } 01010 return 1; 01011 } 01012 else 01013 { 01014 ACE_DEBUG ((LM_DEBUG, 01015 ACE_TEXT ("(%P:%t|%T) ACE_Process_Manager::notify_proc_handler:") 01016 ACE_TEXT (" unknown/unmanaged process reaped\n"))); 01017 return 0; 01018 } 01019 } |
|
Initialize an ACE_Process_Manager with a table containing up to size processes. This table resizes itself automatically as needed. If a reactor is provided, this ACE_Process_Manager 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 972 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_Manager::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 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 pid from the ACE_Process_Manager's internal records. This is called automatically by the reap() method after it successfully reaps a process. It's also possible to call this method directly from a signal handler, but don't call both reap() and remove()! 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 n 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_Manager::Process_Descriptor::exit_notify_, ACE_Process::gethandle(), ACE_Event_Handler::handle_close(), ACE_Process_Manager::Process_Descriptor::process_, process_table_, ACE_Event_Handler::reactor(), ACE_Reactor::remove_handler(), and ACE_Process::unmanage(). Referenced by close(), handle_signal(), remove(), 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 Process_Descriptor *temp = 0; 00200 00201 ACE_NEW_RETURN (temp, 00202 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 process identified by pid by passing params, pid to ACE_OS::sched_params().
Definition at line 646 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.
00648 { 00649 ACE_TRACE ("ACE_Process_Manager::set_scheduler"); 00650 00651 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, 00652 ace_mon, this->lock_, -1)); 00653 00654 // Check to see if the process identified by the given pid is managed by 00655 // this instance of ACE_Process_Manager. 00656 ssize_t const i = this->find_proc (pid); 00657 00658 if (i == -1) 00659 // set "no such process" error 00660 return ACE_INVALID_PID; 00661 00662 return ACE_OS::sched_params (params, pid); 00663 } |
|
Sets the scheduling parameters for all the processes managed by this ACE_Process_Manager by passing params to ACE_OS::sched_params().
Definition at line 666 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_TRACE, current_count_, ACE_Process::getpid(), pid_t, ACE_Process_Manager::Process_Descriptor::process_, process_table_, and ACE_OS::sched_params().
00667 { 00668 ACE_TRACE ("ACE_Process_Manager::set_scheduler_all"); 00669 00670 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, 00671 ace_mon, this->lock_, -1)); 00672 00673 for (size_t i = 0; i < this->current_count_; ++i) 00674 { 00675 pid_t const pid = this->process_table_[i].process_->getpid (); 00676 if (ACE_OS::sched_params (params, pid) != 0) 00677 return -1; 00678 } 00679 return 0; 00680 00681 } |
|
Create a new process with the specified options. Register event_handler 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 with specified options. Register event_handler 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 n new processes with the same options. If child_pids is non-0 it is expected to be an array of at least n pid_t, which are filled in with the process IDs of the spawned processes. Register event_handler 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 } |
|
Sends the specified signal to the specified process.
Definition at line 627 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_TRACE, find_proc(), ACE_OS::kill(), pid_t, and ssize_t.
00628 { 00629 ACE_TRACE ("ACE_Process_Manager::terminate"); 00630 00631 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00632 00633 // Check for duplicates and bail out if they're already 00634 // registered... 00635 ssize_t const i = this->find_proc (pid); 00636 00637 if (i == -1) 00638 // set "no such process" error 00639 return -1; 00640 00641 return ACE_OS::kill (pid, sig); 00642 } |
|
Abruptly terminate a single process with id pid using the ACE::terminate_process() method which works on both signal-capable systems and on Windows.
Definition at line 609 of file Process_Manager.cpp. References ACE_GUARD_RETURN, ACE_TRACE, find_proc(), pid_t, 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 return ACE::terminate_process (pid); 00624 } |
|
Wait indefinitely for a single, specified process to terminate. If pid is 0, waits for any of the managed processes (but see the note concerning "sloppy process cleanup on unix"). If pid != 0, this method waits for that process only.
Definition at line 759 of file Process_Manager.cpp. References ACE_exitcode, ACE_TRACE, pid_t, and wait().
|
|
Wait up to timeout for a single specified process to terminate. If pid is 0, this method waits for any of the managed processes (but see the note concerning "sloppy process cleanup on unix"). If pid != 0, waits for that process only.
Definition at line 774 of file Process_Manager.cpp. References ACE_ASSERT, ACE_DEBUG, ACE_ERROR_RETURN, ACE_exitcode, ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_NEW_RETURN, ACE_SignalHandler, ACE_TEXT, 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_Manager::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.
00777 { 00778 ACE_TRACE ("ACE_Process_Manager::wait"); 00779 00780 ACE_exitcode local_stat = 0; 00781 if (status == 0) 00782 status = &local_stat; 00783 00784 *status = 0; 00785 00786 ssize_t idx = -1; 00787 ACE_Process *proc = 0; 00788 00789 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00790 00791 if (pid != 0) 00792 { 00793 idx = this->find_proc (pid); 00794 if (idx == -1) 00795 return ACE_INVALID_PID; 00796 else 00797 proc = process_table_[idx].process_; 00798 } 00799 00800 if (proc != 0) 00801 pid = proc->wait (timeout, status); 00802 else 00803 { 00804 // Wait for any Process spawned by this Process_Manager. 00805 #if defined (ACE_WIN32) 00806 HANDLE *handles = 0; 00807 00808 ACE_NEW_RETURN (handles, 00809 HANDLE[this->current_count_], 00810 ACE_INVALID_PID); 00811 00812 for (size_t i = 0; 00813 i < this->current_count_; 00814 ++i) 00815 handles[i] = 00816 process_table_[i].process_->gethandle (); 00817 00818 DWORD handle_count = static_cast<DWORD> (this->current_count_); 00819 DWORD result = ::WaitForMultipleObjects (handle_count, 00820 handles, 00821 FALSE, 00822 timeout == ACE_Time_Value::max_time 00823 ? INFINITE 00824 : timeout.msec ()); 00825 if (result == WAIT_FAILED) 00826 pid = ACE_INVALID_PID; 00827 else if (result == WAIT_TIMEOUT) 00828 pid = 0; 00829 else 00830 { 00831 // Green Hills produces a warning that result >= WAIT_OBJECT_0 is 00832 // a pointless comparison because WAIT_OBJECT_0 is zero and DWORD is 00833 // unsigned long, so this test is skipped for Green Hills. 00834 // Same for mingw. 00835 # if defined (ghs) || defined (__MINGW32__) || (defined (_MSC_VER) && _MSC_VER >= 1300) 00836 ACE_ASSERT (result < WAIT_OBJECT_0 + this->current_count_); 00837 # else 00838 ACE_ASSERT (result >= WAIT_OBJECT_0 00839 && result < WAIT_OBJECT_0 + this->current_count_); 00840 # endif 00841 00842 idx = this->find_proc (handles[result - WAIT_OBJECT_0]); 00843 00844 if (idx != -1) 00845 { 00846 pid = process_table_[idx].process_->getpid (); 00847 result = ::GetExitCodeProcess (handles[result - WAIT_OBJECT_0], 00848 status); 00849 if (result == 0) 00850 { 00851 // <GetExitCodeProcess> failed! 00852 this->remove_proc (idx); 00853 pid = ACE_INVALID_PID; 00854 } 00855 } 00856 else 00857 { 00858 // uh oh...handle removed from process_table_, even though 00859 // we're holding a lock! 00860 delete [] handles; 00861 ACE_ERROR_RETURN ((LM_ERROR, 00862 ACE_TEXT ("Process removed") 00863 ACE_TEXT (" -- somebody's ignoring the lock!\n")), 00864 -1); 00865 } 00866 } 00867 00868 delete [] handles; 00869 #else /* !defined(ACE_WIN32) */ 00870 if (timeout == ACE_Time_Value::max_time) 00871 { 00872 pid = ACE_OS::waitpid (-1, status, 0); 00873 } 00874 else if (timeout == ACE_Time_Value::zero) 00875 { 00876 pid = ACE_OS::waitpid (-1, status, WNOHANG); 00877 } 00878 else 00879 { 00880 # if defined (ACE_LACKS_UNIX_SIGNALS) 00881 pid = 0; 00882 ACE_Time_Value sleeptm (1); // 1 msec 00883 if (sleeptm > timeout) // if sleeptime > waittime 00884 sleeptm = timeout; 00885 ACE_Time_Value tmo (timeout); // Need one we can change 00886 for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ()) 00887 { 00888 pid = ACE_OS::waitpid (-1, status, WNOHANG); 00889 if (pid > 0 || pid == ACE_INVALID_PID) 00890 break; // Got a child or an error - all done 00891 00892 // pid 0, nothing is ready yet, so wait. 00893 // Do a (very) short sleep (only this thread sleeps). 00894 ACE_OS::sleep (sleeptm); 00895 } 00896 # else 00897 // Force generation of SIGCHLD, even though we don't want to 00898 // catch it - just need it to interrupt the sleep below. 00899 // If this object has a reactor set, assume it was given at 00900 // open(), and there's already a SIGCHLD action set, so no 00901 // action is needed here. 00902 ACE_Sig_Action old_action; 00903 if (this->reactor () == 0) 00904 { 00905 ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop); 00906 do_sigchld.register_action (SIGCHLD, &old_action); 00907 } 00908 00909 ACE_Time_Value tmo (timeout); // Need one we can change 00910 for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ()) 00911 { 00912 pid = ACE_OS::waitpid (-1, status, WNOHANG); 00913 # if defined (ACE_VXWORKS) && (ACE_VXWORKS >= 0x600) 00914 if (pid > 0 || (pid == ACE_INVALID_PID && errno != EINTR)) 00915 # else 00916 if (pid > 0 || pid == ACE_INVALID_PID) 00917 # endif 00918 break; // Got a child or an error - all done 00919 00920 // pid 0, nothing is ready yet, so wait. 00921 // Do a sleep (only this thread sleeps) til something 00922 // happens. This relies on SIGCHLD interrupting the sleep. 00923 // If SIGCHLD isn't delivered, we'll need to do something 00924 // with sigaction to force it. 00925 if (-1 == ACE_OS::sleep (tmo) && errno == EINTR) 00926 continue; 00927 // Timed out 00928 pid = 0; 00929 break; 00930 } 00931 00932 // Restore the previous SIGCHLD action if it was changed. 00933 if (this->reactor () == 0) 00934 { 00935 old_action.register_action (SIGCHLD); 00936 } 00937 # endif /* !ACE_LACKS_UNIX_SIGNALS */ 00938 } 00939 #endif /* !defined (ACE_WIN32) */ 00940 } 00941 00942 if (pid != ACE_INVALID_PID && pid != 0) 00943 { 00944 if (proc == 0) 00945 { 00946 idx = this->find_proc (pid); 00947 if (idx == -1) 00948 { 00949 // oops, reaped an unmanaged process! 00950 ACE_DEBUG ((LM_DEBUG, 00951 ACE_TEXT ("(%P|%t) oops, reaped unmanaged %d\n"), 00952 pid)); 00953 return pid; 00954 } 00955 else 00956 proc = process_table_[idx].process_; 00957 } 00958 else 00959 ACE_ASSERT (pid == proc->getpid ()); 00960 00961 this->notify_proc_handler (idx, 00962 *status); 00963 this->remove (pid); 00964 } 00965 00966 return pid; 00967 } |
|
Block until there are no more child processes running that were spawned by this ACE_Process_Manager. Unlike the wait() method below, this method does not require a signal handler or use of ACE_OS::sigwait() because it simply blocks synchronously waiting for all the children managed by this ACE_Process_Manager 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.
Definition at line 720 of file Process_Manager.cpp. References ACE_INVALID_PID, ACE_TRACE, current_count_, ACE_OS::gettimeofday(), and pid_t. Referenced by reap(), and wait().
00721 { 00722 ACE_TRACE ("ACE_Process_Manager::wait"); 00723 00724 ACE_Time_Value until = timeout; 00725 ACE_Time_Value remaining = timeout; 00726 00727 if (until < ACE_Time_Value::max_time) 00728 until += ACE_OS::gettimeofday (); 00729 00730 while (this->current_count_ > 0) 00731 { 00732 pid_t const pid = this->wait (0, remaining); 00733 00734 if (pid == ACE_INVALID_PID) // wait() failed 00735 return -1; 00736 else if (pid == 0) // timeout 00737 break; 00738 00739 remaining = until < ACE_Time_Value::max_time 00740 ? until - ACE_OS::gettimeofday () 00741 : ACE_Time_Value::max_time; 00742 00743 if (remaining <= ACE_Time_Value::zero) 00744 break; 00745 00746 // else Process terminated...wait for more... 00747 } 00748 return static_cast<int> (this->current_count_); 00749 } |
|
Definition at line 101 of file Process_Manager.h. |
|
Declare the dynamic allocation hooks.
Definition at line 338 of file Process_Manager.h. |
|
Current number of processes we are managing.
Definition at line 454 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 458 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 469 of file Process_Manager.h. |
|
Maximum number of processes we can manage (should be dynamically allocated). Definition at line 451 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 447 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(). |