version 1.15, 2005/02/27 04:10:53
|
version 1.22, 2005/11/22 19:16:56
|
|
|
#else | #else |
# include <unistd.h> // For fork(), exec(), and _exit() | # include <unistd.h> // For fork(), exec(), and _exit() |
# include <errno.h> | # include <errno.h> |
|
# include <sys/types.h> |
|
# if defined(PEGASUS_HAS_SIGNALS) |
|
# include <sys/wait.h> |
|
# endif |
#endif | #endif |
| |
#include "OOPProviderManagerRouter.h" | #include "OOPProviderManagerRouter.h" |
|
|
with an error result. | with an error result. |
| |
Note: The caller must lock the _agentMutex. | Note: The caller must lock the _agentMutex. |
|
|
|
@param cleanShutdown Indicates whether the provider agent process |
|
exited cleanly. A value of true indicates that responses have been |
|
sent for all requests that have been processed. A value of false |
|
indicates that one or more requests may have been partially processed. |
|
*/ |
|
void _uninitialize(Boolean cleanShutdown); |
|
|
|
/** |
|
Performs the processMessage work, but does not retry on a transient |
|
error. |
*/ | */ |
void _uninitialize(); |
CIMResponseMessage* _processMessage(CIMRequestMessage* request); |
| |
/** | /** |
Read and process response messages from the Provider Agent until | Read and process response messages from the Provider Agent until |
|
|
*/ | */ |
AutoPtr<AnonymousPipe> _pipeToAgent; | AutoPtr<AnonymousPipe> _pipeToAgent; |
| |
|
#if defined(PEGASUS_HAS_SIGNALS) |
|
/** |
|
Process ID of the active Provider Agent. |
|
*/ |
|
pid_t _pid; |
|
#endif |
|
|
/** | /** |
The _outstandingRequestTable holds an entry for each request that has | The _outstandingRequestTable holds an entry for each request that has |
been sent to this Provider Agent for which no response has been | been sent to this Provider Agent for which no response has been |
|
|
static Uint32 _maxProviderProcesses; | static Uint32 _maxProviderProcesses; |
| |
/** | /** |
|
A value indicating that a request message has not been processed. |
|
A CIMResponseMessage pointer with this value indicates that the |
|
corresponding CIMRequestMessage has not been processed. This is |
|
used to indicate that a provider agent exited without starting to |
|
process the request, and that the request should be retried. |
|
*/ |
|
static CIMResponseMessage* _REQUEST_NOT_PROCESSED; |
|
|
|
/** |
Indicates whether the Indication Service has completed initialization. | Indicates whether the Indication Service has completed initialization. |
| |
For more information, please see the description of the | For more information, please see the description of the |
|
|
Mutex ProviderAgentContainer::_numProviderProcessesMutex; | Mutex ProviderAgentContainer::_numProviderProcessesMutex; |
Uint32 ProviderAgentContainer::_maxProviderProcesses = PEG_NOT_FOUND; | Uint32 ProviderAgentContainer::_maxProviderProcesses = PEG_NOT_FOUND; |
| |
|
// Set this to a value that no valid CIMResponseMessage* will have. |
|
CIMResponseMessage* ProviderAgentContainer::_REQUEST_NOT_PROCESSED = |
|
reinterpret_cast<CIMResponseMessage*>(&_REQUEST_NOT_PROCESSED); |
|
|
ProviderAgentContainer::ProviderAgentContainer( | ProviderAgentContainer::ProviderAgentContainer( |
const String & moduleName, | const String & moduleName, |
const String & userName, | const String & userName, |
|
|
// Ensure the destructor does not throw an exception | // Ensure the destructor does not throw an exception |
try | try |
{ | { |
|
if (isInitialized()) |
|
{ |
// Stop the responseProcessor thread by closing its connection | // Stop the responseProcessor thread by closing its connection |
_pipeFromAgent->closeReadHandle(); | _pipeFromAgent->closeReadHandle(); |
| |
|
|
pegasus_yield(); | pegasus_yield(); |
} | } |
} | } |
|
} |
catch (...) | catch (...) |
{ | { |
} | } |
|
|
PEG_METHOD_ENTER(TRC_PROVIDERMANAGER, | PEG_METHOD_ENTER(TRC_PROVIDERMANAGER, |
"ProviderAgentContainer::_startAgentProcess"); | "ProviderAgentContainer::_startAgentProcess"); |
| |
|
// |
|
// Serialize the starting of agent processes. If two agent processes are |
|
// started at the same time, they may get copies of each other's pipe |
|
// descriptors. If this happens, the cimserver will not get a pipe read |
|
// error when one of the agent processes exits, because the pipe will |
|
// still be writable by the other process. This locking control needs to |
|
// cover the period from where the pipes are created to where the agent |
|
// ends of the pipes are closed by the cimserver. |
|
// |
|
static Mutex agentStartupMutex; |
|
AutoMutex lock(agentStartupMutex); |
|
|
AutoPtr<AnonymousPipe> pipeFromAgent(new AnonymousPipe()); | AutoPtr<AnonymousPipe> pipeFromAgent(new AnonymousPipe()); |
AutoPtr<AnonymousPipe> pipeToAgent(new AnonymousPipe()); | AutoPtr<AnonymousPipe> pipeToAgent(new AnonymousPipe()); |
| |
|
|
| |
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
} | } |
|
#elif defined (PEGASUS_OS_OS400) |
|
|
|
//Out of provider support for OS400 goes here when needed. |
|
|
#else | #else |
pid_t pid = fork(); | pid_t pid = fork(); |
if (pid < 0) | if (pid < 0) |
|
|
_exit(1); | _exit(1); |
} | } |
} | } |
|
# if defined(PEGASUS_HAS_SIGNALS) |
|
_pid = pid; |
|
# endif |
#endif | #endif |
| |
// | // |
|
|
{ | { |
_startAgentProcess(); | _startAgentProcess(); |
| |
_sendInitializationData(); |
|
|
|
_isInitialized = true; | _isInitialized = true; |
| |
|
_sendInitializationData(); |
|
|
// Start a thread to read and process responses from the Provider Agent | // Start a thread to read and process responses from the Provider Agent |
while (!MessageQueueService::get_thread_pool()->allocate_and_awaken( |
ThreadStatus rtn = PEGASUS_THREAD_OK; |
this, _responseProcessor)) |
while ((rtn = MessageQueueService::get_thread_pool()-> |
|
allocate_and_awaken(this, _responseProcessor)) != |
|
PEGASUS_THREAD_OK) |
|
{ |
|
if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES) |
{ | { |
pegasus_yield(); | pegasus_yield(); |
} | } |
|
else |
|
{ |
|
Logger::put( |
|
Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE, |
|
"Not enough threads to process responses from the " |
|
"provider agent."); |
|
|
|
Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2, |
|
"Could not allocate thread to process responses from the " |
|
"provider agent."); |
|
|
|
throw Exception(MessageLoaderParms( |
|
"ProviderManager.OOPProviderManagerRouter." |
|
"CIMPROVAGT_THREAD_ALLOCATION_FAILED", |
|
"Failed to allocate thread for cimprovagt \"$0\".", |
|
_moduleName)); |
|
} |
|
} |
} | } |
catch (...) | catch (...) |
{ | { |
_isInitialized = false; |
// Closing the connection causes the agent process to exit |
_pipeToAgent.reset(); | _pipeToAgent.reset(); |
_pipeFromAgent.reset(); | _pipeFromAgent.reset(); |
| |
|
#if defined(PEGASUS_HAS_SIGNALS) |
|
if (_isInitialized) |
|
{ |
|
// Harvest the status of the agent process to prevent a zombie |
|
Boolean keepWaiting = false; |
|
do |
|
{ |
|
pid_t status = waitpid(_pid, 0, 0); |
|
if (status == -1) |
|
{ |
|
if (errno == EINTR) |
|
{ |
|
keepWaiting = true; |
|
} |
|
else |
|
{ |
|
Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"ProviderAgentContainer::_initialize(): " |
|
"waitpid failed; errno = %d.", errno); |
|
} |
|
} |
|
} while (keepWaiting); |
|
} |
|
#endif |
|
|
|
_isInitialized = false; |
|
|
{ | { |
AutoMutex lock(_numProviderProcessesMutex); | AutoMutex lock(_numProviderProcessesMutex); |
_numProviderProcesses--; | _numProviderProcesses--; |
|
|
} | } |
| |
// Note: Caller must lock _agentMutex | // Note: Caller must lock _agentMutex |
void ProviderAgentContainer::_uninitialize() |
void ProviderAgentContainer::_uninitialize(Boolean cleanShutdown) |
{ | { |
PEG_METHOD_ENTER(TRC_PROVIDERMANAGER, | PEG_METHOD_ENTER(TRC_PROVIDERMANAGER, |
"ProviderAgentContainer::_uninitialize"); | "ProviderAgentContainer::_uninitialize"); |
|
|
_numProviderProcesses--; | _numProviderProcesses--; |
} | } |
| |
|
#if defined(PEGASUS_HAS_SIGNALS) |
|
// Harvest the status of the agent process to prevent a zombie |
|
Boolean keepWaiting = false; |
|
do |
|
{ |
|
pid_t status = waitpid(_pid, 0, 0); |
|
if (status == -1) |
|
{ |
|
if (errno == EINTR) |
|
{ |
|
keepWaiting = true; |
|
} |
|
else |
|
{ |
|
Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"ProviderAgentContainer::_uninitialize(): " |
|
"waitpid failed; errno = %d.", errno); |
|
} |
|
} |
|
} while (keepWaiting); |
|
#endif |
|
|
_isInitialized = false; | _isInitialized = false; |
| |
// | // |
|
|
{ | { |
AutoMutex tableLock(_outstandingRequestTableMutex); | AutoMutex tableLock(_outstandingRequestTableMutex); |
| |
|
CIMResponseMessage* response = |
|
cleanShutdown ? _REQUEST_NOT_PROCESSED : 0; |
|
|
for (OutstandingRequestTable::Iterator i = | for (OutstandingRequestTable::Iterator i = |
_outstandingRequestTable.start(); | _outstandingRequestTable.start(); |
i != 0; i++) | i != 0; i++) |
|
|
PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2, | PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2, |
String("Completing messageId \"") + i.value()->messageId + | String("Completing messageId \"") + i.value()->messageId + |
"\" with a null response."); | "\" with a null response."); |
i.value()->responseMessage = 0; |
i.value()->responseMessage = response; |
i.value()->responseReady->signal(); | i.value()->responseReady->signal(); |
} | } |
| |
|
|
"ProviderAgentContainer::processMessage"); | "ProviderAgentContainer::processMessage"); |
| |
CIMResponseMessage* response; | CIMResponseMessage* response; |
|
|
|
do |
|
{ |
|
response = _processMessage(request); |
|
} while (response == _REQUEST_NOT_PROCESSED); |
|
|
|
PEG_METHOD_EXIT(); |
|
return response; |
|
} |
|
|
|
CIMResponseMessage* ProviderAgentContainer::_processMessage( |
|
CIMRequestMessage* request) |
|
{ |
|
PEG_METHOD_ENTER(TRC_PROVIDERMANAGER, |
|
"ProviderAgentContainer::_processMessage"); |
|
|
|
CIMResponseMessage* response; |
String originalMessageId = request->messageId; | String originalMessageId = request->messageId; |
| |
// These three variables are used for the provider module optimization. | // These three variables are used for the provider module optimization. |
|
|
throw; | throw; |
} | } |
| |
|
// A response value of _REQUEST_NOT_PROCESSED indicates that the |
|
// provider agent process was terminating when the request was sent. |
|
// The request was not processed by the provider agent, so it can be |
|
// retried safely. |
|
if (response == _REQUEST_NOT_PROCESSED) |
|
{ |
|
return response; |
|
} |
|
|
// A null response is returned when an agent connection is closed | // A null response is returned when an agent connection is closed |
// while requests remain outstanding. | // while requests remain outstanding. |
if (response == 0) | if (response == 0) |
|
|
(readStatus == AnonymousPipe::STATUS_CLOSED)) | (readStatus == AnonymousPipe::STATUS_CLOSED)) |
{ | { |
AutoMutex lock(_agentMutex); | AutoMutex lock(_agentMutex); |
_uninitialize(); |
_uninitialize(false); |
|
return; |
|
} |
|
|
|
// A null message indicates that the provider agent process has |
|
// finished its processing and is ready to exit. |
|
if (message == 0) |
|
{ |
|
AutoMutex lock(_agentMutex); |
|
_uninitialize(true); |
return; | return; |
} | } |
| |