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"
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
)
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
) :
49 if (this->procman_
.managed() > 0)
51 this->procman_
.wait(0, ACE_Time_Value(0, 25000));
55 ACE_OS::sleep (ACE_Time_Value(0, 25000));
64 return this->activate() == 0;
72 #endif /* ACE_WIN32 */
74 ImR_Activator_i::ImR_Activator_i ()
75 : registration_token_(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
;
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
);
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.)
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
);
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",
159 this->registration_token_
= locator_
->register_activator (name_
.c_str (), activator
);
162 ORBSVCS_DEBUG((LM_DEBUG
, "(%P|%t) ImR Activator: Registered with ImR\n"));
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
)
173 ex
._tao_print_exception ("ImR Activator: Can't register with ImR.");
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)
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 (),
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 ());
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 ();
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");
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 ());
256 catch (const CORBA::Exception
& ex
)
258 ex
._tao_print_exception ("ImR_Activator_i::init_with_orb");
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
);
282 ImR_Activator_i::fini ()
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
&)
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
&)
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");
324 this->orb_
->destroy ();
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");
338 ImR_Activator_i::run ()
345 ImR_Activator_i::shutdown ()
347 this->shutdown (false);
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
& )
366 ImR_Activator_i::shutdown (bool signaled
)
368 if (signaled
&& this->in_upcall ())
372 ORBSVCS_DEBUG ((LM_DEBUG
, "(%P|%t) ImR Activator: ignoring signal during upcall\n"));
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);
394 ImR_Activator_i::kill_server (const char* name
, CORBA::Long lastpid
, CORBA::Short signum
)
397 ORBSVCS_DEBUG((LM_DEBUG
,
398 "(%P|%t) ImR Activator: Killing server <%C>, lastpid <%d>\n",
400 pid_t
const lpid
= static_cast<pid_t
>(lastpid
);
404 for (ProcessMap::iterator iter
= process_map_
.begin();
405 !found
&& iter
!= process_map_
.end (); iter
++)
407 if (iter
->item () == name
)
413 if (!found
&& pid
== 0)
418 #if defined (ACE_WIN32)
419 found
= false; // sigchild apparently doesn't work on windows
424 #if !defined (ACE_WIN32)
425 (signum
!= 9) ? ACE_OS::kill (pid
, signum
) :
427 ACE::terminate_process (pid
);
429 if (this->running_server_list_
.remove (name
) == 0)
431 this->dying_server_list_
.insert (name
);
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 ());
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)
458 pid_t
const waitp
= this->process_mgr_
.wait (pt
, ACE_Time_Value::zero
);
459 is_running
= (waitp
!= pt
);
461 #endif /* ACE_WIN32 */
466 ImR_Activator_i::still_running_i (const char *name
, pid_t
&pid
)
468 bool is_running
= this->running_server_list_
.find (name
) == 0;
472 pid
= ACE_INVALID_PID
;
473 for (ProcessMap::ITERATOR iter
= this->process_map_
.begin ();
474 iter
!= process_map_
.end ();
477 if (ACE_OS::strcmp (name
, iter
->item ().c_str()) == 0)
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 */
496 ImR_Activator_i::start_server(const char* name
,
499 const ImplementationRepository::EnvironmentList
& env
)
502 if (ACE_OS::strlen (name
) > unique_prefix_len
&&
503 ACE_OS::strncmp (name
, unique_prefix
, unique_prefix_len
) == 0)
506 name
+= unique_prefix_len
;
511 ORBSVCS_DEBUG((LM_DEBUG
,
512 "(%P|%t) ImR Activator: Starting %C <%C>...\n",
513 (unique
? "unique server" : "server"), name
));
517 if (unique
&& this->still_running_i (name
, pid
))
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
)));
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
);
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 (
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"));
588 ORBSVCS_DEBUG((LM_DEBUG
,
589 "(%P|%t) ImR Activator: Register death handler for server <%C> pid <%d>\n",
591 static_cast<int> (pid
)));
593 this->process_map_
.rebind (pid
, name
);
596 this->running_server_list_
.insert (name
);
598 if (!CORBA::is_nil (this->locator_
.in ()))
600 if (this->notify_imr_
)
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
)
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"),
621 static_cast<int> (pid
)));
623 throw ImplementationRepository::CannotActivate(CORBA::string_dup ("Invocation of spawn_pid failed"));
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.
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 ()))
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
)
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"),
674 static_cast<int> (pid
)));
683 ImR_Activator_i::handle_exit (ACE_Process
* process
)
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
);
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 ());
712 this->handle_exit_i (process
->getpid());
713 #endif /* ACE_WIN32 */
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
));