summaryrefslogtreecommitdiff
path: root/TAO/orbsvcs/LoadBalancer
diff options
context:
space:
mode:
authorWilliam R. Otte <wotte@dre.vanderbilt.edu>2006-07-24 15:50:21 +0000
committerWilliam R. Otte <wotte@dre.vanderbilt.edu>2006-07-24 15:50:21 +0000
commit3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c (patch)
tree197c810e5f5bce17b1233a7cb8d7b50c0bcd25e2 /TAO/orbsvcs/LoadBalancer
parent6b846cf03c0bcbd8c276cb0af61a181e5f98eaae (diff)
downloadATCD-3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c.tar.gz
Repo restructuring
Diffstat (limited to 'TAO/orbsvcs/LoadBalancer')
-rw-r--r--TAO/orbsvcs/LoadBalancer/.cvsignore2
-rw-r--r--TAO/orbsvcs/LoadBalancer/LoadBalancer.mpc24
-rw-r--r--TAO/orbsvcs/LoadBalancer/LoadManager.cpp310
-rw-r--r--TAO/orbsvcs/LoadBalancer/LoadMonitor.cpp417
-rw-r--r--TAO/orbsvcs/LoadBalancer/Makefile.am117
-rw-r--r--TAO/orbsvcs/LoadBalancer/Monitor_Signal_Handler.cpp51
-rw-r--r--TAO/orbsvcs/LoadBalancer/Monitor_Signal_Handler.h62
-rw-r--r--TAO/orbsvcs/LoadBalancer/Push_Handler.cpp57
-rw-r--r--TAO/orbsvcs/LoadBalancer/Push_Handler.h66
-rw-r--r--TAO/orbsvcs/LoadBalancer/README183
-rw-r--r--TAO/orbsvcs/LoadBalancer/Signal_Handler.cpp147
-rw-r--r--TAO/orbsvcs/LoadBalancer/Signal_Handler.h100
12 files changed, 1536 insertions, 0 deletions
diff --git a/TAO/orbsvcs/LoadBalancer/.cvsignore b/TAO/orbsvcs/LoadBalancer/.cvsignore
new file mode 100644
index 00000000000..11ebf643a83
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/.cvsignore
@@ -0,0 +1,2 @@
+LoadManager
+LoadMonitor
diff --git a/TAO/orbsvcs/LoadBalancer/LoadBalancer.mpc b/TAO/orbsvcs/LoadBalancer/LoadBalancer.mpc
new file mode 100644
index 00000000000..2574a799cfd
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/LoadBalancer.mpc
@@ -0,0 +1,24 @@
+// -*- MPC -*-
+//
+// $Id$
+
+
+project(LoadManager): namingexe, portableserver, core, iortable, iormanip, loadbalancing {
+ exename = LoadManager
+ requires += ami interceptors
+ Source_Files {
+ LoadManager.cpp
+ Signal_Handler.cpp
+ }
+}
+
+project(LoadMonitor): namingexe, portableserver, core, loadbalancing {
+ requires += ami interceptors
+ exename = LoadMonitor
+ Source_Files {
+ LoadMonitor.cpp
+ Push_Handler.cpp
+ Monitor_Signal_Handler.cpp
+ Signal_Handler.cpp
+ }
+}
diff --git a/TAO/orbsvcs/LoadBalancer/LoadManager.cpp b/TAO/orbsvcs/LoadBalancer/LoadManager.cpp
new file mode 100644
index 00000000000..b95c5ca9c6b
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/LoadManager.cpp
@@ -0,0 +1,310 @@
+#include "Signal_Handler.h"
+
+#include "orbsvcs/LoadBalancing/LB_LoadManager.h"
+
+#include "tao/ORB_Core.h"
+
+#include "ace/Get_Opt.h"
+#include "ace/OS_main.h"
+#include "ace/OS_NS_strings.h"
+
+#include "tao/IORTable/IORTable.h"
+
+#if defined (linux) && defined (ACE_HAS_THREADS)
+# include "ace/Signal.h"
+#endif /* linux && ACE_HAS_THREADS */
+
+
+ACE_RCSID (LoadBalancer,
+ LoadBalancer,
+ "$Id$")
+
+
+static const char * lm_ior_file = "lm.ior";
+
+void
+usage (const ACE_TCHAR * cmd)
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Usage:\n")
+ ACE_TEXT (" %s\n")
+ ACE_TEXT (" -o <ior_output_file>\n")
+ ACE_TEXT (" -s <RoundRobin | Random | LeastLoaded>\n")
+ ACE_TEXT (" -h\n")
+ ACE_TEXT ("\n")
+ ACE_TEXT (" NOTE: Standard default values will be used ")
+ ACE_TEXT ("for \"LeastLoaded\" strategy.\n"),
+ cmd));
+}
+
+void
+parse_args (int argc,
+ ACE_TCHAR *argv[],
+ int & default_strategy
+ ACE_ENV_ARG_DECL)
+{
+ ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("o:s:h"));
+
+ int c = 0;
+
+ while ((c = get_opts ()) != -1)
+ {
+ switch (c)
+ {
+ case 'o':
+ ::lm_ior_file = get_opts.opt_arg ();
+ break;
+
+ case 's':
+ if (ACE_OS::strcasecmp (get_opts.opt_arg (),
+ "RoundRobin") == 0)
+ default_strategy = 0;
+ else if (ACE_OS::strcasecmp (get_opts.opt_arg (),
+ "Random") == 0)
+ default_strategy = 1;
+ else if (ACE_OS::strcasecmp (get_opts.opt_arg (),
+ "LeastLoaded") == 0)
+ default_strategy = 2;
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Unknown strategy, using RoundRobin\n")));
+ break;
+
+ case 'h':
+ ::usage (argv[0]);
+ ACE_OS::exit (0);
+ break;
+
+ default:
+ ::usage (argv[0]);
+ ACE_THROW (CORBA::BAD_PARAM ());
+ }
+ }
+}
+
+#if defined (linux) && defined (ACE_HAS_THREADS)
+// Only the main thread can handle signals in Linux. Run the
+// LoadManager in thread other than main().
+extern "C"
+void *
+TAO_LB_run_load_manager (void * orb_arg)
+{
+ CORBA::ORB_ptr orb = static_cast<CORBA::ORB_ptr> (orb_arg);
+
+ // Only the main thread should handle signals.
+ //
+ // @@ This is probably unnecessary since no signals should be
+ // delivered to this thread on Linux.
+ ACE_Sig_Guard signal_guard;
+
+ ACE_DECLARE_NEW_CORBA_ENV;
+ ACE_TRY
+ {
+ orb->run (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ ACE_CATCHANY
+ {
+ ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION,
+ "TAO Load Manager");
+
+ return reinterpret_cast<void *> (-1);
+ }
+ ACE_ENDTRY;
+ ACE_CHECK_RETURN (reinterpret_cast<void *> (-1));
+
+ return 0;
+}
+#endif /* linux && ACE_HAS_THREADS */
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_DECLARE_NEW_CORBA_ENV;
+ ACE_TRY
+ {
+ // The usual server side boilerplate code.
+
+ CORBA::ORB_var orb = CORBA::ORB_init (argc,
+ argv,
+ ""
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CORBA::Object_var obj =
+ orb->resolve_initial_references ("RootPOA"
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ PortableServer::POA_var root_poa =
+ PortableServer::POA::_narrow (obj.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ PortableServer::POAManager_var poa_manager =
+ root_poa->the_POAManager (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ poa_manager->activate (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ // "built-in" strategies are the following:
+ // 0 = RoundRobin
+ // 1 = Random
+ // 2 = LeastLoaded
+ int default_strategy = 1;
+
+ // Check the non-ORB arguments.
+ ::parse_args (argc,
+ argv,
+ default_strategy
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ TAO_LB_LoadManager * lm = 0;
+ ACE_NEW_THROW_EX (lm,
+ TAO_LB_LoadManager,
+ CORBA::NO_MEMORY (
+ CORBA::SystemException::_tao_minor_code (
+ TAO::VMCID,
+ ENOMEM),
+ CORBA::COMPLETED_NO));
+ ACE_TRY_CHECK;
+
+ PortableServer::ServantBase_var safe_lm = lm;
+
+ // Initalize the LoadManager servant.
+ lm->init (orb->orb_core ()->reactor (),
+ orb.in (),
+ root_poa.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ PortableGroup::Properties props (1);
+ props.length (1);
+ props[0].nam.length (1);
+ props[0].nam[0].id =
+ CORBA::string_dup ("org.omg.CosLoadBalancing.StrategyInfo");
+
+ CosLoadBalancing::StrategyInfo strategy_info;
+
+ switch (default_strategy)
+ {
+ case 0:
+ strategy_info.name = CORBA::string_dup ("RoundRobin");
+ break;
+ case 1:
+ strategy_info.name = CORBA::string_dup ("Random");
+ break;
+ case 2:
+ strategy_info.name = CORBA::string_dup ("LeastLoaded");
+ break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("ERROR: LoadBalancer internal error.\n")
+ ACE_TEXT (" Unknown built-in strategy.\n")),
+ -1);
+ }
+
+ props[0].val <<= strategy_info;
+
+ lm->set_default_properties (props
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosLoadBalancing::LoadManager_var load_manager =
+ lm->_this (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CORBA::String_var str =
+ orb->object_to_string (load_manager.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ // to support corbaloc
+ // Get a reference to the IOR table.
+ CORBA::Object_var tobj = orb->resolve_initial_references ("IORTable"
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ IORTable::Table_var table = IORTable::Table::_narrow (tobj.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ // bind your stringified IOR in the IOR table
+ table->bind ("LoadManager", str.in () ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ FILE * lm_ior = ACE_OS::fopen (lm_ior_file, "w");
+ ACE_OS::fprintf (lm_ior, "%s", str.in ());
+ ACE_OS::fclose (lm_ior);
+
+#if defined (linux) && defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn (::TAO_LB_run_load_manager,
+ orb.in ()) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "ERROR: Unable to spawn TAO LoadManager's "
+ "ORB thread.\n"),
+ -1);
+ }
+
+ ACE_Sig_Set sigset;
+ sigset.sig_add (SIGINT);
+ sigset.sig_add (SIGTERM);
+
+ int signum = -1;
+
+ // Block waiting for the registered signals.
+ if (ACE_OS::sigwait (sigset, &signum) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%P|%t) %p\n",
+ "ERROR waiting on signal"),
+ -1);
+ }
+
+ ACE_ASSERT (signum == SIGINT || signum == SIGTERM);
+#else
+ // Activate/register the signal handler that (attempts) to
+ // ensure graceful shutdown of the LoadManager so that remote
+ // resources created by the LoadManager can be cleaned up.
+ TAO_LB_Signal_Handler signal_handler (orb.in (), root_poa.in ());
+
+ if (signal_handler.activate () != 0)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Error: can't activate LB signal handler, exiting.\n"),
+ -1);
+ }
+
+ // @@ There is a subtle race condition here. If the signal
+ // handler thread shuts down the ORB before it is run, the
+ // below call to ORB::run() will throw a CORBA::BAD_INV_ORDER
+ // exception.
+ orb->run (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ // Wait for the signal handler thread to finish
+ // before the process exits.
+ signal_handler.wait ();
+#endif /* linux && ACE_HAS_THREADS */
+
+ orb->destroy (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+// ACE_CATCH (PortableGroup::InvalidProperty, ex)
+// {
+// ACE_DEBUG ((LM_DEBUG, "Property ----> %s\n", ex.nam[0].id.in ()));
+// }
+ ACE_CATCHANY
+ {
+ ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION,
+ "TAO Load Manager");
+
+ return -1;
+ }
+ ACE_ENDTRY;
+
+ return 0;
+}
diff --git a/TAO/orbsvcs/LoadBalancer/LoadMonitor.cpp b/TAO/orbsvcs/LoadBalancer/LoadMonitor.cpp
new file mode 100644
index 00000000000..b0bb0a36701
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/LoadMonitor.cpp
@@ -0,0 +1,417 @@
+#include "Push_Handler.h"
+#include "Monitor_Signal_Handler.h"
+
+#include "orbsvcs/LoadBalancing/LB_CPU_Load_Average_Monitor.h"
+#include "orbsvcs/LoadBalancing/LB_conf.h"
+
+#include "tao/ORB_Core.h"
+
+#include "ace/Reactor.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_main.h"
+#include "ace/OS_NS_strings.h"
+
+
+ACE_RCSID (LoadBalancer,
+ LoadMonitor,
+ "$Id$")
+
+
+static const char * location_id = 0;
+static const char * location_kind = 0;
+static const char * mtype = "CPU";
+static const char * mstyle = "PUSH";
+static const char * custom_monitor_ior = 0;
+
+// For the sake of consistency, make default push monitoring interval
+// the same as the pull monitoring interval.
+static long push_interval = TAO_LB_PULL_HANDLER_INTERVAL;
+
+void
+usage (const ACE_TCHAR * cmd)
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Usage:\n")
+ ACE_TEXT (" %s\n")
+ ACE_TEXT (" -l <location_id>\n")
+ ACE_TEXT (" -k <location_kind>\n")
+ ACE_TEXT (" -t <CPU | Disk | Memory | Network>\n")
+ ACE_TEXT (" -s <PULL | PUSH>\n")
+ ACE_TEXT (" -i <push_interval> (in seconds,")
+ ACE_TEXT (" and requires \"PUSH\" style monitoring)\n")
+ ACE_TEXT (" -m <custom_monitor_ior>")
+ ACE_TEXT (" (overrides \"-t\", \"-l\" and \"-k\")\n")
+ ACE_TEXT (" -h\n")
+ ACE_TEXT ("\n"),
+ cmd));
+}
+
+void
+parse_args (int argc,
+ ACE_TCHAR *argv[]
+ ACE_ENV_ARG_DECL)
+{
+ ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("l:k:t:s:i:m:h"));
+
+ int c = 0;
+ const char * s;
+
+ while ((c = get_opts ()) != -1)
+ {
+ switch (c)
+ {
+ case 'm':
+ ::custom_monitor_ior = get_opts.opt_arg ();
+ break;
+
+ case 'l':
+ ::location_id = get_opts.opt_arg ();
+ break;
+
+ case 'k':
+ ::location_kind = get_opts.opt_arg ();
+ break;
+
+ case 't':
+ ::mtype = get_opts.opt_arg ();
+ break;
+
+ case 's':
+ ::mstyle = get_opts.opt_arg ();
+ break;
+
+ case 'i':
+ s = get_opts.opt_arg ();
+ push_interval = ACE_OS::atoi (s);
+ if (push_interval < 1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ERROR: Invalid push interval: %s\n"),
+ s));
+
+ ACE_THROW (CORBA::BAD_PARAM ());
+ }
+ break;
+
+ case 'h':
+ ::usage (argv[0]);
+ ACE_OS::exit (0);
+ break;
+
+ default:
+ ::usage (argv[0]);
+ ACE_THROW (CORBA::BAD_PARAM ());
+ }
+ }
+}
+
+#if defined (linux) && defined (ACE_HAS_THREADS)
+// Only the main thread can handle signals in Linux. Run the
+// LoadManager in thread other than main().
+extern "C"
+void *
+TAO_LB_run_load_monitor (void * orb_arg)
+{
+ CORBA::ORB_ptr orb = static_cast<CORBA::ORB_ptr> (orb_arg);
+
+ // Only the main thread should handle signals.
+ //
+ // @@ This is probably unnecessary since no signals should be
+ // delivered to this thread on Linux.
+ ACE_Sig_Guard signal_guard;
+
+ ACE_DECLARE_NEW_CORBA_ENV;
+ ACE_TRY
+ {
+ orb->run (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ ACE_CATCHANY
+ {
+ ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION,
+ "TAO Load Monitor");
+
+ return reinterpret_cast<void *> (-1);
+ }
+ ACE_ENDTRY;
+ ACE_CHECK_RETURN (reinterpret_cast<void *> (-1));
+
+ return 0;
+}
+#endif /* linux && ACE_HAS_THREADS */
+
+
+CosLoadBalancing::LoadMonitor_ptr
+get_load_monitor (CORBA::ORB_ptr orb,
+ PortableServer::POA_ptr root_poa
+ ACE_ENV_ARG_DECL)
+{
+ if (::custom_monitor_ior != 0)
+ {
+ CORBA::Object_var obj =
+ orb->string_to_object (::custom_monitor_ior
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CosLoadBalancing::LoadMonitor::_nil ());
+
+ return CosLoadBalancing::LoadMonitor::_narrow (obj.in ()
+ ACE_ENV_ARG_PARAMETER);
+ }
+ else
+ {
+ // The POA is only needed for the built-in load monitors since
+ // they must be activated.
+ PortableServer::POAManager_var poa_manager =
+ root_poa->the_POAManager (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CosLoadBalancing::LoadMonitor::_nil ());
+
+ poa_manager->activate (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CosLoadBalancing::LoadMonitor::_nil ());
+
+ if (ACE_OS::strcasecmp (::mtype, "CPU") == 0)
+ {
+ TAO_LB_CPU_Load_Average_Monitor * monitor = 0;
+ ACE_NEW_THROW_EX (monitor,
+ TAO_LB_CPU_Load_Average_Monitor (::location_id,
+ ::location_kind),
+ CORBA::NO_MEMORY ());
+ ACE_CHECK_RETURN (CosLoadBalancing::LoadMonitor::_nil ());
+
+ // Transfer ownership to the POA.
+ PortableServer::ServantBase_var s = monitor;
+
+ return monitor->_this (ACE_ENV_SINGLE_ARG_PARAMETER);
+ }
+ else if (ACE_OS::strcasecmp (::mtype, "Disk") == 0
+ || ACE_OS::strcasecmp (::mtype, "Memory") == 0
+ || ACE_OS::strcasecmp (::mtype, "Network") == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ERROR: \"%s\" load monitor currently ")
+ ACE_TEXT ("unimplemented.\n"),
+ ::mtype));
+
+ ACE_THROW_RETURN (CORBA::NO_IMPLEMENT (),
+ CosLoadBalancing::LoadMonitor::_nil ());
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ERROR: Unrecognized built-in load monitor ")
+ ACE_TEXT ("type: <%s>.\n"),
+ ::mtype));
+
+ ACE_THROW_RETURN (CORBA::BAD_PARAM (),
+ CosLoadBalancing::LoadMonitor::_nil ());
+ }
+ }
+}
+
+void
+register_load_monitor (CosLoadBalancing::LoadManager_ptr manager,
+ CosLoadBalancing::LoadMonitor_ptr monitor,
+ TAO_LB_Push_Handler * handler,
+ ACE_Reactor * reactor,
+ long & timer_id
+ ACE_ENV_ARG_DECL)
+{
+ if (ACE_OS::strcasecmp (::mstyle, "PULL") == 0)
+ {
+ PortableGroup::Location_var location =
+ monitor->the_location (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+
+ manager->register_load_monitor (location.in (),
+ monitor
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ else if (ACE_OS::strcasecmp (::mstyle, "PUSH") == 0)
+ {
+ ACE_Time_Value interval (::push_interval, 0);
+ ACE_Time_Value restart (::push_interval, 0);
+ timer_id = reactor->schedule_timer (handler,
+ 0,
+ interval,
+ restart);
+
+ if (timer_id == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ERROR: Unable to schedule timer for ")
+ ACE_TEXT ("\"PUSH\" style load monitoring.\n")));
+
+ ACE_THROW (CORBA::INTERNAL ());
+ }
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ERROR: Unrecognized load monitoring ")
+ ACE_TEXT ("style: <%s>.\n"),
+ ::mstyle));
+
+ ACE_THROW (CORBA::BAD_PARAM ());
+ }
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_DECLARE_NEW_CORBA_ENV;
+ ACE_TRY
+ {
+ // The usual server side boilerplate code.
+
+ CORBA::ORB_var orb = CORBA::ORB_init (argc,
+ argv,
+ ""
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ // Check the non-ORB arguments.
+ ::parse_args (argc,
+ argv
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CORBA::Object_var obj =
+ orb->resolve_initial_references ("RootPOA"
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ PortableServer::POA_var root_poa =
+ PortableServer::POA::_narrow (obj.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosLoadBalancing::LoadMonitor_var load_monitor =
+ ::get_load_monitor (orb.in (),
+ root_poa.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ PortableGroup::Location_var location =
+ load_monitor->the_location (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ // The "LoadManager" reference should have already been
+ // registered with the ORB by its ORBInitializer.
+ obj = orb->resolve_initial_references ("LoadManager"
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosLoadBalancing::LoadManager_var load_manager =
+ CosLoadBalancing::LoadManager::_narrow (obj.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ // This "push" handler will only be used if the load monitor
+ // style is "PUSH".
+ TAO_LB_Push_Handler push_handler (load_monitor.in (),
+ location.in (),
+ load_manager.in ());
+
+ ACE_Reactor * reactor = orb->orb_core ()->reactor ();
+
+ long timer_id = -1;
+
+ ::register_load_monitor (load_manager.in (),
+ load_monitor.in (),
+ &push_handler,
+ reactor,
+ timer_id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosLoadBalancing::LoadManager_ptr tmp;;
+
+ if (timer_id == -1)
+ tmp = load_manager.in (); // PULL monitoring
+ else
+ tmp = CosLoadBalancing::LoadManager::_nil (); // PUSH
+ // monitoring
+
+#if defined (linux) && defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn (::TAO_LB_run_load_monitor,
+ orb.in ()) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "ERROR: Unable to spawn TAO LoadMonitor's "
+ "ORB thread.\n"),
+ -1);
+ }
+
+ ACE_Sig_Set sigset;
+ sigset.sig_add (SIGINT);
+ sigset.sig_add (SIGTERM);
+
+ int signum = -1;
+
+ // Block waiting for the registered signals.
+ if (ACE_OS::sigwait (sigset, &signum) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%P|%t) %p\n",
+ "ERROR waiting on signal"),
+ -1);
+ }
+
+ ACE_ASSERT (signum == SIGINT || signum == SIGTERM);
+
+ // Deregister the LoadMonitor from the LoadManager in the PULL
+ // load monitoring case.
+ if (timer_id == -1)
+ {
+ load_manager->remove_load_monitor (location.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+#else
+ // Activate/register the signal handler that (attempts) to
+ // ensure graceful shutdown of the LoadMonitor so that
+ // LoadMonitors registered with the LoadManager can be
+ // deregistered.
+ TAO_LB_Monitor_Signal_Handler signal_handler (
+ orb.in (),
+ root_poa.in (),
+ tmp,
+ location.in ());
+
+ if (signal_handler.activate () != 0)
+ return -1;
+
+ // @@ There is a subtle race condition here. If the signal
+ // handler thread shuts down the ORB before it is run, the
+ // below call to ORB::run() will throw a CORBA::BAD_INV_ORDER
+ // exception.
+ orb->run (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ // Wait for the signal handler thread to finish
+ // before the process exits.
+ signal_handler.wait ();
+#endif /* linux && ACE_HAS_THREADS */
+
+ if (timer_id != -1 && reactor->cancel_timer (timer_id) == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ERROR: Unable to cancel \"push\" load ")
+ ACE_TEXT ("monitoring timer.\n")));
+
+ // Just keep going. We're shutting down anyway.
+ }
+
+ orb->destroy (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ ACE_CATCHANY
+ {
+ ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION,
+ "TAO Load Monitor");
+
+ return -1;
+ }
+ ACE_ENDTRY;
+
+ return 0;
+}
diff --git a/TAO/orbsvcs/LoadBalancer/Makefile.am b/TAO/orbsvcs/LoadBalancer/Makefile.am
new file mode 100644
index 00000000000..4956f9d2aa2
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/Makefile.am
@@ -0,0 +1,117 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## ../bin/mwc.pl -type automake -noreldefs TAO.mwc
+
+ACE_BUILDDIR = $(top_builddir)/..
+ACE_ROOT = $(top_srcdir)/..
+TAO_BUILDDIR = $(top_builddir)
+TAO_ROOT = $(top_srcdir)
+
+bin_PROGRAMS =
+
+## Makefile.LoadManager.am
+
+if BUILD_AMI
+if BUILD_CORBA_MESSAGING
+if BUILD_INTERCEPTORS
+if !BUILD_MINIMUM_CORBA
+
+bin_PROGRAMS += LoadManager
+
+LoadManager_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -I$(TAO_ROOT) \
+ -I$(TAO_BUILDDIR) \
+ -I$(TAO_ROOT)/orbsvcs \
+ -I$(TAO_BUILDDIR)/orbsvcs
+
+LoadManager_SOURCES = \
+ LoadManager.cpp \
+ Signal_Handler.cpp \
+ Signal_Handler.h
+
+LoadManager_LDADD = \
+ $(TAO_BUILDDIR)/orbsvcs/orbsvcs/libTAO_CosLoadBalancing.la \
+ $(TAO_BUILDDIR)/tao/libTAO_IORInterceptor.la \
+ $(TAO_BUILDDIR)/tao/libTAO_ObjRefTemplate.la \
+ $(TAO_BUILDDIR)/tao/libTAO_PI_Server.la \
+ $(TAO_BUILDDIR)/orbsvcs/orbsvcs/libTAO_PortableGroup.la \
+ $(TAO_BUILDDIR)/tao/libTAO_Messaging.la \
+ $(TAO_BUILDDIR)/tao/libTAO_PI.la \
+ $(TAO_BUILDDIR)/tao/libTAO_CodecFactory.la \
+ $(TAO_BUILDDIR)/tao/libTAO_Valuetype.la \
+ $(TAO_BUILDDIR)/tao/libTAO_IORManip.la \
+ $(TAO_BUILDDIR)/tao/libTAO_IORTable.la \
+ $(TAO_BUILDDIR)/tao/libTAO_PortableServer.la \
+ $(TAO_BUILDDIR)/orbsvcs/orbsvcs/libTAO_CosNaming.la \
+ $(TAO_BUILDDIR)/tao/libTAO_AnyTypeCode.la \
+ $(TAO_BUILDDIR)/tao/libTAO.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_MINIMUM_CORBA
+endif BUILD_INTERCEPTORS
+endif BUILD_CORBA_MESSAGING
+endif BUILD_AMI
+
+## Makefile.LoadMonitor.am
+
+if BUILD_AMI
+if BUILD_CORBA_MESSAGING
+if BUILD_INTERCEPTORS
+if !BUILD_MINIMUM_CORBA
+
+bin_PROGRAMS += LoadMonitor
+
+LoadMonitor_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -I$(TAO_ROOT) \
+ -I$(TAO_BUILDDIR) \
+ -I$(TAO_ROOT)/orbsvcs \
+ -I$(TAO_BUILDDIR)/orbsvcs
+
+LoadMonitor_SOURCES = \
+ LoadMonitor.cpp \
+ Monitor_Signal_Handler.cpp \
+ Push_Handler.cpp \
+ Signal_Handler.cpp \
+ Monitor_Signal_Handler.h \
+ Push_Handler.h \
+ Signal_Handler.h
+
+LoadMonitor_LDADD = \
+ $(TAO_BUILDDIR)/orbsvcs/orbsvcs/libTAO_CosLoadBalancing.la \
+ $(TAO_BUILDDIR)/tao/libTAO_IORInterceptor.la \
+ $(TAO_BUILDDIR)/tao/libTAO_ObjRefTemplate.la \
+ $(TAO_BUILDDIR)/tao/libTAO_PI_Server.la \
+ $(TAO_BUILDDIR)/orbsvcs/orbsvcs/libTAO_PortableGroup.la \
+ $(TAO_BUILDDIR)/tao/libTAO_IORManip.la \
+ $(TAO_BUILDDIR)/tao/libTAO_Messaging.la \
+ $(TAO_BUILDDIR)/tao/libTAO_PI.la \
+ $(TAO_BUILDDIR)/tao/libTAO_CodecFactory.la \
+ $(TAO_BUILDDIR)/tao/libTAO_Valuetype.la \
+ $(TAO_BUILDDIR)/tao/libTAO_PortableServer.la \
+ $(TAO_BUILDDIR)/orbsvcs/orbsvcs/libTAO_CosNaming.la \
+ $(TAO_BUILDDIR)/tao/libTAO_AnyTypeCode.la \
+ $(TAO_BUILDDIR)/tao/libTAO.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_MINIMUM_CORBA
+endif BUILD_INTERCEPTORS
+endif BUILD_CORBA_MESSAGING
+endif BUILD_AMI
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/TAO/orbsvcs/LoadBalancer/Monitor_Signal_Handler.cpp b/TAO/orbsvcs/LoadBalancer/Monitor_Signal_Handler.cpp
new file mode 100644
index 00000000000..3153f62e98a
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/Monitor_Signal_Handler.cpp
@@ -0,0 +1,51 @@
+#include "Monitor_Signal_Handler.h"
+
+
+ACE_RCSID (LoadBalancer,
+ Monitor_Signal_Handler,
+ "$Id$")
+
+
+TAO_LB_Monitor_Signal_Handler::TAO_LB_Monitor_Signal_Handler (
+ CORBA::ORB_ptr orb,
+ PortableServer::POA_ptr poa,
+ CosLoadBalancing::LoadManager_ptr load_manager,
+ const PortableGroup::Location & location)
+ : TAO_LB_Signal_Handler (orb, poa),
+ load_manager_ (CosLoadBalancing::LoadManager::_duplicate (load_manager)),
+ location_ (location)
+{
+}
+
+
+int
+TAO_LB_Monitor_Signal_Handler::perform_cleanup (int signum)
+{
+ ACE_DECLARE_NEW_CORBA_ENV;
+ ACE_TRY
+ {
+ // Deregister the LoadMonitor from the LoadManager in the PULL
+ // load monitoring case.
+ if (!CORBA::is_nil (this->load_manager_.in ()))
+ {
+ this->load_manager_->remove_load_monitor (this->location_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ }
+ ACE_CATCHANY
+ {
+ ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION,
+ "Caught exception");
+
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Problem during LoadMonitor cleanup "
+ "initiated by signal %d.\n",
+ signum),
+ -1);
+ }
+ ACE_ENDTRY;
+ ACE_CHECK_RETURN (-1);
+
+ return this->TAO_LB_Signal_Handler::perform_cleanup (signum);
+}
diff --git a/TAO/orbsvcs/LoadBalancer/Monitor_Signal_Handler.h b/TAO/orbsvcs/LoadBalancer/Monitor_Signal_Handler.h
new file mode 100644
index 00000000000..aee41ca5e76
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/Monitor_Signal_Handler.h
@@ -0,0 +1,62 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Monitor_Signal_Handler.h
+ *
+ * $Id$
+ *
+ * @author Ossama Othman <ossama@uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef TAO_LB_MONITOR_SIGNAL_HANDLER_H
+#define TAO_LB_MONITOR_SIGNAL_HANDLER_H
+
+#include "Signal_Handler.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "orbsvcs/CosLoadBalancingC.h"
+
+
+/**
+ * @class TAO_LB_Monitor_Signal_Handler
+ *
+ * @brief LoadMonitor-specific signal handler.
+ *
+ * This class simply builds on the TAO_LB_Signal_Handler class to add
+ * some LoadMonitor-specific cleanup.
+ */
+class TAO_LB_Monitor_Signal_Handler : public TAO_LB_Signal_Handler
+{
+public:
+
+ /// Constructor.
+ TAO_LB_Monitor_Signal_Handler (
+ CORBA::ORB_ptr orb,
+ PortableServer::POA_ptr poa,
+ CosLoadBalancing::LoadManager_ptr load_manager,
+ const PortableGroup::Location & location);
+
+protected:
+
+ /// Template method that initiates the cleanup process.
+ virtual int perform_cleanup (int signum);
+
+private:
+
+ /// Reference to the LoadManager with which the LoadMonitor is
+ /// registered.
+ CosLoadBalancing::LoadManager_var load_manager_;
+
+ /// Reference to the location the LoadMonitor resides at.
+ const PortableGroup::Location & location_;
+
+};
+
+
+#endif /* TAO_LB_MONITOR_SIGNAL_HANDLER_H */
diff --git a/TAO/orbsvcs/LoadBalancer/Push_Handler.cpp b/TAO/orbsvcs/LoadBalancer/Push_Handler.cpp
new file mode 100644
index 00000000000..de2f9ef1f51
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/Push_Handler.cpp
@@ -0,0 +1,57 @@
+#include "Push_Handler.h"
+
+#include "tao/debug.h"
+
+
+ACE_RCSID (LoadBalancing,
+ Push_Handler,
+ "$Id$")
+
+
+TAO_LB_Push_Handler::TAO_LB_Push_Handler (
+ CosLoadBalancing::LoadMonitor_ptr monitor,
+ const PortableGroup::Location & location,
+ CosLoadBalancing::LoadManager_ptr manager)
+ : monitor_ (CosLoadBalancing::LoadMonitor::_duplicate (monitor)),
+ location_ (location),
+ manager_ (CosLoadBalancing::LoadManager::_duplicate (manager))
+{
+}
+
+int
+TAO_LB_Push_Handler::handle_timeout (
+ const ACE_Time_Value & /* current_time */,
+ const void * /* arg */)
+{
+ ACE_DECLARE_NEW_CORBA_ENV;
+ ACE_TRY
+ {
+ CosLoadBalancing::LoadList_var loads =
+ this->monitor_->loads (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+// ACE_DEBUG ((LM_DEBUG,
+// "PUSHING LOAD:\n"
+// " id: %u\n"
+// " value: %f\n",
+// loads[0].id,
+// loads[0].value));
+
+ this->manager_->push_loads (this->location_,
+ loads.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ ACE_CATCHANY
+ {
+ // Catch the exception and ignore it.
+ // @@ Yah?
+
+ if (TAO_debug_level > 0)
+ ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION,
+ "(%P|%t) Push_Handler::handle_timeout()\n");
+ }
+ ACE_ENDTRY;
+
+ return 0;
+}
diff --git a/TAO/orbsvcs/LoadBalancer/Push_Handler.h b/TAO/orbsvcs/LoadBalancer/Push_Handler.h
new file mode 100644
index 00000000000..7913a399f72
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/Push_Handler.h
@@ -0,0 +1,66 @@
+// -*- C++ -*-
+
+//=======================================================================
+/**
+ * @file Push_Handler.h
+ *
+ * $Id$
+ *
+ * @author Ossama Othman <ossama@uci.edu>
+ */
+//=======================================================================
+
+
+#ifndef TAO_LB_PUSH_HANDLER_H
+#define TAO_LB_PUSH_HANDLER_H
+
+#include /**/ "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "orbsvcs/CosLoadBalancingC.h"
+
+#include "ace/Event_Handler.h"
+
+
+/**
+ * @class TAO_LB_Push_Handler
+ *
+ * @brief Event handler used when the "push" monitoring style is
+ * configured.
+ *
+ * An event handler designed to push loads to the LoadManager.
+ */
+class TAO_LB_Push_Handler : public ACE_Event_Handler
+{
+public:
+
+ /// Constructor
+ TAO_LB_Push_Handler (CosLoadBalancing::LoadMonitor_ptr monitor,
+ const PortableGroup::Location & location,
+ CosLoadBalancing::LoadManager_ptr manager);
+
+ /// Receive the timeout event.
+ virtual int handle_timeout (const ACE_Time_Value &current_time,
+ const void *arg);
+
+private:
+
+ /// Reference to the LoadMonitor.
+ CosLoadBalancing::LoadMonitor_var monitor_;
+
+ /// Location where the LoadMonitor resides.
+ const PortableGroup::Location location_;
+
+ /// Reference to the LoadManager.
+ CosLoadBalancing::LoadManager_var manager_;
+
+};
+
+#include /**/ "ace/post.h"
+
+#endif /* TAO_LB_PUSH_HANDLER_H */
diff --git a/TAO/orbsvcs/LoadBalancer/README b/TAO/orbsvcs/LoadBalancer/README
new file mode 100644
index 00000000000..04de23e0fb8
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/README
@@ -0,0 +1,183 @@
+#
+# $Id$
+#
+
+This directory contains the sources for two binaries:
+
+ 1) LoadManager
+ 2) LoadMonitor
+
+Descriptions of each follow.
+
+LoadManager
+===========
+The "LoadManager" binary is the stand-alone load balancing/managing
+service.
+
+A listing of available "LoadManager" command line options is available
+by invoking the "LoadManager" binary with the "-h" command line option.
+
+Usage
+-----
+The below comments assume a non-adaptive load balancing configuration.
+Documentation on adaptive load balancing will be added in the future.
+
+Approach 1: Portable Approach
+..............................
+
+1. Start the `LoadManager' binary in $TAO_ROOT/orbsvcs/LoadBalancer.
+
+2. In your server, obtain a reference to the "LoadManager" object
+ using the canonical resolve_initial_references() mechanism. Don't
+ forget to pass your server the appropriate
+ "-ORBInitRef LoadManager=..." ORB option.
+
+3. One (not more!) of your servers must create an "object group." For
+ example, to create an object group that your application will
+ populate (i.e. "application controlled" membership, as opposed to
+ "infrastructure controlled membership):
+
+ // The object group will contain members of this type.
+ const char * repository_id = "IDL:MyObject:1.0";
+
+ PortableGroup::Criteria criteria (1);
+ criteria.length (1);
+
+ PortableGroup::Property & property = criteria[0];
+ property.nam.length (1);
+
+ property.nam[0].id =
+ CORBA::string_dup ("org.omg.PortableGroup.MembershipStyle");
+
+ // Configure for application-controlled membership.
+ PortableGroup::MembershipStyleValue msv =
+ PortableGroup::MEMB_APP_CTRL;
+ property.val <<= msv;
+
+ PortableGroup::GenericFactory::FactoryCreationId_var fcid;
+
+ CORBA::Object_var group =
+ load_manager->create_object (repository_id,
+ criteria,
+ fcid.out ());
+
+ You then "export" the "group" object reference to your clients as
+ you would with any other object reference, such as those returned
+ from _this(). You can for example call object_to_string() on the
+ above "group" reference. You can even put it into any Naming
+ Service, not just TAO's.
+
+ Note that the default load balancing strategy is "Random," which is
+ non-adaptive. It is currently possible to override it with a
+ custom one but that functionality hasn't been fully tested yet. If
+ you want to know how to do that, please let me know on the mailing
+ list so that others may benefit, too.
+
+4. Once you've created the object group, you need to populate it with
+ your object group members, i.e. your objects:
+
+ CORBA::Object_var member = my_servant._this ();
+
+ PortableGroup::Location location (1);
+ location.length (1);
+
+ // Location this member resides at.
+ location[0].id = CORBA::string_dup ("My Location 1");
+
+ // "group" is the object group reference. add_member() may
+ // change it (TAO's implementation does NOT) so store the new
+ // reference in the same variable.
+ group =
+ load_manager->add_member (group.in (),
+ location,
+ member.in ());
+
+ Only one member of a given object group can reside at a given
+ location. For example, you cannot add two members of object group
+ A at "My Location 1". You can, however, have multiple members of
+ different object groups residing at the same location. For
+ example, a member of object group A and a member of object group B
+ can reside at "My Location 1". Also, multiple object group of the
+ same type, e.g. "IDL:MyObject:1.0", can exist. In that case,
+ a member from each object group may reside at the location, despite
+ the fact they are of the same type.
+
+5. At this point, load balancing will automatically occur once clients
+ start making invocation via the object group reference.
+
+
+6. Once you longer have any need of the object group, destroy it as
+ follows:
+
+ load_manager->delete_object (fcid.in ());
+
+ "fcid" is the factory creation ID that was returned as an "out"
+ parameter in the LoadManager::create_object() call.
+
+Approach 2:
+Quick, Transparent, Non-Portable and Somewhat Experimental Approach
+...................................................................
+
+Use the "LB_Component" Service Object to transparently add load
+balancer support to your dynamically linked servers. It will
+automatically register whatever CORBA objects you want with the load
+balancer, and override object reference creation methods such as
+_this() and POA::create_reference() so that they return the object
+group reference instead of the individual object's reference. All of
+this is done "behind the scenes," meaning that no modification to your
+existing code is necessary.
+
+This approach is "experimental" since I'm still tweaking the
+configuration interface available to the user, and since I may rename
+"LB_Component" to something else like "LB_ServerComponent." It's
+"non-portable" since other ORB's do not use the same dynamic loading
+approach the "LB_Component" uses, i.e. ACE's Service Configurator. It
+is, however, portable to all platforms supported by TAO.
+
+Other than that, the underlying group registration mechanisms are
+portable since they are straight CORBA calls. The "LB_Component" just
+makes all of the calls on the "LoadManager" for you.
+
+If you want try this approach, try adding the following to your
+primary (i.e. the one that creates the object group) server's
+`svc.conf' file:
+
+ dynamic LB_Component Service_Object * TAO_CosLoadBalancing:_make_TAO_LB_Component() "-LBLocation LOCATION_1 -LBGroup CREATE -LBTypeId IDL:MyObject:1.0"
+
+and the following to your other servers that do NOT create object
+groups and simply add themselves to the object group:
+
+ dynamic LB_Component Service_Object * TAO_CosLoadBalancing:_make_TAO_LB_Component() "-LBLocation LOCATION_2 -LBGroup file://group.ior -LBTypeId IDL:MyObject:1.0"
+
+etc. Don't forget to change the location for each object group
+member. With this approach, all of the LoadManager calls I described
+in the "standard" approach are handled for you. Again, this approach
+is still really experimental.
+
+If none of this makes sense, you may want to just wait for the
+documentation to be completed, and simply use the above "standard"
+procedure.
+
+
+LoadMonitor
+===========
+The "LoadMonitor" binary is a stand-alone load monitoring utility. It
+can be used to report loads for the standard load monitor types (CPU,
+Disk, Memory and Network), in addition to custom load monitors.
+A custom load monitor is used by passing its IOR to the "LoadMonitor"
+utility through the "-m" command line option.
+
+Both "PUSH" and "PULL" load monitoring styles may be configured. The
+"PUSH" interval may be configured, as well.
+
+A listing of available "LoadMonitor" command line options is available
+by invoking the "LoadMonitor" binary with the "-h" command line
+option.
+
+The LoadManager object's IOR must be made available to the
+"LoadMonitor" binary. This can be done using the standard
+Interoperable Naming Service "-ORBInitRef" option. For example, the
+following will work if LoadManager IOR is available in the file
+`lm.ior'
+
+ LoadMonitor -ORBInitRef LoadManager=file://lm.ior
diff --git a/TAO/orbsvcs/LoadBalancer/Signal_Handler.cpp b/TAO/orbsvcs/LoadBalancer/Signal_Handler.cpp
new file mode 100644
index 00000000000..e6c646c9833
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/Signal_Handler.cpp
@@ -0,0 +1,147 @@
+#include "Signal_Handler.h"
+
+#include "tao/ORB_Core.h"
+#include "ace/Reactor.h"
+
+ACE_RCSID (LoadBalancer,
+ Signal_Handler,
+ "$Id$")
+
+
+TAO_LB_Signal_Handler::TAO_LB_Signal_Handler (CORBA::ORB_ptr orb,
+ PortableServer::POA_ptr poa)
+ :
+#ifdef ACE_HAS_THREADS
+ signal_guard_ (),
+#endif /* ACE_HAS_THREADS */
+ sigset_ (),
+ orb_ (CORBA::ORB::_duplicate (orb)),
+ poa_ (PortableServer::POA::_duplicate (poa))
+{
+ // Register signal handlers.
+ this->sigset_.sig_add (SIGINT);
+ this->sigset_.sig_add (SIGTERM);
+}
+
+int
+TAO_LB_Signal_Handler::svc (void)
+{
+ // This method is only invoked when performing synchronous signal
+ // handling.
+
+ int signum = -1;
+
+ // Block waiting for the registered signals.
+ if (ACE_OS::sigwait (this->sigset_, &signum) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%P|%t) %p\n",
+ "ERROR waiting on signal"),
+ -1);
+ }
+
+ ACE_ASSERT (signum == SIGINT || signum == SIGTERM);
+
+// ACE_DEBUG ((LM_DEBUG,
+// ACE_TEXT ("(%P|%t) synchronous signal handler done\n")));
+
+ return this->perform_cleanup (signum);
+}
+
+int
+TAO_LB_Signal_Handler::activate (long flags,
+ int n_threads,
+ int force_active,
+ long priority,
+ int grp_id,
+ ACE_Task_Base *task,
+ ACE_hthread_t thread_handles[],
+ void *stack[],
+ size_t stack_size[],
+ ACE_thread_t thread_ids[])
+{
+ // sigwait() is not implemented on MS Windows. Handle signals
+ // asynchronously through the ORB's reactor in that case instead.
+ // Otherwise, handle signals synchronously in another thread.
+
+#if defined (ACE_HAS_THREADS) && !defined (ACE_WIN32)
+ return this->ACE_Task_Base::activate (flags,
+ n_threads,
+ force_active,
+ priority,
+ grp_id,
+ task,
+ thread_handles,
+ stack,
+ stack_size,
+ thread_ids);
+#else
+ ACE_UNUSED_ARG (flags);
+ ACE_UNUSED_ARG (n_threads);
+ ACE_UNUSED_ARG (force_active);
+ ACE_UNUSED_ARG (priority);
+ ACE_UNUSED_ARG (grp_id);
+ ACE_UNUSED_ARG (task);
+ ACE_UNUSED_ARG (thread_handles);
+ ACE_UNUSED_ARG (stack);
+ ACE_UNUSED_ARG (stack_size);
+ ACE_UNUSED_ARG (thread_ids);
+
+ return
+ this->orb_->orb_core ()->reactor ()->register_handler (this->sigset_,
+ this);
+#endif /* ACE_HAS_THREADS */
+}
+
+int
+TAO_LB_Signal_Handler::handle_signal (int signum, siginfo_t *, ucontext_t *)
+{
+// ACE_DEBUG ((LM_DEBUG,
+// ACE_TEXT ("(%P|%t) ASYNCHRONOUS signal handler done\n")));
+
+ // This method is only used in the asynchronous signal handling case
+ // (i.e. when single-threaded build is used).
+
+ // @note Is it okay to perform ORB operations from this method? The
+ // issue here is whether or not
+ // ACE_Event_Handler::handle_signal() is called from within an
+ // OS signal handler, and if that did occur is it safe to
+ // perform ORB operations?
+ return this->perform_cleanup (signum);
+}
+
+int
+TAO_LB_Signal_Handler::perform_cleanup (int signum)
+{
+ ACE_DECLARE_NEW_CORBA_ENV;
+ ACE_TRY
+ {
+ // Shutdown the POA.
+ //
+ // Shutting down the POA will cause servants "owned" by the POA
+ // to be destroyed. Servants will then have the opportunity to
+ // clean up all resources they are responsible for.
+ this->poa_->destroy (1, 1
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ // Now shutdown the ORB.
+ this->orb_->shutdown (1
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ ACE_CATCHANY
+ {
+ ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION,
+ "Caught exception");
+
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Problem during cleanup initiated by signal %d.\n",
+ signum),
+ -1);
+ }
+ ACE_ENDTRY;
+ ACE_CHECK_RETURN (-1);
+
+ return 0;
+}
diff --git a/TAO/orbsvcs/LoadBalancer/Signal_Handler.h b/TAO/orbsvcs/LoadBalancer/Signal_Handler.h
new file mode 100644
index 00000000000..5e9e7c2dea2
--- /dev/null
+++ b/TAO/orbsvcs/LoadBalancer/Signal_Handler.h
@@ -0,0 +1,100 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Signal_Handler.h
+ *
+ * $Id$
+ *
+ * @author Ossama Othman <ossama@uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef TAO_LB_SIGNAL_HANDLER_H
+#define TAO_LB_SIGNAL_HANDLER_H
+
+#include "ace/Task.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "tao/ORB.h"
+#include "tao/PortableServer/PortableServer.h"
+#include "ace/Signal.h"
+
+/**
+ * @class TAO_LB_Signal_Handler
+ *
+ * @brief Active object designed to handle signals synchronously.
+ *
+ * This class handles signals synchronously in the multi-threaded case,
+ * and asynchronously through a Reactor in the single-threaded case.
+ * @par
+ * The goal of this signal handler is to ensure proper cleanup of
+ * resources created by servants upon interruption by signals. For
+ * example, suppose a user sends a
+ * SIGINT (e.g. types CTRL-C) signal to an application. The servants
+ * in that application should be shutdown gracefully so that all
+ * resources handled by those servants are cleaned up. This is
+ * particularly important for resources that are not cleaned up
+ * automatically.
+ */
+class TAO_LB_Signal_Handler : public ACE_Task_Base
+{
+public:
+
+ /// Constructor.
+ TAO_LB_Signal_Handler (CORBA::ORB_ptr orb,
+ PortableServer::POA_ptr poa);
+
+ /// Run by a daemon thread to handle signals synchronously.
+ virtual int svc (void);
+
+ /// Active object activation method.
+ /**
+ * This override blocks all signals in the calling thread before
+ * spawning the synchronous signal handler.
+ */
+ virtual int activate (long flags = THR_NEW_LWP | THR_JOINABLE,
+ int n_threads = 1,
+ int force_active = 0,
+ long priority = ACE_DEFAULT_THREAD_PRIORITY,
+ int grp_id = -1,
+ ACE_Task_Base *task = 0,
+ ACE_hthread_t thread_handles[] = 0,
+ void *stack[] = 0,
+ size_t stack_size[] = 0,
+ ACE_thread_t thread_ids[] = 0);
+
+ /// Called when object is signaled by OS (either via UNIX signals or
+ /// when a Win32 object becomes signaled).
+ virtual int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0);
+
+protected:
+
+ /// Template method that initiates the cleanup process.
+ virtual int perform_cleanup (int signum);
+
+private:
+
+#ifdef ACE_HAS_THREADS
+ /// Block all signals before spawning the threads. Then, unblock
+ /// these signals when this handler is destroyed.
+ ACE_Sig_Guard signal_guard_;
+#endif /* ACE_HAS_THREADS */
+
+ /// The set of signals which this handler will handle.
+ ACE_Sig_Set sigset_;
+
+ /// Pseudo-reference to the ORB in which the LoadManager is running.
+ CORBA::ORB_var orb_;
+
+ /// Reference to the POA within which the LoadManager servant is
+ /// registered.
+ PortableServer::POA_var poa_;
+
+};
+
+#endif /* TAO_LB_SIGNAL_HANDLER_H */