Manages a group of processes. More...
#include <Process_Manager.h>
Classes | |
struct | Process_Descriptor |
Information describing each process that's controlled by an ACE_Process_Manager. More... | |
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 | |
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 |
Utility methods | |
| |
ACE_ALLOC_HOOK_DECLARE | |
Declare the dynamic allocation hooks. | |
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. |
Manages a group of processes.
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 ());
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.)
If, on the other hand you want to wait "in line" to handle the terminated process cleanup code, call one of the wait functions whenever there might be managed processes that have exited.
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 251 of file Process_Manager.cpp.
: ACE_Event_Handler (), process_table_ (0), max_process_table_size_ (0), current_count_ (0), default_exit_handler_ (0) #if defined (ACE_HAS_THREADS) , lock_ () #endif /* ACE_HAS_THREADS */ { ACE_TRACE ("ACE_Process_Manager::ACE_Process_Manager"); if (this->open (size, r) == -1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_Process_Manager"))); } }
ACE_Process_Manager::~ACE_Process_Manager | ( | void | ) | [virtual] |
Destructor releases all resources and does not wait for processes to exit.
Definition at line 307 of file Process_Manager.cpp.
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 503 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::append_proc"); // Try to resize the array to twice its existing size (or the DEFAULT_SIZE, // if there are no array entries) if we run out of space... if (this->current_count_ >= this->max_process_table_size_) { size_t new_size = this->max_process_table_size_ * 2; if (new_size == 0) new_size = ACE_Process_Manager::DEFAULT_SIZE; if (this->resize (new_size) == -1) return -1; } Process_Descriptor &proc_desc = this->process_table_[this->current_count_]; proc_desc.process_ = proc; proc_desc.exit_notify_ = event_handler; #if defined (ACE_WIN32) // If we have a Reactor, then we're supposed to reap Processes // automagically. Get a handle to this new Process and tell the // Reactor we're interested in <handling_input> on it. ACE_Reactor * const r = this->reactor (); if (r != 0) r->register_handler (this, proc->gethandle ()); #endif /* ACE_WIN32 */ ++this->current_count_; return 0; }
static void ACE_Process_Manager::cleanup | ( | void * | instance, | |
void * | arg | |||
) | [static] |
Cleanup method, used by the ACE_Object_Manager to destroy the singleton.
int ACE_Process_Manager::close | ( | void | ) |
Release all resources. Do not wait for processes to exit.
Definition at line 275 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::close"); if (this->reactor () != 0) { #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS) this->reactor ()->remove_handler (SIGCHLD, (ACE_Sig_Action *) 0); #endif /* !ACE_WIN32 */ this->reactor (0); } ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); if (this->process_table_ != 0) { while (this->current_count_ > 0) this->remove_proc (0); delete [] this->process_table_; this->process_table_ = 0; this->max_process_table_size_ = 0; this->current_count_ = 0; } if (this->default_exit_handler_ != 0) this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE,0); this->default_exit_handler_ = 0; return 0; }
void ACE_Process_Manager::close_singleton | ( | void | ) | [static] |
Delete the dynamically allocated singleton.
Definition at line 182 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::close_singleton"); ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, *ACE_Static_Object_Lock::instance ())); if (ACE_Process_Manager::delete_instance_) { delete ACE_Process_Manager::instance_; ACE_Process_Manager::instance_ = 0; ACE_Process_Manager::delete_instance_ = false; } }
void ACE_Process_Manager::dump | ( | void | ) | const |
Dump the state of an object.
Definition at line 86 of file Process_Manager.cpp.
{ #if defined (ACE_HAS_DUMP) ACE_TRACE ("ACE_Process_Manager::dump"); ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmax_process_table_size_ = %d"), this->max_process_table_size_)); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncurrent_count_ = %d"), this->current_count_)); for (size_t i = 0; i < this->current_count_; i++) this->process_table_[i].dump (); ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* ACE_HAS_DUMP */ }
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 691 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::find_proc"); for (size_t i = 0; i < this->current_count_; ++i) { if (pid == this->process_table_[i].process_->getpid ()) { return ACE_Utils::truncate_cast<ssize_t> (i); } } return -1; }
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 322 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::handle_input"); pid_t pid; do pid = this->wait (0, ACE_Time_Value::zero); while (pid != 0 && pid != ACE_INVALID_PID); return 0; }
int ACE_Process_Manager::handle_signal | ( | int | signum, | |
siginfo_t * | si = 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 347 of file Process_Manager.cpp.
{ #if defined (ACE_WIN32) ACE_HANDLE proc = si->si_handle_; ACE_exitcode status = 0; BOOL result = ::GetExitCodeProcess (proc, &status); if (result) { if (status != STILL_ACTIVE) { { ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, lock_, -1)); ssize_t const i = this->find_proc (proc); if (i == -1) return -1; #if 0 pid_t pid = i != -1 ? process_table_[i].process_->getpid () : ACE_INVALID_PID; #endif this->notify_proc_handler (i, status); this->remove_proc (i); } return -1; // remove this HANDLE/Event_Handler combination } else ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Process still active") ACE_TEXT (" -- shouldn't have been called yet!\n")), 0); // return 0 : stay registered } else { // <GetExitCodeProcess> failed. ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("GetExitCodeProcess failed")), -1); // return -1: unregister } #else /* !ACE_WIN32 */ ACE_UNUSED_ARG (si); return reactor ()->notify (this, ACE_Event_Handler::READ_MASK); #endif /* !ACE_WIN32 */ }
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 542 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::insert_proc"); // Check for duplicates and bail out if they're already // registered... if (this->find_proc (proc->getpid ()) != -1) return -1; return this->append_proc (proc, event_handler); }
ACE_Process_Manager * ACE_Process_Manager::instance | ( | ACE_Process_Manager * | tm | ) | [static] |
Set pointer to a process-wide ACE_Process_Manager and return existing pointer.
Definition at line 151 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::instance"); ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, *ACE_Static_Object_Lock::instance (), 0)); ACE_Process_Manager *t = ACE_Process_Manager::instance_; // We can't safely delete it since we don't know who created it! ACE_Process_Manager::delete_instance_ = false; // Register with the Object_Manager so that the wrapper to // delete the proactor will be called when Object_Manager is // being terminated. #if defined ACE_HAS_SIG_C_FUNC ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_, ACE_Process_Manager_cleanup, 0, typeid (*ACE_Process_Manager::instance_).name ()); #else ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_, ACE_Process_Manager::cleanup, 0, typeid (*ACE_Process_Manager::instance_).name ()); #endif /* ACE_HAS_SIG_C_FUNC */ ACE_Process_Manager::instance_ = tm; return t; }
ACE_Process_Manager * ACE_Process_Manager::instance | ( | void | ) | [static] |
Get pointer to a process-wide ACE_Process_Manager.
Definition at line 111 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::instance"); if (ACE_Process_Manager::instance_ == 0) { // Perform Double-Checked Locking Optimization. ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, *ACE_Static_Object_Lock::instance (), 0)); if (ACE_Process_Manager::instance_ == 0) { ACE_NEW_RETURN (ACE_Process_Manager::instance_, ACE_Process_Manager, 0); ACE_Process_Manager::delete_instance_ = true; // Register with the Object_Manager so that the wrapper to // delete the proactor will be called when Object_Manager is // being terminated. #if defined ACE_HAS_SIG_C_FUNC ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_, ACE_Process_Manager_cleanup, 0, typeid (*ACE_Process_Manager::instance_).name ()); #else ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_, ACE_Process_Manager::cleanup, 0, typeid (*ACE_Process_Manager::instance_).name ()); #endif /* ACE_HAS_SIG_C_FUNC */ } } return ACE_Process_Manager::instance_; }
size_t ACE_Process_Manager::managed | ( | void | ) | const |
Return the number of managed processes.
Definition at line 8 of file Process_Manager.inl.
{ return current_count_; }
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 998 of file Process_Manager.cpp.
{ if (i < this->current_count_) { Process_Descriptor &proc_desc = this->process_table_[i]; proc_desc.process_->exit_code (exit_code); if (proc_desc.exit_notify_ != 0) proc_desc.exit_notify_->handle_exit (proc_desc.process_); else if (this->default_exit_handler_ != 0 && this->default_exit_handler_->handle_exit (proc_desc.process_) < 0) { this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE, 0); this->default_exit_handler_ = 0; } return 1; } else { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P:%t|%T) ACE_Process_Manager::notify_proc_handler:") ACE_TEXT (" unknown/unmanaged process reaped\n"))); return 0; } }
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 228 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::open"); if (r) { this->reactor (r); #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS) // Register signal handler object. if (r->register_handler (SIGCHLD, this) == -1) return -1; #endif /* !defined(ACE_WIN32) */ } ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); if (this->max_process_table_size_ < size) this->resize (size); return 0; }
int ACE_Process_Manager::reap | ( | pid_t | pid = -1 , |
|
ACE_exitcode * | stat_loc = 0 , |
|||
int | options = WNOHANG | |||
) |
Definition at line 980 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::reap"); return this->wait (pid, (ACE_BIT_ENABLED (options, WNOHANG) ? ACE_Time_Value::zero : ACE_Time_Value::max_time), stat_loc); }
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 396 of file Process_Manager.cpp.
{ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); if (pid == ACE_INVALID_PID) { if (this->default_exit_handler_ != 0) this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE, 0); this->default_exit_handler_ = eh; return 0; } ssize_t const i = this->find_proc (pid); if (i == -1) { errno = EINVAL; return -1; } Process_Descriptor &proc_desc = this->process_table_[i]; if (proc_desc.exit_notify_ != 0) proc_desc.exit_notify_->handle_close (ACE_INVALID_HANDLE, 0); proc_desc.exit_notify_ = eh; return 0; }
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 558 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::remove"); ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); ssize_t const i = this->find_proc (pid); if (i != -1) return this->remove_proc (i); // set "process not found" error return -1; }
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 576 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::remove_proc"); // If there's an exit_notify_ <Event_Handler> for this pid, call its // <handle_close> method. if (this->process_table_[i].exit_notify_ != 0) { this->process_table_[i].exit_notify_->handle_close (this->process_table_[i].process_->gethandle(), 0); this->process_table_[i].exit_notify_ = 0; } #if defined (ACE_WIN32) ACE_Reactor * const r = this->reactor (); if (r != 0) r->remove_handler (this->process_table_[i].process_->gethandle (), ACE_Event_Handler::DONT_CALL); #endif /* ACE_WIN32 */ this->process_table_[i].process_->unmanage (); this->process_table_[i].process_ = 0; this->current_count_--; if (this->current_count_ > 0) // Compact the table by moving the last item into the slot vacated // by the index being removed (this is a structure assignment). this->process_table_[i] = this->process_table_[this->current_count_]; return 0; }
int ACE_Process_Manager::resize | ( | size_t | size | ) | [private] |
Resize the pool of Process_Descriptors.
Definition at line 198 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::resize"); if (size <= this->max_process_table_size_) return 0; Process_Descriptor *temp = 0; ACE_NEW_RETURN (temp, Process_Descriptor[size], -1); for (size_t i = 0; i < this->current_count_; i++) // Structure assignment. temp[i] = this->process_table_[i]; this->max_process_table_size_ = size; delete [] this->process_table_; this->process_table_ = temp; return 0; }
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 651 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::set_scheduler"); ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); // Check to see if the process identified by the given pid is managed by // this instance of ACE_Process_Manager. ssize_t const i = this->find_proc (pid); if (i == -1) // set "no such process" error return ACE_INVALID_PID; return ACE_OS::sched_params (params, pid); }
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 671 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::set_scheduler_all"); ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); for (size_t i = 0; i < this->current_count_; ++i) { pid_t const pid = this->process_table_[i].process_->getpid (); if (ACE_OS::sched_params (params, pid) != 0) return -1; } return 0; }
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 428 of file Process_Manager.cpp.
{ ACE_Process *process = 0; ACE_NEW_RETURN (process, ACE_Managed_Process, ACE_INVALID_PID); pid_t const pid = this->spawn (process, options, event_handler); if (pid == ACE_INVALID_PID || pid == 0) delete process; return pid; }
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 446 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::spawn"); pid_t const pid = process->spawn (options); // Only include the pid in the parent's table. if (pid == ACE_INVALID_PID || pid == 0) return pid; ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); if (this->append_proc (process, event_handler) == -1) // bad news: spawned, but not registered in table. return ACE_INVALID_PID; return pid; }
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 471 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::spawn_n"); if (child_pids != 0) for (size_t i = 0; i < n; ++i) child_pids[i] = ACE_INVALID_PID; for (size_t i = 0; i < n; i++) { pid_t const pid = this->spawn (options, event_handler); if (pid == ACE_INVALID_PID || pid == 0) // We're in the child or something's gone wrong. return pid; else if (child_pids != 0) child_pids[i] = pid; } return 0; }
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 614 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::terminate"); ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); // Check for duplicates and bail out if they're already // registered... ssize_t const i = this->find_proc (pid); if (i == -1) // set "no such process" error return -1; return ACE::terminate_process (pid); }
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 632 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::terminate"); ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); // Check for duplicates and bail out if they're already // registered... ssize_t const i = this->find_proc (pid); if (i == -1) // set "no such process" error return -1; return ACE_OS::kill (pid, sig); }
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 731 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::wait"); ACE_Time_Value until = timeout; ACE_Time_Value remaining = timeout; if (until < ACE_Time_Value::max_time) until += ACE_OS::gettimeofday (); while (this->current_count_ > 0) { pid_t const pid = this->wait (0, remaining); if (pid == ACE_INVALID_PID) // wait() failed return -1; else if (pid == 0) // timeout break; remaining = until < ACE_Time_Value::max_time ? until - ACE_OS::gettimeofday () : ACE_Time_Value::max_time; if (remaining <= ACE_Time_Value::zero) break; // else Process terminated...wait for more... } return static_cast<int> (this->current_count_); }
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 770 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::wait"); return this->wait (pid, ACE_Time_Value::max_time, status); }
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 785 of file Process_Manager.cpp.
{ ACE_TRACE ("ACE_Process_Manager::wait"); ACE_exitcode local_stat = 0; if (status == 0) status = &local_stat; *status = 0; ssize_t idx = -1; ACE_Process *proc = 0; { // fake context after which the lock is released ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); if (pid != 0) { idx = this->find_proc (pid); if (idx == -1) return ACE_INVALID_PID; else proc = process_table_[idx].process_; } // release the lock. } if (proc != 0) pid = proc->wait (timeout, status); else { ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); // Wait for any Process spawned by this Process_Manager. #if defined (ACE_WIN32) HANDLE *handles = 0; ACE_NEW_RETURN (handles, HANDLE[this->current_count_], ACE_INVALID_PID); for (size_t i = 0; i < this->current_count_; ++i) handles[i] = process_table_[i].process_->gethandle (); DWORD handle_count = static_cast<DWORD> (this->current_count_); DWORD result = ::WaitForMultipleObjects (handle_count, handles, FALSE, timeout == ACE_Time_Value::max_time ? INFINITE : timeout.msec ()); if (result == WAIT_FAILED) pid = ACE_INVALID_PID; else if (result == WAIT_TIMEOUT) pid = 0; else { // Green Hills produces a warning that result >= // WAIT_OBJECT_0 is a pointless comparison because // WAIT_OBJECT_0 is zero and DWORD is unsigned long, so this // test is skipped for Green Hills. Same for mingw. # if defined (ghs) || defined (__MINGW32__) || defined (_MSC_VER) ACE_ASSERT (result < WAIT_OBJECT_0 + this->current_count_); # else ACE_ASSERT (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + this->current_count_); # endif idx = this->find_proc (handles[result - WAIT_OBJECT_0]); if (idx != -1) { pid = process_table_[idx].process_->getpid (); result = ::GetExitCodeProcess (handles[result - WAIT_OBJECT_0], status); if (result == 0) { // <GetExitCodeProcess> failed! this->remove_proc (idx); pid = ACE_INVALID_PID; } } else { // uh oh...handle removed from process_table_, even though // we're holding a lock! delete [] handles; ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Process removed") ACE_TEXT (" -- somebody's ignoring the lock!\n")), -1); } } delete [] handles; #else /* !defined(ACE_WIN32) */ if (timeout == ACE_Time_Value::max_time) pid = ACE_OS::waitpid (-1, status, 0); else if (timeout == ACE_Time_Value::zero) pid = ACE_OS::waitpid (-1, status, WNOHANG); else { # if defined (ACE_LACKS_UNIX_SIGNALS) pid = 0; ACE_Time_Value sleeptm (1); // 1 msec if (sleeptm > timeout) // if sleeptime > waittime sleeptm = timeout; ACE_Time_Value tmo (timeout); // Need one we can change for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ()) { pid = ACE_OS::waitpid (-1, status, WNOHANG); if (pid > 0 || pid == ACE_INVALID_PID) break; // Got a child or an error - all done // pid 0, nothing is ready yet, so wait. // Do a (very) short sleep (only this thread sleeps). ACE_OS::sleep (sleeptm); } # else // Force generation of SIGCHLD, even though we don't want to // catch it - just need it to interrupt the sleep below. // If this object has a reactor set, assume it was given at // open(), and there's already a SIGCHLD action set, so no // action is needed here. ACE_Sig_Action old_action; if (this->reactor () == 0) { ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop); do_sigchld.register_action (SIGCHLD, &old_action); } ACE_Time_Value tmo (timeout); // Need one we can change for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ()) { pid = ACE_OS::waitpid (-1, status, WNOHANG); # if defined (ACE_VXWORKS) && (ACE_VXWORKS >= 0x600) if (pid > 0 || (pid == ACE_INVALID_PID && errno != EINTR)) # else if (pid > 0 || pid == ACE_INVALID_PID) # endif break; // Got a child or an error - all done // pid 0, nothing is ready yet, so wait. // Do a sleep (only this thread sleeps) til something // happens. This relies on SIGCHLD interrupting the sleep. // If SIGCHLD isn't delivered, we'll need to do something // with sigaction to force it. if (-1 == ACE_OS::sleep (tmo) && errno == EINTR) continue; // Timed out pid = 0; break; } // Restore the previous SIGCHLD action if it was changed. if (this->reactor () == 0) old_action.register_action (SIGCHLD); # endif /* !ACE_LACKS_UNIX_SIGNALS */ } #endif /* !defined (ACE_WIN32) */ } ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); if (pid != ACE_INVALID_PID && pid != 0) { //we always need to get our id, because we could have been moved in the table meanwhile idx = this->find_proc (pid); if (idx == -1) { // oops, reaped an unmanaged process! ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) oops, reaped unmanaged %d\n"), pid)); return pid; } else proc = process_table_[idx].process_; if (proc != 0) ACE_ASSERT (pid == proc->getpid ()); this->notify_proc_handler (idx, *status); this->remove (pid); } return pid; }
friend class ACE_Process_Control [friend] |
Definition at line 101 of file Process_Manager.h.
Declare the dynamic allocation hooks.
Definition at line 336 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.
This event handler is used to notify when a process we control exits.
Definition at line 455 of file Process_Manager.h.
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.
ACE_Process_Manager * ACE_Process_Manager::instance_ = 0 [static, private] |
Singleton pointer.
Definition at line 458 of file Process_Manager.h.
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.
Vector that describes process state within the Process_Manager.
Definition at line 444 of file Process_Manager.h.