Merge pull request #1844 from jrw972/monterey
[ACE_TAO.git] / TAO / orbsvcs / LoadBalancer / LoadMonitor.cpp
blob6cbeb21046701e0daf13359f5e44992a507c9f51
1 #include "orbsvcs/Log_Macros.h"
2 #include "Push_Handler.h"
3 #include "Monitor_Signal_Handler.h"
5 #include "orbsvcs/LoadBalancing/LB_CPU_Load_Average_Monitor.h"
6 #include "orbsvcs/LoadBalancing/LB_conf.h"
8 #include "tao/ORB_Core.h"
10 #include "ace/Reactor.h"
11 #include "ace/Get_Opt.h"
12 #include "ace/OS_main.h"
13 #include "ace/OS_NS_strings.h"
15 static const ACE_TCHAR * location_id = 0;
16 static const ACE_TCHAR * location_kind = 0;
17 static const ACE_TCHAR * mtype = ACE_TEXT("CPU");
18 static const ACE_TCHAR * mstyle = ACE_TEXT("PUSH");
19 static const ACE_TCHAR * custom_monitor_ior = 0;
21 // For the sake of consistency, make default push monitoring interval
22 // the same as the pull monitoring interval.
23 static long push_interval = TAO_LB_PULL_HANDLER_INTERVAL;
25 void
26 usage (const ACE_TCHAR * cmd)
28 ORBSVCS_DEBUG ((LM_INFO,
29 ACE_TEXT ("Usage:\n")
30 ACE_TEXT (" %s\n")
31 ACE_TEXT (" -l <location_id>\n")
32 ACE_TEXT (" -k <location_kind>\n")
33 ACE_TEXT (" -t <CPU | Disk | Memory | Network>\n")
34 ACE_TEXT (" -s <PULL | PUSH>\n")
35 ACE_TEXT (" -i <push_interval> (in seconds,")
36 ACE_TEXT (" and requires \"PUSH\" style monitoring)\n")
37 ACE_TEXT (" -m <custom_monitor_ior>")
38 ACE_TEXT (" (overrides \"-t\", \"-l\" and \"-k\")\n")
39 ACE_TEXT (" -h\n")
40 ACE_TEXT ("\n"),
41 cmd));
44 void
45 parse_args (int argc, ACE_TCHAR *argv[])
47 ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("l:k:t:s:i:m:h"));
49 int c = 0;
50 const ACE_TCHAR * s = 0;
52 while ((c = get_opts ()) != -1)
54 switch (c)
56 case 'm':
57 ::custom_monitor_ior = get_opts.opt_arg ();
58 break;
60 case 'l':
61 ::location_id = get_opts.opt_arg ();
62 break;
64 case 'k':
65 ::location_kind = get_opts.opt_arg ();
66 break;
68 case 't':
69 ::mtype = get_opts.opt_arg ();
70 break;
72 case 's':
73 ::mstyle = get_opts.opt_arg ();
74 break;
76 case 'i':
77 s = get_opts.opt_arg ();
78 push_interval = ACE_OS::atoi (s);
79 if (push_interval < 1)
81 ORBSVCS_ERROR ((LM_ERROR,
82 ACE_TEXT ("ERROR: Invalid push interval: %s\n"),
83 s));
85 throw CORBA::BAD_PARAM ();
87 break;
89 case 'h':
90 ::usage (argv[0]);
91 ACE_OS::exit (0);
92 break;
94 default:
95 ::usage (argv[0]);
96 throw CORBA::BAD_PARAM ();
101 #if defined (linux) && defined (ACE_HAS_THREADS)
102 // Only the main thread can handle signals in Linux. Run the
103 // LoadManager in thread other than main().
104 extern "C"
105 void *
106 TAO_LB_run_load_monitor (void * orb_arg)
108 CORBA::ORB_ptr orb = static_cast<CORBA::ORB_ptr> (orb_arg);
110 // Only the main thread should handle signals.
112 // @@ This is probably unnecessary since no signals should be
113 // delivered to this thread on Linux.
114 ACE_Sig_Guard signal_guard;
118 orb->run ();
120 catch (const CORBA::Exception& ex)
122 ex._tao_print_exception ("TAO Load Monitor");
124 return reinterpret_cast<void *> (-1);
127 return 0;
129 #endif /* linux && ACE_HAS_THREADS */
132 CosLoadBalancing::LoadMonitor_ptr
133 get_load_monitor (CORBA::ORB_ptr orb,
134 PortableServer::POA_ptr root_poa)
136 if (::custom_monitor_ior != 0)
138 CORBA::Object_var obj =
139 orb->string_to_object (::custom_monitor_ior);
141 return CosLoadBalancing::LoadMonitor::_narrow (obj.in ());
143 else
145 // The POA is only needed for the built-in load monitors since
146 // they must be activated.
147 PortableServer::POAManager_var poa_manager =
148 root_poa->the_POAManager ();
150 poa_manager->activate ();
152 if (ACE_OS::strcasecmp (::mtype, ACE_TEXT("CPU")) == 0)
154 TAO_LB_CPU_Load_Average_Monitor * monitor = 0;
155 ACE_NEW_THROW_EX (monitor,
156 TAO_LB_CPU_Load_Average_Monitor (::location_id,
157 ::location_kind),
158 CORBA::NO_MEMORY ());
160 // Transfer ownership to the POA.
161 PortableServer::ServantBase_var s = monitor;
163 return monitor->_this ();
165 else if (ACE_OS::strcasecmp (::mtype, ACE_TEXT("Disk")) == 0
166 || ACE_OS::strcasecmp (::mtype, ACE_TEXT("Memory")) == 0
167 || ACE_OS::strcasecmp (::mtype, ACE_TEXT("Network")) == 0)
169 ORBSVCS_ERROR ((LM_ERROR,
170 ACE_TEXT ("ERROR: \"%s\" load monitor currently ")
171 ACE_TEXT ("unimplemented.\n"),
172 ::mtype));
174 throw CORBA::NO_IMPLEMENT ();
176 else
178 ORBSVCS_ERROR ((LM_ERROR,
179 ACE_TEXT ("ERROR: Unrecognized built-in load monitor ")
180 ACE_TEXT ("type: <%s>.\n"),
181 ::mtype));
183 throw CORBA::BAD_PARAM ();
188 void
189 register_load_monitor (CosLoadBalancing::LoadManager_ptr manager,
190 CosLoadBalancing::LoadMonitor_ptr monitor,
191 TAO_LB_Push_Handler * handler,
192 ACE_Reactor * reactor,
193 long & timer_id)
195 if (ACE_OS::strcasecmp (::mstyle, ACE_TEXT("PULL")) == 0)
197 PortableGroup::Location_var location =
198 monitor->the_location ();
200 manager->register_load_monitor (location.in (),
201 monitor);
203 else if (ACE_OS::strcasecmp (::mstyle, ACE_TEXT("PUSH")) == 0)
205 ACE_Time_Value interval (::push_interval, 0);
206 ACE_Time_Value restart (::push_interval, 0);
207 timer_id = reactor->schedule_timer (handler,
209 interval,
210 restart);
212 if (timer_id == -1)
214 ORBSVCS_ERROR ((LM_ERROR,
215 ACE_TEXT ("ERROR: Unable to schedule timer for ")
216 ACE_TEXT ("\"PUSH\" style load monitoring.\n")));
218 throw CORBA::INTERNAL ();
221 else
223 ORBSVCS_ERROR ((LM_ERROR,
224 ACE_TEXT ("ERROR: Unrecognized load monitoring ")
225 ACE_TEXT ("style: <%s>.\n"),
226 ::mstyle));
228 throw CORBA::BAD_PARAM ();
233 ACE_TMAIN (int argc, ACE_TCHAR *argv[])
237 // The usual server side boilerplate code.
239 CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);
241 // Check the non-ORB arguments.
242 ::parse_args (argc,
243 argv);
245 CORBA::Object_var obj =
246 orb->resolve_initial_references ("RootPOA");
248 PortableServer::POA_var root_poa =
249 PortableServer::POA::_narrow (obj.in ());
251 CosLoadBalancing::LoadMonitor_var load_monitor =
252 ::get_load_monitor (orb.in (),
253 root_poa.in ());
255 PortableGroup::Location_var location =
256 load_monitor->the_location ();
258 // The "LoadManager" reference should have already been
259 // registered with the ORB by its ORBInitializer.
260 obj = orb->resolve_initial_references ("LoadManager");
262 CosLoadBalancing::LoadManager_var load_manager =
263 CosLoadBalancing::LoadManager::_narrow (obj.in ());
265 // This "push" handler will only be used if the load monitor
266 // style is "PUSH".
267 TAO_LB_Push_Handler push_handler (load_monitor.in (),
268 location.in (),
269 load_manager.in ());
271 ACE_Reactor * reactor = orb->orb_core ()->reactor ();
273 long timer_id = -1;
275 ::register_load_monitor (load_manager.in (),
276 load_monitor.in (),
277 &push_handler,
278 reactor,
279 timer_id);
281 #if defined (linux) && defined (ACE_HAS_THREADS)
282 if (ACE_Thread_Manager::instance ()->spawn (::TAO_LB_run_load_monitor,
283 orb.in ()) == -1)
285 ORBSVCS_ERROR_RETURN ((LM_ERROR,
286 "ERROR: Unable to spawn TAO LoadMonitor's "
287 "ORB thread.\n"),
288 -1);
291 ACE_Sig_Set sigset;
292 sigset.sig_add (SIGINT);
293 sigset.sig_add (SIGTERM);
295 int signum = -1;
297 // Block waiting for the registered signals.
298 if (ACE_OS::sigwait (sigset, &signum) == -1)
300 ORBSVCS_ERROR_RETURN ((LM_ERROR,
301 "(%P|%t) %p\n",
302 "ERROR waiting on signal"),
303 -1);
306 ACE_ASSERT (signum == SIGINT || signum == SIGTERM);
308 // Deregister the LoadMonitor from the LoadManager in the PULL
309 // load monitoring case.
310 if (timer_id == -1)
312 load_manager->remove_load_monitor (location.in ());
314 #else
315 // Activate/register the signal handler that (attempts) to
316 // ensure graceful shutdown of the LoadMonitor so that
317 // LoadMonitors registered with the LoadManager can be
318 // deregistered.
319 CosLoadBalancing::LoadManager_ptr tmp;
321 if (timer_id == -1)
322 tmp = load_manager.in (); // PULL monitoring
323 else
324 tmp = CosLoadBalancing::LoadManager::_nil (); // PUSH
325 // monitoring
326 TAO_LB_Monitor_Signal_Handler signal_handler (
327 orb.in (),
328 root_poa.in (),
329 tmp,
330 location.in ());
332 if (signal_handler.activate () != 0)
333 return -1;
335 // @@ There is a subtle race condition here. If the signal
336 // handler thread shuts down the ORB before it is run, the
337 // below call to ORB::run() will throw a CORBA::BAD_INV_ORDER
338 // exception.
339 orb->run ();
341 // Wait for the signal handler thread to finish
342 // before the process exits.
343 signal_handler.wait ();
344 #endif /* linux && ACE_HAS_THREADS */
346 if (timer_id != -1 && reactor->cancel_timer (timer_id) == 0)
348 ORBSVCS_ERROR ((LM_ERROR,
349 ACE_TEXT ("ERROR: Unable to cancel \"push\" load ")
350 ACE_TEXT ("monitoring timer.\n")));
352 // Just keep going. We're shutting down anyway.
355 orb->destroy ();
357 catch (const CORBA::Exception& ex)
359 ex._tao_print_exception ("TAO Load Monitor");
361 return -1;
364 return 0;