Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

ACE_Process_Manager Class Reference

Manages a group of processes. More...

#include <Process_Manager.h>

Inheritance diagram for ACE_Process_Manager:

Inheritance graph
[legend]
Collaboration diagram for ACE_Process_Manager:

Collaboration graph
[legend]
List of all members.

Public Types

enum  { DEFAULT_SIZE = 100 }

Public Methods

 ACE_Process_Manager (size_t size=ACE_Process_Manager::DEFAULT_SIZE, ACE_Reactor *reactor=0)
int open (size_t size=DEFAULT_SIZE, ACE_Reactor *r=0)
int close (void)
 Release all resources. Do not wait for processes to exit. More...

virtual ~ACE_Process_Manager (void)
 Destructor releases all resources and does not wait for processes to exit. More...

pid_t spawn (ACE_Process *proc, ACE_Process_Options &options)
pid_t spawn (ACE_Process_Options &options)
int spawn_n (size_t n, ACE_Process_Options &options, pid_t *child_pids=0)
int wait (const ACE_Time_Value &timeout=ACE_Time_Value::max_time)
pid_t wait (pid_t pid, const ACE_Time_Value &timeout, ACE_exitcode *status=0)
pid_t wait (pid_t pid, ACE_exitcode *status=0)
int reap (pid_t pid=-1, ACE_exitcode *stat_loc=0, int options=WNOHANG)
int register_handler (ACE_Event_Handler *event_handler, pid_t pid=ACE_INVALID_PID)
int remove (pid_t pid)
int terminate (pid_t pid)
int terminate (pid_t pid, int sig)
 On OSs that support signals, send the signal to the specified process. Returns 0 on success and -1 on failure. More...

size_t managed (void) const
 Return the number of managed Processes. More...

void dump (void) const
 Dump the state of an object. More...


Static Public Methods

ACE_Process_Manager * instance (void)
 Get pointer to a process-wide <ACE_Process_Manager>. More...

ACE_Process_Manager * instance (ACE_Process_Manager *)
 Set pointer to a process-wide <ACE_Process_Manager> and return existing pointer. More...

void close_singleton (void)
 Delete the dynamically allocated singleton. More...

void cleanup (void *instance, void *arg)
 Cleanup method, used by the <ACE_Object_Manager> to destroy the singleton. More...


Public Attributes

 ACE_ALLOC_HOOK_DECLARE
 Declare the dynamic allocation hooks. More...


Protected Methods

virtual int handle_signal (int signum, siginfo_t *=0, ucontext_t *=0)

Private Methods

int resize (size_t)
 Resize the pool of Process_Descriptors. More...

ssize_t find_proc (pid_t process_id)
 Locate the index of the table slot occupied by <process_id>. Returns -1 if <process_id> is not in the <process_table_>. More...

ssize_t find_proc (ACE_HANDLE process_handle)
 Locate the index of the table slot occupied by <process_handle>. Returns ~0 if <process_handle> is not in the <process_table_>. More...

int insert_proc (ACE_Process *process)
 Insert a process in the table (checks for duplicates). Omitting the process handle won't work on Win32... More...

int append_proc (ACE_Process *process)
int remove_proc (size_t n)
 Actually removes the process at index <n> from the table. This method must be called with locks held. More...

int notify_proc_handler (size_t n, ACE_exitcode status)
 If there's a specific handler for the Process at index <n> in the table, or there's a default handler, call it. More...


Private Attributes

ACE_Process_Descriptorprocess_table_
 Vector that describes process state within the Process_Manager. More...

size_t max_process_table_size_
 Maximum number of processes we can manage (should be dynamically allocated). More...

size_t current_count_
 Current number of processes we are managing. More...

ACE_Event_Handlerdefault_exit_handler_
 This event handler is used to notify when a process we control exits. More...

ACE_Recursive_Thread_Mutex lock_
 This lock protects access/ops on <process_table_>. More...


Static Private Attributes

ACE_Process_Manager * instance_ = 0
 Singleton pointer. More...

int delete_instance_ = 0
 Controls whether the <Process_Manager> is deleted when we shut down (we can only delete it safely if we created it!). More...


Friends

class ACE_Process_Control

Detailed Description

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 <ACE_Process>es. If you just want <Process>es to go away when they're finished, simply register the <Process_Manager> with an <ACE_Reactor>: ACE_Process_Manager mgr( 100, some_reactor ) -or- ACE_Process_Manager mgr; ... mgr.open( 100, some_reactor ); Then, the <Process_Manager> will clean up after any <Process>es that it spawns. (On Unix, this means executing a wait(2) to collect the exit status -- and avoid zombie processes; on Win32, it means closing the process and thread HANDLEs that are created when CreateProcess is called.) If, on the other hand (and for some inexplicable reason) you want to explicitly invoke the terminated <Process> cleanup code, then *don't* register the <Process_Manager> with a Reactor, and be sure to call one of the <Process_Manager::wait> functions whenever there might be managed <Process>es that have exited. Note that in either case, <Process_Manager> allows you to register "<Event_Handlers>" to be called when a specific <Process> exits, or when any <Process> without a specific <Event_Handler> exits. When a <Process> exits, the appropriate <Event_Handler>'s <handle_input> is called; the <ACE_HANDLE> passed is either the Process' HANDLE (on Win32), or its pid cast to an <ACE_HANDLE> (on unix). It is also possible to call the <Process_Manager::wait> functions even though the <Process_Manager> is registered with a <Reactor>. Note also that the wait functions are "sloppy" on Unix, because there's no good way to wait for a subset of the children of a process. The wait functions may end up collecting the exit status of a process that's not managed by the <Process_Manager> whose <wait> you invoked. It's best to only use a single <Process_Manager>, and to create all subprocesses by calling that <Process_Manager>'s <spawn> method. Incidentally, when you register your <Process_Manager> with a <Reactor> its notification pipe is used to help "reap" the available exit statuses. Therefore, you must not use a <Reactor> whose notify pipe has been disabled. Here's the sequence of steps used to reap the exit statuses in this case: + The <Process_Manager> registers a signal handler for SIGCHLD. + The SIGCHLD handler, when invoked, uses the <Reactor>'s <notify> method to inform the <Reactor> to wake up. + Next, the <Reactor> calls the <Process_Manager>'s <handle_input>, this happens synchronously, not in sighandler-space. + The <handle_input> method collects all available exit statuses.

Definition at line 115 of file Process_Manager.h.


Member Enumeration Documentation

anonymous enum
 

Enumeration values:
DEFAULT_SIZE 

Definition at line 120 of file Process_Manager.h.

00121   {
00122     DEFAULT_SIZE = 100
00123   };


Constructor & Destructor Documentation

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 non-NULL <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.

References ACE_ERROR, ACE_LIB_TEXT, ACE_TRACE, LM_ERROR, and open.

00230   : ACE_Event_Handler (),
00231     process_table_ (0),
00232     max_process_table_size_ (0),
00233     current_count_ (0),
00234     default_exit_handler_ (0)
00235 #if defined (ACE_HAS_THREADS)
00236   , lock_ ()
00237 #endif /* ACE_HAS_THREADS */
00238 {
00239   ACE_TRACE ("ACE_Process_Manager::ACE_Process_Manager");
00240 
00241   if (this->open (size,
00242                   r) == -1)
00243     ACE_ERROR ((LM_ERROR,
00244                 ACE_LIB_TEXT ("%p\n"),
00245                 ACE_LIB_TEXT ("ACE_Process_Manager")));
00246 }

ACE_Process_Manager::~ACE_Process_Manager void    [virtual]
 

Destructor releases all resources and does not wait for processes to exit.

Definition at line 283 of file Process_Manager.cpp.

References ACE_TRACE, and close.

00284 {
00285   ACE_TRACE ("ACE_Process_Manager::~ACE_Process_Manager");
00286   this->close ();
00287 }


Member Function Documentation

int ACE_Process_Manager::append_proc ACE_Process   process [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.

Definition at line 479 of file Process_Manager.cpp.

References ACE_TRACE, current_count_, ACE_Process_Descriptor::exit_notify_, ACE_Process::gethandle, max_process_table_size_, ACE_Process_Descriptor::process_, process_table_, ACE_Event_Handler::reactor, ACE_Reactor::register_handler, and resize.

Referenced by insert_proc, and spawn.

00480 {
00481   ACE_TRACE ("ACE_Process_Manager::append_proc");
00482 
00483   // Try to resize the array to twice its existing size if we run out
00484   // of space...
00485   if (this->current_count_ >= this->max_process_table_size_
00486       && this->resize (this->max_process_table_size_ * 2) == -1)
00487     return -1;
00488   else
00489     {
00490       ACE_Process_Descriptor &proc_desc =
00491         this->process_table_[this->current_count_];
00492 
00493       proc_desc.process_ = proc;
00494       proc_desc.exit_notify_ = 0;
00495 
00496 #if defined (ACE_WIN32)
00497       // If we have a Reactor, then we're supposed to reap Processes
00498       // automagically.  Get a handle to this new Process and tell the
00499       // Reactor we're interested in <handling_input> on it.
00500 
00501       ACE_Reactor *r = this->reactor ();
00502       if (r != 0)
00503         r->register_handler (this,
00504                              proc->gethandle ());
00505 #endif /* ACE_WIN32 */
00506 
00507       this->current_count_++;
00508       return 0;
00509     }
00510 }

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 27 of file Process_Manager.cpp.

References close_singleton.

Referenced by instance.

00028 {
00029   ACE_Process_Manager::close_singleton ();
00030 }

int ACE_Process_Manager::close void   
 

Release all resources. Do not wait for processes to exit.

Definition at line 251 of file Process_Manager.cpp.

References ACE_GUARD_RETURN, ACE_MT, 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.

00252 {
00253   ACE_TRACE ("ACE_Process_Manager::close");
00254 
00255 #if !defined (ACE_WIN32)
00256   if (this->reactor ())
00257     {
00258       this->reactor ()->remove_handler (SIGCHLD, (ACE_Sig_Action *) 0);
00259       this->reactor (0);
00260     }
00261 #endif /*  !ACE_WIN32  */
00262 
00263   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00264 
00265   if (this->process_table_ != 0)
00266     {
00267       while (this->current_count_ > 0)
00268         this->remove_proc (0);
00269 
00270       delete [] this->process_table_;
00271       this->process_table_ = 0;
00272       this->max_process_table_size_ = 0;
00273       this->current_count_ = 0;
00274     }
00275 
00276   if (this->default_exit_handler_ != 0)
00277       this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE,0);
00278   this->default_exit_handler_ = 0;
00279 
00280   return 0;
00281 }

void ACE_Process_Manager::close_singleton void    [static]
 

Delete the dynamically allocated singleton.

Definition at line 161 of file Process_Manager.cpp.

References ACE_GUARD, ACE_MT, ACE_TRACE, delete_instance_, ACE_Static_Object_Lock::instance, and instance_.

Referenced by cleanup.

00162 {
00163   ACE_TRACE ("ACE_Process_Manager::close_singleton");
00164 
00165   ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
00166                      *ACE_Static_Object_Lock::instance ()));
00167 
00168   if (ACE_Process_Manager::delete_instance_)
00169     {
00170       delete ACE_Process_Manager::instance_;
00171       ACE_Process_Manager::instance_ = 0;
00172       ACE_Process_Manager::delete_instance_ = 0;
00173     }
00174 }

void ACE_Process_Manager::dump void    const
 

Dump the state of an object.

Definition at line 71 of file Process_Manager.cpp.

References ACE_BEGIN_DUMP, ACE_DEBUG, ACE_END_DUMP, ACE_LIB_TEXT, ACE_TRACE, current_count_, ACE_Process_Descriptor::dump, LM_DEBUG, and process_table_.

00072 {
00073   ACE_TRACE ("ACE_Process_Manager::dump");
00074 
00075   ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00076 
00077   ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("\nmax_process_table_size_ = %d"), this->max_process_table_size_));
00078   ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("\ncurrent_count_ = %d"), this->current_count_));
00079 
00080   for (size_t i = 0; i < this->current_count_; i++)
00081     this->process_table_[i].dump ();
00082 
00083   ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00084 }

ssize_t ACE_Process_Manager::find_proc ACE_HANDLE    process_handle [private]
 

Locate the index of the table slot occupied by <process_handle>. Returns ~0 if <process_handle> is not in the <process_table_>.

Definition at line 653 of file Process_Manager.cpp.

References ACE_TRACE, current_count_, ACE_Process::gethandle, ACE_Process_Descriptor::process_, and process_table_.

00654 {
00655   ACE_TRACE ("ACE_Process_Manager::find_proc");
00656 
00657   for (size_t i = 0; i < this->current_count_; ++i)
00658     if (h == this->process_table_[i].process_->gethandle ())
00659       return i;
00660 
00661   return -1;
00662 }

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 637 of file Process_Manager.cpp.

References ACE_TRACE, current_count_, ACE_Process::getpid, pid_t, ACE_Process_Descriptor::process_, and process_table_.

Referenced by handle_signal, insert_proc, register_handler, remove, terminate, and wait.

00638 {
00639   ACE_TRACE ("ACE_Process_Manager::find_proc");
00640 
00641   for (size_t i = 0; i < this->current_count_; ++i)
00642     if (pid == this->process_table_[i].process_->getpid ())
00643       return i;
00644 
00645   return -1;
00646 }

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 323 of file Process_Manager.cpp.

References ACE_ERROR_RETURN, ACE_exitcode, ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_LIB_TEXT, ACE_MT, find_proc, ACE_Process::getpid, LM_ERROR, lock_, ACE_Reactor::notify, notify_proc_handler, pid_t, ACE_Process_Descriptor::process_, process_table_, ACE_Event_Handler::reactor, ACE_Event_Handler::READ_MASK, remove_proc, siginfo_t::si_handle_, ssize_t, and ucontext_t.

00326 {
00327 #if defined (ACE_WIN32)
00328   ACE_HANDLE proc = si->si_handle_;
00329   ACE_exitcode status = 0;
00330   BOOL result = ::GetExitCodeProcess (proc,
00331                                       &status);
00332   if (result)
00333     {
00334       if (status != STILL_ACTIVE)
00335         {
00336           {
00337             ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, lock_, -1));
00338 
00339             ssize_t i = this->find_proc (proc);
00340             if (i == -1)
00341               return -1;
00342 #if 0
00343             pid_t pid = i != -1
00344               ? process_table_[i].process_->getpid ()
00345               : ACE_INVALID_PID;
00346 #endif
00347             this->notify_proc_handler (i, status);
00348             this->remove_proc (i);
00349           }
00350           return -1; // remove this HANDLE/Event_Handler combination
00351         }
00352       else
00353         ACE_ERROR_RETURN ((LM_ERROR,
00354                            ACE_LIB_TEXT ("Process still active")
00355                            ACE_LIB_TEXT (" -- shouldn't have been called yet!\n")),
00356                           0); // return 0 : stay registered
00357     }
00358   else
00359     {
00360       // <GetExitCodeProcess> failed.
00361       ACE_ERROR_RETURN ((LM_ERROR,
00362                          ACE_LIB_TEXT ("GetExitCodeProcess failed")),
00363                         -1); // return -1: unregister
00364     }
00365 #else /* !ACE_WIN32 */
00366   ACE_UNUSED_ARG (si);
00367   return reactor ()->notify
00368     (this,
00369      ACE_Event_Handler::READ_MASK);
00370 #endif /* !ACE_WIN32 */
00371 }

int ACE_Process_Manager::insert_proc ACE_Process   process [private]
 

Insert a process in the table (checks for duplicates). Omitting the process handle won't work on Win32...

Definition at line 516 of file Process_Manager.cpp.

References ACE_TRACE, append_proc, find_proc, and ACE_Process::getpid.

00517 {
00518   ACE_TRACE ("ACE_Process_Manager::insert_proc");
00519 
00520   // Check for duplicates and bail out if they're already
00521   // registered...
00522   if (this->find_proc (proc->getpid ()) != -1)
00523     return -1;
00524 
00525   return this->append_proc (proc);
00526 }

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 132 of file Process_Manager.cpp.

References ACE_GUARD_RETURN, ACE_MT, ACE_TRACE, ACE_Object_Manager::at_exit, cleanup, delete_instance_, ACE_Static_Object_Lock::instance, and instance_.

00133 {
00134   ACE_TRACE ("ACE_Process_Manager::instance");
00135   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
00136                             *ACE_Static_Object_Lock::instance (), 0));
00137 
00138   ACE_Process_Manager *t = ACE_Process_Manager::instance_;
00139   // We can't safely delete it since we don't know who created it!
00140   ACE_Process_Manager::delete_instance_ = 0;
00141 
00142           // Register with the Object_Manager so that the wrapper to
00143           // delete the proactor will be called when Object_Manager is
00144           // being terminated.
00145 
00146 #if defined ACE_HAS_SIG_C_FUNC
00147           ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
00148                                        ACE_Process_Manager_cleanup,
00149                                        0);
00150 #else
00151           ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
00152                                        ACE_Process_Manager::cleanup,
00153                                        0);
00154 #endif /* ACE_HAS_SIG_C_FUNC */
00155 
00156   ACE_Process_Manager::instance_ = tm;
00157   return t;
00158 }

ACE_Process_Manager * ACE_Process_Manager::instance void    [static]
 

Get pointer to a process-wide <ACE_Process_Manager>.

Definition at line 94 of file Process_Manager.cpp.

References ACE_GUARD_RETURN, ACE_MT, ACE_NEW_RETURN, ACE_TRACE, ACE_Object_Manager::at_exit, cleanup, delete_instance_, ACE_Static_Object_Lock::instance, and instance_.

00095 {
00096   ACE_TRACE ("ACE_Process_Manager::instance");
00097 
00098   if (ACE_Process_Manager::instance_ == 0)
00099     {
00100       // Perform Double-Checked Locking Optimization.
00101       ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
00102                                 *ACE_Static_Object_Lock::instance (), 0));
00103 
00104       if (ACE_Process_Manager::instance_ == 0)
00105         {
00106           ACE_NEW_RETURN (ACE_Process_Manager::instance_,
00107                           ACE_Process_Manager,
00108                           0);
00109           ACE_Process_Manager::delete_instance_ = 1;
00110 
00111           // Register with the Object_Manager so that the wrapper to
00112           // delete the proactor will be called when Object_Manager is
00113           // being terminated.
00114 
00115 #if defined ACE_HAS_SIG_C_FUNC
00116           ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
00117                                        ACE_Process_Manager_cleanup,
00118                                        0);
00119 #else
00120           ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
00121                                        ACE_Process_Manager::cleanup,
00122                                        0);
00123 #endif /* ACE_HAS_SIG_C_FUNC */
00124 
00125         }
00126     }
00127 
00128   return ACE_Process_Manager::instance_;
00129 }

ACE_INLINE size_t ACE_Process_Manager::managed void    const
 

Return the number of managed Processes.

Definition at line 5 of file Process_Manager.i.

References current_count_.

00006 {
00007   return current_count_;
00008 }

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 917 of file Process_Manager.cpp.

References ACE_DEBUG, ACE_exitcode, ACE_LIB_TEXT, current_count_, default_exit_handler_, ACE_Process::exit_code, ACE_Process_Descriptor::exit_notify_, ACE_Event_Handler::handle_close, ACE_Event_Handler::handle_exit, LM_DEBUG, ACE_Process_Descriptor::process_, and process_table_.

Referenced by handle_signal, and wait.

00919 {
00920   if (i < this->current_count_)
00921     {
00922       ACE_Process_Descriptor &proc_desc =
00923         this->process_table_[i];
00924 
00925       proc_desc.process_->exit_code (exit_code);
00926 
00927       if (proc_desc.exit_notify_ != 0)
00928         proc_desc.exit_notify_->handle_exit (proc_desc.process_);
00929       else if (this->default_exit_handler_ != 0
00930                && this->default_exit_handler_->handle_exit (proc_desc.process_) < 0)
00931         {
00932           this->default_exit_handler_->handle_close
00933             (ACE_INVALID_HANDLE,
00934              0);
00935           this->default_exit_handler_ = 0;
00936         }
00937       return 1;
00938     }
00939   else
00940     {
00941       ACE_DEBUG ((LM_DEBUG,
00942                   ACE_LIB_TEXT ("(%P:%t|%T) ACE_Process_Manager::notify_proc_handler:"),
00943                   ACE_LIB_TEXT (" unknown/unmanaged process reaped\n")));
00944       return 0;
00945     }
00946 }

int ACE_Process_Manager::open size_t    size = 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 non-NULL <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 204 of file Process_Manager.cpp.

References ACE_GUARD_RETURN, ACE_MT, ACE_TRACE, max_process_table_size_, ACE_Event_Handler::reactor, ACE_Reactor::register_handler, resize, and SIGCHLD.

Referenced by ACE_Process_Manager.

00206 {
00207   ACE_TRACE ("ACE_Process_Manager::open");
00208 
00209   if (r)
00210     {
00211       this->reactor (r);
00212 #if !defined (ACE_WIN32) && !defined (ACE_PSOS)
00213       // Register signal handler object.
00214       if (r->register_handler (SIGCHLD, this) == -1)
00215         return -1;
00216 #endif  // !defined(ACE_WIN32) && !defined (ACE_PSOS)
00217     }
00218 
00219   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00220 
00221   if (this->max_process_table_size_ < size)
00222     this->resize (size);
00223   return 0;
00224 }

int ACE_Process_Manager::reap pid_t    pid = -1,
ACE_exitcode   stat_loc = 0,
int    options = WNOHANG
 

Reap the result of a single process by calling <ACE_OS::waitpid>, therefore, this method is not portable to Win32. If the child is successfully reaped, <remove> is called automatically. This method does the same thing that the <wait> method directly above it does -- It's just here for backwards compatibility.

Definition at line 899 of file Process_Manager.cpp.

References ACE_BIT_ENABLED, ACE_exitcode, ACE_TRACE, ACE_Time_Value::max_time, pid_t, wait, WNOHANG, and ACE_Time_Value::zero.

00902 {
00903   ACE_TRACE ("ACE_Process_Manager::reap");
00904 
00905   return this->wait (pid,
00906                      (ACE_BIT_ENABLED (options, WNOHANG)
00907                       ? ACE_Time_Value::zero
00908                       : ACE_Time_Value::max_time),
00909                      stat_loc);
00910 }

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 374 of file Process_Manager.cpp.

References ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_MT, default_exit_handler_, ACE_Process_Descriptor::exit_notify_, find_proc, ACE_Event_Handler::handle_close, pid_t, process_table_, and ssize_t.

00376 {
00377   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00378 
00379   if (pid == ACE_INVALID_PID)
00380     {
00381       if (this->default_exit_handler_ != 0)
00382         this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE, 0);
00383       this->default_exit_handler_ = eh;
00384       return 0;
00385     }
00386 
00387   ssize_t i = this->find_proc (pid);
00388 
00389   if (i == -1)
00390     {
00391       errno = EINVAL;
00392       return -1;
00393     }
00394 
00395   ACE_Process_Descriptor &proc_desc = this->process_table_[i];
00396 
00397   if (proc_desc.exit_notify_ != 0)
00398     proc_desc.exit_notify_->handle_close (ACE_INVALID_HANDLE, 0);
00399   proc_desc.exit_notify_ = eh;
00400   return 0;
00401 }

int ACE_Process_Manager::remove pid_t    pid
 

Remove process <pid> from the table. This is called automatically by the <reap> method after it successfully reaped a <SIGCHLD> signal. It's also possible to call this method directly from a signal handler, but don't call both <reap> and <remove>!

Definition at line 531 of file Process_Manager.cpp.

References ACE_GUARD_RETURN, ACE_MT, ACE_TRACE, find_proc, pid_t, remove_proc, and ssize_t.

00532 {
00533   ACE_TRACE ("ACE_Process_Manager::remove");
00534 
00535   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00536 
00537   ssize_t i = this->find_proc (pid);
00538 
00539   if (i != -1)
00540     return this->remove_proc (i);
00541 
00542   // set "process not found" error
00543   return -1;
00544 }

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 549 of file Process_Manager.cpp.

References ACE_TRACE, current_count_, ACE_Event_Handler::DONT_CALL, ACE_Process_Descriptor::exit_notify_, ACE_Process::gethandle, ACE_Event_Handler::handle_close, ACE_Process_Descriptor::process_, process_table_, ACE_Event_Handler::reactor, ACE_Reactor::remove_handler, and ACE_Process::unmanage.

Referenced by close, handle_signal, remove, terminate, and wait.

00550 {
00551   ACE_TRACE ("ACE_Process_Manager::remove_proc");
00552 
00553   // If there's an exit_notify_ <Event_Handler> for this pid, call its
00554   // <handle_close> method.
00555 
00556   if (this->process_table_[i].exit_notify_ != 0)
00557     {
00558       this->process_table_[i].exit_notify_->handle_close
00559         (this->process_table_[i].process_->gethandle(),
00560          0);
00561       this->process_table_[i].exit_notify_ = 0;
00562     }
00563 
00564 #if defined (ACE_WIN32)
00565   ACE_Reactor *r = this->reactor ();
00566   if (r != 0)
00567     r->remove_handler (this->process_table_[i].process_->gethandle (),
00568                        ACE_Event_Handler::DONT_CALL);
00569 #endif /* ACE_WIN32 */
00570 
00571   this->process_table_[i].process_->unmanage ();
00572 
00573   this->process_table_[i].process_ = 0;
00574 
00575   this->current_count_--;
00576 
00577   if (this->current_count_ > 0)
00578     // Compact the table by moving the last item into the slot vacated
00579     // by the index being removed (this is a structure assignment).
00580     this->process_table_[i] =
00581       this->process_table_[this->current_count_];
00582 
00583   return 0;
00584 }

int ACE_Process_Manager::resize size_t    [private]
 

Resize the pool of Process_Descriptors.

Definition at line 177 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.

00178 {
00179   ACE_TRACE ("ACE_Process_Manager::resize");
00180 
00181   ACE_Process_Descriptor *temp;
00182 
00183   ACE_NEW_RETURN (temp,
00184                   ACE_Process_Descriptor[size],
00185                   -1);
00186 
00187   for (size_t i = 0;
00188        i < this->current_count_;
00189        i++)
00190     // Structure assignment.
00191     temp[i] = this->process_table_[i];
00192 
00193   this->max_process_table_size_ = size;
00194 
00195   delete [] this->process_table_;
00196 
00197   this->process_table_ = temp;
00198   return 0;
00199 }

pid_t ACE_Process_Manager::spawn ACE_Process_Options   options
 

Create a new process by passing <options> to <ACE_Process::spawn>. On success, returns the process id of the child that was created. On failure, returns ACE_INVALID_PID.

Definition at line 406 of file Process_Manager.cpp.

References ACE_INVALID_PID, ACE_NEW_RETURN, pid_t, and spawn.

00407 {
00408   ACE_Process *process;
00409   ACE_NEW_RETURN (process,
00410                   ACE_Managed_Process,
00411                   ACE_INVALID_PID);
00412 
00413   pid_t pid = spawn (process, options);
00414   if (pid == ACE_INVALID_PID || pid == 0)
00415     delete process;
00416 
00417   return pid;
00418 }

pid_t ACE_Process_Manager::spawn ACE_Process   proc,
ACE_Process_Options   options
 

Create a new process by passing <options> to <proc.spawn>. On success, returns the process id of the child that was created. On failure, returns ACE_INVALID_PID.

Definition at line 423 of file Process_Manager.cpp.

References ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_MT, ACE_TRACE, append_proc, pid_t, and ACE_Process::spawn.

Referenced by spawn, and spawn_n.

00425 {
00426   ACE_TRACE ("ACE_Process_Manager::spawn");
00427 
00428   pid_t pid = process->spawn (options);
00429 
00430   // Only include the pid in the parent's table.
00431   if (pid == ACE_INVALID_PID
00432       || pid == 0)
00433     return pid;
00434 
00435   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
00436                             ace_mon, this->lock_, -1));
00437 
00438   if (this->append_proc (process) == -1)
00439     // bad news: spawned, but not registered in table.
00440     return ACE_INVALID_PID;
00441 
00442   return pid;
00443 }

int ACE_Process_Manager::spawn_n size_t    n,
ACE_Process_Options   options,
pid_t   child_pids = 0
 

Create <n> new processes by passing <options> to <ACE_Process::spawn>, which is called <n> times. If <child_pids> is non-0 it is expected to be an array of <n> <pid_t>'s, which are filled in with the process ids of each newly created process. Returns 0 on success and -1 on failure.

Definition at line 448 of file Process_Manager.cpp.

References ACE_INVALID_PID, ACE_TRACE, pid_t, and spawn.

00451 {
00452   ACE_TRACE ("ACE_Process_Manager::spawn_n");
00453 
00454   if (child_pids != 0)
00455     for (size_t i = 0;
00456          i < n;
00457          ++i)
00458       child_pids[i] = ACE_INVALID_PID;
00459 
00460   for (size_t i = 0;
00461        i < n;
00462        i++)
00463     {
00464       pid_t pid = this->spawn (options);
00465       if (pid == ACE_INVALID_PID || pid == 0)
00466         // We're in the child or something's gone wrong.
00467         return pid;
00468       else if (child_pids != 0)
00469         child_pids[i] = pid;
00470     }
00471 
00472   return 0;
00473 }

int ACE_Process_Manager::terminate pid_t    pid,
int    sig
 

On OSs that support signals, send the signal to the specified process. Returns 0 on success and -1 on failure.

Definition at line 615 of file Process_Manager.cpp.

References ACE_GUARD_RETURN, ACE_MT, ACE_TRACE, find_proc, ACE_OS::kill, pid_t, and ssize_t.

00617 {
00618   ACE_TRACE ("ACE_Process_Manager::terminate");
00619 
00620   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00621 
00622   // Check for duplicates and bail out if they're already
00623   // registered...
00624   ssize_t i = this->find_proc (pid);
00625 
00626   if (i == -1)
00627     // set "no such process" error
00628     return -1;
00629 
00630   return ACE_OS::kill (pid, sig);
00631 }

int ACE_Process_Manager::terminate pid_t    pid
 

Abruptly terminate a single process with id <pid> using the <ACE::terminate_process> method. Note that this call is potentially dangerous to use since the process being terminated may not have a chance to cleanup before it shuts down. Returns 0 on success and -1 on failure.

Definition at line 587 of file Process_Manager.cpp.

References ACE_GUARD_RETURN, ACE_MT, ACE_TRACE, find_proc, pid_t, remove_proc, ssize_t, and ACE::terminate_process.

00588 {
00589   ACE_TRACE ("ACE_Process_Manager::terminate");
00590 
00591   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00592 
00593   // Check for duplicates and bail out if they're already
00594   // registered...
00595   ssize_t i = this->find_proc (pid);
00596 
00597   if (i == -1)
00598     // set "no such process" error
00599     return -1;
00600 
00601   int result = ACE::terminate_process (pid);
00602 
00603   if (result != -1)
00604     {
00605       // Save/restore errno.
00606       ACE_Errno_Guard error (errno);
00607       this->remove_proc (i);
00608       return 0;
00609     }
00610   else
00611     return -1;
00612 }

pid_t ACE_Process_Manager::wait pid_t    pid,
ACE_exitcode   status = 0
 

Wait indefinitely for a single process to terminate. If pid==0, waits for any of the managed <Process>es (but see the note in the class documentation for caveats about this -- "sloppy Process cleanup on unix") If pid != 0, waits for that <Process> only. Returns the pid of the process whose exit was handled, or ACE_INVALID_PID on error.

Definition at line 708 of file Process_Manager.cpp.

References ACE_exitcode, ACE_TRACE, ACE_Time_Value::max_time, pid_t, and wait.

00710 {
00711   ACE_TRACE ("ACE_Process_Manager::wait");
00712 
00713   return this->wait (pid,
00714                      ACE_Time_Value::max_time,
00715                      status);
00716 }

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 process to terminate. If pid==0, waits for any of the managed <Process>es (but see the note in the class documentation above for caveats about this -- "sloppy process cleanup on unix") If pid != 0, waits for that <Process> only. Returns the pid of the Process whose exit was handled, 0 if a timeout occurred, or ACE_INVALID_PID on error.

Definition at line 723 of file Process_Manager.cpp.

References ACE_ASSERT, ACE_DEBUG, ACE_ERROR_RETURN, ACE_exitcode, ACE_GUARD_RETURN, ACE_INVALID_PID, ACE_LIB_TEXT, ACE_MT, ACE_NEW_RETURN, ACE_SignalHandler, ACE_TRACE, current_count_, find_proc, ACE_Process::gethandle, ACE_Process::getpid, LM_DEBUG, LM_ERROR, ACE_Time_Value::max_time, ACE_Time_Value::msec, notify_proc_handler, pid_t, ACE_Process_Descriptor::process_, process_table_, ACE_Event_Handler::reactor, ACE_Sig_Action::register_action, remove_proc, SIGCHLD, ACE_OS::sleep, ssize_t, ACE_Countdown_Time::update, ACE_Process::wait, ACE_OS::waitpid, WNOHANG, and ACE_Time_Value::zero.

00726 {
00727   ACE_TRACE ("ACE_Process_Manager::wait");
00728 
00729   ACE_exitcode local_stat = 0;
00730   if (status == 0)
00731     status = &local_stat;
00732 
00733   *status = 0;
00734 
00735   ssize_t idx = -1;
00736   ACE_Process *proc = 0;
00737 
00738   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00739 
00740   if (pid != 0)
00741     {
00742       idx = this->find_proc (pid);
00743       if (idx == -1)
00744         return ACE_INVALID_PID;
00745       else
00746         proc = process_table_[idx].process_;
00747     }
00748 
00749   if (proc != 0)
00750     pid = proc->wait (timeout, status);
00751   else
00752     {
00753       // Wait for any Process spawned by this Process_Manager.
00754 #if defined (ACE_WIN32)
00755       HANDLE *handles;
00756 
00757       ACE_NEW_RETURN (handles,
00758                       HANDLE[this->current_count_],
00759                       ACE_INVALID_PID);
00760 
00761       for (size_t i = 0;
00762            i < this->current_count_;
00763            ++i)
00764         handles[i] =
00765           process_table_[i].process_->gethandle ();
00766 
00767       DWORD handle_count = ACE_static_cast (DWORD, this->current_count_);
00768       DWORD result = ::WaitForMultipleObjects (handle_count,
00769                                                handles,
00770                                                FALSE,
00771                                                timeout == ACE_Time_Value::max_time
00772                                                ? INFINITE
00773                                                : timeout.msec ());
00774       if (result == WAIT_FAILED)
00775         pid = ACE_INVALID_PID;
00776       else if (result == WAIT_TIMEOUT)
00777         pid = 0;
00778       else
00779         {
00780           // Green Hills produces a warning that result >= WAIT_OBJECT_0 is
00781           // a pointless comparison because WAIT_OBJECT_0 is zero and DWORD is
00782           // unsigned long, so this test is skipped for Green Hills.
00783           // Same for mingw.
00784 # if defined (ghs) || defined (__MINGW32__)
00785           ACE_ASSERT (result < WAIT_OBJECT_0 + this->current_count_);
00786 # else
00787           ACE_ASSERT (result >= WAIT_OBJECT_0
00788                       && result < WAIT_OBJECT_0 + this->current_count_);
00789 # endif
00790 
00791           idx = this->find_proc (handles[result - WAIT_OBJECT_0]);
00792 
00793           if (idx != -1)
00794             {
00795               pid = process_table_[idx].process_->getpid ();
00796               result = ::GetExitCodeProcess (handles[result - WAIT_OBJECT_0],
00797                                              status);
00798               if (result == 0)
00799                 {
00800                   // <GetExitCodeProcess> failed!
00801                   this->remove_proc (idx);
00802                   pid = ACE_INVALID_PID;
00803                 }
00804             }
00805           else
00806             {
00807               // uh oh...handle removed from process_table_, even though
00808               // we're holding a lock!
00809               delete [] handles;
00810               ACE_ERROR_RETURN ((LM_ERROR,
00811                                  ACE_LIB_TEXT ("Process removed")
00812                                  ACE_LIB_TEXT (" -- somebody's ignoring the lock!\n")),
00813                                 -1);
00814             }
00815         }
00816 
00817       delete [] handles;
00818 #else /* !defined(ACE_WIN32) */
00819       if (timeout == ACE_Time_Value::max_time)
00820         {
00821           pid = ACE_OS::waitpid (-1, status, 0);
00822         }
00823       else if (timeout == ACE_Time_Value::zero)
00824         {
00825           pid = ACE_OS::waitpid (-1, status, WNOHANG);
00826         }
00827       else
00828         {
00829           // Force generation of SIGCHLD, even though we don't want to
00830           // catch it - just need it to interrupt the sleep below.
00831           // If this object has a reactor set, assume it was given at
00832           // open(), and there's already a SIGCHLD action set, so no
00833           // action is needed here.
00834           ACE_Sig_Action old_action;
00835           if (this->reactor () == 0)
00836             {
00837               ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop);
00838               do_sigchld.register_action (SIGCHLD, &old_action);
00839             }
00840 
00841           ACE_Time_Value tmo (timeout);  // Need one we can change
00842           for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ())
00843             {
00844               pid = ACE_OS::waitpid (-1, status, WNOHANG);
00845               if (pid > 0 || pid == ACE_INVALID_PID)
00846                 break;          // Got a child or an error - all done
00847 
00848               // pid 0, nothing is ready yet, so wait.
00849               // Do a sleep (only this thread sleeps) til something
00850               // happens. This relies on SIGCHLD interrupting the sleep.
00851               // If SIGCHLD isn't delivered, we'll need to do something
00852               // with sigaction to force it.
00853               if (-1 == ACE_OS::sleep (tmo) && errno == EINTR)
00854                 continue;
00855               // Timed out
00856               pid = 0;
00857               break;
00858             }
00859 
00860           // Restore the previous SIGCHLD action if it was changed.
00861           if (this->reactor () == 0)
00862             {
00863               old_action.register_action (SIGCHLD);
00864             }
00865         }
00866 #endif /* !defined (ACE_WIN32) */
00867     }
00868 
00869   if (pid != ACE_INVALID_PID && pid != 0)
00870     {
00871       if (proc == 0)
00872         {
00873           idx = this->find_proc (pid);
00874           if (idx == -1)
00875             {
00876               // oops, reaped an unmanaged process!
00877               ACE_DEBUG ((LM_DEBUG,
00878                           ACE_LIB_TEXT ("(%P|%t) oops, reaped unmanaged %d\n"),
00879                           pid));
00880               return pid;
00881             }
00882           else
00883             proc = process_table_[idx].process_;
00884         }
00885       else
00886         ACE_ASSERT (pid == proc->getpid ());
00887 
00888       this->notify_proc_handler (idx,
00889                                  *status);
00890       this->remove_proc (idx);
00891     }
00892 
00893   return pid;
00894 }

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 <spawn>ed by this <ACE_Process_Manager>. Unlike the <wait> call below, this method does not require a signal handler or <ACE_OS::sigwait> because it simply blocks synchronously waiting for all the children managed by this <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. Returns 0 on success (and <remove>s the corresponding <ACE_Process_Descriptor> entries from the <Process_Manager>; otherwise, returns -1 on failure.

Definition at line 669 of file Process_Manager.cpp.

References ACE_INVALID_PID, ACE_TRACE, current_count_, ACE_OS::gettimeofday, ACE_Time_Value::max_time, pid_t, and ACE_Time_Value::zero.

Referenced by reap, and wait.

00670 {
00671   ACE_TRACE ("ACE_Process_Manager::wait");
00672 
00673   ACE_Time_Value until = timeout;
00674   ACE_Time_Value remaining = timeout;
00675 
00676   if (until < ACE_Time_Value::max_time)
00677     until += ACE_OS::gettimeofday ();
00678 
00679   while (this->current_count_ > 0)
00680     {
00681       pid_t pid = this->wait (0, remaining);
00682 
00683       if (pid == ACE_INVALID_PID)       // wait() failed
00684         return -1;
00685       else if (pid == 0)     // timeout
00686         break;
00687 
00688       remaining = until < ACE_Time_Value::max_time
00689         ? until - ACE_OS::gettimeofday ()
00690         : ACE_Time_Value::max_time;
00691 
00692       if (remaining <= ACE_Time_Value::zero)
00693         break;
00694 
00695       // else Process terminated...wait for more...
00696     }
00697   return ACE_static_cast (int, this->current_count_);
00698 }


Friends And Related Function Documentation

friend class ACE_Process_Control [friend]
 

Definition at line 118 of file Process_Manager.h.


Member Data Documentation

ACE_Process_Manager::ACE_ALLOC_HOOK_DECLARE
 

Declare the dynamic allocation hooks.

Definition at line 287 of file Process_Manager.h.

size_t ACE_Process_Manager::current_count_ [private]
 

Current number of processes we are managing.

Definition at line 373 of file Process_Manager.h.

Referenced by append_proc, close, dump, find_proc, managed, notify_proc_handler, remove_proc, resize, and wait.

ACE_Event_Handler* ACE_Process_Manager::default_exit_handler_ [private]
 

This event handler is used to notify when a process we control exits.

Definition at line 377 of file Process_Manager.h.

Referenced by close, notify_proc_handler, and register_handler.

int ACE_Process_Manager::delete_instance_ = 0 [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 51 of file Process_Manager.cpp.

Referenced by close_singleton, and instance.

ACE_Process_Manager * ACE_Process_Manager::instance_ = 0 [static, private]
 

Singleton pointer.

Definition at line 47 of file Process_Manager.cpp.

Referenced by close_singleton, and instance.

ACE_Recursive_Thread_Mutex ACE_Process_Manager::lock_ [private]
 

This lock protects access/ops on <process_table_>.

Definition at line 388 of file Process_Manager.h.

Referenced by handle_signal.

size_t ACE_Process_Manager::max_process_table_size_ [private]
 

Maximum number of processes we can manage (should be dynamically allocated).

Definition at line 370 of file Process_Manager.h.

Referenced by append_proc, close, open, and resize.

ACE_Process_Descriptor* ACE_Process_Manager::process_table_ [private]
 

Vector that describes process state within the Process_Manager.

Definition at line 366 of file Process_Manager.h.

Referenced by append_proc, close, dump, find_proc, handle_signal, notify_proc_handler, register_handler, remove_proc, resize, and wait.


The documentation for this class was generated from the following files:
Generated on Mon Jun 16 12:54:30 2003 for ACE by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002