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

Process_Manager.cpp

Go to the documentation of this file.
00001 #include "ace_pch.h"
00002 // $Id: Process_Manager.cpp,v 1.1.1.4.2.2 2003/04/16 16:41:14 taoadmin Exp $
00003 
00004 // Process_Manager.cpp
00005 #include "ace/Synch_T.h"
00006 #include "ace/Process.h"
00007 #include "ace/Signal.h"
00008 #include "ace/Process_Manager.h"
00009 #include "ace/Object_Manager.h"
00010 #include "ace/Log_Msg.h"
00011 
00012 #if !defined (__ACE_INLINE__)
00013 #include "ace/Process_Manager.i"
00014 #endif /* __ACE_INLINE__ */
00015 
00016 ACE_RCSID(ace, Process_Manager, "$Id: Process_Manager.cpp,v 1.1.1.4.2.2 2003/04/16 16:41:14 taoadmin Exp $")
00017 
00018 #if defined (ACE_HAS_SIG_C_FUNC)
00019 extern "C" void
00020 ACE_Process_Manager_cleanup (void *instance, void *arg)
00021 {
00022   ACE_Process_Manager::cleanup (instance, arg);
00023 }
00024 #endif
00025 
00026 void
00027 ACE_Process_Manager::cleanup (void *, void *)
00028 {
00029   ACE_Process_Manager::close_singleton ();
00030 }
00031 
00032 // This function acts as a signal handler for SIGCHLD. We don't really want
00033 // to do anything with the signal - it's just needed to interrupt a sleep.
00034 // See wait() for more info.
00035 #if !defined (ACE_WIN32)
00036 static void
00037 sigchld_nop (int, siginfo_t *, ucontext_t *)
00038 {
00039   return;
00040 }
00041 #endif /* ACE_WIN32 */
00042 
00043 
00044 ACE_ALLOC_HOOK_DEFINE(ACE_Process_Manager)
00045 
00046 // Singleton instance.
00047 ACE_Process_Manager *ACE_Process_Manager::instance_ = 0;
00048 
00049 // Controls whether the <Process_Manager> is deleted when we shut down
00050 // (we can only delete it safely if we created it!)
00051 int ACE_Process_Manager::delete_instance_ = 0;
00052 
00053 ACE_Process_Descriptor::~ACE_Process_Descriptor (void)
00054 {
00055 }
00056 
00057 void
00058 ACE_Process_Descriptor::dump (void) const
00059 {
00060   ACE_TRACE ("ACE_Process_Descriptor::dump");
00061 
00062   ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00063 
00064   ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("\nproc_id_ = %d"),
00065                           this->process_->getpid( )));
00066 
00067   ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00068 }
00069 
00070 void
00071 ACE_Process_Manager::dump (void) const
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 }
00085 
00086 ACE_Process_Descriptor::ACE_Process_Descriptor (void)
00087   : process_ (0),
00088     exit_notify_ (0)
00089 {
00090   ACE_TRACE ("ACE_Process_Descriptor::ACE_Process_Descriptor");
00091 }
00092 
00093 ACE_Process_Manager *
00094 ACE_Process_Manager::instance (void)
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 }
00130 
00131 ACE_Process_Manager *
00132 ACE_Process_Manager::instance (ACE_Process_Manager *tm)
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 }
00159 
00160 void
00161 ACE_Process_Manager::close_singleton( void )
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 }
00175 
00176 int
00177 ACE_Process_Manager::resize (size_t size)
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 }
00200 
00201 // Create and initialize the table to keep track of the process pool.
00202 
00203 int
00204 ACE_Process_Manager::open (size_t size,
00205                            ACE_Reactor *r)
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 }
00225 
00226 // Initialize the synchronization variables.
00227 
00228 ACE_Process_Manager::ACE_Process_Manager (size_t size,
00229                                           ACE_Reactor *r)
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 }
00247 
00248 // Close up and release all resources.
00249 
00250 int
00251 ACE_Process_Manager::close (void)
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 }
00282 
00283 ACE_Process_Manager::~ACE_Process_Manager (void)
00284 {
00285   ACE_TRACE ("ACE_Process_Manager::~ACE_Process_Manager");
00286   this->close ();
00287 }
00288 
00289 #if !defined (ACE_WIN32)
00290 
00291 // This is called when the Reactor notices that a Process has exited.
00292 // What has actually happened is a SIGCHLD invoked the <handle_signal>
00293 // routine, which fooled the Reactor into thinking that this routine
00294 // needed to be called.  Since we don't know which Process exited, we
00295 // must reap as many exit statuses as are immediately available.
00296 
00297 int
00298 ACE_Process_Manager::handle_input (ACE_HANDLE)
00299 {
00300   ACE_TRACE ("ACE_Process_Manager::handle_input");
00301 
00302    pid_t pid;
00303 
00304    do
00305      pid = this->wait (0,
00306                        ACE_Time_Value::zero);
00307    while (pid != 0 && pid != ACE_INVALID_PID);
00308 
00309   return 0;
00310 }
00311 
00312 #endif /* !ACE_WIN32 */
00313 
00314 // On Unix, this routine is called asynchronously when a SIGCHLD is
00315 // received.  We just tweak the reactor so that it'll call back our
00316 // <handle_input> function, which allows us to handle Process exits
00317 // synchronously.
00318 //
00319 // On Win32, this routine is called synchronously, and is passed the
00320 // HANDLE of the Process that exited, so we can do all our work here.
00321 
00322 int
00323 ACE_Process_Manager::handle_signal (int,
00324                                     siginfo_t *si,
00325                                     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 }
00372 
00373 int
00374 ACE_Process_Manager::register_handler (ACE_Event_Handler *eh,
00375                                        pid_t pid)
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 }
00402 
00403 // Create a new process.
00404 
00405 pid_t
00406 ACE_Process_Manager::spawn (ACE_Process_Options &options)
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 }
00419 
00420 // Create a new process.
00421 
00422 pid_t
00423 ACE_Process_Manager::spawn (ACE_Process *process,
00424                             ACE_Process_Options &options)
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 }
00444 
00445 // Create N new processs.
00446 
00447 int
00448 ACE_Process_Manager::spawn_n (size_t n,
00449                               ACE_Process_Options &options,
00450                               pid_t *child_pids)
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 }
00474 
00475 // Append a process into the pool (does not check for duplicates).
00476 // Must be called with locks held.
00477 
00478 int
00479 ACE_Process_Manager::append_proc (ACE_Process *proc)
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 }
00511 
00512 // Insert a process into the pool (checks for duplicates and doesn't
00513 // allow them to be inserted twice).
00514 
00515 int
00516 ACE_Process_Manager::insert_proc (ACE_Process *proc)
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 }
00527 
00528 // Remove a process from the pool.
00529 
00530 int
00531 ACE_Process_Manager::remove (pid_t pid)
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 }
00545 
00546 // Remove a process from the pool.  Must be called with locks held.
00547 
00548 int
00549 ACE_Process_Manager::remove_proc (size_t i)
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 }
00585 
00586 int
00587 ACE_Process_Manager::terminate (pid_t pid)
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 }
00613 
00614 int
00615 ACE_Process_Manager::terminate (pid_t pid,
00616                                 int sig)
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 }
00632 
00633 // Locate the index in the table associated with <pid>.  Must be
00634 // called with the lock held.
00635 
00636 ssize_t
00637 ACE_Process_Manager::find_proc (pid_t pid)
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 }
00647 
00648 #if defined (ACE_WIN32)
00649 // Locate the index in the table associated with <h>.  Must be
00650 // called with the lock held.
00651 
00652 ssize_t
00653 ACE_Process_Manager::find_proc (ACE_HANDLE h)
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 }
00663 #endif /* ACE_WIN32 */
00664 
00665 // Wait for all the Processs to exit, or until <timeout> elapses.
00666 // Returns the number of Processes remaining, or -1 on an error.
00667 
00668 int
00669 ACE_Process_Manager::wait (const ACE_Time_Value &timeout)
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 }
00699 
00700 // Collect a single child process' exit status.  Store the exit code
00701 // in *<stat_loc> if non-zero.  Call the appropriate exit_notify.  If
00702 // <pid> == 0, wait for any of the Process_Manager's children (or as
00703 // near as possible -- on Unix, we might accidentally get some other
00704 // Process_Manager's Process, or an unmanaged Process, or a child
00705 // process started by some other means.
00706 
00707 pid_t
00708 ACE_Process_Manager::wait (pid_t pid,
00709                            ACE_exitcode *status)
00710 {
00711   ACE_TRACE ("ACE_Process_Manager::wait");
00712 
00713   return this->wait (pid,
00714                      ACE_Time_Value::max_time,
00715                      status);
00716 }
00717 
00718 // Collect a single child processes' exit status, unless <timeout>
00719 // elapses before the process exits.  Same caveats about accidental
00720 // Process reaping on Unix as above.
00721 
00722 pid_t
00723 ACE_Process_Manager::wait (pid_t pid,
00724                            const ACE_Time_Value &timeout,
00725                            ACE_exitcode *status)
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 }
00895 
00896 // Legacy method:
00897 
00898 int
00899 ACE_Process_Manager::reap (pid_t pid,
00900                            ACE_exitcode *stat_loc,
00901                            int options)
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 }
00911 
00912 // Notify either the process-specific handler or the generic handler.
00913 // If process-specific, call handle_close on the handler.  Returns 1
00914 // if process found, 0 if not.  Must be called with locks held.
00915 
00916 int
00917 ACE_Process_Manager::notify_proc_handler (size_t i,
00918                                           ACE_exitcode exit_code)
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 }

Generated on Mon Jun 16 11:20:55 2003 for ACE by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002