Process_Manager.cpp

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

Generated on Tue Feb 2 17:18:42 2010 for ACE by  doxygen 1.4.7