Process_Manager.cpp

Go to the documentation of this file.
00001 // Process_Manager.cpp,v 4.98 2006/06/01 09:16:38 jwillemsen Exp
00002 
00003 // Process_Manager.cpp
00004 #include "ace/Process_Manager.h"
00005 
00006 #if !defined (__ACE_INLINE__)
00007 #include "ace/Process_Manager.inl"
00008 #endif /* __ACE_INLINE__ */
00009 
00010 #include "ace/ACE.h"
00011 #include "ace/Guard_T.h"
00012 #include "ace/Process.h"
00013 #include "ace/Signal.h"
00014 #include "ace/Object_Manager.h"
00015 #include "ace/Log_Msg.h"
00016 #include "ace/Reactor.h"
00017 #include "ace/Countdown_Time.h"
00018 #include "ace/OS_NS_sys_wait.h"
00019 #include "ace/OS_NS_signal.h"
00020 #include "ace/OS_NS_unistd.h"
00021 #include "ace/OS_NS_sys_time.h"
00022 
00023 ACE_RCSID (ace,
00024            Process_Manager,
00025            "Process_Manager.cpp,v 4.98 2006/06/01 09:16:38 jwillemsen Exp")
00026 
00027 #if defined (ACE_HAS_SIG_C_FUNC)
00028 extern "C" void
00029 ACE_Process_Manager_cleanup (void *instance, void *arg)
00030 {
00031   ACE_Process_Manager::cleanup (instance, arg);
00032 }
00033 #endif
00034 
00035 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00036 
00037 void
00038 ACE_Process_Manager::cleanup (void *, void *)
00039 {
00040   ACE_Process_Manager::close_singleton ();
00041 }
00042 
00043 // This function acts as a signal handler for SIGCHLD. We don't really want
00044 // to do anything with the signal - it's just needed to interrupt a sleep.
00045 // See wait() for more info.
00046 #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS)
00047 static void
00048 sigchld_nop (int, siginfo_t *, ucontext_t *)
00049 {
00050   return;
00051 }
00052 #endif /* ACE_WIN32 */
00053 
00054 
00055 ACE_ALLOC_HOOK_DEFINE(ACE_Process_Manager)
00056 
00057 // Singleton instance.
00058 ACE_Process_Manager *ACE_Process_Manager::instance_ = 0;
00059 
00060 // Controls whether the <Process_Manager> is deleted when we shut down
00061 // (we can only delete it safely if we created it!)
00062 int ACE_Process_Manager::delete_instance_ = 0;
00063 
00064 ACE_Process_Descriptor::~ACE_Process_Descriptor (void)
00065 {
00066 }
00067 
00068 void
00069 ACE_Process_Descriptor::dump (void) const
00070 {
00071 #if defined (ACE_HAS_DUMP)
00072   ACE_TRACE ("ACE_Process_Descriptor::dump");
00073 
00074   ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00075 
00076   ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("\nproc_id_ = %d"),
00077                           this->process_->getpid( )));
00078 
00079   ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00080 #endif /* ACE_HAS_DUMP */
00081 }
00082 
00083 void
00084 ACE_Process_Manager::dump (void) const
00085 {
00086 #if defined (ACE_HAS_DUMP)
00087   ACE_TRACE ("ACE_Process_Manager::dump");
00088 
00089   ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00090 
00091   ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("\nmax_process_table_size_ = %d"), this->max_process_table_size_));
00092   ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("\ncurrent_count_ = %d"), this->current_count_));
00093 
00094   for (size_t i = 0; i < this->current_count_; i++)
00095     this->process_table_[i].dump ();
00096 
00097   ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00098 #endif /* ACE_HAS_DUMP */
00099 }
00100 
00101 ACE_Process_Descriptor::ACE_Process_Descriptor (void)
00102   : process_ (0),
00103     exit_notify_ (0)
00104 {
00105   ACE_TRACE ("ACE_Process_Descriptor::ACE_Process_Descriptor");
00106 }
00107 
00108 ACE_Process_Manager *
00109 ACE_Process_Manager::instance (void)
00110 {
00111   ACE_TRACE ("ACE_Process_Manager::instance");
00112 
00113   if (ACE_Process_Manager::instance_ == 0)
00114     {
00115       // Perform Double-Checked Locking Optimization.
00116       ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
00117                                 *ACE_Static_Object_Lock::instance (), 0));
00118 
00119       if (ACE_Process_Manager::instance_ == 0)
00120         {
00121           ACE_NEW_RETURN (ACE_Process_Manager::instance_,
00122                           ACE_Process_Manager,
00123                           0);
00124           ACE_Process_Manager::delete_instance_ = 1;
00125 
00126           // Register with the Object_Manager so that the wrapper to
00127           // delete the proactor will be called when Object_Manager is
00128           // being terminated.
00129 
00130 #if defined ACE_HAS_SIG_C_FUNC
00131           ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
00132                                        ACE_Process_Manager_cleanup,
00133                                        0);
00134 #else
00135           ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
00136                                        ACE_Process_Manager::cleanup,
00137                                        0);
00138 #endif /* ACE_HAS_SIG_C_FUNC */
00139 
00140         }
00141     }
00142 
00143   return ACE_Process_Manager::instance_;
00144 }
00145 
00146 ACE_Process_Manager *
00147 ACE_Process_Manager::instance (ACE_Process_Manager *tm)
00148 {
00149   ACE_TRACE ("ACE_Process_Manager::instance");
00150   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
00151                             *ACE_Static_Object_Lock::instance (), 0));
00152 
00153   ACE_Process_Manager *t = ACE_Process_Manager::instance_;
00154   // We can't safely delete it since we don't know who created it!
00155   ACE_Process_Manager::delete_instance_ = 0;
00156 
00157           // Register with the Object_Manager so that the wrapper to
00158           // delete the proactor will be called when Object_Manager is
00159           // being terminated.
00160 
00161 #if defined ACE_HAS_SIG_C_FUNC
00162           ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
00163                                        ACE_Process_Manager_cleanup,
00164                                        0);
00165 #else
00166           ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
00167                                        ACE_Process_Manager::cleanup,
00168                                        0);
00169 #endif /* ACE_HAS_SIG_C_FUNC */
00170 
00171   ACE_Process_Manager::instance_ = tm;
00172   return t;
00173 }
00174 
00175 void
00176 ACE_Process_Manager::close_singleton( void )
00177 {
00178   ACE_TRACE ("ACE_Process_Manager::close_singleton");
00179 
00180   ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
00181                      *ACE_Static_Object_Lock::instance ()));
00182 
00183   if (ACE_Process_Manager::delete_instance_)
00184     {
00185       delete ACE_Process_Manager::instance_;
00186       ACE_Process_Manager::instance_ = 0;
00187       ACE_Process_Manager::delete_instance_ = 0;
00188     }
00189 }
00190 
00191 int
00192 ACE_Process_Manager::resize (size_t size)
00193 {
00194   ACE_TRACE ("ACE_Process_Manager::resize");
00195 
00196   if (size <= this->max_process_table_size_)
00197     return 0;
00198 
00199   ACE_Process_Descriptor *temp = 0;
00200 
00201   ACE_NEW_RETURN (temp,
00202                   ACE_Process_Descriptor[size],
00203                   -1);
00204 
00205   for (size_t i = 0;
00206        i < this->current_count_;
00207        i++)
00208     // Structure assignment.
00209     temp[i] = this->process_table_[i];
00210 
00211   this->max_process_table_size_ = size;
00212 
00213   delete [] this->process_table_;
00214 
00215   this->process_table_ = temp;
00216   return 0;
00217 }
00218 
00219 // Create and initialize the table to keep track of the process pool.
00220 
00221 int
00222 ACE_Process_Manager::open (size_t size,
00223                            ACE_Reactor *r)
00224 {
00225   ACE_TRACE ("ACE_Process_Manager::open");
00226 
00227   if (r)
00228     {
00229       this->reactor (r);
00230 #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS)
00231       // Register signal handler object.
00232       if (r->register_handler (SIGCHLD, this) == -1)
00233         return -1;
00234 #endif /* !defined(ACE_WIN32) */
00235     }
00236 
00237   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00238 
00239   if (this->max_process_table_size_ < size)
00240     this->resize (size);
00241   return 0;
00242 }
00243 
00244 // Initialize the synchronization variables.
00245 
00246 ACE_Process_Manager::ACE_Process_Manager (size_t size,
00247                                           ACE_Reactor *r)
00248   : ACE_Event_Handler (),
00249     process_table_ (0),
00250     max_process_table_size_ (0),
00251     current_count_ (0),
00252     default_exit_handler_ (0)
00253 #if defined (ACE_HAS_THREADS)
00254   , lock_ ()
00255 #endif /* ACE_HAS_THREADS */
00256 {
00257   ACE_TRACE ("ACE_Process_Manager::ACE_Process_Manager");
00258 
00259   if (this->open (size,
00260                   r) == -1)
00261     ACE_ERROR ((LM_ERROR,
00262                 ACE_LIB_TEXT ("%p\n"),
00263                 ACE_LIB_TEXT ("ACE_Process_Manager")));
00264 }
00265 
00266 // Close up and release all resources.
00267 
00268 int
00269 ACE_Process_Manager::close (void)
00270 {
00271   ACE_TRACE ("ACE_Process_Manager::close");
00272 
00273   if (this->reactor () != 0)
00274     {
00275 #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS)
00276       this->reactor ()->remove_handler (SIGCHLD, (ACE_Sig_Action *) 0);
00277 #endif /*  !ACE_WIN32  */
00278       this->reactor (0);
00279     }
00280 
00281   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00282 
00283   if (this->process_table_ != 0)
00284     {
00285       while (this->current_count_ > 0)
00286         this->remove_proc (0);
00287 
00288       delete [] this->process_table_;
00289       this->process_table_ = 0;
00290       this->max_process_table_size_ = 0;
00291       this->current_count_ = 0;
00292     }
00293 
00294   if (this->default_exit_handler_ != 0)
00295       this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE,0);
00296   this->default_exit_handler_ = 0;
00297 
00298   return 0;
00299 }
00300 
00301 ACE_Process_Manager::~ACE_Process_Manager (void)
00302 {
00303   ACE_TRACE ("ACE_Process_Manager::~ACE_Process_Manager");
00304   this->close ();
00305 }
00306 
00307 #if !defined (ACE_WIN32)
00308 
00309 // This is called when the Reactor notices that a Process has exited.
00310 // What has actually happened is a SIGCHLD invoked the <handle_signal>
00311 // routine, which fooled the Reactor into thinking that this routine
00312 // needed to be called.  Since we don't know which Process exited, we
00313 // must reap as many exit statuses as are immediately available.
00314 
00315 int
00316 ACE_Process_Manager::handle_input (ACE_HANDLE)
00317 {
00318   ACE_TRACE ("ACE_Process_Manager::handle_input");
00319 
00320    pid_t pid;
00321 
00322    do
00323      pid = this->wait (0,
00324                        ACE_Time_Value::zero);
00325    while (pid != 0 && pid != ACE_INVALID_PID);
00326 
00327   return 0;
00328 }
00329 
00330 #endif /* !ACE_WIN32 */
00331 
00332 // On Unix, this routine is called asynchronously when a SIGCHLD is
00333 // received.  We just tweak the reactor so that it'll call back our
00334 // <handle_input> function, which allows us to handle Process exits
00335 // synchronously.
00336 //
00337 // On Win32, this routine is called synchronously, and is passed the
00338 // HANDLE of the Process that exited, so we can do all our work here.
00339 
00340 int
00341 ACE_Process_Manager::handle_signal (int,
00342                                     siginfo_t *si,
00343                                     ucontext_t *)
00344 {
00345 #if defined (ACE_WIN32)
00346   ACE_HANDLE proc = si->si_handle_;
00347   ACE_exitcode status = 0;
00348   BOOL result = ::GetExitCodeProcess (proc,
00349                                       &status);
00350   if (result)
00351     {
00352       if (status != STILL_ACTIVE)
00353         {
00354           {
00355             ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, lock_, -1));
00356 
00357             ssize_t const i = this->find_proc (proc);
00358             if (i == -1)
00359               return -1;
00360 #if 0
00361             pid_t pid = i != -1
00362               ? process_table_[i].process_->getpid ()
00363               : ACE_INVALID_PID;
00364 #endif
00365             this->notify_proc_handler (i, status);
00366             this->remove_proc (i);
00367           }
00368           return -1; // remove this HANDLE/Event_Handler combination
00369         }
00370       else
00371         ACE_ERROR_RETURN ((LM_ERROR,
00372                            ACE_LIB_TEXT ("Process still active")
00373                            ACE_LIB_TEXT (" -- shouldn't have been called yet!\n")),
00374                           0); // return 0 : stay registered
00375     }
00376   else
00377     {
00378       // <GetExitCodeProcess> failed.
00379       ACE_ERROR_RETURN ((LM_ERROR,
00380                          ACE_LIB_TEXT ("GetExitCodeProcess failed")),
00381                         -1); // return -1: unregister
00382     }
00383 #else /* !ACE_WIN32 */
00384   ACE_UNUSED_ARG (si);
00385   return reactor ()->notify (this, ACE_Event_Handler::READ_MASK);
00386 #endif /* !ACE_WIN32 */
00387 }
00388 
00389 int
00390 ACE_Process_Manager::register_handler (ACE_Event_Handler *eh,
00391                                        pid_t pid)
00392 {
00393   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00394 
00395   if (pid == ACE_INVALID_PID)
00396     {
00397       if (this->default_exit_handler_ != 0)
00398         this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE, 0);
00399       this->default_exit_handler_ = eh;
00400       return 0;
00401     }
00402 
00403   ssize_t const i = this->find_proc (pid);
00404 
00405   if (i == -1)
00406     {
00407       errno = EINVAL;
00408       return -1;
00409     }
00410 
00411   ACE_Process_Descriptor &proc_desc = this->process_table_[i];
00412 
00413   if (proc_desc.exit_notify_ != 0)
00414     proc_desc.exit_notify_->handle_close (ACE_INVALID_HANDLE, 0);
00415   proc_desc.exit_notify_ = eh;
00416   return 0;
00417 }
00418 
00419 // Create a new process.
00420 
00421 pid_t
00422 ACE_Process_Manager::spawn (ACE_Process_Options &options,
00423                             ACE_Event_Handler *event_handler)
00424 {
00425   ACE_Process *process = 0;
00426   ACE_NEW_RETURN (process,
00427                   ACE_Managed_Process,
00428                   ACE_INVALID_PID);
00429 
00430   pid_t const pid = spawn (process, options, event_handler);
00431   if (pid == ACE_INVALID_PID || pid == 0)
00432     delete process;
00433 
00434   return pid;
00435 }
00436 
00437 // Create a new process.
00438 
00439 pid_t
00440 ACE_Process_Manager::spawn (ACE_Process *process,
00441                             ACE_Process_Options &options,
00442                             ACE_Event_Handler *event_handler)
00443 {
00444   ACE_TRACE ("ACE_Process_Manager::spawn");
00445 
00446   pid_t const pid = process->spawn (options);
00447 
00448   // Only include the pid in the parent's table.
00449   if (pid == ACE_INVALID_PID || pid == 0)
00450     return pid;
00451 
00452   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
00453                             ace_mon, this->lock_, -1));
00454 
00455   if (this->append_proc (process, event_handler) == -1)
00456     // bad news: spawned, but not registered in table.
00457     return ACE_INVALID_PID;
00458 
00459   return pid;
00460 }
00461 
00462 // Create N new processs.
00463 
00464 int
00465 ACE_Process_Manager::spawn_n (size_t n,
00466                               ACE_Process_Options &options,
00467                               pid_t *child_pids,
00468                               ACE_Event_Handler *event_handler)
00469 {
00470   ACE_TRACE ("ACE_Process_Manager::spawn_n");
00471 
00472   if (child_pids != 0)
00473     for (size_t i = 0;
00474          i < n;
00475          ++i)
00476       child_pids[i] = ACE_INVALID_PID;
00477 
00478   for (size_t i = 0;
00479        i < n;
00480        i++)
00481     {
00482       pid_t const pid = this->spawn (options, event_handler);
00483       if (pid == ACE_INVALID_PID || pid == 0)
00484         // We're in the child or something's gone wrong.
00485         return pid;
00486       else if (child_pids != 0)
00487         child_pids[i] = pid;
00488     }
00489 
00490   return 0;
00491 }
00492 
00493 // Append a process into the pool (does not check for duplicates).
00494 // Must be called with locks held.
00495 
00496 int
00497 ACE_Process_Manager::append_proc (ACE_Process *proc,
00498                                   ACE_Event_Handler *event_handler)
00499 {
00500   ACE_TRACE ("ACE_Process_Manager::append_proc");
00501 
00502   // Try to resize the array to twice its existing size (or the DEFAULT_SIZE,
00503   // if there are no array entries) if we run out of space...
00504   if (this->current_count_ >= this->max_process_table_size_)
00505     {
00506       size_t new_size = this->max_process_table_size_ * 2;
00507       if (new_size == 0)
00508         new_size = ACE_Process_Manager::DEFAULT_SIZE;
00509       if (this->resize (new_size) == -1)
00510         return -1;
00511     }
00512 
00513   ACE_Process_Descriptor &proc_desc =
00514     this->process_table_[this->current_count_];
00515 
00516   proc_desc.process_ = proc;
00517   proc_desc.exit_notify_ = event_handler;
00518 
00519 #if defined (ACE_WIN32)
00520   // If we have a Reactor, then we're supposed to reap Processes
00521   // automagically.  Get a handle to this new Process and tell the
00522   // Reactor we're interested in <handling_input> on it.
00523 
00524   ACE_Reactor * const r = this->reactor ();
00525   if (r != 0)
00526     r->register_handler (this, proc->gethandle ());
00527 #endif /* ACE_WIN32 */
00528 
00529   ++this->current_count_;
00530   return 0;
00531 }
00532 
00533 // Insert a process into the pool (checks for duplicates and doesn't
00534 // allow them to be inserted twice).
00535 
00536 int
00537 ACE_Process_Manager::insert_proc (ACE_Process *proc,
00538                                   ACE_Event_Handler *event_handler)
00539 {
00540   ACE_TRACE ("ACE_Process_Manager::insert_proc");
00541 
00542   // Check for duplicates and bail out if they're already
00543   // registered...
00544   if (this->find_proc (proc->getpid ()) != -1)
00545     return -1;
00546 
00547   return this->append_proc (proc, event_handler);
00548 }
00549 
00550 // Remove a process from the pool.
00551 
00552 int
00553 ACE_Process_Manager::remove (pid_t pid)
00554 {
00555   ACE_TRACE ("ACE_Process_Manager::remove");
00556 
00557   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00558 
00559   ssize_t const i = this->find_proc (pid);
00560 
00561   if (i != -1)
00562     return this->remove_proc (i);
00563 
00564   // set "process not found" error
00565   return -1;
00566 }
00567 
00568 // Remove a process from the pool.  Must be called with locks held.
00569 
00570 int
00571 ACE_Process_Manager::remove_proc (size_t i)
00572 {
00573   ACE_TRACE ("ACE_Process_Manager::remove_proc");
00574 
00575   // If there's an exit_notify_ <Event_Handler> for this pid, call its
00576   // <handle_close> method.
00577 
00578   if (this->process_table_[i].exit_notify_ != 0)
00579     {
00580       this->process_table_[i].exit_notify_->handle_close
00581         (this->process_table_[i].process_->gethandle(),
00582          0);
00583       this->process_table_[i].exit_notify_ = 0;
00584     }
00585 
00586 #if defined (ACE_WIN32)
00587   ACE_Reactor * const r = this->reactor ();
00588   if (r != 0)
00589     r->remove_handler (this->process_table_[i].process_->gethandle (),
00590                        ACE_Event_Handler::DONT_CALL);
00591 #endif /* ACE_WIN32 */
00592 
00593   this->process_table_[i].process_->unmanage ();
00594 
00595   this->process_table_[i].process_ = 0;
00596 
00597   this->current_count_--;
00598 
00599   if (this->current_count_ > 0)
00600     // Compact the table by moving the last item into the slot vacated
00601     // by the index being removed (this is a structure assignment).
00602     this->process_table_[i] =
00603       this->process_table_[this->current_count_];
00604 
00605   return 0;
00606 }
00607 
00608 int
00609 ACE_Process_Manager::terminate (pid_t pid)
00610 {
00611   ACE_TRACE ("ACE_Process_Manager::terminate");
00612 
00613   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00614 
00615   // Check for duplicates and bail out if they're already
00616   // registered...
00617   ssize_t const i = this->find_proc (pid);
00618 
00619   if (i == -1)
00620     // set "no such process" error
00621     return -1;
00622 
00623   int const result = ACE::terminate_process (pid);
00624 
00625   if (result != -1)
00626     {
00627       // Save/restore errno.
00628       ACE_Errno_Guard error (errno);
00629       this->remove_proc (i);
00630       return 0;
00631     }
00632 
00633   return -1;
00634 }
00635 
00636 int
00637 ACE_Process_Manager::terminate (pid_t pid,
00638                                 int sig)
00639 {
00640   ACE_TRACE ("ACE_Process_Manager::terminate");
00641 
00642   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00643 
00644   // Check for duplicates and bail out if they're already
00645   // registered...
00646   ssize_t const i = this->find_proc (pid);
00647 
00648   if (i == -1)
00649     // set "no such process" error
00650     return -1;
00651 
00652   return ACE_OS::kill (pid, sig);
00653 }
00654 
00655 
00656 int
00657 ACE_Process_Manager::set_scheduler (const ACE_Sched_Params & params,
00658                                     pid_t pid)
00659 {
00660   ACE_TRACE ("ACE_Process_Manager::set_scheduler");
00661 
00662   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
00663                             ace_mon, this->lock_, -1));
00664 
00665   // Check to see if the process identified by the given pid is managed by
00666   // this instance of ACE_Process_Manager.
00667   ssize_t const i = this->find_proc (pid);
00668 
00669   if (i == -1)
00670     // set "no such process" error
00671     return ACE_INVALID_PID;
00672 
00673   return ACE_OS::sched_params (params, pid);
00674 }
00675 
00676 int
00677 ACE_Process_Manager::set_scheduler_all (const ACE_Sched_Params & params)
00678 {
00679   ACE_TRACE ("ACE_Process_Manager::set_scheduler_all");
00680 
00681   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
00682                             ace_mon, this->lock_, -1));
00683 
00684   for (size_t i = 0; i < this->current_count_; ++i)
00685     {
00686       pid_t const pid = this->process_table_[i].process_->getpid ();
00687       if (ACE_OS::sched_params (params, pid) != 0)
00688         return -1;
00689     }
00690   return 0;
00691 
00692 }
00693 
00694 
00695 // Locate the index in the table associated with <pid>.  Must be
00696 // called with the lock held.
00697 
00698 ssize_t
00699 ACE_Process_Manager::find_proc (pid_t pid)
00700 {
00701   ACE_TRACE ("ACE_Process_Manager::find_proc");
00702 
00703   for (size_t i = 0; i < this->current_count_; ++i)
00704     if (pid == this->process_table_[i].process_->getpid ())
00705       return i;
00706 
00707   return -1;
00708 }
00709 
00710 #if defined (ACE_WIN32)
00711 // Locate the index in the table associated with <h>.  Must be
00712 // called with the lock held.
00713 
00714 ssize_t
00715 ACE_Process_Manager::find_proc (ACE_HANDLE h)
00716 {
00717   ACE_TRACE ("ACE_Process_Manager::find_proc");
00718 
00719   for (size_t i = 0; i < this->current_count_; ++i)
00720     if (h == this->process_table_[i].process_->gethandle ())
00721       return i;
00722 
00723   return -1;
00724 }
00725 #endif /* ACE_WIN32 */
00726 
00727 // Wait for all the Processs to exit, or until <timeout> elapses.
00728 // Returns the number of Processes remaining, or -1 on an error.
00729 
00730 int
00731 ACE_Process_Manager::wait (const ACE_Time_Value &timeout)
00732 {
00733   ACE_TRACE ("ACE_Process_Manager::wait");
00734 
00735   ACE_Time_Value until = timeout;
00736   ACE_Time_Value remaining = timeout;
00737 
00738   if (until < ACE_Time_Value::max_time)
00739     until += ACE_OS::gettimeofday ();
00740 
00741   while (this->current_count_ > 0)
00742     {
00743       pid_t const pid = this->wait (0, remaining);
00744 
00745       if (pid == ACE_INVALID_PID)       // wait() failed
00746         return -1;
00747       else if (pid == 0)     // timeout
00748         break;
00749 
00750       remaining = until < ACE_Time_Value::max_time
00751         ? until - ACE_OS::gettimeofday ()
00752         : ACE_Time_Value::max_time;
00753 
00754       if (remaining <= ACE_Time_Value::zero)
00755         break;
00756 
00757       // else Process terminated...wait for more...
00758     }
00759   return static_cast<int> (this->current_count_);
00760 }
00761 
00762 // Collect a single child process' exit status.  Store the exit code
00763 // in *<stat_loc> if non-zero.  Call the appropriate exit_notify.  If
00764 // <pid> == 0, wait for any of the Process_Manager's children (or as
00765 // near as possible -- on Unix, we might accidentally get some other
00766 // Process_Manager's Process, or an unmanaged Process, or a child
00767 // process started by some other means.
00768 
00769 pid_t
00770 ACE_Process_Manager::wait (pid_t pid,
00771                            ACE_exitcode *status)
00772 {
00773   ACE_TRACE ("ACE_Process_Manager::wait");
00774 
00775   return this->wait (pid,
00776                      ACE_Time_Value::max_time,
00777                      status);
00778 }
00779 
00780 // Collect a single child processes' exit status, unless <timeout>
00781 // elapses before the process exits.  Same caveats about accidental
00782 // Process reaping on Unix as above.
00783 
00784 pid_t
00785 ACE_Process_Manager::wait (pid_t pid,
00786                            const ACE_Time_Value &timeout,
00787                            ACE_exitcode *status)
00788 {
00789   ACE_TRACE ("ACE_Process_Manager::wait");
00790 
00791   ACE_exitcode local_stat = 0;
00792   if (status == 0)
00793     status = &local_stat;
00794 
00795   *status = 0;
00796 
00797   ssize_t idx = -1;
00798   ACE_Process *proc = 0;
00799 
00800   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00801 
00802   if (pid != 0)
00803     {
00804       idx = this->find_proc (pid);
00805       if (idx == -1)
00806         return ACE_INVALID_PID;
00807       else
00808         proc = process_table_[idx].process_;
00809     }
00810 
00811   if (proc != 0)
00812     pid = proc->wait (timeout, status);
00813   else
00814     {
00815       // Wait for any Process spawned by this Process_Manager.
00816 #if defined (ACE_WIN32)
00817       HANDLE *handles = 0;
00818 
00819       ACE_NEW_RETURN (handles,
00820                       HANDLE[this->current_count_],
00821                       ACE_INVALID_PID);
00822 
00823       for (size_t i = 0;
00824            i < this->current_count_;
00825            ++i)
00826         handles[i] =
00827           process_table_[i].process_->gethandle ();
00828 
00829       DWORD handle_count = static_cast<DWORD> (this->current_count_);
00830       DWORD result = ::WaitForMultipleObjects (handle_count,
00831                                                handles,
00832                                                FALSE,
00833                                                timeout == ACE_Time_Value::max_time
00834                                                ? INFINITE
00835                                                : timeout.msec ());
00836       if (result == WAIT_FAILED)
00837         pid = ACE_INVALID_PID;
00838       else if (result == WAIT_TIMEOUT)
00839         pid = 0;
00840       else
00841         {
00842           // Green Hills produces a warning that result >= WAIT_OBJECT_0 is
00843           // a pointless comparison because WAIT_OBJECT_0 is zero and DWORD is
00844           // unsigned long, so this test is skipped for Green Hills.
00845           // Same for mingw.
00846 # if defined (ghs) || defined (__MINGW32__) || (defined (_MSC_VER) && _MSC_VER >= 1300)
00847           ACE_ASSERT (result < WAIT_OBJECT_0 + this->current_count_);
00848 # else
00849           ACE_ASSERT (result >= WAIT_OBJECT_0
00850                       && result < WAIT_OBJECT_0 + this->current_count_);
00851 # endif
00852 
00853           idx = this->find_proc (handles[result - WAIT_OBJECT_0]);
00854 
00855           if (idx != -1)
00856             {
00857               pid = process_table_[idx].process_->getpid ();
00858               result = ::GetExitCodeProcess (handles[result - WAIT_OBJECT_0],
00859                                              status);
00860               if (result == 0)
00861                 {
00862                   // <GetExitCodeProcess> failed!
00863                   this->remove_proc (idx);
00864                   pid = ACE_INVALID_PID;
00865                 }
00866             }
00867           else
00868             {
00869               // uh oh...handle removed from process_table_, even though
00870               // we're holding a lock!
00871               delete [] handles;
00872               ACE_ERROR_RETURN ((LM_ERROR,
00873                                  ACE_LIB_TEXT ("Process removed")
00874                                  ACE_LIB_TEXT (" -- somebody's ignoring the lock!\n")),
00875                                 -1);
00876             }
00877         }
00878 
00879       delete [] handles;
00880 #else /* !defined(ACE_WIN32) */
00881       if (timeout == ACE_Time_Value::max_time)
00882         {
00883           pid = ACE_OS::waitpid (-1, status, 0);
00884         }
00885       else if (timeout == ACE_Time_Value::zero)
00886         {
00887           pid = ACE_OS::waitpid (-1, status, WNOHANG);
00888         }
00889       else
00890         {
00891 # if defined (ACE_LACKS_UNIX_SIGNALS)
00892           pid = 0;
00893           ACE_Time_Value sleeptm (1);    // 1 msec
00894           if (sleeptm > timeout)         // if sleeptime > waittime
00895             sleeptm = timeout;
00896           ACE_Time_Value tmo (timeout);  // Need one we can change
00897           for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ())
00898             {
00899               pid = ACE_OS::waitpid (-1, status, WNOHANG);
00900               if (pid > 0 || pid == ACE_INVALID_PID)
00901                 break;          // Got a child or an error - all done
00902 
00903               // pid 0, nothing is ready yet, so wait.
00904               // Do a (very) short sleep (only this thread sleeps).
00905               ACE_OS::sleep (sleeptm);
00906             }
00907 # else
00908           // Force generation of SIGCHLD, even though we don't want to
00909           // catch it - just need it to interrupt the sleep below.
00910           // If this object has a reactor set, assume it was given at
00911           // open(), and there's already a SIGCHLD action set, so no
00912           // action is needed here.
00913           ACE_Sig_Action old_action;
00914           if (this->reactor () == 0)
00915             {
00916               ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop);
00917               do_sigchld.register_action (SIGCHLD, &old_action);
00918             }
00919 
00920           ACE_Time_Value tmo (timeout);  // Need one we can change
00921           for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ())
00922             {
00923               pid = ACE_OS::waitpid (-1, status, WNOHANG);
00924 #   if defined (ACE_VXWORKS) && (ACE_VXWORKS >= 0x600)
00925               if (pid > 0 || (pid == ACE_INVALID_PID && errno != EINTR))
00926 #   else
00927               if (pid > 0 || pid == ACE_INVALID_PID)
00928 #   endif
00929                 break;          // Got a child or an error - all done
00930 
00931               // pid 0, nothing is ready yet, so wait.
00932               // Do a sleep (only this thread sleeps) til something
00933               // happens. This relies on SIGCHLD interrupting the sleep.
00934               // If SIGCHLD isn't delivered, we'll need to do something
00935               // with sigaction to force it.
00936               if (-1 == ACE_OS::sleep (tmo) && errno == EINTR)
00937                 continue;
00938               // Timed out
00939               pid = 0;
00940               break;
00941             }
00942 
00943           // Restore the previous SIGCHLD action if it was changed.
00944           if (this->reactor () == 0)
00945             {
00946               old_action.register_action (SIGCHLD);
00947             }
00948 # endif /* !ACE_LACKS_UNIX_SIGNALS */
00949         }
00950 #endif /* !defined (ACE_WIN32) */
00951     }
00952 
00953   if (pid != ACE_INVALID_PID && pid != 0)
00954     {
00955       if (proc == 0)
00956         {
00957           idx = this->find_proc (pid);
00958           if (idx == -1)
00959             {
00960               // oops, reaped an unmanaged process!
00961               ACE_DEBUG ((LM_DEBUG,
00962                           ACE_LIB_TEXT ("(%P|%t) oops, reaped unmanaged %d\n"),
00963                           pid));
00964               return pid;
00965             }
00966           else
00967             proc = process_table_[idx].process_;
00968         }
00969       else
00970         ACE_ASSERT (pid == proc->getpid ());
00971 
00972       this->notify_proc_handler (idx,
00973                                  *status);
00974       this->remove (pid);
00975     }
00976 
00977   return pid;
00978 }
00979 
00980 // Legacy method:
00981 
00982 int
00983 ACE_Process_Manager::reap (pid_t pid,
00984                            ACE_exitcode *stat_loc,
00985                            int options)
00986 {
00987   ACE_TRACE ("ACE_Process_Manager::reap");
00988 
00989   return this->wait (pid,
00990                      (ACE_BIT_ENABLED (options, WNOHANG)
00991                       ? ACE_Time_Value::zero
00992                       : ACE_Time_Value::max_time),
00993                      stat_loc);
00994 }
00995 
00996 // Notify either the process-specific handler or the generic handler.
00997 // If process-specific, call handle_close on the handler.  Returns 1
00998 // if process found, 0 if not.  Must be called with locks held.
00999 
01000 int
01001 ACE_Process_Manager::notify_proc_handler (size_t i,
01002                                           ACE_exitcode exit_code)
01003 {
01004   if (i < this->current_count_)
01005     {
01006       ACE_Process_Descriptor &proc_desc =
01007         this->process_table_[i];
01008 
01009       proc_desc.process_->exit_code (exit_code);
01010 
01011       if (proc_desc.exit_notify_ != 0)
01012         proc_desc.exit_notify_->handle_exit (proc_desc.process_);
01013       else if (this->default_exit_handler_ != 0
01014                && this->default_exit_handler_->handle_exit (proc_desc.process_) < 0)
01015         {
01016           this->default_exit_handler_->handle_close
01017             (ACE_INVALID_HANDLE,
01018              0);
01019           this->default_exit_handler_ = 0;
01020         }
01021       return 1;
01022     }
01023   else
01024     {
01025       ACE_DEBUG ((LM_DEBUG,
01026                   ACE_LIB_TEXT ("(%P:%t|%T) ACE_Process_Manager::notify_proc_handler:")
01027                   ACE_LIB_TEXT (" unknown/unmanaged process reaped\n")));
01028       return 0;
01029     }
01030 }
01031 
01032 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Thu Nov 9 09:42:00 2006 for ACE by doxygen 1.3.6