Merge pull request #2309 from mitza-oci/warnings
[ACE_TAO.git] / TAO / orbsvcs / ImplRepo_Service / ImR_Activator_i.cpp
blob4b281396eb30388f35e6ada6e2c3aa875a626972
1 #include "orbsvcs/Log_Macros.h"
2 #include "ImR_Activator_i.h"
4 #include "Activator_Options.h"
6 #include "tao/ORB_Core.h"
8 #include "ace/Reactor.h"
9 #include "ace/ARGV.h"
10 #include "ace/OS_NS_unistd.h"
11 #include "ace/OS_NS_stdio.h"
12 #include "ace/OS_NS_signal.h"
14 #include "ace/os_include/os_netdb.h"
16 static const char *unique_prefix = "\001\002\003\004";
17 static size_t unique_prefix_len = 4;
19 static ACE_CString getHostName ()
21 char host_name[MAXHOSTNAMELEN];
22 ACE_OS::hostname (host_name, MAXHOSTNAMELEN);
23 return ACE_CString (host_name);
26 #if defined (ACE_WIN32)
27 Active_Pid_Setter::Active_Pid_Setter(ImR_Activator_i &owner, pid_t pid)
28 :owner_(owner)
30 owner_.active_check_pid_ = pid;
33 Active_Pid_Setter::~Active_Pid_Setter()
35 owner_.active_check_pid_ = ACE_INVALID_PID;
38 Watchdog::Watchdog(ACE_Process_Manager& procman) :
39 stop_(false),
40 procman_(procman)
44 int
45 Watchdog::svc()
47 while (!this->stop_)
49 if (this->procman_.managed() > 0)
51 this->procman_.wait(0, ACE_Time_Value(0, 25000));
53 else
55 ACE_OS::sleep (ACE_Time_Value(0, 25000));
58 return 0;
61 bool
62 Watchdog::start()
64 return this->activate() == 0;
66 void
67 Watchdog::stop()
69 this->stop_ = true;
70 this->wait();
72 #endif /* ACE_WIN32 */
74 ImR_Activator_i::ImR_Activator_i ()
75 : registration_token_(0)
76 , debug_(0)
77 , notify_imr_ (false)
78 , induce_delay_ (0)
79 , name_ (getHostName ())
80 , env_buf_len_ (Activator_Options::ENVIRONMENT_BUFFER)
81 , max_env_vars_ (Activator_Options::ENVIRONMENT_MAX_VARS)
82 , detach_child_ (false)
83 , active_check_pid_ (ACE_INVALID_PID)
84 #if defined (ACE_WIN32)
85 , process_watcher_ (process_mgr_)
86 #endif /* ACE_WIN32 */
90 static PortableServer::POA_ptr
91 createPersistentPOA (PortableServer::POA_ptr root_poa, const char* poa_name)
93 PortableServer::LifespanPolicy_var life =
94 root_poa->create_lifespan_policy (PortableServer::PERSISTENT);
96 PortableServer::IdAssignmentPolicy_var assign =
97 root_poa->create_id_assignment_policy (PortableServer::USER_ID);
99 CORBA::PolicyList pols;
100 pols.length (2);
101 pols[0] = PortableServer::LifespanPolicy::_duplicate (life.in ());
102 pols[1] = PortableServer::IdAssignmentPolicy::_duplicate (assign.in ());
104 PortableServer::POAManager_var mgr = root_poa->the_POAManager ();
105 PortableServer::POA_var poa =
106 root_poa->create_POA(poa_name, mgr.in (), pols);
108 life->destroy ();
109 assign->destroy ();
111 return poa._retn ();
114 // It's ok if we can't register with the ImR. It just
115 // means we won't be able to notify it of any events
116 // (Currently, just that we're shutting down and to
117 // notify of the ImR when a child process exits.)
118 void
119 ImR_Activator_i::register_with_imr (ImplementationRepository::Activator_ptr activator)
123 if (this->debug_ > 1)
124 ORBSVCS_DEBUG( (LM_DEBUG, "(%P|%t) ImR Activator: Contacting ImplRepoService...\n"));
126 #if defined (ACE_WIN32)
127 // On Windows the notify of a death of a child process requires the
128 // WFMO reactor which is not the default ORB reactor type so on
129 // Windows we are using a separate task to detect a child death
130 if (!this->process_watcher_.start ())
132 if (this->debug_ > 1)
134 ORBSVCS_ERROR ((LM_ERROR, "(%P|%t) ImR Activator: Failed to start process watchdog\n"));
138 this->process_mgr_.open (ACE_Process_Manager::DEFAULT_SIZE);
139 #else
140 this->process_mgr_.open (ACE_Process_Manager::DEFAULT_SIZE,
141 this->orb_->orb_core ()->reactor ());
142 #endif /* ACE_WIN32 */
144 // First, resolve the ImR, without this we can go no further
145 CORBA::Object_var obj =
146 orb_->resolve_initial_references ("ImplRepoService");
148 locator_ = ImplementationRepository::Locator::_narrow (obj.in ());
150 if (!CORBA::is_nil (locator_.in ()))
152 if (this->debug_ > 9)
154 CORBA::String_var ior = orb_->object_to_string (obj.in ());
155 ORBSVCS_DEBUG((LM_DEBUG, "(%P|%t) ImR Activator: ImplRepoService ior <%C>\n",
156 ior.in()));
159 this->registration_token_ = locator_->register_activator (name_.c_str (), activator);
161 if (debug_ > 0)
162 ORBSVCS_DEBUG((LM_DEBUG, "(%P|%t) ImR Activator: Registered with ImR\n"));
164 return;
166 else if (this->debug_ > 1)
167 ORBSVCS_DEBUG((LM_DEBUG, "(%P|%t) ImR Activator: ImplRepoService not found\n"));
169 catch (const CORBA::Exception& ex)
171 if (debug_ > 1)
173 ex._tao_print_exception ("ImR Activator: Can't register with ImR.");
177 if (debug_ > 0)
178 ORBSVCS_DEBUG ((LM_DEBUG, "(%P|%t) ImR Activator: Not registered with ImR\n"));
182 ImR_Activator_i::init_with_orb (CORBA::ORB_ptr orb, const Activator_Options& opts)
184 ACE_ASSERT(! CORBA::is_nil (orb));
185 orb_ = CORBA::ORB::_duplicate (orb);
186 debug_ = opts.debug ();
187 notify_imr_ = opts.notify_imr ();
188 induce_delay_ = opts.induce_delay ();
189 env_buf_len_ = opts.env_buf_len ();
190 max_env_vars_ = opts.max_env_vars ();
191 detach_child_ = opts.detach_child ();
193 if (opts.name ().length () > 0)
195 name_ = opts.name();
200 CORBA::Object_var obj = orb->resolve_initial_references ("RootPOA");
201 ACE_ASSERT (! CORBA::is_nil (obj.in ()));
202 this->root_poa_ = PortableServer::POA::_narrow (obj.in ());
203 ACE_ASSERT (! CORBA::is_nil(this->root_poa_.in ()));
205 // The activator must use a persistent POA so that it can be started before the
206 // locator in some scenarios, such as when the locator persists its database, and
207 // wants to reconnect to running activators to auto_start some servers.
208 this->imr_poa_ = createPersistentPOA (this->root_poa_.in (),
209 "ImR_Activator");
210 ACE_ASSERT (! CORBA::is_nil(this->imr_poa_.in ()));
212 obj = orb->resolve_initial_references ("POACurrent");
213 ACE_ASSERT (! CORBA::is_nil (obj.in ()));
214 this->current_ = PortableServer::Current::_narrow (obj.in ());
216 // Activate ourself
217 PortableServer::ObjectId_var id =
218 PortableServer::string_to_ObjectId ("ImR_Activator");
219 this->imr_poa_->activate_object_with_id (id.in (), this);
220 obj = this->imr_poa_->id_to_reference (id.in ());
221 ImplementationRepository::ActivatorExt_var activator =
222 ImplementationRepository::ActivatorExt::_narrow (obj.in ());
223 ACE_ASSERT(! CORBA::is_nil (activator.in ()));
225 CORBA::String_var ior = this->orb_->object_to_string (activator.in ());
227 if (this->debug_ > 0)
228 ORBSVCS_DEBUG((LM_DEBUG, "(%P|%t) ImR Activator: Starting <%C>\n", name_.c_str ()));
230 this->register_with_imr (activator.in ()); // no throw
232 PortableServer::POAManager_var poaman =
233 this->root_poa_->the_POAManager ();
234 poaman->activate ();
236 if (this->debug_ > 1)
238 ORBSVCS_DEBUG ((LM_DEBUG,
239 "(%P|%t) ImR Activator: The Activator IOR is: <%C>\n", ior.in ()));
242 // The last thing we do is write out the ior so that a test program can assume
243 // that the activator is ready to go as soon as the ior is written.
244 if (opts.ior_filename ().length () > 0)
246 FILE* fp = ACE_OS::fopen (opts.ior_filename ().c_str (), "w");
247 if (fp == 0)
249 ORBSVCS_ERROR_RETURN ((LM_ERROR,
250 "(%P|%t) ImR Activator: Could not open file <%s>\n", opts.ior_filename ().c_str ()), -1);
252 ACE_OS::fprintf (fp, "%s", ior.in ());
253 ACE_OS::fclose (fp);
256 catch (const CORBA::Exception& ex)
258 ex._tao_print_exception ("ImR_Activator_i::init_with_orb");
259 throw;
261 return 0;
265 ImR_Activator_i::init (Activator_Options& opts)
267 ACE_CString cmdline = opts.cmdline();
268 // Must use IOR style objrefs, because URLs sometimes get mangled when passed
269 // to ACE_Process::spawn().
270 cmdline += "-ORBUseImR 0 -ORBObjRefStyle IOR ";
271 ACE_ARGV av (ACE_TEXT_CHAR_TO_TCHAR (cmdline.c_str ()));
272 int argc = av.argc ();
274 CORBA::ORB_var orb = CORBA::ORB_init (argc, av.argv (), "TAO_ImR_Activator");
276 int const ret = this->init_with_orb(orb.in (), opts);
278 return ret;
282 ImR_Activator_i::fini ()
286 if (debug_ > 1)
287 ORBSVCS_DEBUG ((LM_DEBUG, "(%P|%t) ImR Activator: Shutting down...\n"));
289 #if defined (ACE_WIN32)
290 // Stop our process watcher task
291 this->process_watcher_.stop ();
292 #endif /* ACE_WIN32 */
294 this->process_mgr_.close ();
296 this->root_poa_->destroy (1, 1);
298 if (! CORBA::is_nil (this->locator_.in ()) && this->registration_token_ != 0)
300 this->locator_->unregister_activator (name_.c_str(),
301 this->registration_token_);
304 catch (const CORBA::COMM_FAILURE&)
306 if (debug_ > 1)
307 ORBSVCS_ERROR ((LM_ERROR,
308 ACE_TEXT ("(%P|%t) ImR Activator: COMM_FAILURE, unable to unregister from ImR\n")));
310 catch (const CORBA::TRANSIENT&)
312 if (debug_ > 1)
313 ORBSVCS_ERROR ((LM_ERROR,
314 ACE_TEXT ("(%P|%t) ImR Activator: TRANSIENT, unable to unregister from ImR\n")));
316 catch (const CORBA::Exception& ex)
318 ex._tao_print_exception ("ImR Activator: fini");
319 throw;
324 this->orb_->destroy ();
326 if (debug_ > 0)
327 ORBSVCS_DEBUG ((LM_DEBUG, "(%P|%t) ImR Activator: Shut down successfully\n"));
329 catch (const CORBA::Exception& ex)
331 ex._tao_print_exception ("ImR Activator: fini 2");
332 throw;
334 return 0;
338 ImR_Activator_i::run ()
340 this->orb_->run ();
341 return 0;
344 void
345 ImR_Activator_i::shutdown ()
347 this->shutdown (false);
350 bool
351 ImR_Activator_i::in_upcall ()
355 PortableServer::POA_var poa = current_->get_POA ();
356 return !CORBA::is_nil (poa.in ());
358 catch (const CORBA::Exception& )
360 // no-op
362 return false;
365 void
366 ImR_Activator_i::shutdown (bool signaled)
368 if (signaled && this->in_upcall ())
370 if (debug_ > 0)
372 ORBSVCS_DEBUG ((LM_DEBUG, "(%P|%t) ImR Activator: ignoring signal during upcall\n"));
374 return;
376 if (! CORBA::is_nil (this->locator_.in ()) && this->registration_token_ != 0)
380 this->locator_->unregister_activator (name_.c_str(),
381 this->registration_token_);
383 catch (const CORBA::Exception& )
385 // the locator may have already shutdown
388 this->locator_ = ImplementationRepository::Locator::_nil ();
390 this->orb_->shutdown (false);
393 CORBA::Boolean
394 ImR_Activator_i::kill_server (const char* name, CORBA::Long lastpid, CORBA::Short signum)
396 if (debug_ > 1)
397 ORBSVCS_DEBUG((LM_DEBUG,
398 "(%P|%t) ImR Activator: Killing server <%C>, lastpid <%d>\n",
399 name, lastpid));
400 pid_t const lpid = static_cast<pid_t>(lastpid);
401 pid_t pid = 0;
402 bool found = false;
403 int result = -1;
404 for (ProcessMap::iterator iter = process_map_.begin();
405 !found && iter != process_map_.end (); iter++)
407 if (iter->item () == name)
409 pid = iter->key ();
410 found = pid == lpid;
413 if (!found && pid == 0)
415 pid = lpid;
418 #if defined (ACE_WIN32)
419 found = false; // sigchild apparently doesn't work on windows
420 #endif
421 if (pid != 0)
423 result =
424 #if !defined (ACE_WIN32)
425 (signum != 9) ? ACE_OS::kill (pid, signum) :
426 #endif
427 ACE::terminate_process (pid);
429 if (this->running_server_list_.remove (name) == 0)
431 this->dying_server_list_.insert (name);
434 if (debug_ > 1)
435 ORBSVCS_DEBUG((LM_DEBUG,
436 "(%P|%t) ImR Activator: Killing server <%C> "
437 "signal <%d> to pid <%d> found <%d> this->notify_imr_ <%d> result <%d>\n",
438 name, signum, static_cast<int> (pid), found, this->notify_imr_, result));
439 if (!found && result == 0 && this->notify_imr_)
441 this->process_map_.bind (pid, name);
442 ACE_Reactor *r = this->orb_->orb_core()->reactor();
443 Act_token_type token = static_cast<Act_token_type>(pid);
444 r->schedule_timer (this, reinterpret_cast<void *>(token), ACE_Time_Value ());
447 return result == 0;
450 CORBA::Boolean
451 ImR_Activator_i::still_alive (CORBA::Long pid)
453 pid_t const pt = static_cast<pid_t>(pid);
454 bool is_running = this->process_map_.find (pt) == 0;
455 #if defined (ACE_WIN32)
456 if (is_running)
458 pid_t const waitp = this->process_mgr_.wait (pt, ACE_Time_Value::zero);
459 is_running = (waitp != pt);
461 #endif /* ACE_WIN32 */
462 return is_running;
465 bool
466 ImR_Activator_i::still_running_i (const char *name, pid_t &pid)
468 bool is_running = this->running_server_list_.find (name) == 0;
470 if (is_running)
472 pid = ACE_INVALID_PID;
473 for (ProcessMap::ITERATOR iter = this->process_map_.begin ();
474 iter != process_map_.end ();
475 iter++)
477 if (ACE_OS::strcmp (name, iter->item ().c_str()) == 0)
479 pid = iter->key ();
480 break;
483 #if defined (ACE_WIN32)
484 if (pid != ACE_INVALID_PID)
486 Active_Pid_Setter aps(*this, pid);
487 pid_t waitp = this->process_mgr_.wait (pid, ACE_Time_Value::zero);
488 is_running = (waitp != pid);
490 #endif /* ACE_WIN32 */
492 return is_running;
495 void
496 ImR_Activator_i::start_server(const char* name,
497 const char* cmdline,
498 const char* dir,
499 const ImplementationRepository::EnvironmentList & env)
501 bool unique = false;
502 if (ACE_OS::strlen (name) > unique_prefix_len &&
503 ACE_OS::strncmp (name, unique_prefix, unique_prefix_len) == 0)
505 unique = true;
506 name += unique_prefix_len;
509 if (debug_ > 0)
511 ORBSVCS_DEBUG((LM_DEBUG,
512 "(%P|%t) ImR Activator: Starting %C <%C>...\n",
513 (unique ? "unique server" : "server"), name));
516 pid_t pid;
517 if (unique && this->still_running_i (name, pid))
519 if (debug_ > 0)
521 ORBSVCS_ERROR((LM_ERROR,
522 "(%P|%t) ImR Activator: Unique instance for <%C> already running pid <%d>\n",
523 name, static_cast<int> (pid)));
525 char reason[32];
526 ACE_OS::snprintf (reason,32,"pid:%d",static_cast<int> (pid));
527 throw ImplementationRepository::CannotActivate(CORBA::string_dup (reason));
530 size_t const cmdline_buf_len = ACE_OS::strlen(cmdline);
531 if (debug_ > 0)
532 ORBSVCS_DEBUG((LM_DEBUG,
533 "(%P|%t) ImR Activator: command line len <%d> <%C> directory <%C>\n",
534 cmdline_buf_len, cmdline, dir) );
536 ACE_Process_Options proc_opts (
538 cmdline_buf_len + 1,
539 this->env_buf_len_, this->max_env_vars_);
540 proc_opts.command_line (ACE_TEXT("%") ACE_TEXT_PRIs, ACE_TEXT_CHAR_TO_TCHAR(cmdline));
541 proc_opts.working_directory (dir);
542 // Win32 does not support the CLOSE_ON_EXEC semantics for sockets
543 // the way unix does, so in order to avoid having the child process
544 // hold the listen socket open, we force the child to inherit no
545 // handles. This includes stdin, stdout, logs, etc.
546 proc_opts.handle_inheritance (0);
548 // We always enable the unicode environment buffer on Windows. This works
549 // around a 32kb environment buffer limitation. This must come before any of
550 // the setenv() calls, since the first of those will copy the current
551 // process's environment.
552 proc_opts.enable_unicode_environment ();
554 // Guard against possible signal reflection which can happen on very heavily
555 // loaded systems. Detaching the child process avoids that possibility but at
556 // the cost of required explicit child termination prior to activator shutdown
557 if (this->detach_child_)
559 proc_opts.setgroup (0);
562 proc_opts.setenv (ACE_TEXT ("TAO_USE_IMR"), ACE_TEXT ("1"));
563 if (!CORBA::is_nil (this->locator_.in ()))
565 CORBA::String_var ior = orb_->object_to_string (locator_.in ());
566 proc_opts.setenv (ACE_TEXT ("ImplRepoServiceIOR"),
567 ACE_TEXT("%") ACE_TEXT_PRIs, ACE_TEXT_CHAR_TO_TCHAR (ior.in ()));
570 for (CORBA::ULong i = 0; i < env.length (); ++i)
572 proc_opts.setenv (ACE_TEXT_CHAR_TO_TCHAR (env[i].name.in ()),
573 ACE_TEXT("%") ACE_TEXT_PRIs, ACE_TEXT_CHAR_TO_TCHAR (env[i].value.in ()));
576 pid = this->process_mgr_.spawn (proc_opts, this);
577 if (pid == ACE_INVALID_PID)
579 ORBSVCS_ERROR ((LM_ERROR,
580 "(%P|%t) ImR Activator: Cannot start server <%C> using <%C>\n", name, cmdline));
582 throw ImplementationRepository::CannotActivate(CORBA::string_dup ("Process Creation Failed"));
584 else
586 if (debug_ > 1)
588 ORBSVCS_DEBUG((LM_DEBUG,
589 "(%P|%t) ImR Activator: Register death handler for server <%C> pid <%d>\n",
590 name,
591 static_cast<int> (pid)));
593 this->process_map_.rebind (pid, name);
594 if (unique)
596 this->running_server_list_.insert (name);
598 if (!CORBA::is_nil (this->locator_.in ()))
600 if (this->notify_imr_)
602 if (debug_ > 1)
604 ORBSVCS_DEBUG ((LM_DEBUG,
605 ACE_TEXT ("(%P|%t) ImR Activator: Notifying ImR that ")
606 ACE_TEXT ("<%C> has started with pid <%d>\n"),
607 name, static_cast<int> (pid)));
611 this->locator_->spawn_pid (name, pid);
613 catch (const CORBA::Exception &ex)
615 if (debug_ > 1)
617 ex._tao_print_exception ("ImR_Activator_i::start_server");
618 ORBSVCS_ERROR ((LM_ERROR,
619 ACE_TEXT ("(%P|%t) ImR Activator: From locator::spawn_pid for server <%C> pid <%d>\n"),
620 name,
621 static_cast<int> (pid)));
623 throw ImplementationRepository::CannotActivate(CORBA::string_dup ("Invocation of spawn_pid failed"));
629 if (debug_ > 0)
631 ORBSVCS_DEBUG ((LM_DEBUG,
632 ACE_TEXT ("(%P|%t) ImR Activator: Successfully started <%C> pid <%d>\n"),
633 name, static_cast<int> (pid)));
638 ImR_Activator_i::handle_exit_i (pid_t pid)
640 // We use the process_manager so that we're notified when
641 // any of our launched processes die. We notify the locator
642 // when this happens.
643 ACE_CString name;
644 if (this->process_map_.find (pid, name) == 0)
646 this->process_map_.unbind (pid);
648 if (this->running_server_list_.remove (name) == -1)
650 this->dying_server_list_.remove (name);
653 if (this->notify_imr_ && !CORBA::is_nil (this->locator_.in ()))
655 if (debug_ > 1)
657 ORBSVCS_DEBUG ((LM_DEBUG,
658 ACE_TEXT ("(%P|%t) ImR Activator: Notifying ImR that ")
659 ACE_TEXT ("server <%C> pid <%d> has exited.\n"),
660 name.c_str(), static_cast<int> (pid)));
664 this->locator_->child_death_pid (name.c_str(), pid);
666 catch (const CORBA::Exception &ex)
668 if (debug_ > 1)
670 ex._tao_print_exception ("ImR_Activator_i::handle_exit_i");
671 ORBSVCS_ERROR ((LM_ERROR,
672 ACE_TEXT ("(%P|%t) ImR Activator: from locator::child_death_pid for server <%C> pid <%d>\n"),
673 name.c_str (),
674 static_cast<int> (pid)));
679 return 0;
683 ImR_Activator_i::handle_exit (ACE_Process * process)
685 if (debug_ > 0)
687 ORBSVCS_DEBUG
688 ((LM_DEBUG,
689 ACE_TEXT ("(%P|%t) ImR Activator: Process %d exited with exit code %d, delay = %d\n"),
690 process->getpid (), process->return_value (), this->induce_delay_));
693 if (this->induce_delay_ > 0 && this->active_check_pid_ == ACE_INVALID_PID)
695 ACE_Reactor *r = this->orb_->orb_core()->reactor();
696 ACE_Time_Value dtv (0, this->induce_delay_ * 1000);
697 pid_t const pid = process->getpid();
698 Act_token_type token = static_cast<Act_token_type>(pid);
699 r->schedule_timer (this, reinterpret_cast<void *>(token), dtv);
701 else
703 #if defined (ACE_WIN32)
704 // On Windows this is called from the context of the watchdog thread
705 // so we are using the reactor here to trigger a thread switch so that
706 // handle_exit_i is called from the reactor thread
707 ACE_Reactor *r = this->orb_->orb_core ()->reactor ();
708 pid_t const pid = process->getpid ();
709 Act_token_type token = static_cast<Act_token_type>(pid);
710 r->schedule_timer (this, reinterpret_cast<void *>(token), ACE_Time_Value ());
711 #else
712 this->handle_exit_i (process->getpid());
713 #endif /* ACE_WIN32 */
715 return 0;
719 ImR_Activator_i::handle_timeout (const ACE_Time_Value &, const void * tok)
721 Act_token_type token = reinterpret_cast<Act_token_type>(tok);
722 this->handle_exit_i (static_cast<pid_t>(token));
723 return 0;