Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / Process_Manager.cpp
blob4fb0c5a1034f236ecd442499be0f55ff6e38e42a
1 // Process_Manager.cpp
2 #include "ace/Process_Manager.h"
4 #if !defined (__ACE_INLINE__)
5 #include "ace/Process_Manager.inl"
6 #endif /* __ACE_INLINE__ */
8 #include "ace/ACE.h"
9 #include "ace/Guard_T.h"
10 #include "ace/Process.h"
11 #include "ace/Signal.h"
12 #include "ace/Object_Manager.h"
13 #include "ace/Log_Category.h"
14 #include "ace/Reactor.h"
15 #include "ace/Countdown_Time.h"
16 #include "ace/OS_NS_sys_wait.h"
17 #include "ace/OS_NS_signal.h"
18 #include "ace/OS_NS_unistd.h"
19 #include "ace/OS_NS_sys_time.h"
20 #include "ace/os_include/os_typeinfo.h"
21 #include "ace/Truncate.h"
23 #if defined (ACE_HAS_SIG_C_FUNC)
24 extern "C" void
25 ACE_Process_Manager_cleanup (void *instance, void *arg)
27 ACE_Process_Manager::cleanup (instance, arg);
29 #define ACE_PROCESS_MANAGER_CLEANUP_FUNCTION ACE_Process_Manager_cleanup
30 #else
31 #define ACE_PROCESS_MANAGER_CLEANUP_FUNCTION ACE_Process_Manager::cleanup
32 #endif
34 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
36 void
37 ACE_Process_Manager::cleanup (void *, void *)
39 ACE_Process_Manager::close_singleton ();
42 // This function acts as a signal handler for SIGCHLD. We don't really
43 // want to do anything with the signal - it's just needed to interrupt
44 // a sleep. See wait() for more info.
45 #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS)
46 static void
47 sigchld_nop (int, siginfo_t *, ucontext_t *)
49 return;
51 #endif /* ACE_WIN32 */
54 ACE_ALLOC_HOOK_DEFINE(ACE_Process_Manager)
56 // Singleton instance.
57 ACE_Process_Manager *ACE_Process_Manager::instance_ = 0;
59 // Controls whether the Process_Manager is deleted when we shut down
60 // (we can only delete it safely if we created it!)
61 bool ACE_Process_Manager::delete_instance_ = false;
63 ACE_Process_Manager::Process_Descriptor::~Process_Descriptor ()
67 ACE_ALLOC_HOOK_DEFINE(ACE_Process_Manager::Process_Descriptor)
69 void
70 ACE_Process_Manager::Process_Descriptor::dump () const
72 #if defined (ACE_HAS_DUMP)
73 ACE_TRACE ("ACE_Process_Manager::Process_Descriptor::dump");
75 ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
77 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nproc_id_ = %d"),
78 this->process_->getpid( )));
80 ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
81 #endif /* ACE_HAS_DUMP */
84 void
85 ACE_Process_Manager::dump () const
87 #if defined (ACE_HAS_DUMP)
88 ACE_TRACE ("ACE_Process_Manager::dump");
90 ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
92 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmax_process_table_size_ = %d"), this->max_process_table_size_));
93 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncurrent_count_ = %d"), this->current_count_));
95 for (size_t i = 0; i < this->current_count_; i++)
96 this->process_table_[i].dump ();
98 ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
99 #endif /* ACE_HAS_DUMP */
102 ACE_Process_Manager::Process_Descriptor::Process_Descriptor ()
103 : process_ (0),
104 exit_notify_ (0)
106 ACE_TRACE ("ACE_Process_Manager::Process_Descriptor::Process_Descriptor");
109 ACE_Process_Manager *
110 ACE_Process_Manager::instance ()
112 ACE_TRACE ("ACE_Process_Manager::instance");
114 if (ACE_Process_Manager::instance_ == 0)
116 // Perform Double-Checked Locking Optimization.
117 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
118 *ACE_Static_Object_Lock::instance (), 0));
120 if (ACE_Process_Manager::instance_ == 0)
122 ACE_NEW_RETURN (ACE_Process_Manager::instance_,
123 ACE_Process_Manager,
125 ACE_Process_Manager::delete_instance_ = true;
127 // Register with the Object_Manager so that the wrapper to
128 // delete the proactor will be called when Object_Manager is
129 // being terminated.
130 ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
131 ACE_PROCESS_MANAGER_CLEANUP_FUNCTION,
133 typeid (ACE_Process_Manager).name ());
137 return ACE_Process_Manager::instance_;
140 ACE_Process_Manager *
141 ACE_Process_Manager::instance (ACE_Process_Manager *tm)
143 ACE_TRACE ("ACE_Process_Manager::instance");
144 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
145 *ACE_Static_Object_Lock::instance (), 0));
147 ACE_Process_Manager *t = ACE_Process_Manager::instance_;
148 // We can't safely delete it since we don't know who created it!
149 ACE_Process_Manager::delete_instance_ = false;
151 // Register with the Object_Manager so that the wrapper to
152 // delete the proactor will be called when Object_Manager is
153 // being terminated.
154 ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
155 ACE_PROCESS_MANAGER_CLEANUP_FUNCTION,
157 typeid (*t).name ());
159 ACE_Process_Manager::instance_ = tm;
160 return t;
163 void
164 ACE_Process_Manager::close_singleton( )
166 ACE_TRACE ("ACE_Process_Manager::close_singleton");
168 ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
169 *ACE_Static_Object_Lock::instance ()));
171 if (ACE_Process_Manager::delete_instance_)
173 delete ACE_Process_Manager::instance_;
174 ACE_Process_Manager::instance_ = 0;
175 ACE_Process_Manager::delete_instance_ = false;
180 ACE_Process_Manager::resize (size_t size)
182 ACE_TRACE ("ACE_Process_Manager::resize");
184 if (size <= this->max_process_table_size_)
185 return 0;
187 Process_Descriptor *temp = 0;
189 ACE_NEW_RETURN (temp,
190 Process_Descriptor[size],
191 -1);
193 for (size_t i = 0;
194 i < this->current_count_;
195 i++)
196 // Structure assignment.
197 temp[i] = this->process_table_[i];
199 this->max_process_table_size_ = size;
201 delete [] this->process_table_;
203 this->process_table_ = temp;
204 return 0;
207 // Create and initialize the table to keep track of the process pool.
209 ACE_Process_Manager::open (size_t size, ACE_Reactor *r)
211 ACE_TRACE ("ACE_Process_Manager::open");
213 if (r)
215 this->reactor (r);
216 #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS)
217 // Register signal handler object.
218 if (r->register_handler (SIGCHLD, this) == -1)
219 return -1;
220 #endif /* !defined(ACE_WIN32) */
223 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
225 if (this->max_process_table_size_ < size)
226 this->resize (size);
227 return 0;
230 // Initialize the synchronization variables.
231 ACE_Process_Manager::ACE_Process_Manager (size_t size,
232 ACE_Reactor *r)
233 : ACE_Event_Handler (),
234 process_table_ (0),
235 max_process_table_size_ (0),
236 current_count_ (0),
237 default_exit_handler_ (0)
238 #if defined (ACE_HAS_THREADS)
239 , lock_ ()
240 #endif /* ACE_HAS_THREADS */
242 ACE_TRACE ("ACE_Process_Manager::ACE_Process_Manager");
244 if (this->open (size, r) == -1)
246 ACELIB_ERROR ((LM_ERROR,
247 ACE_TEXT ("%p\n"),
248 ACE_TEXT ("ACE_Process_Manager")));
252 // Close up and release all resources.
254 ACE_Process_Manager::close ()
256 ACE_TRACE ("ACE_Process_Manager::close");
258 if (this->reactor () != 0)
260 #if !defined (ACE_WIN32) && !defined (ACE_LACKS_UNIX_SIGNALS)
261 this->reactor ()->remove_handler (SIGCHLD, (ACE_Sig_Action *) 0);
262 #endif /* !ACE_WIN32 */
263 this->reactor (0);
266 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
268 if (this->process_table_ != 0)
270 while (this->current_count_ > 0)
271 this->remove_proc (0);
273 delete [] this->process_table_;
274 this->process_table_ = 0;
275 this->max_process_table_size_ = 0;
276 this->current_count_ = 0;
279 if (this->default_exit_handler_ != 0)
280 this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE,0);
281 this->default_exit_handler_ = 0;
283 return 0;
286 ACE_Process_Manager::~ACE_Process_Manager ()
288 ACE_TRACE ("ACE_Process_Manager::~ACE_Process_Manager");
289 this->close ();
292 #if !defined (ACE_WIN32)
294 // This is called when the Reactor notices that a Process has exited.
295 // What has actually happened is a SIGCHLD invoked the <handle_signal>
296 // routine, which fooled the Reactor into thinking that this routine
297 // needed to be called. Since we don't know which Process exited, we
298 // must reap as many exit statuses as are immediately available.
300 ACE_Process_Manager::handle_input (ACE_HANDLE)
302 ACE_TRACE ("ACE_Process_Manager::handle_input");
304 pid_t pid;
307 pid = this->wait (0, ACE_Time_Value::zero);
308 while (pid != 0 && pid != ACE_INVALID_PID);
310 return 0;
314 ACE_Process_Manager::handle_close (ACE_HANDLE /* handle */,
315 ACE_Reactor_Mask close_mask)
317 ACE_TRACE ("ACE_Process_Manager::handle_close");
318 if (close_mask == ACE_Event_Handler::SIGNAL_MASK)
320 // Reactor is telling us we're gone; don't unregister again later.
321 this->reactor (0);
323 return 0;
326 #endif /* !ACE_WIN32 */
328 // On Unix, this routine is called asynchronously when a SIGCHLD is
329 // received. We just tweak the reactor so that it'll call back our
330 // <handle_input> function, which allows us to handle Process exits
331 // synchronously.
333 // On Win32, this routine is called synchronously, and is passed the
334 // HANDLE of the Process that exited, so we can do all our work here.
336 ACE_Process_Manager::handle_signal (int, siginfo_t *si, ucontext_t *)
338 #if defined (ACE_WIN32)
339 ACE_HANDLE proc = si->si_handle_;
340 ACE_exitcode status = 0;
341 BOOL result = ::GetExitCodeProcess (proc, &status);
342 if (result)
344 if (status != STILL_ACTIVE)
347 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, lock_, -1));
349 ssize_t const i = this->find_proc (proc);
350 if (i == -1)
351 return -1;
352 #if 0
353 pid_t pid = i != -1
354 ? process_table_[i].process_->getpid ()
355 : ACE_INVALID_PID;
356 #endif
357 this->notify_proc_handler (i, status);
358 this->remove_proc (i);
360 return -1; // remove this HANDLE/Event_Handler combination
362 else
363 ACELIB_ERROR_RETURN ((LM_ERROR,
364 ACE_TEXT ("Process still active")
365 ACE_TEXT (" -- shouldn't have been called yet!\n")),
366 0); // return 0 : stay registered
368 else
370 // <GetExitCodeProcess> failed.
371 ACELIB_ERROR_RETURN ((LM_ERROR,
372 ACE_TEXT ("GetExitCodeProcess failed\n")),
373 -1); // return -1: unregister
375 #else /* !ACE_WIN32 */
376 ACE_UNUSED_ARG (si);
377 return reactor ()->notify (this, ACE_Event_Handler::READ_MASK);
378 #endif /* !ACE_WIN32 */
382 ACE_Process_Manager::register_handler (ACE_Event_Handler *eh,
383 pid_t pid)
385 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
387 if (pid == ACE_INVALID_PID)
389 if (this->default_exit_handler_ != 0)
390 this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE, 0);
391 this->default_exit_handler_ = eh;
392 return 0;
395 ssize_t const i = this->find_proc (pid);
397 if (i == -1)
399 errno = EINVAL;
400 return -1;
403 Process_Descriptor &proc_desc = this->process_table_[i];
405 if (proc_desc.exit_notify_ != 0)
406 proc_desc.exit_notify_->handle_close (ACE_INVALID_HANDLE, 0);
407 proc_desc.exit_notify_ = eh;
408 return 0;
411 // Create a new process.
412 pid_t
413 ACE_Process_Manager::spawn (ACE_Process_Options &options,
414 ACE_Event_Handler *event_handler)
416 ACE_Process *process = 0;
417 ACE_NEW_RETURN (process,
418 ACE_Managed_Process,
419 ACE_INVALID_PID);
421 pid_t const pid = this->spawn (process, options, event_handler);
422 if (pid == ACE_INVALID_PID || pid == 0)
423 delete process;
425 return pid;
428 // Create a new process.
429 pid_t
430 ACE_Process_Manager::spawn (ACE_Process *process,
431 ACE_Process_Options &options,
432 ACE_Event_Handler *event_handler)
434 ACE_TRACE ("ACE_Process_Manager::spawn");
436 pid_t const pid = process->spawn (options);
438 // Only include the pid in the parent's table.
439 if (pid == ACE_INVALID_PID || pid == 0)
440 return pid;
442 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
443 ace_mon, this->lock_, -1));
445 if (this->append_proc (process, event_handler) == -1)
446 // bad news: spawned, but not registered in table.
447 return ACE_INVALID_PID;
449 return pid;
452 // Create N new processs.
454 ACE_Process_Manager::spawn_n (size_t n,
455 ACE_Process_Options &options,
456 pid_t *child_pids,
457 ACE_Event_Handler *event_handler)
459 ACE_TRACE ("ACE_Process_Manager::spawn_n");
461 if (child_pids != 0)
462 for (size_t i = 0;
463 i < n;
464 ++i)
465 child_pids[i] = ACE_INVALID_PID;
467 for (size_t i = 0;
468 i < n;
469 i++)
471 pid_t const pid = this->spawn (options, event_handler);
472 if (pid == ACE_INVALID_PID || pid == 0)
473 // We're in the child or something's gone wrong.
474 return pid;
475 else if (child_pids != 0)
476 child_pids[i] = pid;
479 return 0;
482 // Append a process into the pool (does not check for duplicates).
483 // Must be called with locks held.
485 ACE_Process_Manager::append_proc (ACE_Process *proc,
486 ACE_Event_Handler *event_handler)
488 ACE_TRACE ("ACE_Process_Manager::append_proc");
490 // Try to resize the array to twice its existing size (or the DEFAULT_SIZE,
491 // if there are no array entries) if we run out of space...
492 if (this->current_count_ >= this->max_process_table_size_)
494 size_t new_size = this->max_process_table_size_ * 2;
495 if (new_size == 0)
496 new_size = ACE_Process_Manager::DEFAULT_SIZE;
497 if (this->resize (new_size) == -1)
498 return -1;
501 Process_Descriptor &proc_desc =
502 this->process_table_[this->current_count_];
504 proc_desc.process_ = proc;
505 proc_desc.exit_notify_ = event_handler;
507 #if defined (ACE_WIN32)
508 // If we have a Reactor, then we're supposed to reap Processes
509 // automagically. Get a handle to this new Process and tell the
510 // Reactor we're interested in <handling_input> on it.
511 ACE_Reactor * const r = this->reactor ();
512 if (r != 0)
513 r->register_handler (this, proc->gethandle ());
514 #endif /* ACE_WIN32 */
516 ++this->current_count_;
517 return 0;
520 // Insert a process into the pool (checks for duplicates and doesn't
521 // allow them to be inserted twice).
523 ACE_Process_Manager::insert_proc (ACE_Process *proc,
524 ACE_Event_Handler *event_handler)
526 ACE_TRACE ("ACE_Process_Manager::insert_proc");
528 // Check for duplicates and bail out if they're already
529 // registered...
530 if (this->find_proc (proc->getpid ()) != -1)
531 return -1;
533 return this->append_proc (proc, event_handler);
536 // Remove a process from the pool.
538 ACE_Process_Manager::remove (pid_t pid)
540 ACE_TRACE ("ACE_Process_Manager::remove");
542 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
544 ssize_t const i = this->find_proc (pid);
546 if (i != -1)
547 return this->remove_proc (i);
549 // set "process not found" error
550 return -1;
553 // Remove a process from the pool. Must be called with locks held.
555 ACE_Process_Manager::remove_proc (size_t i)
557 ACE_TRACE ("ACE_Process_Manager::remove_proc");
559 // If there's an exit_notify_ <Event_Handler> for this pid, call its
560 // <handle_close> method.
562 if (this->process_table_[i].exit_notify_ != 0)
564 this->process_table_[i].exit_notify_->handle_close
565 (this->process_table_[i].process_->gethandle(),
567 this->process_table_[i].exit_notify_ = 0;
570 #if defined (ACE_WIN32)
571 ACE_Reactor * const r = this->reactor ();
572 if (r != 0)
573 r->remove_handler (this->process_table_[i].process_->gethandle (),
574 ACE_Event_Handler::DONT_CALL);
575 #endif /* ACE_WIN32 */
577 this->process_table_[i].process_->unmanage ();
579 this->process_table_[i].process_ = 0;
581 this->current_count_--;
583 if (this->current_count_ > 0)
584 // Compact the table by moving the last item into the slot vacated
585 // by the index being removed (this is a structure assignment).
586 this->process_table_[i] =
587 this->process_table_[this->current_count_];
589 return 0;
593 ACE_Process_Manager::terminate (pid_t pid)
595 ACE_TRACE ("ACE_Process_Manager::terminate");
597 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
599 // Check for duplicates and bail out if they're already
600 // registered...
601 ssize_t const i = this->find_proc (pid);
603 if (i == -1)
604 // set "no such process" error
605 return -1;
607 return ACE::terminate_process (pid);
611 ACE_Process_Manager::terminate (pid_t pid, int sig)
613 ACE_TRACE ("ACE_Process_Manager::terminate");
615 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
617 // Check for duplicates and bail out if they're already
618 // registered...
619 ssize_t const i = this->find_proc (pid);
621 if (i == -1)
622 // set "no such process" error
623 return -1;
625 return ACE_OS::kill (pid, sig);
629 ACE_Process_Manager::set_scheduler (const ACE_Sched_Params & params,
630 pid_t pid)
632 ACE_TRACE ("ACE_Process_Manager::set_scheduler");
634 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
635 ace_mon, this->lock_, -1));
637 // Check to see if the process identified by the given pid is managed by
638 // this instance of ACE_Process_Manager.
639 ssize_t const i = this->find_proc (pid);
641 if (i == -1)
642 // set "no such process" error
643 return ACE_INVALID_PID;
645 return ACE_OS::sched_params (params, pid);
649 ACE_Process_Manager::set_scheduler_all (const ACE_Sched_Params & params)
651 ACE_TRACE ("ACE_Process_Manager::set_scheduler_all");
653 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
654 ace_mon, this->lock_, -1));
656 for (size_t i = 0; i < this->current_count_; ++i)
658 pid_t const pid = this->process_table_[i].process_->getpid ();
659 if (ACE_OS::sched_params (params, pid) != 0)
660 return -1;
662 return 0;
665 // Locate the index in the table associated with <pid>. Must be
666 // called with the lock held.
667 ssize_t
668 ACE_Process_Manager::find_proc (pid_t pid)
670 ACE_TRACE ("ACE_Process_Manager::find_proc");
672 for (size_t i = 0; i < this->current_count_; ++i)
674 if (pid == this->process_table_[i].process_->getpid ())
676 return ACE_Utils::truncate_cast<ssize_t> (i);
680 return -1;
683 #if defined (ACE_WIN32)
684 // Locate the index in the table associated with <h>. Must be
685 // called with the lock held.
686 ssize_t
687 ACE_Process_Manager::find_proc (ACE_HANDLE h)
689 ACE_TRACE ("ACE_Process_Manager::find_proc");
691 for (size_t i = 0; i < this->current_count_; ++i)
693 if (h == this->process_table_[i].process_->gethandle ())
695 return ACE_Utils::truncate_cast<ssize_t> (i);
699 return -1;
701 #endif /* ACE_WIN32 */
703 // Wait for all the Processs to exit, or until @a timeout elapses.
704 // Returns the number of Processes remaining, or -1 on an error.
706 ACE_Process_Manager::wait (const ACE_Time_Value &timeout)
708 ACE_TRACE ("ACE_Process_Manager::wait");
710 ACE_Time_Value until = timeout;
711 ACE_Time_Value remaining = timeout;
713 if (until < ACE_Time_Value::max_time)
714 until += ACE_OS::gettimeofday ();
716 while (this->current_count_ > 0)
718 pid_t const pid = this->wait (0, remaining);
720 if (pid == ACE_INVALID_PID) // wait() failed
721 return -1;
722 else if (pid == 0) // timeout
723 break;
725 remaining = until < ACE_Time_Value::max_time
726 ? until - ACE_OS::gettimeofday ()
727 : ACE_Time_Value::max_time;
729 if (remaining <= ACE_Time_Value::zero)
730 break;
732 // else Process terminated...wait for more...
734 return static_cast<int> (this->current_count_);
737 // Collect a single child process' exit status. Store the exit code
738 // in *<stat_loc> if non-zero. Call the appropriate exit_notify. If
739 // <pid> == 0, wait for any of the Process_Manager's children (or as
740 // near as possible -- on Unix, we might accidentally get some other
741 // Process_Manager's Process, or an unmanaged Process, or a child
742 // process started by some other means.
743 pid_t
744 ACE_Process_Manager::wait (pid_t pid,
745 ACE_exitcode *status)
747 ACE_TRACE ("ACE_Process_Manager::wait");
749 return this->wait (pid,
750 ACE_Time_Value::max_time,
751 status);
754 // Collect a single child processes' exit status, unless @a timeout
755 // elapses before the process exits. Same caveats about accidental
756 // Process reaping on Unix as above.
757 pid_t
758 ACE_Process_Manager::wait (pid_t pid,
759 const ACE_Time_Value &timeout,
760 ACE_exitcode *status)
762 ACE_TRACE ("ACE_Process_Manager::wait");
764 ACE_exitcode local_stat = 0;
765 if (status == 0)
766 status = &local_stat;
768 *status = 0;
770 ssize_t idx = -1;
771 ACE_Process *proc = 0;
774 // fake context after which the lock is released
775 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
777 if (pid != 0)
779 idx = this->find_proc (pid);
780 if (idx == -1)
781 return ACE_INVALID_PID;
782 else
783 proc = process_table_[idx].process_;
785 // release the lock.
787 if (proc != 0)
788 pid = proc->wait (timeout, status);
789 else
791 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
792 // Wait for any Process spawned by this Process_Manager.
793 #if defined (ACE_WIN32)
794 HANDLE *handles = 0;
796 ACE_NEW_RETURN (handles,
797 HANDLE[this->current_count_],
798 ACE_INVALID_PID);
800 for (size_t i = 0;
801 i < this->current_count_;
802 ++i)
803 handles[i] =
804 process_table_[i].process_->gethandle ();
806 DWORD handle_count = static_cast<DWORD> (this->current_count_);
807 DWORD result = ::WaitForMultipleObjects (handle_count,
808 handles,
809 FALSE,
810 timeout == ACE_Time_Value::max_time
811 ? INFINITE
812 : timeout.msec ());
813 if (result == WAIT_FAILED)
814 pid = ACE_INVALID_PID;
815 else if (result == WAIT_TIMEOUT)
816 pid = 0;
817 else
819 // Green Hills produces a warning that result >=
820 // WAIT_OBJECT_0 is a pointless comparison because
821 // WAIT_OBJECT_0 is zero and DWORD is unsigned long, so this
822 // test is skipped for Green Hills. Same for mingw.
823 # if defined (__MINGW32__) || defined (_MSC_VER)
824 ACE_ASSERT (result < WAIT_OBJECT_0 + this->current_count_);
825 # else
826 ACE_ASSERT (result >= WAIT_OBJECT_0
827 && result < WAIT_OBJECT_0 + this->current_count_);
828 # endif
830 idx = this->find_proc (handles[result - WAIT_OBJECT_0]);
832 if (idx != -1)
834 pid = process_table_[idx].process_->getpid ();
835 result = ::GetExitCodeProcess (handles[result - WAIT_OBJECT_0],
836 status);
837 if (result == 0)
839 // <GetExitCodeProcess> failed!
840 this->remove_proc (idx);
841 pid = ACE_INVALID_PID;
844 else
846 // uh oh...handle removed from process_table_, even though
847 // we're holding a lock!
848 delete [] handles;
849 ACELIB_ERROR_RETURN ((LM_ERROR,
850 ACE_TEXT ("Process removed")
851 ACE_TEXT (" -- somebody's ignoring the lock!\n")),
852 -1);
856 delete [] handles;
857 #else /* !defined(ACE_WIN32) */
858 if (timeout == ACE_Time_Value::max_time)
859 pid = ACE_OS::waitpid (-1, status, 0);
860 else if (timeout == ACE_Time_Value::zero)
861 pid = ACE_OS::waitpid (-1, status, WNOHANG);
862 else
864 # if defined (ACE_LACKS_UNIX_SIGNALS)
865 pid = 0;
866 ACE_Time_Value sleeptm (1); // 1 msec
867 if (sleeptm > timeout) // if sleeptime > waittime
868 sleeptm = timeout;
869 ACE_Time_Value tmo (timeout); // Need one we can change
870 for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ())
872 pid = ACE_OS::waitpid (-1, status, WNOHANG);
873 if (pid > 0 || pid == ACE_INVALID_PID)
874 break; // Got a child or an error - all done
876 // pid 0, nothing is ready yet, so wait.
877 // Do a (very) short sleep (only this thread sleeps).
878 ACE_OS::sleep (sleeptm);
880 # else
881 // Force generation of SIGCHLD, even though we don't want to
882 // catch it - just need it to interrupt the sleep below.
883 // If this object has a reactor set, assume it was given at
884 // open(), and there's already a SIGCHLD action set, so no
885 // action is needed here.
886 ACE_Sig_Action old_action;
887 if (this->reactor () == 0)
889 ACE_Sig_Handler_Ex sigchld_nop_ptr = sigchld_nop;
890 ACE_Sig_Action do_sigchld (reinterpret_cast<ACE_SignalHandler> (reinterpret_cast<void*> (sigchld_nop_ptr)));
891 do_sigchld.register_action (SIGCHLD, &old_action);
894 ACE_Time_Value tmo (timeout); // Need one we can change
895 for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ())
897 pid = ACE_OS::waitpid (-1, status, WNOHANG);
898 # if defined (ACE_VXWORKS)
899 if (pid > 0 || (pid == ACE_INVALID_PID && errno != EINTR))
900 # else
901 if (pid > 0 || pid == ACE_INVALID_PID)
902 # endif
903 break; // Got a child or an error - all done
905 // pid 0, nothing is ready yet, so wait.
906 // Do a sleep (only this thread sleeps) til something
907 // happens. This relies on SIGCHLD interrupting the sleep.
908 // If SIGCHLD isn't delivered, we'll need to do something
909 // with sigaction to force it.
910 if (-1 == ACE_OS::sleep (tmo) && errno == EINTR)
911 continue;
912 // Timed out
913 pid = 0;
914 break;
917 // Restore the previous SIGCHLD action if it was changed.
918 if (this->reactor () == 0)
919 old_action.register_action (SIGCHLD);
920 # endif /* !ACE_LACKS_UNIX_SIGNALS */
922 #endif /* !defined (ACE_WIN32) */
925 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
926 if (pid != ACE_INVALID_PID && pid != 0)
928 //we always need to get our id, because we could have been moved in the table meanwhile
929 idx = this->find_proc (pid);
930 if (idx == -1)
932 // oops, reaped an unmanaged process!
933 ACELIB_DEBUG ((LM_DEBUG,
934 ACE_TEXT ("(%P|%t) oops, reaped unmanaged %d\n"),
935 pid));
936 return pid;
938 else
939 proc = process_table_[idx].process_;
940 if (proc != 0)
941 ACE_ASSERT (pid == proc->getpid ());
943 this->notify_proc_handler (idx,
944 *status);
945 this->remove (pid);
948 return pid;
951 // Notify either the process-specific handler or the generic handler.
952 // If process-specific, call handle_close on the handler. Returns 1
953 // if process found, 0 if not. Must be called with locks held.
955 ACE_Process_Manager::notify_proc_handler (size_t i,
956 ACE_exitcode exit_code)
958 if (i < this->current_count_)
960 Process_Descriptor &proc_desc =
961 this->process_table_[i];
963 proc_desc.process_->exit_code (exit_code);
965 if (proc_desc.exit_notify_ != 0)
966 proc_desc.exit_notify_->handle_exit (proc_desc.process_);
967 else if (this->default_exit_handler_ != 0
968 && this->default_exit_handler_->handle_exit (proc_desc.process_) < 0)
970 this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE, 0);
971 this->default_exit_handler_ = 0;
973 return 1;
975 else
977 ACELIB_DEBUG ((LM_DEBUG,
978 ACE_TEXT ("(%P:%t|%T) ACE_Process_Manager::notify_proc_handler:")
979 ACE_TEXT (" unknown/unmanaged process reaped\n")));
980 return 0;
984 ACE_END_VERSIONED_NAMESPACE_DECL