#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 ¶ms) |
void | dump (void) const |
Dump the state of an object. | |
ACE_ALLOC_HOOK_DECLARE | |
Declare the dynamic allocation hooks. | |
Public Types | |
DEFAULT_SIZE = 100 | |
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 | |
static ACE_Process_Manager * | instance (void) |
Get pointer to a process-wide ACE_Process_Manager. | |
static ACE_Process_Manager * | instance (ACE_Process_Manager *) |
static void | close_singleton (void) |
Delete the dynamically allocated singleton. | |
static void | cleanup (void *instance, void *arg) |
Protected Member Functions | |
virtual int | handle_input (ACE_HANDLE proc) |
Collect one (or more, on unix) process exit status. | |
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) |
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_ |
Static Private Attributes | |
static ACE_Process_Manager * | instance_ = 0 |
Singleton pointer. | |
static bool | delete_instance_ = false |
Friends | |
class | ACE_Process_Control |
Classes | |
struct | Process_Descriptor |
Information describing each process that's controlled by an ACE_Process_Manager. More... |
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:
ACE_Process_Manager mgr; // ... mgr.open (100, ACE_Reactor::instance ());
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.
anonymous enum |
ACE_Process_Manager::ACE_Process_Manager | ( | size_t | size = ACE_Process_Manager::DEFAULT_SIZE , |
|
ACE_Reactor * | reactor = 0 | |||
) |
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 245 of file Process_Manager.cpp.
References ACE_ERROR, ACE_TEXT, ACE_TRACE, and LM_ERROR.
00247 : ACE_Event_Handler (), 00248 process_table_ (0), 00249 max_process_table_size_ (0), 00250 current_count_ (0), 00251 default_exit_handler_ (0) 00252 #if defined (ACE_HAS_THREADS) 00253 , lock_ () 00254 #endif /* ACE_HAS_THREADS */ 00255 { 00256 ACE_TRACE ("ACE_Process_Manager::ACE_Process_Manager"); 00257 00258 if (this->open (size, 00259 r) == -1) 00260 ACE_ERROR ((LM_ERROR, 00261 ACE_TEXT ("%p\n"), 00262 ACE_TEXT ("ACE_Process_Manager"))); 00263 }
ACE_Process_Manager::~ACE_Process_Manager | ( | void | ) | [virtual] |
int ACE_Process_Manager::append_proc | ( | ACE_Process * | process, | |
ACE_Event_Handler * | event_handler = 0 | |||
) | [private] |
Append information about a process, i.e., its <process_id> in the process_table_
. 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 496 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(), and ACE_Reactor::register_handler().
Referenced by insert_proc().
00498 { 00499 ACE_TRACE ("ACE_Process_Manager::append_proc"); 00500 00501 // Try to resize the array to twice its existing size (or the DEFAULT_SIZE, 00502 // if there are no array entries) if we run out of space... 00503 if (this->current_count_ >= this->max_process_table_size_) 00504 { 00505 size_t new_size = this->max_process_table_size_ * 2; 00506 if (new_size == 0) 00507 new_size = ACE_Process_Manager::DEFAULT_SIZE; 00508 if (this->resize (new_size) == -1) 00509 return -1; 00510 } 00511 00512 Process_Descriptor &proc_desc = 00513 this->process_table_[this->current_count_]; 00514 00515 proc_desc.process_ = proc; 00516 proc_desc.exit_notify_ = event_handler; 00517 00518 #if defined (ACE_WIN32) 00519 // If we have a Reactor, then we're supposed to reap Processes 00520 // automagically. Get a handle to this new Process and tell the 00521 // Reactor we're interested in <handling_input> on it. 00522 ACE_Reactor * const r = this->reactor (); 00523 if (r != 0) 00524 r->register_handler (this, proc->gethandle ()); 00525 #endif /* ACE_WIN32 */ 00526 00527 ++this->current_count_; 00528 return 0; 00529 }
ACE_BEGIN_VERSIONED_NAMESPACE_DECL void ACE_Process_Manager::cleanup | ( | void * | instance, | |
void * | arg | |||
) | [static] |
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 }
int ACE_Process_Manager::close | ( | void | ) |
Release all resources. Do not wait for processes to exit.
Definition at line 268 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().
00269 { 00270 ACE_TRACE ("ACE_Process_Manager::close"); 00271 00272 if (this->reactor () != 0) 00273 { 00274 #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS) 00275 this->reactor ()->remove_handler (SIGCHLD, (ACE_Sig_Action *) 0); 00276 #endif /* !ACE_WIN32 */ 00277 this->reactor (0); 00278 } 00279 00280 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00281 00282 if (this->process_table_ != 0) 00283 { 00284 while (this->current_count_ > 0) 00285 this->remove_proc (0); 00286 00287 delete [] this->process_table_; 00288 this->process_table_ = 0; 00289 this->max_process_table_size_ = 0; 00290 this->current_count_ = 0; 00291 } 00292 00293 if (this->default_exit_handler_ != 0) 00294 this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE,0); 00295 this->default_exit_handler_ = 0; 00296 00297 return 0; 00298 }
void ACE_Process_Manager::close_singleton | ( | void | ) | [static] |
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_ = false; 00188 } 00189 }
void ACE_Process_Manager::dump | ( | void | ) | const |
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_, and LM_DEBUG.
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 }
ssize_t ACE_Process_Manager::find_proc | ( | pid_t | process_id | ) | [private] |
Locate the index of the table slot occupied by process_id. Returns -1 if process_id is not in the process_table_
Definition at line 684 of file Process_Manager.cpp.
References ACE_TRACE, and current_count_.
Referenced by handle_signal(), register_handler(), remove(), set_scheduler(), terminate(), and wait().
00685 { 00686 ACE_TRACE ("ACE_Process_Manager::find_proc"); 00687 00688 for (size_t i = 0; i < this->current_count_; ++i) 00689 if (pid == this->process_table_[i].process_->getpid ()) 00690 return i; 00691 00692 return -1; 00693 }
int ACE_Process_Manager::handle_input | ( | ACE_HANDLE | proc | ) | [protected, virtual] |
Collect one (or more, on unix) process exit status.
Reimplemented from ACE_Event_Handler.
Definition at line 315 of file Process_Manager.cpp.
References ACE_INVALID_PID, ACE_TRACE, wait(), and ACE_Time_Value::zero.
00316 { 00317 ACE_TRACE ("ACE_Process_Manager::handle_input"); 00318 00319 pid_t pid; 00320 00321 do 00322 pid = this->wait (0, 00323 ACE_Time_Value::zero); 00324 while (pid != 0 && pid != ACE_INVALID_PID); 00325 00326 return 0; 00327 }
int ACE_Process_Manager::handle_signal | ( | int | signum, | |
siginfo_t * | = 0 , |
|||
ucontext_t * | = 0 | |||
) | [protected, virtual] |
On Unix, this routine is called asynchronously when a SIGCHLD is received. We just tweak the reactor so that it'll call back our <handle_input> 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 340 of file Process_Manager.cpp.
References ACE_ERROR_RETURN, ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_TEXT, find_proc(), ACE_Process::getpid(), LM_ERROR, ACE_Reactor::notify(), notify_proc_handler(), ACE_Process_Manager::Process_Descriptor::process_, process_table_, ACE_Event_Handler::reactor(), ACE_Event_Handler::READ_MASK, remove_proc(), and siginfo_t::si_handle_.
00343 { 00344 #if defined (ACE_WIN32) 00345 ACE_HANDLE proc = si->si_handle_; 00346 ACE_exitcode status = 0; 00347 BOOL result = ::GetExitCodeProcess (proc, 00348 &status); 00349 if (result) 00350 { 00351 if (status != STILL_ACTIVE) 00352 { 00353 { 00354 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, lock_, -1)); 00355 00356 ssize_t const i = this->find_proc (proc); 00357 if (i == -1) 00358 return -1; 00359 #if 0 00360 pid_t pid = i != -1 00361 ? process_table_[i].process_->getpid () 00362 : ACE_INVALID_PID; 00363 #endif 00364 this->notify_proc_handler (i, status); 00365 this->remove_proc (i); 00366 } 00367 return -1; // remove this HANDLE/Event_Handler combination 00368 } 00369 else 00370 ACE_ERROR_RETURN ((LM_ERROR, 00371 ACE_TEXT ("Process still active") 00372 ACE_TEXT (" -- shouldn't have been called yet!\n")), 00373 0); // return 0 : stay registered 00374 } 00375 else 00376 { 00377 // <GetExitCodeProcess> failed. 00378 ACE_ERROR_RETURN ((LM_ERROR, 00379 ACE_TEXT ("GetExitCodeProcess failed")), 00380 -1); // return -1: unregister 00381 } 00382 #else /* !ACE_WIN32 */ 00383 ACE_UNUSED_ARG (si); 00384 return reactor ()->notify (this, ACE_Event_Handler::READ_MASK); 00385 #endif /* !ACE_WIN32 */ 00386 }
int ACE_Process_Manager::insert_proc | ( | ACE_Process * | process, | |
ACE_Event_Handler * | event_handler = 0 | |||
) | [private] |
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 535 of file Process_Manager.cpp.
References ACE_TRACE, append_proc(), and ACE_Process::getpid().
00537 { 00538 ACE_TRACE ("ACE_Process_Manager::insert_proc"); 00539 00540 // Check for duplicates and bail out if they're already 00541 // registered... 00542 if (this->find_proc (proc->getpid ()) != -1) 00543 return -1; 00544 00545 return this->append_proc (proc, event_handler); 00546 }
ACE_Process_Manager * ACE_Process_Manager::instance | ( | ACE_Process_Manager * | ) | [static] |
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_ = false; 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 }
ACE_Process_Manager * ACE_Process_Manager::instance | ( | void | ) | [static] |
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_ = true; 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 }
ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_INLINE size_t ACE_Process_Manager::managed | ( | void | ) | const |
Return the number of managed processes.
Definition at line 8 of file Process_Manager.inl.
References current_count_.
00009 { 00010 return current_count_; 00011 }
int ACE_Process_Manager::notify_proc_handler | ( | size_t | n, | |
ACE_exitcode | status | |||
) | [private] |
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 983 of file Process_Manager.cpp.
References ACE_DEBUG, ACE_TEXT, default_exit_handler_, ACE_Process::exit_code(), ACE_Process_Manager::Process_Descriptor::exit_notify_, ACE_Event_Handler::handle_exit(), LM_DEBUG, ACE_Process_Manager::Process_Descriptor::process_, and process_table_.
Referenced by handle_signal(), and wait().
00985 { 00986 if (i < this->current_count_) 00987 { 00988 Process_Descriptor &proc_desc = 00989 this->process_table_[i]; 00990 00991 proc_desc.process_->exit_code (exit_code); 00992 00993 if (proc_desc.exit_notify_ != 0) 00994 proc_desc.exit_notify_->handle_exit (proc_desc.process_); 00995 else if (this->default_exit_handler_ != 0 00996 && this->default_exit_handler_->handle_exit (proc_desc.process_) < 0) 00997 { 00998 this->default_exit_handler_->handle_close 00999 (ACE_INVALID_HANDLE, 01000 0); 01001 this->default_exit_handler_ = 0; 01002 } 01003 return 1; 01004 } 01005 else 01006 { 01007 ACE_DEBUG ((LM_DEBUG, 01008 ACE_TEXT ("(%P:%t|%T) ACE_Process_Manager::notify_proc_handler:") 01009 ACE_TEXT (" unknown/unmanaged process reaped\n"))); 01010 return 0; 01011 } 01012 }
int ACE_Process_Manager::open | ( | size_t | size = ACE_Process_Manager::DEFAULT_SIZE , |
|
ACE_Reactor * | r = 0 | |||
) |
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, ACE_Event_Handler::reactor(), resize(), and SIGCHLD.
00223 { 00224 ACE_TRACE ("ACE_Process_Manager::open"); 00225 00226 if (r) 00227 { 00228 this->reactor (r); 00229 #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS) 00230 // Register signal handler object. 00231 if (r->register_handler (SIGCHLD, this) == -1) 00232 return -1; 00233 #endif /* !defined(ACE_WIN32) */ 00234 } 00235 00236 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00237 00238 if (this->max_process_table_size_ < size) 00239 this->resize (size); 00240 return 0; 00241 }
int ACE_Process_Manager::reap | ( | pid_t | pid = -1 , |
|
ACE_exitcode * | stat_loc = 0 , |
|||
int | options = WNOHANG | |||
) |
Definition at line 965 of file Process_Manager.cpp.
References ACE_BIT_ENABLED, ACE_TRACE, ACE_Time_Value::max_time, wait(), WNOHANG, and ACE_Time_Value::zero.
00968 { 00969 ACE_TRACE ("ACE_Process_Manager::reap"); 00970 00971 return this->wait (pid, 00972 (ACE_BIT_ENABLED (options, WNOHANG) 00973 ? ACE_Time_Value::zero 00974 : ACE_Time_Value::max_time), 00975 stat_loc); 00976 }
int ACE_Process_Manager::register_handler | ( | ACE_Event_Handler * | event_handler, | |
pid_t | pid = ACE_INVALID_PID | |||
) |
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 389 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(), and process_table_.
00391 { 00392 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00393 00394 if (pid == ACE_INVALID_PID) 00395 { 00396 if (this->default_exit_handler_ != 0) 00397 this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE, 0); 00398 this->default_exit_handler_ = eh; 00399 return 0; 00400 } 00401 00402 ssize_t const i = this->find_proc (pid); 00403 00404 if (i == -1) 00405 { 00406 errno = EINVAL; 00407 return -1; 00408 } 00409 00410 Process_Descriptor &proc_desc = this->process_table_[i]; 00411 00412 if (proc_desc.exit_notify_ != 0) 00413 proc_desc.exit_notify_->handle_close (ACE_INVALID_HANDLE, 0); 00414 proc_desc.exit_notify_ = eh; 00415 return 0; 00416 }
int ACE_Process_Manager::remove | ( | pid_t | pid | ) |
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 551 of file Process_Manager.cpp.
References ACE_GUARD_RETURN, ACE_TRACE, find_proc(), and remove_proc().
Referenced by wait().
00552 { 00553 ACE_TRACE ("ACE_Process_Manager::remove"); 00554 00555 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00556 00557 ssize_t const i = this->find_proc (pid); 00558 00559 if (i != -1) 00560 return this->remove_proc (i); 00561 00562 // set "process not found" error 00563 return -1; 00564 }
int ACE_Process_Manager::remove_proc | ( | size_t | n | ) | [private] |
Actually removes the process at index n from the table. This method must be called with locks held.
Definition at line 569 of file Process_Manager.cpp.
References ACE_TRACE, current_count_, ACE_Event_Handler::DONT_CALL, ACE_Process_Manager::Process_Descriptor::exit_notify_, 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().
00570 { 00571 ACE_TRACE ("ACE_Process_Manager::remove_proc"); 00572 00573 // If there's an exit_notify_ <Event_Handler> for this pid, call its 00574 // <handle_close> method. 00575 00576 if (this->process_table_[i].exit_notify_ != 0) 00577 { 00578 this->process_table_[i].exit_notify_->handle_close 00579 (this->process_table_[i].process_->gethandle(), 00580 0); 00581 this->process_table_[i].exit_notify_ = 0; 00582 } 00583 00584 #if defined (ACE_WIN32) 00585 ACE_Reactor * const r = this->reactor (); 00586 if (r != 0) 00587 r->remove_handler (this->process_table_[i].process_->gethandle (), 00588 ACE_Event_Handler::DONT_CALL); 00589 #endif /* ACE_WIN32 */ 00590 00591 this->process_table_[i].process_->unmanage (); 00592 00593 this->process_table_[i].process_ = 0; 00594 00595 this->current_count_--; 00596 00597 if (this->current_count_ > 0) 00598 // Compact the table by moving the last item into the slot vacated 00599 // by the index being removed (this is a structure assignment). 00600 this->process_table_[i] = 00601 this->process_table_[this->current_count_]; 00602 00603 return 0; 00604 }
int ACE_Process_Manager::resize | ( | size_t | ) | [private] |
Resize the pool of Process_Descriptors.
Definition at line 192 of file Process_Manager.cpp.
References ACE_NEW_RETURN, ACE_TRACE, current_count_, and max_process_table_size_.
Referenced by 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 }
int ACE_Process_Manager::set_scheduler | ( | const ACE_Sched_Params & | params, | |
pid_t | pid | |||
) |
Sets the scheduling parameters for process identified by pid by passing params, pid to ACE_OS::sched_params().
0 | on success, -1 on failure, and ACE_INVALID_PID when the specified pid is not managed by this ACE_Process_Manager. |
Definition at line 644 of file Process_Manager.cpp.
References ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_TRACE, find_proc(), and ACE_OS::sched_params().
00646 { 00647 ACE_TRACE ("ACE_Process_Manager::set_scheduler"); 00648 00649 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, 00650 ace_mon, this->lock_, -1)); 00651 00652 // Check to see if the process identified by the given pid is managed by 00653 // this instance of ACE_Process_Manager. 00654 ssize_t const i = this->find_proc (pid); 00655 00656 if (i == -1) 00657 // set "no such process" error 00658 return ACE_INVALID_PID; 00659 00660 return ACE_OS::sched_params (params, pid); 00661 }
int ACE_Process_Manager::set_scheduler_all | ( | const ACE_Sched_Params & | params | ) |
Sets the scheduling parameters for all the processes managed by this ACE_Process_Manager by passing params to ACE_OS::sched_params().
0 | on success, -1 on failure. |
Definition at line 664 of file Process_Manager.cpp.
References ACE_GUARD_RETURN, ACE_TRACE, current_count_, and ACE_OS::sched_params().
00665 { 00666 ACE_TRACE ("ACE_Process_Manager::set_scheduler_all"); 00667 00668 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, 00669 ace_mon, this->lock_, -1)); 00670 00671 for (size_t i = 0; i < this->current_count_; ++i) 00672 { 00673 pid_t const pid = this->process_table_[i].process_->getpid (); 00674 if (ACE_OS::sched_params (params, pid) != 0) 00675 return -1; 00676 } 00677 return 0; 00678 }
pid_t ACE_Process_Manager::spawn | ( | ACE_Process_Options & | options, | |
ACE_Event_Handler * | event_handler = 0 | |||
) |
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 421 of file Process_Manager.cpp.
References ACE_INVALID_PID, ACE_NEW_RETURN, and spawn().
00423 { 00424 ACE_Process *process = 0; 00425 ACE_NEW_RETURN (process, 00426 ACE_Managed_Process, 00427 ACE_INVALID_PID); 00428 00429 pid_t const pid = spawn (process, options, event_handler); 00430 if (pid == ACE_INVALID_PID || pid == 0) 00431 delete process; 00432 00433 return pid; 00434 }
pid_t ACE_Process_Manager::spawn | ( | ACE_Process * | proc, | |
ACE_Process_Options & | options, | |||
ACE_Event_Handler * | event_handler = 0 | |||
) |
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 439 of file Process_Manager.cpp.
References ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_TRACE, and ACE_Process::spawn().
Referenced by spawn().
00442 { 00443 ACE_TRACE ("ACE_Process_Manager::spawn"); 00444 00445 pid_t const pid = process->spawn (options); 00446 00447 // Only include the pid in the parent's table. 00448 if (pid == ACE_INVALID_PID || pid == 0) 00449 return pid; 00450 00451 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, 00452 ace_mon, this->lock_, -1)); 00453 00454 if (this->append_proc (process, event_handler) == -1) 00455 // bad news: spawned, but not registered in table. 00456 return ACE_INVALID_PID; 00457 00458 return pid; 00459 }
int ACE_Process_Manager::spawn_n | ( | size_t | n, | |
ACE_Process_Options & | options, | |||
pid_t * | child_pids = 0 , |
|||
ACE_Event_Handler * | event_Handler = 0 | |||
) |
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 464 of file Process_Manager.cpp.
References ACE_INVALID_PID, and ACE_TRACE.
00468 { 00469 ACE_TRACE ("ACE_Process_Manager::spawn_n"); 00470 00471 if (child_pids != 0) 00472 for (size_t i = 0; 00473 i < n; 00474 ++i) 00475 child_pids[i] = ACE_INVALID_PID; 00476 00477 for (size_t i = 0; 00478 i < n; 00479 i++) 00480 { 00481 pid_t const pid = this->spawn (options, event_handler); 00482 if (pid == ACE_INVALID_PID || pid == 0) 00483 // We're in the child or something's gone wrong. 00484 return pid; 00485 else if (child_pids != 0) 00486 child_pids[i] = pid; 00487 } 00488 00489 return 0; 00490 }
int ACE_Process_Manager::terminate | ( | pid_t | pid, | |
int | sig | |||
) |
Sends the specified signal to the specified process.
0 | on success and -1 on failure. |
Definition at line 625 of file Process_Manager.cpp.
References ACE_GUARD_RETURN, ACE_TRACE, find_proc(), and ACE_OS::kill().
00626 { 00627 ACE_TRACE ("ACE_Process_Manager::terminate"); 00628 00629 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00630 00631 // Check for duplicates and bail out if they're already 00632 // registered... 00633 ssize_t const i = this->find_proc (pid); 00634 00635 if (i == -1) 00636 // set "no such process" error 00637 return -1; 00638 00639 return ACE_OS::kill (pid, sig); 00640 }
int ACE_Process_Manager::terminate | ( | pid_t | pid | ) |
Abruptly terminate a single process with id pid using the ACE::terminate_process() method which works on both signal-capable systems and on Windows.
0 | on success and -1 on failure. |
Definition at line 607 of file Process_Manager.cpp.
References ACE_GUARD_RETURN, ACE_TRACE, find_proc(), and ACE::terminate_process().
00608 { 00609 ACE_TRACE ("ACE_Process_Manager::terminate"); 00610 00611 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00612 00613 // Check for duplicates and bail out if they're already 00614 // registered... 00615 ssize_t const i = this->find_proc (pid); 00616 00617 if (i == -1) 00618 // set "no such process" error 00619 return -1; 00620 00621 return ACE::terminate_process (pid); 00622 }
pid_t ACE_Process_Manager::wait | ( | pid_t | pid, | |
ACE_exitcode * | status = 0 | |||
) |
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.
The | pid of the process which exited, or ACE_INVALID_PID on error. |
Definition at line 755 of file Process_Manager.cpp.
References ACE_TRACE, ACE_Time_Value::max_time, and wait().
00757 { 00758 ACE_TRACE ("ACE_Process_Manager::wait"); 00759 00760 return this->wait (pid, 00761 ACE_Time_Value::max_time, 00762 status); 00763 }
pid_t ACE_Process_Manager::wait | ( | pid_t | pid, | |
const ACE_Time_Value & | timeout, | |||
ACE_exitcode * | status = 0 | |||
) |
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.
pid | Process ID | |
timeout | Relative time to wait for process to terminate | |
status | Exit status of terminated process |
The | pid of the process which exited, 0 if a timeout occurred, or ACE_INVALID_PID on error. |
Definition at line 770 of file Process_Manager.cpp.
References ACE_ASSERT, ACE_DEBUG, ACE_ERROR_RETURN, ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_NEW_RETURN, ACE_TEXT, ACE_TRACE, find_proc(), ACE_Process::getpid(), LM_DEBUG, LM_ERROR, ACE_Time_Value::max_time, ACE_Time_Value::msec(), notify_proc_handler(), ACE_Process_Manager::Process_Descriptor::process_, process_table_, ACE_Sig_Action::register_action(), remove(), remove_proc(), SIGCHLD, sigchld_nop(), ACE_OS::sleep(), ACE_Process::wait(), ACE_OS::waitpid(), WNOHANG, and ACE_Time_Value::zero.
00773 { 00774 ACE_TRACE ("ACE_Process_Manager::wait"); 00775 00776 ACE_exitcode local_stat = 0; 00777 if (status == 0) 00778 status = &local_stat; 00779 00780 *status = 0; 00781 00782 ssize_t idx = -1; 00783 ACE_Process *proc = 0; 00784 00785 { 00786 // fake context after which the lock is released 00787 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00788 00789 if (pid != 0) 00790 { 00791 idx = this->find_proc (pid); 00792 if (idx == -1) 00793 return ACE_INVALID_PID; 00794 else 00795 proc = process_table_[idx].process_; 00796 } 00797 // release the lock. 00798 } 00799 if (proc != 0) 00800 pid = proc->wait (timeout, status); 00801 else 00802 { 00803 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 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 >= 00832 // WAIT_OBJECT_0 is a pointless comparison because 00833 // WAIT_OBJECT_0 is zero and DWORD is unsigned long, so this 00834 // test is skipped for Green Hills. 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 pid = ACE_OS::waitpid (-1, status, 0); 00872 else if (timeout == ACE_Time_Value::zero) 00873 pid = ACE_OS::waitpid (-1, status, WNOHANG); 00874 else 00875 { 00876 # if defined (ACE_LACKS_UNIX_SIGNALS) 00877 pid = 0; 00878 ACE_Time_Value sleeptm (1); // 1 msec 00879 if (sleeptm > timeout) // if sleeptime > waittime 00880 sleeptm = timeout; 00881 ACE_Time_Value tmo (timeout); // Need one we can change 00882 for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ()) 00883 { 00884 pid = ACE_OS::waitpid (-1, status, WNOHANG); 00885 if (pid > 0 || pid == ACE_INVALID_PID) 00886 break; // Got a child or an error - all done 00887 00888 // pid 0, nothing is ready yet, so wait. 00889 // Do a (very) short sleep (only this thread sleeps). 00890 ACE_OS::sleep (sleeptm); 00891 } 00892 # else 00893 // Force generation of SIGCHLD, even though we don't want to 00894 // catch it - just need it to interrupt the sleep below. 00895 // If this object has a reactor set, assume it was given at 00896 // open(), and there's already a SIGCHLD action set, so no 00897 // action is needed here. 00898 ACE_Sig_Action old_action; 00899 if (this->reactor () == 0) 00900 { 00901 ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop); 00902 do_sigchld.register_action (SIGCHLD, &old_action); 00903 } 00904 00905 ACE_Time_Value tmo (timeout); // Need one we can change 00906 for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ()) 00907 { 00908 pid = ACE_OS::waitpid (-1, status, WNOHANG); 00909 # if defined (ACE_VXWORKS) && (ACE_VXWORKS >= 0x600) 00910 if (pid > 0 || (pid == ACE_INVALID_PID && errno != EINTR)) 00911 # else 00912 if (pid > 0 || pid == ACE_INVALID_PID) 00913 # endif 00914 break; // Got a child or an error - all done 00915 00916 // pid 0, nothing is ready yet, so wait. 00917 // Do a sleep (only this thread sleeps) til something 00918 // happens. This relies on SIGCHLD interrupting the sleep. 00919 // If SIGCHLD isn't delivered, we'll need to do something 00920 // with sigaction to force it. 00921 if (-1 == ACE_OS::sleep (tmo) && errno == EINTR) 00922 continue; 00923 // Timed out 00924 pid = 0; 00925 break; 00926 } 00927 00928 // Restore the previous SIGCHLD action if it was changed. 00929 if (this->reactor () == 0) 00930 old_action.register_action (SIGCHLD); 00931 # endif /* !ACE_LACKS_UNIX_SIGNALS */ 00932 } 00933 #endif /* !defined (ACE_WIN32) */ 00934 } 00935 00936 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); 00937 if (pid != ACE_INVALID_PID && pid != 0) 00938 { 00939 //we always need to get our id, because we could have been moved in the table meanwhile 00940 idx = this->find_proc (pid); 00941 if (idx == -1) 00942 { 00943 // oops, reaped an unmanaged process! 00944 ACE_DEBUG ((LM_DEBUG, 00945 ACE_TEXT ("(%P|%t) oops, reaped unmanaged %d\n"), 00946 pid)); 00947 return pid; 00948 } 00949 else 00950 proc = process_table_[idx].process_; 00951 if (proc != 0) 00952 ACE_ASSERT (pid == proc->getpid ()); 00953 00954 this->notify_proc_handler (idx, 00955 *status); 00956 this->remove (pid); 00957 } 00958 00959 return pid; 00960 }
int ACE_Process_Manager::wait | ( | const ACE_Time_Value & | timeout = ACE_Time_Value::max_time |
) |
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.
timeout | Relative time to wait for processes to terminate. |
0 | on success; -1 on failure. |
Definition at line 716 of file Process_Manager.cpp.
References ACE_INVALID_PID, ACE_TRACE, ACE_OS::gettimeofday(), ACE_Time_Value::max_time, and ACE_Time_Value::zero.
Referenced by handle_input(), reap(), and wait().
00717 { 00718 ACE_TRACE ("ACE_Process_Manager::wait"); 00719 00720 ACE_Time_Value until = timeout; 00721 ACE_Time_Value remaining = timeout; 00722 00723 if (until < ACE_Time_Value::max_time) 00724 until += ACE_OS::gettimeofday (); 00725 00726 while (this->current_count_ > 0) 00727 { 00728 pid_t const pid = this->wait (0, remaining); 00729 00730 if (pid == ACE_INVALID_PID) // wait() failed 00731 return -1; 00732 else if (pid == 0) // timeout 00733 break; 00734 00735 remaining = until < ACE_Time_Value::max_time 00736 ? until - ACE_OS::gettimeofday () 00737 : ACE_Time_Value::max_time; 00738 00739 if (remaining <= ACE_Time_Value::zero) 00740 break; 00741 00742 // else Process terminated...wait for more... 00743 } 00744 return static_cast<int> (this->current_count_); 00745 }
friend class ACE_Process_Control [friend] |
Definition at line 101 of file Process_Manager.h.
size_t ACE_Process_Manager::current_count_ [private] |
Current number of processes we are managing.
Definition at line 451 of file Process_Manager.h.
Referenced by append_proc(), close(), dump(), find_proc(), managed(), remove_proc(), resize(), and set_scheduler_all().
This event handler is used to notify when a process we control exits.
Definition at line 455 of file Process_Manager.h.
Referenced by close(), notify_proc_handler(), and register_handler().
bool ACE_Process_Manager::delete_instance_ = false [static, private] |
Controls whether the <Process_Manager> is deleted when we shut down (we can only delete it safely if we created it!)
Definition at line 462 of file Process_Manager.h.
Referenced by close_singleton(), and instance().
ACE_Process_Manager * ACE_Process_Manager::instance_ = 0 [static, private] |
Singleton pointer.
Definition at line 458 of file Process_Manager.h.
Referenced by close_singleton(), and instance().
size_t ACE_Process_Manager::max_process_table_size_ [private] |
Maximum number of processes we can manage (should be dynamically allocated).
Definition at line 448 of file Process_Manager.h.
Referenced by append_proc(), close(), and resize().
Vector that describes process state within the Process_Manager.
Definition at line 444 of file Process_Manager.h.
Referenced by append_proc(), close(), handle_signal(), notify_proc_handler(), register_handler(), remove_proc(), and wait().