diff options
author | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:21 +0000 |
---|---|---|
committer | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:21 +0000 |
commit | 3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c (patch) | |
tree | 197c810e5f5bce17b1233a7cb8d7b50c0bcd25e2 /TAO/orbsvcs/LoadBalancer | |
parent | 6b846cf03c0bcbd8c276cb0af61a181e5f98eaae (diff) | |
download | ATCD-3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c.tar.gz |
Repo restructuring
Diffstat (limited to 'TAO/orbsvcs/LoadBalancer')
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/.cvsignore | 2 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/LoadBalancer.mpc | 24 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/LoadManager.cpp | 310 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/LoadMonitor.cpp | 417 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/Makefile.am | 117 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/Monitor_Signal_Handler.cpp | 51 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/Monitor_Signal_Handler.h | 62 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/Push_Handler.cpp | 57 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/Push_Handler.h | 66 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/README | 183 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/Signal_Handler.cpp | 147 | ||||
-rw-r--r-- | TAO/orbsvcs/LoadBalancer/Signal_Handler.h | 100 |
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 ¤t_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 */ |