1 karl 1.7 //%2005////////////////////////////////////////////////////////////////////////
|
2 kumpf 1.1 //
|
3 karl 1.4 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.7 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 kumpf 1.1 //
12 // Permission is hereby granted, free of charge, to any person obtaining a copy
13 // of this software and associated documentation files (the "Software"), to
14 // deal in the Software without restriction, including without limitation the
15 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
16 // sell copies of the Software, and to permit persons to whom the Software is
17 // furnished to do so, subject to the following conditions:
18 //
19 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
20 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
21 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
22 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
23 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 //==============================================================================
29 //
30 // Author: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
31 // Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com)
32 kumpf 1.1 //
|
33 carolann.graves 1.8 // Modified By: Carol Ann Krug Graves, Hewlett-Packard Company
34 // (carolann_graves@hp.com)
|
35 kumpf 1.1 //
36 //%/////////////////////////////////////////////////////////////////////////////
37
38 #include <Pegasus/Common/Array.h>
39 #include <Pegasus/Common/AutoPtr.h>
40 #include <Pegasus/Common/CIMMessageSerializer.h>
41 #include <Pegasus/Common/CIMMessageDeserializer.h>
42 #include <Pegasus/Common/Tracer.h>
43 #include <Pegasus/Config/ConfigManager.h>
44
45 #include "ProviderAgent.h"
46
47 PEGASUS_USING_STD;
48
49 PEGASUS_NAMESPACE_BEGIN
50
51 /////////////////////////////////////////////////////////////////////////////
52 //
53 // ProviderAgentRequest
54 //
55 /////////////////////////////////////////////////////////////////////////////
56 kumpf 1.1
57 /**
58 This class encapsulates the data required by a work thread to process a
59 request in a Provider Agent.
60 */
61 class ProviderAgentRequest
62 {
63 public:
64 ProviderAgentRequest(ProviderAgent* agent_, CIMRequestMessage* request_)
65 {
66 agent = agent_;
67 request = request_;
|
68 a.dunfey 1.6 request->requestIsOOP = true;
|
69 kumpf 1.1 }
70
71 ProviderAgent* agent;
72 CIMRequestMessage* request;
73 };
74
75
76 /////////////////////////////////////////////////////////////////////////////
77 //
78 // ProviderAgent
79 //
80 /////////////////////////////////////////////////////////////////////////////
81
82 // Time values used in ThreadPool construction
83 static struct timeval create_time = {0, 1};
84 static struct timeval destroy_time = {300, 0};
85 static struct timeval deadlock_time = {0, 0};
86
87 ProviderAgent* ProviderAgent::_providerAgent = 0;
88
89 ProviderAgent::ProviderAgent(
90 kumpf 1.1 const String& agentId,
91 AnonymousPipe* pipeFromServer,
92 AnonymousPipe* pipeToServer)
|
93 w.otsuka 1.5 : _threadPool(0, "ProviderAgent", 0, 0, create_time, destroy_time, deadlock_time),
94 _providerManagerRouter(_indicationCallback)
|
95 kumpf 1.1 {
96 PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::ProviderAgent");
97
98 _terminating = false;
99 _agentId = agentId;
100 _pipeFromServer = pipeFromServer;
101 _pipeToServer = pipeToServer;
102 _providerAgent = this;
|
103 carolann.graves 1.8 _subscriptionInitComplete = false;
|
104 kumpf 1.1
105 PEG_METHOD_EXIT();
106 }
107
108 ProviderAgent::~ProviderAgent()
109 {
110 PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::~ProviderAgent");
111
112 _providerAgent = 0;
113
114 PEG_METHOD_EXIT();
115 }
116
117 // Private, unimplemented constructor
118 ProviderAgent::ProviderAgent()
|
119 w.otsuka 1.5 : _threadPool(0, "null", 0, 0, create_time, destroy_time, deadlock_time),
120 _providerManagerRouter(0)
|
121 kumpf 1.1 {
122 }
123
124 // Private, unimplemented constructor
125 ProviderAgent::ProviderAgent(const ProviderAgent&)
|
126 w.otsuka 1.5 : _threadPool(0, "null", 0, 0, create_time, destroy_time, deadlock_time),
127 _providerManagerRouter(0)
|
128 kumpf 1.1 {
129 }
130
131 // Private, unimplemented assignment operator
132 ProviderAgent& ProviderAgent::operator=(const ProviderAgent&)
133 {
134 return *this;
135 }
136
137 void ProviderAgent::run()
138 {
139 PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::run");
140
141 // Enable the signal handler to terminate gracefully on SIGHUP and SIGTERM
142 getSigHandle()->registerHandler(PEGASUS_SIGHUP, _terminateSignalHandler);
143 getSigHandle()->activate(PEGASUS_SIGHUP);
144 getSigHandle()->registerHandler(PEGASUS_SIGTERM, _terminateSignalHandler);
145 getSigHandle()->activate(PEGASUS_SIGTERM);
146
147 while (!_terminating)
148 {
149 kumpf 1.1 Boolean active = true;
150 try
151 {
152 //
153 // Read and process the next request
154 //
155 active = _readAndProcessRequest();
156 }
157 catch (Exception& e)
158 {
159 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
160 String("Unexpected exception from _readAndProcessRequest(): ") +
161 e.getMessage());
162 _terminating = true;
163 }
164 catch (...)
165 {
166 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
167 "Unexpected exception from _readAndProcessRequest().");
168 _terminating = true;
169 }
170 kumpf 1.1
171 if (_terminating)
172 {
173 //
174 // Stop all providers
175 //
176 CIMStopAllProvidersRequestMessage stopRequest("0", QueueIdStack(0));
177 AutoPtr<Message> stopResponse(_processRequest(&stopRequest));
178 }
179 else if (!active)
180 {
181 //
182 // Stop agent process when no more providers are loaded
183 //
184 try
185 {
186 if (!_providerManagerRouter.hasActiveProviders())
187 {
188 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
189 "No active providers. Exiting.");
190 _terminating = true;
191 kumpf 1.1 }
192 }
193 catch (...)
194 {
195 // Do not terminate the agent on this exception
196 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
197 "Unexpected exception from hasActiveProviders()");
198 }
199 }
200 }
201
202 PEG_METHOD_EXIT();
203 }
204
205 Boolean ProviderAgent::_readAndProcessRequest()
206 {
207 PEG_METHOD_ENTER(TRC_PROVIDERAGENT,
208 "ProviderAgent::_readAndProcessRequest");
209
210 CIMRequestMessage* request;
211
212 kumpf 1.1 //
213 // Read the request from CIM Server
214 //
215 CIMMessage* cimMessage;
216 AnonymousPipe::Status readStatus = _pipeFromServer->readMessage(cimMessage);
217 request = dynamic_cast<CIMRequestMessage*>(cimMessage);
218
219 // Read operation was interrupted
220 if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
221 {
222 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
223 "Read operation was interrupted.");
224 PEG_METHOD_EXIT();
225 return false;
226 }
227
228 if (readStatus == AnonymousPipe::STATUS_CLOSED)
229 {
230 // The CIM Server connection is closed
231 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
232 "CIMServer connection closed. Exiting.");
233 kumpf 1.1 _terminating = true;
234 PEG_METHOD_EXIT();
235 return false;
236 }
237
238 if (readStatus == AnonymousPipe::STATUS_ERROR)
239 {
240 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
241 "Error reading from pipe. Exiting.");
242 Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::WARNING,
243 "ProviderManager.ProviderAgent.ProviderAgent."
244 "CIMSERVER_COMMUNICATION_FAILED",
245 "cimprovagt \"$0\" communication with CIM Server failed. Exiting.",
246 _agentId);
247 _terminating = true;
248 PEG_METHOD_EXIT();
249 return false;
250 }
251
252 // A "wake up" message means we should unload idle providers
253 if (request == 0)
254 kumpf 1.1 {
255 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL4,
256 "Got a wake up message.");
257 try
258 {
259 _unloadIdleProviders();
260 }
261 catch (...)
262 {
263 // Ignore exceptions from idle provider unloading
264 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
265 "Ignoring exception from _unloadIdleProviders()");
266 }
267 PEG_METHOD_EXIT();
268 return false;
269 }
270
271 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL3,
272 String("Received request from server with messageId ") +
273 request->messageId);
274
|
275 kumpf 1.2 // Get the ProviderIdContainer to complete the provider module instance
276 // optimization. If the provider module instance is blank (optimized
277 // out), fill it in from our cache. If it is not blank, update our
278 // cache. (See the _providerModuleCache member description.)
279 try
280 {
281 ProviderIdContainer pidc = request->operationContext.get(
282 ProviderIdContainer::NAME);
283 if (pidc.getModule().isUninitialized())
284 {
285 // Provider module is optimized out. Fill it in from the cache.
286 request->operationContext.set(ProviderIdContainer(
287 _providerModuleCache, pidc.getProvider(),
288 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
289 }
290 else
291 {
292 // Update the cache with the new provider module instance.
293 _providerModuleCache = pidc.getModule();
294 }
295 }
296 kumpf 1.2 catch (...)
297 {
298 // No ProviderIdContainer to optimize
299 }
300
|
301 kumpf 1.1 //
302 // Check for messages to be handled by the Agent itself.
303 //
304 if (request->getType() == CIM_INITIALIZE_PROVIDER_AGENT_REQUEST_MESSAGE)
305 {
306 // Process the request in this thread
|
307 kumpf 1.3 AutoPtr<CIMInitializeProviderAgentRequestMessage> ipaRequest(
308 dynamic_cast<CIMInitializeProviderAgentRequestMessage*>(request));
309 PEGASUS_ASSERT(ipaRequest.get() != 0);
|
310 kumpf 1.1
311 ConfigManager* configManager = ConfigManager::getInstance();
312 configManager->setPegasusHome(ipaRequest->pegasusHome);
313
314 // Initialize the configuration properties
315 for (Uint32 i = 0; i < ipaRequest->configProperties.size(); i++)
316 {
317 configManager->initCurrentValue(
318 ipaRequest->configProperties[i].first,
319 ipaRequest->configProperties[i].second);
320 }
321
322 // Set the default resource bundle directory for the MessageLoader
323 MessageLoader::setPegasusMsgHome(ConfigManager::getHomedPath(
324 configManager->getCurrentValue("messageDir")));
325
326 // Set the log file directory
327 Logger::setHomeDirectory(ConfigManager::getHomedPath(
328 configManager->getCurrentValue("logdir")));
329
330 System::bindVerbose = ipaRequest->bindVerbose;
331 kumpf 1.1
|
332 carolann.graves 1.8 //
333 // Set _subscriptionInitComplete from value in
334 // InitializeProviderAgent request
335 //
336 _subscriptionInitComplete = ipaRequest->subscriptionInitComplete;
337 _providerManagerRouter.setSubscriptionInitComplete
338 (_subscriptionInitComplete);
339
|
340 kumpf 1.1 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
341 "Processed the agent initialization message.");
342
343 // Do not write a response for this request
344 }
345 else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
346 {
347 // Process the request in this thread
|
348 kumpf 1.3 AutoPtr<CIMNotifyConfigChangeRequestMessage> notifyRequest(
349 dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request));
350 PEGASUS_ASSERT(notifyRequest.get() != 0);
|
351 kumpf 1.1
352 //
353 // Update the ConfigManager with the new property value
354 //
355 ConfigManager* configManager = ConfigManager::getInstance();
356 CIMException responseException;
357 try
358 {
359 if (notifyRequest->currentValueModified)
360 {
361 configManager->updateCurrentValue(
362 notifyRequest->propertyName,
363 notifyRequest->newPropertyValue,
364 false);
365 }
366 else
367 {
368 configManager->updatePlannedValue(
369 notifyRequest->propertyName,
370 notifyRequest->newPropertyValue,
371 true);
372 kumpf 1.1 }
373 }
374 catch (Exception& e)
375 {
376 responseException = PEGASUS_CIM_EXCEPTION(
377 CIM_ERR_FAILED, e.getMessage());
378 }
379
|
380 kumpf 1.3 AutoPtr<CIMResponseMessage> response(notifyRequest->buildResponse());
|
381 kumpf 1.1 response->cimException = responseException;
382
383 // Return response to CIM Server
|
384 kumpf 1.3 _writeResponse(response.get());
|
385 kumpf 1.1 }
386 else if ((request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE) ||
387 (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE))
388 {
389 // Process the request in this thread
|
390 kumpf 1.3 AutoPtr<Message> response(_processRequest(request));
391 _writeResponse(response.get());
|
392 kumpf 1.1
393 CIMResponseMessage * respMsg =
|
394 kumpf 1.3 dynamic_cast<CIMResponseMessage*>(response.get());
|
395 kumpf 1.1
396 // If StopAllProviders, terminate the agent process.
397 // If DisableModule not successful, leave agent process running.
398 if ((respMsg->cimException.getCode() == CIM_ERR_SUCCESS) ||
399 (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE))
400 {
401 // Operation is successful. End the agent process.
402 _terminating = true;
403 }
|
404 kumpf 1.3
405 delete request;
|
406 kumpf 1.1 }
|
407 carolann.graves 1.8 else if (request->getType () ==
408 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
409 {
410 _subscriptionInitComplete = true;
411
412 //
413 // Process the request in this thread
414 //
415 AutoPtr <Message> response (_processRequest (request));
416 _writeResponse (response.get ());
417
418 //
419 // Note: the response does not contain interesting data
420 //
421
422 delete request;
423 }
|
424 kumpf 1.1 else
425 {
426 // Start a new thread to process the request
427 ProviderAgentRequest* agentRequest =
428 new ProviderAgentRequest(this, request);
429
430 while (!_threadPool.allocate_and_awaken(
431 agentRequest,
432 ProviderAgent::_processRequestAndWriteResponse))
433 {
434 pegasus_yield();
435 }
436 }
437
438 PEG_METHOD_EXIT();
439 return true;
440 }
441
442 Message* ProviderAgent::_processRequest(CIMRequestMessage* request)
443 {
444 PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::_processRequest");
445 kumpf 1.1
446 Message* response = 0;
447
448 try
449 {
450 // Forward the request to the ProviderManager
451 response = _providerManagerRouter.processMessage(request);
452 }
453 catch (Exception& e)
454 {
455 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
456 String("Caught exception while processing request: ") +
457 e.getMessage());
458 CIMResponseMessage* cimResponse = request->buildResponse();
459 cimResponse->cimException = PEGASUS_CIM_EXCEPTION(
460 CIM_ERR_FAILED, e.getMessage());
461 response = cimResponse;
462 }
463 catch (...)
464 {
465 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
466 kumpf 1.1 "Caught exception while processing request.");
467 CIMResponseMessage* cimResponse = request->buildResponse();
468 cimResponse->cimException = PEGASUS_CIM_EXCEPTION(
469 CIM_ERR_FAILED, String::EMPTY);
470 response = cimResponse;
471 }
472
473 PEG_METHOD_EXIT();
474 return response;
475 }
476
477 void ProviderAgent::_writeResponse(Message* message)
478 {
479 PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::_writeResponse");
480
481 CIMMessage* response = dynamic_cast<CIMMessage*>(message);
482 PEGASUS_ASSERT(response != 0);
483
484 //
485 // Write the response message to the pipe
486 //
487 kumpf 1.1 try
488 {
489 // Use Mutex to prevent concurrent writes to the same pipe
490 AutoMutex pipeLock(_pipeToServerMutex);
491
492 AnonymousPipe::Status writeStatus =
493 _pipeToServer->writeMessage(response);
494
495 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
496 {
497 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
498 "Error writing response to pipe.");
499 Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::WARNING,
500 "ProviderManager.ProviderAgent.ProviderAgent."
501 "CIMSERVER_COMMUNICATION_FAILED",
502 "cimprovagt \"$0\" communication with CIM Server failed. "
503 "Exiting.",
504 _agentId);
505 _terminating = true;
506 }
507 }
508 kumpf 1.1 catch (...)
509 {
510 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
511 "Caught exception while writing response.");
512 Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::WARNING,
513 "ProviderManager.ProviderAgent.ProviderAgent."
514 "CIMSERVER_COMMUNICATION_FAILED",
515 "cimprovagt \"$0\" communication with CIM Server failed. Exiting.",
516 _agentId);
517 _terminating = true;
518 }
519
520 PEG_METHOD_EXIT();
521 }
522
523 PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
524 ProviderAgent::_processRequestAndWriteResponse(void* arg)
525 {
526 PEG_METHOD_ENTER(TRC_PROVIDERAGENT,
527 "ProviderAgent::_processRequestAndWriteResponse");
528
529 kumpf 1.1 AutoPtr<ProviderAgentRequest> agentRequest(
530 reinterpret_cast<ProviderAgentRequest*>(arg));
531 PEGASUS_ASSERT(agentRequest.get() != 0);
532
533 // Get the ProviderAgent and request message from the argument
534 ProviderAgent* agent = agentRequest->agent;
|
535 kumpf 1.3 AutoPtr<CIMRequestMessage> request(agentRequest->request);
|
536 kumpf 1.1
537 // Process the request
|
538 kumpf 1.3 AutoPtr<Message> response(agent->_processRequest(request.get()));
|
539 kumpf 1.1
540 // Write the response
|
541 kumpf 1.3 agent->_writeResponse(response.get());
|
542 kumpf 1.1
543 PEG_METHOD_EXIT();
544 return(PEGASUS_THREAD_RETURN(0));
545 }
546
547 void ProviderAgent::_indicationCallback(
548 CIMProcessIndicationRequestMessage* message)
549 {
550 PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::_indicationCallback");
551
552 // Send request back to the server to process
553 _providerAgent->_writeResponse(message);
554
555 PEG_METHOD_EXIT();
556 }
557
558 void ProviderAgent::_unloadIdleProviders()
559 {
560 PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::_unloadIdleProviders");
561
562 // Ensure that only one _unloadIdleProvidersHandler thread runs at a time
563 kumpf 1.1 _unloadIdleProvidersBusy++;
564 if ((_unloadIdleProvidersBusy.value() == 1) &&
565 (_threadPool.allocate_and_awaken(
566 (void*)this, ProviderAgent::_unloadIdleProvidersHandler)))
567 {
568 // _unloadIdleProvidersBusy is decremented in
569 // _unloadIdleProvidersHandler
570 }
571 else
572 {
573 // If we fail to allocate a thread, don't retry now.
574 _unloadIdleProvidersBusy--;
575 }
576
577 PEG_METHOD_EXIT();
578 }
579
580 PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
581 ProviderAgent::_unloadIdleProvidersHandler(void* arg) throw()
582 {
583 try
584 kumpf 1.1 {
585 PEG_METHOD_ENTER(TRC_PROVIDERAGENT,
586 "ProviderAgent::unloadIdleProvidersHandler");
587
588 ProviderAgent* myself = reinterpret_cast<ProviderAgent*>(arg);
589
590 try
591 {
592 myself->_providerManagerRouter.unloadIdleProviders();
593 }
594 catch (...)
595 {
596 // Ignore errors
597 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
598 "Unexpected exception in _unloadIdleProvidersHandler");
599 }
600
601 myself->_unloadIdleProvidersBusy--;
602 }
603 catch (...)
604 {
605 kumpf 1.1 // Ignore errors
606 try
607 {
608 PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
609 "Unexpected exception in _unloadIdleProvidersHandler");
610 }
611 catch (...)
612 {
613 }
614 }
615
616 // PEG_METHOD_EXIT(); // Note: This statement could throw an exception
617 return(PEGASUS_THREAD_RETURN(0));
618 }
619
620 void ProviderAgent::_terminateSignalHandler(
621 int s_n, PEGASUS_SIGINFO_T* s_info, void* sig)
622 {
623 PEG_METHOD_ENTER(TRC_PROVIDERAGENT,
624 "ProviderAgent::_terminateSignalHandler");
625
626 kumpf 1.1 if (_providerAgent != 0)
627 {
628 _providerAgent->_terminating = true;
629 }
630
631 PEG_METHOD_EXIT();
632 }
633
634 PEGASUS_NAMESPACE_END
|