BUG#: 8762
authorsahana.prabhakar <sahana.prabhakar>
Fri, 2 Jul 2010 09:26:29 +0000 (09:26 +0000)
committersahana.prabhakar <sahana.prabhakar>
Fri, 2 Jul 2010 09:26:29 +0000 (09:26 +0000)
TITLE: PEP 349 implementation.
DESCRIPTION: Improve the availability of the CIMOM by better isolation from faulty providers.

37 files changed:
TestMakefile
src/Pegasus/Common/CIMMessage.cpp
src/Pegasus/Common/CIMMessage.h
src/Pegasus/Common/CimomMessage.cpp
src/Pegasus/Common/CimomMessage.h
src/Pegasus/Common/HTTPConnection.cpp
src/Pegasus/Common/HTTPConnection.h
src/Pegasus/Common/MessageQueue.cpp
src/Pegasus/Common/MessageQueue.h
src/Pegasus/ProviderManagerService/BasicProviderManagerRouter.cpp
src/Pegasus/ProviderManagerService/BasicProviderManagerRouter.h
src/Pegasus/ProviderManagerService/OOPProviderManagerRouter.cpp
src/Pegasus/ProviderManagerService/OOPProviderManagerRouter.h
src/Pegasus/ProviderManagerService/ProviderAgent/ProviderAgent.cpp
src/Pegasus/ProviderManagerService/ProviderManagerRouter.h
src/Pegasus/ProviderManagerService/ProviderManagerService.cpp
src/Pegasus/ProviderManagerService/ProviderManagerService.h
src/Pegasus/Server/CIMServer.cpp
src/Pegasus/msg/Server/pegasusServer_en.txt
src/Providers/TestProviders/FaultyInstanceProvider/Makefile [new file with mode: 0644]
src/Providers/TestProviders/FaultyInstanceProvider/TestFaultyInstanceProvider.cpp [new file with mode: 0644]
src/Providers/TestProviders/FaultyInstanceProvider/TestFaultyInstanceProvider.h [new file with mode: 0644]
src/Providers/TestProviders/FaultyInstanceProvider/TestFaultyProviderMain.cpp [new file with mode: 0644]
src/Providers/TestProviders/FaultyInstanceProvider/TestGoodIndicationProvider.cpp [new file with mode: 0644]
src/Providers/TestProviders/FaultyInstanceProvider/TestGoodIndicationProvider.h [new file with mode: 0644]
src/Providers/TestProviders/FaultyInstanceProvider/testclient/Makefile [new file with mode: 0644]
src/Providers/TestProviders/FaultyInstanceProvider/testclient/TestFaultyInstanceProviderClient.cpp [new file with mode: 0644]
src/Providers/TestProviders/Load/Makefile
src/Providers/TestProviders/Load/TestFaultyProviderRegistration.mof [new file with mode: 0644]
src/Providers/TestProviders/Load/TestFaultyProviderSchema.mof [new file with mode: 0644]
src/Providers/TestProviders/Load/TestGoodInstanceProviderRegistration.mof [new file with mode: 0644]
src/Providers/TestProviders/Makefile
src/Providers/TestProviders/TestGoodInstanceProvider/Makefile [new file with mode: 0644]
src/Providers/TestProviders/TestGoodInstanceProvider/TestGoodInstanceProvider.cpp [new file with mode: 0644]
src/Providers/TestProviders/TestGoodInstanceProvider/TestGoodInstanceProvider.h [new file with mode: 0644]
src/Providers/TestProviders/TestGoodInstanceProvider/TestGoodInstanceProviderMain.cpp [new file with mode: 0644]
src/Unsupported/scripts/Unix/NightlyBuildScriptHP

index 21aa47226edbbd3a0160d9eded345eaed4be011d..d5ec9bafb9fb5178b734b4094a439ff900b27518 100644 (file)
@@ -305,6 +305,7 @@ serversuite: FORCE
        $(MAKE) --directory=$(PEGASUS_ROOT) -f TestMakefile runCBATestSuites
        $(MAKE) --directory=$(PEGASUS_ROOT) -f TestMakefile run_SDK_TS1
        $(MAKE) --directory=$(PEGASUS_ROOT) -f TestMakefile run_ExportClientSSL_TS1
+       $(MAKE) --directory=$(PEGASUS_ROOT) -f TestMakefile run_Cimserver_Availability
 ifeq ($(PEGASUS_ENABLE_CMPI_PROVIDER_MANAGER),true)
        $(MAKE) --directory=$(PEGASUS_ROOT) -f TestMakefile run_Cmpi_Sub
 endif
@@ -777,7 +778,6 @@ run_idleConnectionTimeout1: FORCE
             TESTSUITE_CMDS="$(IDLE_CONNECTION_TIMEOUT_1_TEST_CMDS)"
 ###############################################################################
 
-
 ###############################################################################
 ##  idleConnectionTimeout Test Suite 2:  uses IdleConnectionTimeout client test
 ##
@@ -795,6 +795,22 @@ run_idleConnectionTimeout2: FORCE
             TESTSUITE_CMDS="$(IDLE_CONNECTION_TIMEOUT_2_TEST_CMDS)"
 ###############################################################################
 
+###############################################################################
+##  cimserver thread limit test:
+##
+##  Configuration Options: none
+##
+###############################################################################
+CIMSERVER_THREAD_LIMIT_TEST_CONFIG_OPTIONS = forceProviderProcesses=true
+CIMSERVER_THREAD_LIMIT_TEST_CMDS = \
+       $(MAKE)@@--directory \
+            $(PEGASUS_ROOT)/src/Providers/TestProviders/FaultyInstanceProvider/testclient \
+            -f@@Makefile@@runAvailabilityTest
+run_Cimserver_Availability: FORCE
+       $(MAKE) -f $(PEGASUS_ROOT)/TestMakefile runTestSuite \
+            CIMSERVER_CONFIG_OPTIONS="$(CIMSERVER_THREAD_LIMIT_TEST_CONFIG_OPTIONS)" \
+            TESTSUITE_CMDS="$(CIMSERVER_THREAD_LIMIT_TEST_CMDS)"
+###############################################################################
 
 ###############################################################################
 ##  cimsub CLI Test Suite 1:  PG_InterOp Tests
index 8e1cbe42c4b6b3453754800a43408b0cc5332981..2c80c801c0cc9960cc8307b74620eded3b60ca07 100644 (file)
@@ -603,11 +603,13 @@ CIMResponseMessage::CIMResponseMessage(
     MessageType type_,
     const String& messageId_,
     const CIMException& cimException_,
-    const QueueIdStack& queueIds_)
+    const QueueIdStack& queueIds_,
+    Boolean isAsyncResponsePending_)
     :
     CIMMessage(type_, messageId_),
     queueIds(queueIds_),
-    cimException(cimException_)
+    cimException(cimException_),
+    isAsyncResponsePending(isAsyncResponsePending_)
 {
 }
 
index d67847d9ad4c7941e79f88bd930e5764c2d2c7c0..4d38b9d51fcd36957c3fc7bc4a939ad82070e2f2 100644 (file)
@@ -182,12 +182,17 @@ public:
         MessageType type_,
         const String& messageId_,
         const CIMException& cimException_,
-        const QueueIdStack& queueIds_);
+        const QueueIdStack& queueIds_,
+        Boolean isAsyncResponsePending=false);
 
     void syncAttributes(const CIMRequestMessage* request);
 
     QueueIdStack queueIds;
     CIMException cimException;
+
+    // This flag indicates if the response will arrive asynchronously.
+    Boolean isAsyncResponsePending;
+
 };
 
 //
index d2d189f996f803abad352371dd4fc71eff3ce567..30ff9af3560b2e958f22add80a73df8c9a0032b9 100644 (file)
@@ -208,6 +208,11 @@ Message* AsyncLegacyOperationStart::get_action()
 
 }
 
+void AsyncLegacyOperationStart::put_action(Message *act_)
+{
+    _act = act_;
+}
+
 AsyncLegacyOperationResult::AsyncLegacyOperationResult(
     AsyncOpNode* operation,
     Message* result)
index b4610bdc66f84b44378b085f1a84d1d77c136ec9..4fd6c3c9ea5bd2ce7ed89542f9ba5e7d83ae77ab 100644 (file)
@@ -240,6 +240,8 @@ public:
 
     Message* get_action();
 
+    void put_action(Message *action);
+
 private:
     friend class MessageQueueService;
     friend class cimom;
index a7742de35ccd4e192b5ce629ae584c41db5f3be3..7c88dfc7aad03c5e61bd1e165131e6d6de36a3a0 100644 (file)
@@ -311,7 +311,7 @@ HTTPConnection::~HTTPConnection()
     // HTTPConnection::handleEnqueue(), we are running a risk of
     // accessing a deleted object and crashing cimserver.
     AutoMutex connectionLock(_connection_mut);
-     _socket->close();
+    _socket->close();
 
     PEG_METHOD_EXIT();
 }
@@ -321,6 +321,22 @@ void HTTPConnection::enqueue(Message *message)
     handleEnqueue(message);
 }
 
+Boolean HTTPConnection::isActive()
+{
+    PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::isActive");
+    if(needsReconnect())
+    {
+        PEG_METHOD_EXIT();
+        return false;
+    }
+    else
+    {
+        PEG_METHOD_EXIT();
+        return true;
+    }
+}
+
+
 void HTTPConnection::handleInternalServerError(
     Uint32 respMsgIndex,
     Boolean isComplete)
index 0d471fc2eef5e89ec754c557bdb1cdbf758d8f00..ab18938e26d06eed76636bda9f04ad48158bf9c6 100644 (file)
@@ -71,6 +71,16 @@ public:
 
     virtual void enqueue(Message *);
 
+    /**
+        In this specialization of isActive a check is performed on the
+        non-blocking socket to see if it is active by reading 1 byte. Since the 
+        current thread is processing the request, its safe to try to read 1 byte
+        from the socket as there should be no data on the socket. If read 
+        returns a message of size zero, it is an indication that the client has 
+        closed the connection and the socket at the server end can be closed.
+    */
+    virtual Boolean isActive();
+
     /** This method is called whenever a SocketMessage is enqueued
         on the input queue of the HTTPConnection object.
     */
index b74bd98d038658180ad0cd38c438bc0a11a50415..981349c38a1c3d182400d1b57c7bf96028cf1f34 100644 (file)
@@ -137,6 +137,11 @@ Message* MessageQueue::dequeue()
     return message;
 }
 
+Boolean MessageQueue::isActive()
+{
+    return true;
+}
+
 const char* MessageQueue::getQueueName() const
 {
     return _name;
index a72e98c18e7d414ae9217b9c58c7748f70987c34..9ff7ec024d7e8c7ad6524a9b7d46c36679b0972a 100644 (file)
@@ -77,6 +77,12 @@ public:
     */
     virtual Message* dequeue();
 
+    /**
+        This function will indicate whether the MessageQueue is active or not. 
+        By default this function will return true and do nothing else.
+    */
+    virtual Boolean isActive();
+
     /** Returns true if there are no messages on the queue. */
     Boolean isEmpty() const { return  (Boolean) _messageList.is_empty(); }
 
index 9433aaead39924cd71ab366a6f8c829b426752df..bff99296d48f84bdcf49274c91e7d3623230839a 100644 (file)
@@ -539,10 +539,10 @@ Boolean BasicProviderManagerRouter::hasActiveProviders()
     return false;
 }
 
-void BasicProviderManagerRouter::unloadIdleProviders()
+void BasicProviderManagerRouter::idleTimeCleanup()
 {
     PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
-        "BasicProviderManagerRouter::unloadIdleProviders");
+        "BasicProviderManagerRouter::idleTimeCleanup");
 
     //
     // Save pointers to the ProviderManagerContainers so we don't hold the
index 86e05bbf65df21445eb6ba50b2408de90f6993ba..cb79e8ca850a0f3a44a724b3e885a4e5d0b37a1d 100644 (file)
@@ -67,7 +67,7 @@ public:
      */
     Boolean hasActiveProviders();
 
-    virtual void unloadIdleProviders();
+    virtual void idleTimeCleanup();
 
 private:
     BasicProviderManagerRouter();
index d48d777b5e747e02aaa0d7654b98d775141ce34f..db51475204412365783972cb34a7f998e163460c 100644 (file)
@@ -78,6 +78,43 @@ PEGASUS_NAMESPACE_BEGIN
 static String _GROUP_PREFIX = "grp:";
 static String _MODULE_PREFIX = "mod:";
 
+static struct timeval deallocateWait = {300, 0};
+
+// This calss is used to aggregate the responses sent when a single requests can
+// result in many responses and these responses need to be aggregated before a 
+// response is sent back to the ProviderManageService.
+class RespAggCounter 
+{ 
+public: 
+    RespAggCounter(Uint32 count):
+        _expectedResponseCount(count),
+        _receivedResponseCount(0)
+    { 
+    } 
+
+    Boolean isComplete(CIMException &e) 
+    { 
+        AutoMutex mtx(_mutex); 
+        if (e.getCode()  != CIM_ERR_SUCCESS) 
+        { 
+            _exception = e; 
+        } 
+        _receivedResponseCount++; 
+        return _receivedResponseCount == _expectedResponseCount ; 
+    } 
+
+    CIMException getException() 
+    { 
+        return _exception; 
+    } 
+
+private: 
+    Mutex _mutex; 
+    Uint32 _expectedResponseCount, _receivedResponseCount ; 
+    CIMException _exception; 
+};
+
+
 /////////////////////////////////////////////////////////////////////////////
 // OutstandingRequestTable and OutstandingRequestEntry
 /////////////////////////////////////////////////////////////////////////////
@@ -86,10 +123,10 @@ static String _MODULE_PREFIX = "mod:";
     An OutstandingRequestEntry represents a request message sent to a
     Provider Agent for which no response has been received.  The request
     sender provides the message ID and a location for the response to be
-    returned, and then waits on the semaphore.  When a response matching
-    the message ID is received, it is placed into the specified location
-    and the semaphore is signaled.
- */
+    returned. When a response matching the message ID is received, the 
+    OutstandingRequestEntry is updated to indicate that the response 
+    will arrive asynchronously. This entry will be deleted 
   when the response arrives.  */
 class OutstandingRequestEntry
 {
 public:
@@ -97,11 +134,11 @@ public:
         String originalMessageId_,
         CIMRequestMessage* requestMessage_,
         CIMResponseMessage*& responseMessage_,
-        Semaphore* responseReady_)
+        RespAggCounter* respAggregator_=NULL)
         : originalMessageId(originalMessageId_),
           requestMessage(requestMessage_),
           responseMessage(responseMessage_),
-          responseReady(responseReady_)
+          respAggregator(respAggregator_)
     {
     }
 
@@ -115,12 +152,21 @@ public:
     String originalMessageId;
     CIMRequestMessage* requestMessage;
     CIMResponseMessage*& responseMessage;
-    Semaphore* responseReady;
+
+    // The aggregator object which aggregates the responses for requests 
+    // like CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE etc.
+    RespAggCounter* respAggregator;
 };
 
-typedef HashTable<String, OutstandingRequestEntry*, EqualFunc<String>,
+typedef HashTable<String, SharedPtr<OutstandingRequestEntry>, EqualFunc<String>,
     HashFunc<String> > OutstandingRequestTable;
 
+class RetryThreadParam{
+public:
+    ProviderAgentContainer *pac;
+    Array<CIMRequestMessage *> retryRequestArray;
+};
+
 
 /////////////////////////////////////////////////////////////////////////////
 // ProviderAgentContainer
@@ -136,7 +182,9 @@ public:
         PEGASUS_INDICATION_CALLBACK_T indicationCallback,
         PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
         PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback,
-        Boolean subscriptionInitComplete);
+        PEGASUS_ASYNC_RESPONSE_CALLBACK_T asyncResponseCallback,
+        Boolean subscriptionInitComplete,
+        ThreadPool * threadPool);
 
     ~ProviderAgentContainer();
 
@@ -144,9 +192,21 @@ public:
 
     String getGroupNameWithType() const;
 
-    CIMResponseMessage* processMessage(CIMRequestMessage* request);
+    CIMResponseMessage* processMessage(CIMRequestMessage* request,
+        RespAggCounter * respAggregator=NULL);
+
     void unloadIdleProviders();
 
+    /**
+        Check if the pending responses in the _outstandingRequestTable
+        have active client connections. If not then create a response 
+        to indicate that this client connection can be closed. The
+        entry for this request is also deleted from the 
+        _outstandingRequestTable. This function is called at regular 
+        intervals along with unloadIdleProviders
+    */
+    void cleanDisconnectedClientRequests();
+
 private:
     //
     // Private methods
@@ -197,13 +257,18 @@ private:
         Performs the processMessage work, but does not retry on a transient
         error.
      */
-    CIMResponseMessage* _processMessage(CIMRequestMessage* request);
+    CIMResponseMessage* _processMessage(CIMRequestMessage* request,
+        RespAggCounter *respAggregator);
 
     /**
         Read and process response messages from the Provider Agent until
         the connection is closed.
      */
     void _processResponses();
+
+    void _sendResponse(CIMRequestMessage *request, 
+        CIMResponseMessage *response);
+
     static ThreadReturnType PEGASUS_THREAD_CDECL
         _responseProcessor(void* arg);
 
@@ -214,6 +279,19 @@ private:
     void _processGetSCMOClassRequest(
         ProvAgtGetScmoClassRequestMessage* request);
 
+    /**
+      This function will fetch the bottom most queueid from the 
+      QueueIdStack of the request message and check if the queue isActive().
+    */
+    Boolean _isClientActive(CIMRequestMessage *request_);
+
+    /**
+       This thread will retry the request if the provider goes down
+       before the request is processed.
+    */
+    static ThreadReturnType PEGASUS_THREAD_CDECL _retryRequestHandler(
+        void* arg) ;
+
     //
     // Private data
     //
@@ -264,6 +342,11 @@ private:
      */
     PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T _providerModuleFailCallback;
 
+    /**
+        Callback function for async response.
+    */
+    PEGASUS_ASYNC_RESPONSE_CALLBACK_T _asyncResponseCallback;
+
     /**
         Indicates whether the Provider Agent is active.
      */
@@ -336,6 +419,11 @@ private:
      */
     Boolean _subscriptionInitComplete;
 
+    /**
+        OOPProviderManagerRouter ThreadPool pointer.
+    */
+    ThreadPool* _threadPool;
+
 };
 
 Uint32 ProviderAgentContainer::_numProviderProcesses = 0;
@@ -352,7 +440,9 @@ ProviderAgentContainer::ProviderAgentContainer(
     PEGASUS_INDICATION_CALLBACK_T indicationCallback,
     PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
     PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback,
-    Boolean subscriptionInitComplete)
+    PEGASUS_ASYNC_RESPONSE_CALLBACK_T asyncResponseCallback,
+    Boolean subscriptionInitComplete,
+    ThreadPool* threadPool)
     :
       _groupNameWithType(groupName),
       _userName(userName),
@@ -360,8 +450,10 @@ ProviderAgentContainer::ProviderAgentContainer(
       _indicationCallback(indicationCallback),
       _responseChunkCallback(responseChunkCallback),
       _providerModuleFailCallback(providerModuleFailCallback),
+      _asyncResponseCallback(asyncResponseCallback),
       _isInitialized(false),
-      _subscriptionInitComplete(subscriptionInitComplete)
+      _subscriptionInitComplete(subscriptionInitComplete),
+      _threadPool(threadPool)
 {
     PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
         "ProviderAgentContainer::ProviderAgentContainer");
@@ -676,6 +768,10 @@ void ProviderAgentContainer::_uninitialize(Boolean cleanShutdown)
         pid = _pid;
 #endif
 
+        // In case of a clean shutdown requests which could not be processed are
+        // retried in a new thread. 
+        Array<CIMRequestMessage *> retryReqArray;
+
         //
         // Complete with null responses all outstanding requests on this
         // connection
@@ -683,23 +779,119 @@ void ProviderAgentContainer::_uninitialize(Boolean cleanShutdown)
         {
             AutoMutex tableLock(_outstandingRequestTableMutex);
 
-            CIMResponseMessage* response =
-                cleanShutdown ? _REQUEST_NOT_PROCESSED : 0;
-
             for (OutstandingRequestTable::Iterator i =
                      _outstandingRequestTable.start();
                  i != 0; i++)
             {
-                PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL4,
-                    "Completing messageId \"%s\" with a null response.",
-                    (const char*)i.key().getCString()));
-                i.value()->responseMessage = response;
-                i.value()->responseReady->signal();
-            }
+                Boolean sendResponseNow = false;
+                CIMResponseMessage *response;
+
+                if(cleanShutdown)
+                {
+                    MessageType msgType = i.value()->requestMessage->getType();
+
+                    if(msgType == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE ||
+                        msgType == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE ||
+                        msgType == 
+                            CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE ||
+                        msgType == 
+                            CIM_INDICATION_SERVICE_DISABLED_REQUEST_MESSAGE ||
+                        msgType == CIM_DELETE_SUBSCRIPTION_REQUEST_MESSAGE)
+                    {
+                        response = i.value()->requestMessage->buildResponse();
+                        sendResponseNow = true;
+                    }
+                    else
+                    {
+                        // retry the request
+                        retryReqArray.append(i.value()->requestMessage);
+                    }
+                }
+                else
+                {
+                    response = i.value()->requestMessage->buildResponse();
+                    response->cimException = PEGASUS_CIM_EXCEPTION(
+                       CIM_ERR_FAILED,
+                       MessageLoaderParms(
+                           "ProviderManager.OOPProviderManagerRouter."
+                               "CIMPROVAGT_CONNECTION_LOST",
+                           "Lost connection with cimprovagt \"$0\".",
+                           _moduleOrGroupName));
+                    sendResponseNow = true;
+                }
+
+                if(sendResponseNow)
+                {                
+                    PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL4,
+                        "Completing messageId \"%s\" with a default response.",
+                        (const char*)i.key().getCString()));
 
+                    response->setComplete(true);
+                    _asyncResponseCallback(
+                        i.value()->requestMessage,
+                        response);
+                }
+                // delete the response aggregator
+                delete i.value()->respAggregator;
+            }
             _outstandingRequestTable.clear();
         }
 
+        if(retryReqArray.size() > 0 )
+        {
+            ThreadStatus rtn = PEGASUS_THREAD_OK;
+            AutoPtr<RetryThreadParam> parms(new RetryThreadParam());
+            parms->pac = this;
+            parms->retryRequestArray = retryReqArray;
+            Boolean didRetry = true;
+
+            while((rtn = _threadPool->allocate_and_awaken(
+                (void*)parms.release(),
+                ProviderAgentContainer::_retryRequestHandler))
+                != PEGASUS_THREAD_OK)
+            {
+                if(rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES)
+                {
+                    Threads::yield();
+                }
+                else
+                {
+                    PEG_TRACE((TRC_PROVIDERMANAGER,
+                        Tracer::LEVEL1,
+                        "Could not allocate thread to retry "
+                        "request in %s",
+                        (const char *)_moduleOrGroupName. \
+                        getCString()));
+                    didRetry = false;
+                }
+            }        
+
+            if(!didRetry)
+            {
+                for(Uint32 i=0; i<retryReqArray.size(); i++)
+                {
+                    CIMResponseMessage *response = 
+                        retryReqArray[i]->buildResponse();
+                    response->setComplete(true);
+                    response->cimException =
+                        PEGASUS_CIM_EXCEPTION(
+                            CIM_ERR_FAILED,
+                            MessageLoaderParms("ProviderManager."
+                                "OOPProviderManagerRouter."
+                                    "REQUEST_RETRY_THREAD_"
+                                "ALLOCATION_FAILED",
+                                "Failed to allocate a thread to "
+                                   "retry a request in \"$0\".",
+                                _moduleOrGroupName));
+                    _asyncResponseCallback(
+                        retryReqArray[i],
+                        response);
+               }
+            }
+        } 
+
         //
         //  If not a clean shutdown, call the provider module failure callback
         //
@@ -760,16 +952,17 @@ String ProviderAgentContainer::getGroupNameWithType() const
 }
 
 CIMResponseMessage* ProviderAgentContainer::processMessage(
-    CIMRequestMessage* request)
+    CIMRequestMessage* request,RespAggCounter* respAggregator)
 {
     PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
         "ProviderAgentContainer::processMessage");
 
     CIMResponseMessage* response;
+    MessageType msgType = request->getType();
 
     do
     {
-        response = _processMessage(request);
+        response = _processMessage(request,respAggregator);
 
         if (response == _REQUEST_NOT_PROCESSED)
         {
@@ -803,23 +996,22 @@ CIMResponseMessage* ProviderAgentContainer::processMessage(
         }
     } while (response == _REQUEST_NOT_PROCESSED);
 
-    if (request->getType() == CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
+    if (msgType == CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
     {
         _subscriptionInitComplete = true;
     }
-    else if (request->getType() ==
+    else if (msgType ==
         CIM_INDICATION_SERVICE_DISABLED_REQUEST_MESSAGE)
     {
         _subscriptionInitComplete = false;
     }
 
-
     PEG_METHOD_EXIT();
     return response;
 }
 
 CIMResponseMessage* ProviderAgentContainer::_processMessage(
-    CIMRequestMessage* request)
+    CIMRequestMessage* request, RespAggCounter *respAggregator)
 {
     PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
         "ProviderAgentContainer::_processMessage");
@@ -853,9 +1045,12 @@ CIMResponseMessage* ProviderAgentContainer::_processMessage(
         //
         // Set up the OutstandingRequestEntry for this request
         //
-        Semaphore waitSemaphore(0);
-        OutstandingRequestEntry outstandingRequestEntry(
-            originalMessageId, request, response, &waitSemaphore);
+        SharedPtr<OutstandingRequestEntry> outstandingRequestEntry(
+            new OutstandingRequestEntry(
+                originalMessageId,
+                    request,
+                    response,
+                respAggregator));
 
         //
         // Lock the Provider Agent Container while initializing the
@@ -879,7 +1074,7 @@ CIMResponseMessage* ProviderAgentContainer::_processMessage(
                 AutoMutex tableLock(_outstandingRequestTableMutex);
 
                 _outstandingRequestTable.insert(
-                    uniqueMessageId, &outstandingRequestEntry);
+                    uniqueMessageId, outstandingRequestEntry);
             }
 
             // Get the provider module from the ProviderIdContainer to see if
@@ -921,14 +1116,14 @@ CIMResponseMessage* ProviderAgentContainer::_processMessage(
                     (const char*)uniqueMessageId.getCString()));
 
                 request->messageId = uniqueMessageId;
-                AnonymousPipe::Status writeStatus =
+                AnonymousPipe::Status writeStatus = 
                     _pipeToAgent->writeMessage(request);
                 request->messageId = originalMessageId;
 
                 if (doProviderModuleOptimization)
                 {
                     request->operationContext.set(*origProviderId.get());
-                }
+                } 
 
                 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
                 {
@@ -962,6 +1157,12 @@ CIMResponseMessage* ProviderAgentContainer::_processMessage(
                 {
                     _providerModuleCache = origProviderId->getModule();
                 }
+
+                response = request->buildResponse();
+                response->isAsyncResponsePending = true;
+                PEG_METHOD_EXIT();
+                return response;
             }
             catch (...)
             {
@@ -985,51 +1186,6 @@ CIMResponseMessage* ProviderAgentContainer::_processMessage(
                 throw;
             }
         }
-
-        //
-        // Wait for the response
-        //
-        try
-        {
-            // Must not hold _agentMutex while waiting for the response
-            waitSemaphore.wait();
-        }
-        catch (...)
-        {
-            // Remove the OutstandingRequestTable entry for this request
-            {
-                AutoMutex tableLock(_outstandingRequestTableMutex);
-                Boolean removed =
-                    _outstandingRequestTable.remove(uniqueMessageId);
-                PEGASUS_ASSERT(removed);
-            }
-            PEG_METHOD_EXIT();
-            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)
-        {
-            PEG_METHOD_EXIT();
-            return response;
-        }
-
-        // A null response is returned when an agent connection is closed
-        // while requests remain outstanding.
-        if (response == 0)
-        {
-            response = request->buildResponse();
-            response->cimException = PEGASUS_CIM_EXCEPTION(
-                CIM_ERR_FAILED,
-                MessageLoaderParms(
-                    "ProviderManager.OOPProviderManagerRouter."
-                        "CIMPROVAGT_CONNECTION_LOST",
-                    "Lost connection with cimprovagt \"$0\".",
-                    _moduleOrGroupName));
-        }
     }
     catch (CIMException& e)
     {
@@ -1054,7 +1210,7 @@ CIMResponseMessage* ProviderAgentContainer::_processMessage(
             "Caught unknown exception");
         response = request->buildResponse();
         response->cimException = PEGASUS_CIM_EXCEPTION(
-            CIM_ERR_FAILED, String::EMPTY);
+            CIM_ERR_FAILED, String());
     }
 
     response->messageId = originalMessageId;
@@ -1081,6 +1237,40 @@ void ProviderAgentContainer::unloadIdleProviders()
     PEG_METHOD_EXIT();
 }
 
+void ProviderAgentContainer::cleanDisconnectedClientRequests()
+{
+    PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
+        "ProviderAgentContainer::cleanDisconnectedClientRequests");
+
+    // Array to store the keys which need to be remvoed.
+    Array<String> keys;
+
+    AutoMutex tableLock(_outstandingRequestTableMutex);
+    for (OutstandingRequestTable::Iterator i = _outstandingRequestTable.start();
+        i != 0; i++)
+    {
+        if(!_isClientActive(i.value()->requestMessage))
+        {
+            // create empty response and set isComplete to true. 
+            AutoPtr<CIMResponseMessage> response;
+            SharedPtr<OutstandingRequestEntry> entry = i.value();
+            response.reset(i.value()->requestMessage->buildResponse());
+            response->setComplete(true);
+            response->messageId = i.value()->originalMessageId;
+            _asyncResponseCallback(
+                i.value()->requestMessage,
+                response.release());
+            keys.append(i.key());
+        }
+    }
+
+    for(Uint32 j=0; j<keys.size();j++)
+    {
+         _outstandingRequestTable.remove(keys[j]);
+    }
+    PEG_METHOD_EXIT();
+}
+
 void ProviderAgentContainer::_processGetSCMOClassRequest(
     ProvAgtGetScmoClassRequestMessage* request)
 {
@@ -1153,6 +1343,49 @@ void ProviderAgentContainer::_processGetSCMOClassRequest(
     return;
 }
 
+Boolean ProviderAgentContainer::_isClientActive(CIMRequestMessage *request_)
+{
+    MessageQueue *connectionMQ = MessageQueue::lookup(request_->queueIds[0]);
+    return connectionMQ->isActive();
+}
+
+// Note: This method should not throw an exception.  It is used as a thread
+// entry point, and any exceptions thrown are ignored.
+ThreadReturnType PEGASUS_THREAD_CDECL
+ProviderAgentContainer::_retryRequestHandler(void* arg)
+{
+    PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
+        "ProviderAgentContainer::_retryRequestHandler");
+
+    PEGASUS_ASSERT(arg != 0);
+    RetryThreadParam *threadParams= 
+        reinterpret_cast<RetryThreadParam *>(arg);
+    Array<CIMRequestMessage *> retryRequests = threadParams->retryRequestArray;
+    try
+    {
+        for(Uint32 i=0; i<retryRequests.size(); i++)
+        {
+            threadParams->pac->processMessage(retryRequests[i]);
+        }
+    }
+    catch(Exception &e)
+    {
+        PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL1,
+            "Unexpected exception in _retryRequestHandler: %s",
+            (const char*)e.getMessage().getCString()));
+    }
+    catch (...)
+    {
+        PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
+            "Unexpected exception in _retryRequestHandler.");
+    }
+    PEG_METHOD_EXIT();
+
+    return ThreadReturnType(0);
+}
+
+
 void ProviderAgentContainer::_processResponses()
 {
     PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
@@ -1218,47 +1451,95 @@ void ProviderAgentContainer::_processResponses()
                 response = dynamic_cast<CIMResponseMessage*>(message);
                 PEGASUS_ASSERT(response != 0);
 
+                Boolean foundEntry = false; 
                 // Get the OutstandingRequestEntry for this response chunk
-                OutstandingRequestEntry* _outstandingRequestEntry = 0;
+                SharedPtr<OutstandingRequestEntry> _outstandingRequestEntry;
                 {
                     AutoMutex tableLock(_outstandingRequestTableMutex);
-                    Boolean foundEntry = _outstandingRequestTable.lookup(
+                    foundEntry = _outstandingRequestTable.lookup(
                         response->messageId, _outstandingRequestEntry);
-                    PEGASUS_ASSERT(foundEntry);
                 }
 
-                // Put the original message ID into the response
-                response->messageId =
-                    _outstandingRequestEntry->originalMessageId;
-
-                // Call the response chunk callback to process the chunk
-                _responseChunkCallback(
-                    _outstandingRequestEntry->requestMessage, response);
+                if(foundEntry)
+                {
+                    // Put the original message ID into the response
+                    response->messageId =
+                        _outstandingRequestEntry->originalMessageId;
+
+                    // Call the response chunk callback to process the chunk
+                    // if the client connection is active.
+                    // No need to acquire _agentMutex since this a chunk 
+                    // response callback. The request object will not be
+                    // deleted here.
+                    _responseChunkCallback(
+                        _outstandingRequestEntry->requestMessage, response);
+                }
             }
             else
             {
                 // Process a completed response
-
                 CIMResponseMessage* response;
                 response = dynamic_cast<CIMResponseMessage*>(message);
                 PEGASUS_ASSERT(response != 0);
 
+                Boolean foundEntry = false;
                 // Give the response to the waiting OutstandingRequestEntry
-                OutstandingRequestEntry* _outstandingRequestEntry = 0;
+                SharedPtr<OutstandingRequestEntry> _outstandingRequestEntry;
                 {
                     AutoMutex tableLock(_outstandingRequestTableMutex);
-                    Boolean foundEntry = _outstandingRequestTable.lookup(
+                    foundEntry = _outstandingRequestTable.lookup(
                         response->messageId, _outstandingRequestEntry);
-                    PEGASUS_ASSERT(foundEntry);
 
-                    // Remove the completed request from the table
-                    Boolean removed =
-                        _outstandingRequestTable.remove(response->messageId);
-                    PEGASUS_ASSERT(removed);
+                    if(foundEntry)
+                    {  
+                        // Remove the completed request from the table
+                        Boolean removed = _outstandingRequestTable.remove( \
+                            response->messageId);
+                        PEGASUS_ASSERT(removed);
+                    }
+
                 }
 
-                _outstandingRequestEntry->responseMessage = response;
-                _outstandingRequestEntry->responseReady->signal();
+                if(foundEntry)
+                {
+                    if(_outstandingRequestEntry->respAggregator == NULL)
+                    {
+                       response->messageId = 
+                           _outstandingRequestEntry->originalMessageId;
+
+                       _sendResponse(_outstandingRequestEntry->requestMessage,
+                           response);
+                    }
+                    else 
+                    {
+                        if(_outstandingRequestEntry->respAggregator-> \
+                            isComplete(response->cimException))
+                        {
+                            response->messageId = 
+                                _outstandingRequestEntry->originalMessageId;
+
+                            _sendResponse(
+                                _outstandingRequestEntry->requestMessage,
+                                response);
+
+                            // delete respAggregator pointer now
+                            delete _outstandingRequestEntry->respAggregator;
+                        }
+                        else
+                        {
+                            // this is not the last response for this request.
+                            // Its job is done and it can be deleted now.
+                            delete response;
+                        }
+                    }
+                }
+                else
+                {
+                    PEG_TRACE((TRC_DISCARDED_DATA,Tracer::LEVEL4,
+                        "The response for message id %s arrived after the " \
+                            "client disconnected.",
+                        (const char *)response->messageId.getCString()));
+                }
             }
         }
         catch (Exception& e)
@@ -1275,6 +1556,24 @@ void ProviderAgentContainer::_processResponses()
     }
 }
 
+void ProviderAgentContainer::_sendResponse(CIMRequestMessage *request,
+    CIMResponseMessage *response)
+{
+    response->syncAttributes(request);
+    {
+       // acquire the _agentMutex to make sure that
+       // _processMessage thread has finished
+       // processing the request.
+       AutoMutex agentLock(_agentMutex);
+    }
+
+    // Call the asyncResponseCallback to process
+    // the completed response.
+    _asyncResponseCallback(
+        request,
+        response);
+}
+
 ThreadReturnType PEGASUS_THREAD_CDECL
 ProviderAgentContainer::_responseProcessor(void* arg)
 {
@@ -1297,7 +1596,8 @@ OOPProviderManagerRouter::OOPProviderManagerRouter(
     ProviderRegistrationManager *providerRegistrationManager,
     PEGASUS_INDICATION_CALLBACK_T indicationCallback,
     PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
-    PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback)
+    PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback,
+    PEGASUS_ASYNC_RESPONSE_CALLBACK_T asyncResponseCallback)
 {
     PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
         "OOPProviderManagerRouter::OOPProviderManagerRouter");
@@ -1305,8 +1605,11 @@ OOPProviderManagerRouter::OOPProviderManagerRouter(
     _indicationCallback = indicationCallback;
     _responseChunkCallback = responseChunkCallback;
     _providerModuleFailCallback = providerModuleFailCallback;
+    _asyncResponseCallback = asyncResponseCallback;
     _subscriptionInitComplete = false;
     _providerRegistrationManager = providerRegistrationManager;
+    _threadPool = 
+        new ThreadPool(0, "OOPProviderManagerRouter", 0, 0, deallocateWait);;
     PEG_METHOD_EXIT();
 }
 
@@ -1324,6 +1627,8 @@ OOPProviderManagerRouter::~OOPProviderManagerRouter()
         {
             delete i.value();
         }
+
+        delete _threadPool;
     }
     catch (...) {}
 
@@ -1456,6 +1761,8 @@ Message* OOPProviderManagerRouter::processMessage(Message* message)
         Array<ProviderAgentContainer*> paArray =
             _lookupProviderAgents(groupNameWithType);
 
+        Array<ProviderAgentContainer*> paInit; 
+
         for (Uint32 i=0; i<paArray.size(); i++)
         {
             //
@@ -1463,38 +1770,25 @@ Message* OOPProviderManagerRouter::processMessage(Message* message)
             //
             if (paArray[i]->isInitialized())
             {
-                //
+                paInit.append(paArray[i]);
+            }
+        }
+
+        if(paInit.size() > 0)
+        {
+            RespAggCounter *respAggregator = 
+                new RespAggCounter(paInit.size());
+
+            for (Uint32 i=0; i<paInit.size(); i++)
+            {
                 // Forward the request to the provider agent
                 //
-                response.reset(paArray[i]->processMessage(request));
+                response.reset(
+                    paInit[i]->processMessage(request,respAggregator));
 
                 // Note: Do not uninitialize the ProviderAgentContainer here
                 // when a disable module operation is successful.  Just let the
                 // selecting thread notice when the agent connection is closed.
-
-                // Determine the success of the disable module operation
-                CIMDisableModuleResponseMessage* dmResponse =
-                    dynamic_cast<CIMDisableModuleResponseMessage*>(
-                        response.get());
-                PEGASUS_ASSERT(dmResponse != 0);
-
-                Boolean isStopped = false;
-                for (Uint32 j=0; j < dmResponse->operationalStatus.size(); j++)
-                {
-                    if (dmResponse->operationalStatus[j] ==
-                        CIM_MSE_OPSTATUS_VALUE_STOPPED)
-                    {
-                        isStopped = true;
-                        break;
-                    }
-                }
-
-                // If the operation is unsuccessful, stop and return the error
-                if ((dmResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
-                    !isStopped)
-                {
-                    break;
-                }
             }
         }
 
@@ -1524,41 +1818,30 @@ Message* OOPProviderManagerRouter::processMessage(Message* message)
         Array<ProviderAgentContainer*> paArray =
             _lookupProviderAgents(groupNameWithType);
 
+        // Create an array of initialized provider agents.
+        Array<ProviderAgentContainer*> paInit;
+
+        // create an array of initialized provider agents.
         for (Uint32 i=0; i<paArray.size(); i++)
         {
-            //
-            // Do not start up an agent process just to enable the module
-            //
-            if (paArray[i]->isInitialized())
+            if (paArray[i]->isInitialized()) 
+            {
+                paInit.append(paArray[i]);
+            }
+        }
+       
+        if(paInit.size() > 0 )
+        {
+            RespAggCounter *respAggregator = 
+                new RespAggCounter(paInit.size());
+
+            for (Uint32 i=0; i<paInit.size(); i++)
             {
                 //
                 // Forward the request to the provider agent
                 //
-                response.reset(paArray[i]->processMessage(request));
-
-                // Determine the success of the enable module operation
-                CIMEnableModuleResponseMessage* emResponse =
-                    dynamic_cast<CIMEnableModuleResponseMessage*>(
-                        response.get());
-                PEGASUS_ASSERT(emResponse != 0);
-
-                Boolean isOk = false;
-                for (Uint32 j=0; j < emResponse->operationalStatus.size(); j++)
-                {
-                    if (emResponse->operationalStatus[j] ==
-                        CIM_MSE_OPSTATUS_VALUE_OK)
-                    {
-                        isOk = true;
-                        break;
-                    }
-                }
-
-                // If the operation is unsuccessful, stop and return the error
-                if ((emResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
-                    !isOk)
-                {
-                    break;
-                }
+                response.reset(
+                    paInit[i]->processMessage(request,respAggregator));
             }
         }
 
@@ -1709,7 +1992,9 @@ ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
             groupNameWithType, userName, userContext,
             _indicationCallback, _responseChunkCallback,
             _providerModuleFailCallback,
-            _subscriptionInitComplete);
+            _asyncResponseCallback,
+            _subscriptionInitComplete,
+            _threadPool);
         _providerAgentTable.insert(key, pa);
     }
 
@@ -1747,51 +2032,51 @@ CIMResponseMessage* OOPProviderManagerRouter::_forwardRequestToAllAgents(
         for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
              i != 0; i++)
         {
-            paContainerArray.append(i.value());
+            if(i.value()->isInitialized())
+            {
+                paContainerArray.append(i.value());
+            }
         }
     }
 
-    CIMException responseException;
-
-    // Forward the request to each of the initialized provider agents
-    for (Uint32 j = 0; j < paContainerArray.size(); j++)
+    Boolean responsePending = false;
+    CIMResponseMessage *response = request->buildResponse();
+    
+    if(paContainerArray.size() > 0 )
     {
-        ProviderAgentContainer* pa = paContainerArray[j];
-        if (pa->isInitialized())
+        RespAggCounter *respAggregator = 
+            new RespAggCounter(paContainerArray.size());
+
+        // Forward the request to each of the initialized provider agents
+        for (Uint32 j = 0; j < paContainerArray.size(); j++)
         {
+            ProviderAgentContainer* pa = paContainerArray[j];
+
             // Note: The ProviderAgentContainer could become uninitialized
             // before _ProviderAgentContainer::processMessage() processes
             // this request.  In this case, the Provider Agent process will
             // (unfortunately) be started to process this message.
             AutoPtr<CIMResponseMessage> response;
-            response.reset(pa->processMessage(request));
-            if (response.get() != 0)
-            {
-                // If the operation failed, save the exception data
-                if ((response->cimException.getCode() != CIM_ERR_SUCCESS) &&
-                    (responseException.getCode() == CIM_ERR_SUCCESS))
-                {
-                    responseException = response->cimException;
-                }
-            }
+            response.reset(pa->processMessage(request,respAggregator));
+            responsePending = true;
         }
-    }
 
-    CIMResponseMessage* response = request->buildResponse();
-    response->cimException = responseException;
+        response->isAsyncResponsePending = responsePending;
+    }
 
     PEG_METHOD_EXIT();
     return response;
 }
 
-void OOPProviderManagerRouter::unloadIdleProviders()
+void OOPProviderManagerRouter::idleTimeCleanup()
 {
     PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
-        "OOPProviderManagerRouter::unloadIdleProviders");
+        "OOPProviderManagerRouter::idleTimeCleanup");
 
     // Get a list of the ProviderAgentContainers.  We need our own array copy
     // because we cannot hold the _providerAgentTableMutex while calling
-    // ProviderAgentContainer::unloadIdleProviders().
+    // ProviderAgentContainer::unloadIdleProviders() & 
+    // ProviderAgentContainer::cleanDisconnectedClientRequests().
     Array<ProviderAgentContainer*> paContainerArray;
     {
         AutoMutex tableLock(_providerAgentTableMutex);
@@ -1808,6 +2093,12 @@ void OOPProviderManagerRouter::unloadIdleProviders()
         paContainerArray[j]->unloadIdleProviders();
     }
 
+    // Iterate through the _providerAgentTable cleaning up disconnected clients.
+    for (Uint32 k = 0; k < paContainerArray.size(); k++)
+    {
+        paContainerArray[k]->cleanDisconnectedClientRequests();
+    }
+
     PEG_METHOD_EXIT();
 }
 
index 28d144984550d84c07898d07d1cbd7431f02f9f3..fb235ec32f80d836cce557c0c361c878fbf417ac 100644 (file)
@@ -49,6 +49,9 @@ PEGASUS_NAMESPACE_BEGIN
 typedef void (*PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T)(const String &,
     const String &, Uint16);
 
+typedef void (*PEGASUS_ASYNC_RESPONSE_CALLBACK_T)(
+    CIMRequestMessage* request, CIMResponseMessage* response);
+
 class ProviderAgentContainer;
 
 typedef HashTable<String, ProviderAgentContainer*, EqualFunc<String>,
@@ -62,13 +65,14 @@ public:
         ProviderRegistrationManager *providerRegistrationManager,
         PEGASUS_INDICATION_CALLBACK_T indicationCallback,
         PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
-        PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback);
+        PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback,
+        PEGASUS_ASYNC_RESPONSE_CALLBACK_T asyncResponseCallback);
 
     virtual ~OOPProviderManagerRouter();
 
     virtual Message* processMessage(Message* message);
 
-    virtual void unloadIdleProviders();
+    virtual void idleTimeCleanup();
 
     static ProviderRegistrationManager* getProviderRegistrationManager();
 
@@ -143,6 +147,11 @@ private:
      */
     PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T _providerModuleFailCallback;
 
+    /**
+       Callback function to be called for all async responses.
+    */
+    PEGASUS_ASYNC_RESPONSE_CALLBACK_T _asyncResponseCallback;
+
     /**
         The _providerAgentTable contains a ProviderAgentContainer entry for
         each of the Provider Agent processes for which a request has been
@@ -158,6 +167,11 @@ private:
 
     static ProviderRegistrationManager *_providerRegistrationManager;
 
+    /**
+        Pointer to the MessageQueueService thread pool.
+    */
+    ThreadPool *_threadPool;
+
 };
 
 PEGASUS_NAMESPACE_END
index 61596d874e1961fbeba951f4bed4285b22926617..a0639963b6adff84c879eaa832996fe65bbc73c6 100644 (file)
@@ -32,6 +32,7 @@
 #include <Pegasus/Common/Signal.h>
 #include <Pegasus/Common/Array.h>
 #include <Pegasus/Common/AutoPtr.h>
+#include <Pegasus/Common/AtomicInt.h>
 #include <Pegasus/Common/CIMMessageSerializer.h>
 #include <Pegasus/Common/CIMMessageDeserializer.h>
 #include <Pegasus/Common/Tracer.h>
@@ -55,6 +56,11 @@ PEGASUS_USING_STD;
 
 PEGASUS_NAMESPACE_BEGIN
 
+// threadCreationFailureLogged will indicate if the thread limit related
+// msg has been logged already. This will help avoid flooding the syslog/audit
+// log with thread limit reached errors.
+static AtomicInt threadCreationFailureLogged(0);
+
 /////////////////////////////////////////////////////////////////////////////
 //
 // ProviderAgentRequest
@@ -565,7 +571,18 @@ Boolean ProviderAgent::_readAndProcessRequest()
                    ProviderAgent::_processRequestAndWriteResponse)) !=
                PEGASUS_THREAD_OK)
         {
-            if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES)
+            // Yield only for the following request.
+            // CIM_INITIALIZE_PROVIDER_AGENT_REQUEST_MESSAGE,
+            // CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE,
+            // CIM_DISABLE_MODULE_REQUEST_MESSAGE,
+            // CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE,
+            // CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE,
+            // CIM_INDICATION_SERVICE_DISABLED_REQUEST_MESSAGE,
+            // CIM_EXPORT_INDICATION_REQUEST_MESSAGE 
+            // All the above have already been handled differently
+            // except for CIM_EXPORT_INDICATION_REQUEST_MESSAGE.
+            if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES &&
+                request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE)
             {
                 Threads::yield();
             }
@@ -573,25 +590,42 @@ Boolean ProviderAgent::_readAndProcessRequest()
             {
                 PEG_TRACE_CSTRING(TRC_PROVIDERAGENT, Tracer::LEVEL1,
                     "Could not allocate thread to process agent request.");
+                MessageLoaderParms msgLoaderPrms(
+                    "ProviderManager.ProviderAgent.ProviderAgent."
+                        "THREAD_ALLOCATION_FAILED",
+                    "Failed to allocate a thread in cimprovagt \"$0\".",
+                    _agentId);
 
                 AutoPtr<CIMResponseMessage> response(request->buildResponse());
                 response->cimException = PEGASUS_CIM_EXCEPTION_L(
-                    CIM_ERR_FAILED,
-                    MessageLoaderParms(
-                        "ProviderManager.ProviderAgent.ProviderAgent."
-                            "THREAD_ALLOCATION_FAILED",
-                        "Failed to allocate a thread in cimprovagt \"$0\".",
-                        _agentId));
+                    CIM_ERR_FAILED,msgLoaderPrms);
 
                 // Return response to CIM Server
                 _writeResponse(response.get());
 
+                // make an entry in syslog for this behaviour.
+                if(threadCreationFailureLogged.get() == 0)
+                {
+                    threadCreationFailureLogged.inc();
+                    Logger::put_l(Logger::STANDARD_LOG,
+                        System::CIMSERVER,Logger::WARNING,msgLoaderPrms);
+                }
+                
                 delete agentRequest;
                 delete request;
 
-                break;
+                PEG_METHOD_EXIT();
+                return true;
             }
         }
+
+        // Control will reach here only if the thread creation was successful.
+        // Hence this is the right place to reset threadCreationFailureLogged
+        // to that if the thread limit is reached again it is logged.
+        if(threadCreationFailureLogged.get() == 1)
+        {
+            threadCreationFailureLogged.dec();
+        }
     }
 
     PEG_METHOD_EXIT();
@@ -819,7 +853,7 @@ ProviderAgent::_unloadIdleProvidersHandler(void* arg) throw()
 
         try
         {
-            myself->_providerManagerRouter.unloadIdleProviders();
+            myself->_providerManagerRouter.idleTimeCleanup();
         }
         catch (...)
         {
index ece61a1ce28588fc0400f10f6a368ae920410a93..9cad9e25bc9d1d7d40291ab5ddb3fddab8aaa2c6 100644 (file)
@@ -52,11 +52,12 @@ public:
     virtual Message* processMessage(Message* message) = 0;
 
     /**
-        Unload idle providers in all active ProviderManagers.
+        Cleanup idle providers and disconnected client requests in all 
+        active ProviderManagers.
         Note: This operation may take a long time to complete and should
         be called on a non-critical thread.
      */
-    virtual void unloadIdleProviders() = 0;
+    virtual void idleTimeCleanup() = 0;
 
     /**
         Sets the SubscriptionInitComplete flag indicating whether the Indication
index f4a24dd4932133a7df88d145095d2a78eb7ceae1..da3115e16dbdba04795eda2ee3ce000ce0133f7b 100644 (file)
@@ -55,7 +55,6 @@
 #include <Pegasus/ProviderManager2/ProviderManagerzOS_inline.h>
 #endif
 
-
 PEGASUS_NAMESPACE_BEGIN
 
 const String PG_PROVMODULE_GROUPNAME_CIMSERVER = "CIMServer";
@@ -75,7 +74,7 @@ ProviderManagerService::ProviderManagerService(
 
     _providerRegistrationManager = providerRegistrationManager;
 
-    _unloadIdleProvidersBusy = 0;
+    _idleTimeCleanupBusy = 0;
 
     _forceProviderProcesses = ConfigManager::parseBooleanValue(
         ConfigManager::getInstance()->getCurrentValue(
@@ -85,7 +84,8 @@ ProviderManagerService::ProviderManagerService(
         providerRegistrationManager,
         indicationCallback,
         responseChunkCallback,
-        providerModuleFailureCallback);
+        providerModuleFailureCallback,
+        asyncResponseCallback);
 
     _basicProviderManagerRouter = new BasicProviderManagerRouter(
         indicationCallback,
@@ -191,9 +191,8 @@ ProviderManagerService::handleCimOperation(void* arg)
         PEGASUS_ASSERT(request->getType() == ASYNC_ASYNC_LEGACY_OP_START);
 
         Message* legacy =
-            static_cast<AsyncLegacyOperationStart *>(request)->get_action();
-
-        AutoPtr<Message> xmessage(legacy);
+           static_cast<AsyncLegacyOperationStart *>(request)->get_action();
+        static_cast<AsyncLegacyOperationStart *>(request)->put_action(legacy);
 
         // Set the client's requested language into this service thread.
         // This will allow functions in this service to return messages
@@ -343,18 +342,12 @@ void ProviderManagerService::handleCimRequest(
             // ATTN: Use CIMEnableModuleResponseMessage operationalStatus?
             CIMEnableModuleResponseMessage * emResp =
                 dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
-            if (emResp->cimException.getCode() == CIM_ERR_SUCCESS)
+            // If the provider is not loaded then update the provider status in 
+            // this thread or else the response thread will call 
+            // asyncResponseCallback  which will update the provider status.
+            if(!emResp->isAsyncResponsePending)
             {
-                //
-                //  On a successful enable, remove Stopped status and
-                //  append OK status
-                //
-                Array<Uint16> removeStatus;
-                Array<Uint16> appendStatus;
-                removeStatus.append (CIM_MSE_OPSTATUS_VALUE_STOPPED);
-                appendStatus.append (CIM_MSE_OPSTATUS_VALUE_OK);
-                _updateProviderModuleStatus(
-                    providerModule, removeStatus, appendStatus);
+                _updateModuleStatusToEnabled(emResp, providerModule);
             }
         }
         else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
@@ -382,51 +375,16 @@ void ProviderManagerService::handleCimRequest(
             // Forward the request to the ProviderManager
             response.reset(_processMessage(request));
 
-            // Update provider module status based on success or failure
-            if (updateModuleStatus)
+            // If the provider is not initialized then update the status of the
+            // provider in this thread since there will be no response from
+            // any provider.
+            CIMDisableModuleResponseMessage * dmResp =
+                dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
+            if(!dmResp->isAsyncResponsePending)
             {
-                CIMDisableModuleResponseMessage * dmResp =
-                    dynamic_cast<CIMDisableModuleResponseMessage*>(
-                        response.get());
-                if (dmResp->cimException.getCode() != CIM_ERR_SUCCESS)
+                if (updateModuleStatus)
                 {
-                    //
-                    //  On an unsuccessful disable, remove Stopping status
-                    //
-                    Array<Uint16> removeStatus;
-                    Array<Uint16> appendStatus;
-                    removeStatus.append (CIM_MSE_OPSTATUS_VALUE_STOPPING);
-                    _updateProviderModuleStatus(
-                        providerModule, removeStatus, appendStatus);
-                }
-                else
-                {
-                    // Disable may or may not have been successful,
-                    // depending on whether there are outstanding requests.
-                    // Remove Stopping status
-                    // Append status, if any, from disable module response
-                    Array<Uint16> removeStatus;
-                    Array<Uint16> appendStatus;
-                    removeStatus.append (CIM_MSE_OPSTATUS_VALUE_STOPPING);
-                    if (dmResp->operationalStatus.size() > 0)
-                    {
-                        //
-                        //  On a successful disable, remove an OK or a Degraded
-                        //  status, if present
-                        //
-                        if (dmResp->operationalStatus[
-                            dmResp->operationalStatus.size()-1] ==
-                            CIM_MSE_OPSTATUS_VALUE_STOPPED)
-                        {
-                            removeStatus.append (CIM_MSE_OPSTATUS_VALUE_OK);
-                            removeStatus.append
-                                (CIM_MSE_OPSTATUS_VALUE_DEGRADED);
-                        }
-                        appendStatus.append (dmResp->operationalStatus[
-                            dmResp->operationalStatus.size()-1]);
-                    }
-                    _updateProviderModuleStatus(
-                        providerModule, removeStatus, appendStatus);
+                    _updateModuleStatusToDisabled(dmResp,providerModule);
                 }
             }
         }
@@ -455,12 +413,21 @@ void ProviderManagerService::handleCimRequest(
         response.reset(cimResponse);
     }
 
-    AsyncLegacyOperationResult * async_result =
-        new AsyncLegacyOperationResult(
-        op,
-        response.release());
+    // all responses will be handled by the asyncResponseCallback 
+    // Certain requests like disable and enable module will be processed 
+    // in this thread if the module is not loaded yet.
+    CIMResponseMessage *cimResponse = dynamic_cast<CIMResponseMessage*>(
+        response.get());
 
-    _complete_op_node(op);
+    if(!cimResponse->isAsyncResponsePending)
+    {
+        AsyncLegacyOperationResult * async_result =
+            new AsyncLegacyOperationResult(
+            op,
+            response.release());
+
+        _complete_op_node(op);
+    }
 
     PEG_METHOD_EXIT();
 }
@@ -519,6 +486,103 @@ void ProviderManagerService::responseChunkCallback(
     PEG_METHOD_EXIT();
 }
 
+
+void ProviderManagerService::asyncResponseCallback(
+    CIMRequestMessage* request,
+    CIMResponseMessage* response)
+{
+    PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
+        "ProviderManagerService::asyncResponseCallback");
+
+    AsyncLegacyOperationStart *requestAsync =
+       dynamic_cast<AsyncLegacyOperationStart *>(request->get_async());
+    request->put_async(requestAsync);
+    PEGASUS_ASSERT(requestAsync);
+
+    AsyncOpNode *op = requestAsync->op;
+    PEGASUS_ASSERT(op);
+
+    try
+    {
+        // Only complete responses for async responses are handled
+        // here.
+        PEGASUS_ASSERT(response->isComplete() == true);
+
+        if(request->operationContext.contains(
+            AcceptLanguageListContainer::NAME))
+        {
+            Thread::setLanguages(
+                ((AcceptLanguageListContainer)request->operationContext.get(
+                AcceptLanguageListContainer::NAME)).getLanguages());
+        }
+        else
+        {
+                Thread::setLanguages(AcceptLanguageList());
+        }
+        if(request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
+        {
+            _allProvidersStopped = true;
+        }
+        else if(request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
+        {
+            // Handle CIMEnableModuleRequestMessage
+            CIMEnableModuleRequestMessage * emReq =
+                dynamic_cast<CIMEnableModuleRequestMessage*>(request);
+
+            CIMInstance providerModule = emReq->providerModule;
+
+            // If successful, update provider module status to OK
+            // ATTN: Use CIMEnableModuleResponseMessage operationalStatus?
+            CIMEnableModuleResponseMessage * emResp =
+                dynamic_cast<CIMEnableModuleResponseMessage*>(response);
+            providerManagerService->_updateModuleStatusToEnabled(
+                emResp,providerModule);
+        }
+        else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
+        {
+            // Handle CIMDisableModuleRequestMessage
+            CIMDisableModuleRequestMessage * dmReq =
+                dynamic_cast<CIMDisableModuleRequestMessage*>(request);
+
+            CIMInstance providerModule = dmReq->providerModule;
+            Boolean updateModuleStatus = !dmReq->disableProviderOnly;
+
+            // Update provider module status based on success or failure
+            if (updateModuleStatus)
+            {
+                CIMDisableModuleResponseMessage * dmResp =
+                    dynamic_cast<CIMDisableModuleResponseMessage*>(
+                        response);
+                providerManagerService->_updateModuleStatusToDisabled(
+                    dmResp,providerModule);
+            }
+        } 
+    }
+    catch (Exception &e)
+    {
+        response->cimException =
+            CIMException(CIM_ERR_FAILED, e.getMessage());
+    }
+    catch (PEGASUS_STD(exception)& e)
+    {
+        response->cimException = CIMException(CIM_ERR_FAILED, e.what());
+    }
+    catch (...)
+    {
+        response->cimException = CIMException(CIM_ERR_FAILED, String());
+    }
+
+    AsyncLegacyOperationResult * async_result =
+        new AsyncLegacyOperationResult(
+            op,
+            response);
+
+    providerManagerService->_complete_op_node(op);
+    PEG_METHOD_EXIT();
+}
+
 Message* ProviderManagerService::_processMessage(CIMRequestMessage* request)
 {
     Message* response = 0;
@@ -570,11 +634,6 @@ Message* ProviderManagerService::_processMessage(CIMRequestMessage* request)
 
             response = _oopProviderManagerRouter->processMessage(request);
         }
-
-        if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
-        {
-            _allProvidersStopped = true;
-        }
     }
     else
     {
@@ -710,46 +769,47 @@ Message* ProviderManagerService::_processMessage(CIMRequestMessage* request)
     return response;
 }
 
-void ProviderManagerService::unloadIdleProviders()
+void ProviderManagerService::idleTimeCleanup()
 {
     PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
-        "ProviderManagerService::unloadIdleProviders");
+        "ProviderManagerService::idleTimeCleanup");
 
-    // Ensure that only one _unloadIdleProvidersHandler thread runs at a time
-    _unloadIdleProvidersBusy++;
-    if (_unloadIdleProvidersBusy.get() != 1)
+    // Ensure that only one _idleTimeCleanupHandler thread runs at a time
+    _idleTimeCleanupBusy++;
+    if (_idleTimeCleanupBusy.get() != 1)
     {
-        _unloadIdleProvidersBusy--;
+        _idleTimeCleanupBusy--;
         PEG_METHOD_EXIT();
         return;
     }
 
     //
-    // Start an idle provider unload thread
+    // Start an idle time cleanup thread. 
     //
 
     if (_thread_pool->allocate_and_awaken((void*)this,
-            ProviderManagerService::_unloadIdleProvidersHandler) !=
+            ProviderManagerService::_idleTimeCleanupHandler) !=
                 PEGASUS_THREAD_OK)
     {
         PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL1,
-            "Could not allocate thread for %s to unload idle providers.",
+            "Could not allocate thread for %s to cleanup idle providers \
+                and request.",
             getQueueName()));
 
         // If we fail to allocate a thread, don't retry now.
-        _unloadIdleProvidersBusy--;
+        _idleTimeCleanupBusy--;
         PEG_METHOD_EXIT();
         return;
     }
 
-    // Note: _unloadIdleProvidersBusy is decremented in
-    // _unloadIdleProvidersHandler
+    // Note: _idleTimeCleanupBusy is decremented in
+    // _idleTimeCleanupHandler 
 
     PEG_METHOD_EXIT();
 }
 
 ThreadReturnType PEGASUS_THREAD_CDECL
-ProviderManagerService::_unloadIdleProvidersHandler(void* arg) throw()
+ProviderManagerService::_idleTimeCleanupHandler(void* arg) throw()
 {
     ProviderManagerService* myself =
         reinterpret_cast<ProviderManagerService*>(arg);
@@ -757,20 +817,20 @@ ProviderManagerService::_unloadIdleProvidersHandler(void* arg) throw()
     try
     {
         PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
-            "ProviderManagerService::_unloadIdleProvidersHandler");
+            "ProviderManagerService::_idleTimeCleanupHandler");
 
         if (myself->_basicProviderManagerRouter)
         {
             try
             {
-                myself->_basicProviderManagerRouter->unloadIdleProviders();
+                myself->_basicProviderManagerRouter->idleTimeCleanup();
             }
             catch (...)
             {
                 // Ignore errors
                 PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
                     "Unexpected exception from "
-                        "BasicProviderManagerRouter::_unloadIdleProviders");
+                        "BasicProviderManagerRouter::idleTimeCleanup");
             }
         }
 
@@ -778,32 +838,98 @@ ProviderManagerService::_unloadIdleProvidersHandler(void* arg) throw()
         {
             try
             {
-                myself->_oopProviderManagerRouter->unloadIdleProviders();
+                myself->_oopProviderManagerRouter->idleTimeCleanup();
             }
             catch (...)
             {
                 // Ignore errors
                 PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
                     "Unexpected exception from "
-                        "OOPProviderManagerRouter::_unloadIdleProviders");
+                        "OOPProviderManagerRouter::idleTimeCleanup");
             }
         }
 
-        myself->_unloadIdleProvidersBusy--;
+        myself->_idleTimeCleanupBusy--;
         PEG_METHOD_EXIT();
     }
     catch (...)
     {
         // Ignore errors
         PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
-            "Unexpected exception in _unloadIdleProvidersHandler");
+            "Unexpected exception in _idleTimeCleanupHandler");
 
-        myself->_unloadIdleProvidersBusy--;
+        myself->_idleTimeCleanupBusy--;
     }
 
     return ThreadReturnType(0);
 }
 
+void ProviderManagerService::_updateModuleStatusToEnabled(
+    CIMEnableModuleResponseMessage *emResp,
+    CIMInstance &providerModule)
+{
+    if (emResp->cimException.getCode() == CIM_ERR_SUCCESS)
+    {
+        //
+        //  On a successful enable, remove Stopped status and
+        //  append OK status
+        //
+        Array<Uint16> removeStatus;
+        Array<Uint16> appendStatus;
+        removeStatus.append (CIM_MSE_OPSTATUS_VALUE_STOPPED);
+        appendStatus.append (CIM_MSE_OPSTATUS_VALUE_OK);
+        _updateProviderModuleStatus(
+            providerModule, removeStatus, appendStatus);
+    }
+}
+
+void ProviderManagerService::_updateModuleStatusToDisabled(
+    CIMDisableModuleResponseMessage *dmResp,
+    CIMInstance &providerModule)
+{
+    // Update provider module status based on success or failure
+    if (dmResp->cimException.getCode() != CIM_ERR_SUCCESS)
+    {
+        //
+        //  On an unsuccessful disable, remove Stopping status
+        //
+        Array<Uint16> removeStatus;
+        Array<Uint16> appendStatus;
+        removeStatus.append (CIM_MSE_OPSTATUS_VALUE_STOPPING);
+        _updateProviderModuleStatus(
+            providerModule, removeStatus, appendStatus);
+    }
+    else
+    {
+        // Disable may or may not have been successful,
+        // depending on whether there are outstanding requests.
+        // Remove Stopping status
+        // Append status, if any, from disable module response
+        Array<Uint16> removeStatus;
+        Array<Uint16> appendStatus;
+        removeStatus.append (CIM_MSE_OPSTATUS_VALUE_STOPPING);
+        if (dmResp->operationalStatus.size() > 0)
+        {
+            //
+            //  On a successful disable, remove an OK or 
+            // a Degraded status, if present
+            //
+            if (dmResp->operationalStatus[
+                dmResp->operationalStatus.size()-1] ==
+                CIM_MSE_OPSTATUS_VALUE_STOPPED)
+            {
+                removeStatus.append (CIM_MSE_OPSTATUS_VALUE_OK);
+                removeStatus.append
+                    (CIM_MSE_OPSTATUS_VALUE_DEGRADED);
+            }
+            appendStatus.append (dmResp->operationalStatus[
+                dmResp->operationalStatus.size()-1]);
+        }
+        _updateProviderModuleStatus(
+            providerModule, removeStatus, appendStatus);
+    }
+}
+
 // Updates the providerModule instance and the ProviderRegistrationManager
 //
 // This method is used to update the provider module status when the module is
index 5a0b78485251fa76857f1d096152b5d7bd2635ef..da2034442aca8a440329595ed1a5d381c401a90d 100644 (file)
@@ -58,11 +58,13 @@ public:
 
     virtual ~ProviderManagerService();
 
-    void unloadIdleProviders();
+    void idleTimeCleanup();
 
     static void indicationCallback(CIMProcessIndicationRequestMessage* request);
     static void responseChunkCallback(
         CIMRequestMessage* request, CIMResponseMessage* response);
+    static void asyncResponseCallback(
+        CIMRequestMessage* request, CIMResponseMessage* response);
 
     /**
         Callback function to be called upon detection of failure of a
@@ -87,7 +89,15 @@ private:
     Message* _processMessage(CIMRequestMessage* request);
 
     static ThreadReturnType PEGASUS_THREAD_CDECL
-        _unloadIdleProvidersHandler(void* arg) throw();
+        _idleTimeCleanupHandler(void* arg) throw();
+
+    void _updateModuleStatusToEnabled(
+        CIMEnableModuleResponseMessage *emResp,
+        CIMInstance &providerModule);
+
+    void _updateModuleStatusToDisabled(
+        CIMDisableModuleResponseMessage *dmResp,
+        CIMInstance &providerModule);
 
     void _updateProviderModuleStatus(
         CIMInstance& providerModule,
@@ -111,11 +121,11 @@ private:
     static Uint32 _indicationServiceQueueId;
 
     /**
-        Indicates the number of threads currently attempting to unload idle
-        providers.  This value is used to prevent multiple threads from
-        unloading idle providers at the same time.
+        Indicates the number of threads currently attempting to cleanup idle
+        providers and clean disconnected client requests.  This value is used 
+        to prevent multiple threads from initiating cleanup the same time.
      */
-    AtomicInt _unloadIdleProvidersBusy;
+    AtomicInt _idleTimeCleanupBusy;
 };
 
 PEGASUS_NAMESPACE_END
index 9ad571e18dbf5307ccc3d592c78d9014cab5b348..f0351ce19e3509bb0d3fdb54707b5ab735b2899f 100644 (file)
@@ -724,12 +724,11 @@ void CIMServer::runForever()
 
             try
             {
-                _providerManager->unloadIdleProviders();
+                _providerManager->idleTimeCleanup();
                 MessageQueueService::get_thread_pool()->cleanupIdleThreads();
 #ifdef PEGASUS_ENABLE_PROTOCOL_WSMAN
                 _wsmProcessor->cleanupExpiredContexts();
 #endif
-
             }
             catch (...)
             {
index bd10760059ebcc9851f035fc369f1416ac272b55..568cf7875241df2a1f8640bce1b9bb4f36031947 100644 (file)
@@ -5156,6 +5156,12 @@ CIM server listening on HTTPS port {0}."}
         */
         ProviderManager.OOPProviderManagerRouter.OOP_PROVIDER_MODULE_FAILURE_DETECTED:string {"PGS13606: A failure was detected in provider module {0}.  The generation of indications by providers in this module may be affected.  To ensure these providers are serving active subscriptions, disable and then re-enable this module using the cimprovider command."}
 
+        /**
+        * @note PGS13607
+        *    Substitution {0} is the provider module group name.
+        */
+        ProviderManager.OOPProviderManagerRouter.REQUEST_RETRY_THREAD_ALLOCATION_FAILED:string {"PGS13607: Failed to allocate a thread to retry a request in \"{0}\"."}
+
 
         // ==========================================================
         // Messages for ProviderManager.ProviderAgent.cimprovagt
diff --git a/src/Providers/TestProviders/FaultyInstanceProvider/Makefile b/src/Providers/TestProviders/FaultyInstanceProvider/Makefile
new file mode 100644 (file)
index 0000000..b4d0105
--- /dev/null
@@ -0,0 +1,50 @@
+#//%LICENSE////////////////////////////////////////////////////////////////
+#//
+#// Licensed to The Open Group (TOG) under one or more contributor license
+#// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+#// this work for additional information regarding copyright ownership.
+#// Each contributor licenses this file to you under the OpenPegasus Open
+#// Source License; you may not use this file except in compliance with the
+#// License.
+#//
+#// Permission is hereby granted, free of charge, to any person obtaining a
+#// copy of this software and associated documentation files (the "Software"),
+#// to deal in the Software without restriction, including without limitation
+#// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+#// and/or sell copies of the Software, and to permit persons to whom the
+#// Software is furnished to do so, subject to the following conditions:
+#//
+#// The above copyright notice and this permission notice shall be included
+#// in all copies or substantial portions of the Software.
+#//
+#// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+#// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+#// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+#// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+#// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+#// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#//
+#//////////////////////////////////////////////////////////////////////////
+ROOT = ../../../..
+
+DIR = Providers/TestProviders/FaultyInstanceProvider
+
+include $(ROOT)/mak/config.mak
+
+LIBRARY = TestFaultyProvider
+
+LIBRARIES = \
+       pegprovider \
+       pegclient \
+       pegcommon
+
+SOURCES = \
+       TestFaultyProviderMain.cpp \
+       TestFaultyInstanceProvider.cpp \
+       TestGoodIndicationProvider.cpp
+       
+include $(ROOT)/mak/dynamic-library.mak
+
+tests:
+
diff --git a/src/Providers/TestProviders/FaultyInstanceProvider/TestFaultyInstanceProvider.cpp b/src/Providers/TestProviders/FaultyInstanceProvider/TestFaultyInstanceProvider.cpp
new file mode 100644 (file)
index 0000000..66cd6c8
--- /dev/null
@@ -0,0 +1,186 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%///////////////////////////////////////////////////////////////////////
+
+#include <cstring>
+#include <Pegasus/Common/Config.h>
+#include <Pegasus/Provider/CIMInstanceProvider.h>
+
+#include <Pegasus/Common/CIMDateTime.h>
+#include <Pegasus/Common/Threads.h>
+
+#include "TestFaultyInstanceProvider.h"
+
+PEGASUS_USING_STD;
+PEGASUS_NAMESPACE_BEGIN
+
+#define CIMSERVER_CLEANUP_TIME 600
+#define CONN_TIME_OUT 70
+#define DEFAULT_CLIENT_TIMEOUT 20 // default timeout
+
+TestFaultyInstanceProvider::TestFaultyInstanceProvider()
+{
+}
+
+TestFaultyInstanceProvider::~TestFaultyInstanceProvider()
+{
+}
+
+void TestFaultyInstanceProvider::initialize(CIMOMHandle& cimom)
+{
+    // save cimom handle
+    //_cimom = cimom;
+
+    char namebuf[20];
+    char pathbuf[45];
+    memset(namebuf, 0x00, sizeof(namebuf));
+    memset(pathbuf, 0x00, sizeof(pathbuf));
+
+    // create default instances
+    for (Uint32 i = 1; i <= 2; i++)
+    {
+        sprintf(namebuf, "%u", i);
+        sprintf(pathbuf, "TST_FaultyInstanceInstance.Name=\"%u\"", i);
+        {
+            CIMInstance instance("TST_FaultyInstanceInstance");
+
+            instance.addProperty(CIMProperty("name", String(namebuf)));
+            instance.addProperty(CIMProperty("s", String("specified")));
+            instance.addProperty(CIMProperty("n", Uint64(i)));
+            instance.addProperty(CIMProperty("f", Real64(Real64(i)+0.001)));
+            instance.addProperty(
+                CIMProperty("d", CIMDateTime::getCurrentDateTime()));
+
+            instance.setPath(CIMObjectPath(pathbuf));
+
+            _instances.append(instance);
+        }
+    }
+}
+
+void TestFaultyInstanceProvider::terminate()
+{
+    delete this;
+}
+
+void TestFaultyInstanceProvider::getInstance(
+    const OperationContext& context,
+    const CIMObjectPath& instanceReference,
+    const Boolean includeQualifiers,
+    const Boolean includeClassOrigin,
+    const CIMPropertyList& propertyList,
+    InstanceResponseHandler& handler)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);
+}
+
+void TestFaultyInstanceProvider::enumerateInstances(
+    const OperationContext& context,
+    const CIMObjectPath& ref,
+    const Boolean includeQualifiers,
+    const Boolean includeClassOrigin,
+    const CIMPropertyList& propertyList,
+    InstanceResponseHandler& handler)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);
+}
+
+void TestFaultyInstanceProvider::enumerateInstanceNames(
+    const OperationContext& context,
+    const CIMObjectPath& classReference,
+    ObjectPathResponseHandler& handler)
+{
+    _requestCount.inc(); 
+    Uint32 sleepDuration=0;  
+    if(_requestCount.get() % 2)
+    {
+        //few requets will respond after cimserver  cleanup time.
+        sleepDuration = CIMSERVER_CLEANUP_TIME * 1000 ; 
+    }
+    else if(_requestCount.get() % 16)
+    {
+        // respond correctly.
+    }
+    else
+    {
+        //few requests will respond after client connections have timed out
+        //but before cimserver cleanup time.
+        sleepDuration = CONN_TIME_OUT *1000;
+    }
+
+    handler.processing();
+  
+    Threads::sleep(sleepDuration);
+
+    for (Uint32 i = 0, n = _instances.size(); i < n; i++)
+    {
+        try
+        {
+            handler.deliver(_instances[i].getPath());
+        }
+        catch (CIMException&)
+        {
+            // suppress error
+        }
+    }
+
+    handler.complete();
+}
+
+void TestFaultyInstanceProvider::modifyInstance(
+    const OperationContext& context,
+    const CIMObjectPath& instanceReference,
+    const CIMInstance& instanceObject,
+    const Boolean includeQualifiers,
+    const CIMPropertyList& propertyList,
+    ResponseHandler& handler)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);
+}
+
+void TestFaultyInstanceProvider::createInstance(
+    const OperationContext& context,
+    const CIMObjectPath& instanceReference,
+    const CIMInstance& instanceObject,
+    ObjectPathResponseHandler& handler)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);
+}
+
+void TestFaultyInstanceProvider::deleteInstance(
+    const OperationContext& context,
+    const CIMObjectPath& instanceReference,
+    ResponseHandler& handler)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);
+}
+
+PEGASUS_NAMESPACE_END
diff --git a/src/Providers/TestProviders/FaultyInstanceProvider/TestFaultyInstanceProvider.h b/src/Providers/TestProviders/FaultyInstanceProvider/TestFaultyInstanceProvider.h
new file mode 100644 (file)
index 0000000..626add8
--- /dev/null
@@ -0,0 +1,100 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%///////////////////////////////////////////////////////////////////////
+
+#ifndef Pegasus_TestFaultyInstanceProvider_h
+#define Pegasus_TestFaultyInstanceProvider_h
+
+#include <Pegasus/Common/Config.h>
+#include <Pegasus/Common/AtomicInt.h>
+#include <Pegasus/Provider/CIMInstanceProvider.h>
+
+PEGASUS_NAMESPACE_BEGIN
+
+class TestFaultyInstanceProvider :
+    public CIMInstanceProvider
+{
+public:
+    TestFaultyInstanceProvider();
+    virtual ~TestFaultyInstanceProvider();
+
+    // CIMProvider interface
+    virtual void initialize(CIMOMHandle& cimom);
+    virtual void terminate();
+
+    // CIMInstanceProvider interface
+    virtual void getInstance(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        const Boolean includeQualifiers,
+        const Boolean includeClassOrigin,
+        const CIMPropertyList& propertyList,
+        InstanceResponseHandler& handler);
+
+    virtual void enumerateInstances(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        const Boolean includeQualifiers,
+        const Boolean includeClassOrigin,
+        const CIMPropertyList& propertyList,
+        InstanceResponseHandler& handler);
+
+    virtual void enumerateInstanceNames(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        ObjectPathResponseHandler& handler);
+
+    virtual void modifyInstance(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        const CIMInstance& obj,
+        const Boolean includeQualifiers,
+        const CIMPropertyList& propertyList,
+        ResponseHandler& handler);
+
+    virtual void createInstance(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        const CIMInstance& obj,
+        ObjectPathResponseHandler& handler);
+
+    virtual void deleteInstance(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        ResponseHandler& handler);
+
+protected:
+    Array<CIMInstance> _instances;
+    AtomicInt _requestCount;
+};
+
+PEGASUS_NAMESPACE_END
+
+#endif
diff --git a/src/Providers/TestProviders/FaultyInstanceProvider/TestFaultyProviderMain.cpp b/src/Providers/TestProviders/FaultyInstanceProvider/TestFaultyProviderMain.cpp
new file mode 100644 (file)
index 0000000..4e022bb
--- /dev/null
@@ -0,0 +1,54 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%///////////////////////////////////////////////////////////////////////
+
+#include <Pegasus/Common/Config.h>
+
+#include "TestFaultyInstanceProvider.h"
+#include "TestGoodIndicationProvider.h"
+
+PEGASUS_NAMESPACE_BEGIN
+
+extern "C"
+PEGASUS_EXPORT CIMProvider* PegasusCreateProvider(const String& providerName)
+{
+    if (String::equalNoCase(providerName, "TestFaultyInstanceProvider"))
+    {
+        return new TestFaultyInstanceProvider();
+    }
+    if (String::equalNoCase(providerName, "TestGoodIndicationProvider"))
+    {
+        return new TestGoodIndicationProvider();
+    }
+
+    return 0;
+}
+
+PEGASUS_NAMESPACE_END
diff --git a/src/Providers/TestProviders/FaultyInstanceProvider/TestGoodIndicationProvider.cpp b/src/Providers/TestProviders/FaultyInstanceProvider/TestGoodIndicationProvider.cpp
new file mode 100644 (file)
index 0000000..f5457bc
--- /dev/null
@@ -0,0 +1,92 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%///////////////////////////////////////////////////////////////////////
+
+#include <Pegasus/Common/PegasusAssert.h>
+
+#include "TestGoodIndicationProvider.h"
+
+PEGASUS_USING_STD;
+
+PEGASUS_USING_PEGASUS;
+
+TestGoodIndicationProvider::TestGoodIndicationProvider() throw ()
+{
+}
+
+TestGoodIndicationProvider::~TestGoodIndicationProvider() throw ()
+{
+}
+
+void TestGoodIndicationProvider::initialize(CIMOMHandle& cimom)
+{
+  _cimom = cimom;
+}
+
+void TestGoodIndicationProvider::terminate()
+{
+    delete this;
+}
+
+void TestGoodIndicationProvider::enableIndications(
+    IndicationResponseHandler& handler)
+{
+}
+
+void TestGoodIndicationProvider::disableIndications()
+{
+}
+
+void TestGoodIndicationProvider::createSubscription(
+    const OperationContext& context,
+    const CIMObjectPath& subscriptionName,
+    const Array <CIMObjectPath>& classNames,
+    const CIMPropertyList& propertyList,
+    const Uint16 repeatNotificationPolicy)
+{
+    // do nothing
+}
+
+void TestGoodIndicationProvider::modifySubscription(
+    const OperationContext& context,
+    const CIMObjectPath& subscriptionName,
+    const Array <CIMObjectPath>& classNames,
+    const CIMPropertyList& propertyList,
+    const Uint16 repeatNotificationPolicy)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);    
+}
+
+void TestGoodIndicationProvider::deleteSubscription(
+    const OperationContext& context,
+    const CIMObjectPath& subscriptionName,
+    const Array <CIMObjectPath>& classNames)
+{
+}
diff --git a/src/Providers/TestProviders/FaultyInstanceProvider/TestGoodIndicationProvider.h b/src/Providers/TestProviders/FaultyInstanceProvider/TestGoodIndicationProvider.h
new file mode 100644 (file)
index 0000000..56baabe
--- /dev/null
@@ -0,0 +1,81 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%///////////////////////////////////////////////////////////////////////
+
+#ifndef Pegasus_TestGoodIndicationProvider_h
+#define Pegasus_TestGoodIndicationProvider_h
+
+#include <Pegasus/Common/Config.h>
+#include <Pegasus/Provider/CIMIndicationProvider.h>
+#include <Pegasus/Provider/CIMMethodProvider.h>
+
+PEGASUS_USING_PEGASUS;
+
+class TestGoodIndicationProvider:
+    public CIMIndicationProvider
+{
+public:
+    TestGoodIndicationProvider() throw();
+    virtual ~TestGoodIndicationProvider() throw();
+
+    // CIMProvider interface
+    virtual void initialize(CIMOMHandle& cimom);
+    virtual void terminate();
+
+    // CIMIndicationProvider interface
+    virtual void enableIndications(IndicationResponseHandler& handler);
+    virtual void disableIndications();
+
+    virtual void createSubscription(
+        const OperationContext& context,
+        const CIMObjectPath& subscriptionName,
+        const Array <CIMObjectPath>& classNames,
+        const CIMPropertyList& propertyList,
+        const Uint16 repeatNotificationPolicy);
+
+    virtual void modifySubscription(
+        const OperationContext& context,
+        const CIMObjectPath& subscriptionName,
+        const Array <CIMObjectPath>& classNames,
+        const CIMPropertyList& propertyList,
+        const Uint16 repeatNotificationPolicy);
+
+    virtual void deleteSubscription(
+        const OperationContext& context,
+        const CIMObjectPath& subscriptionName,
+        const Array <CIMObjectPath>& classNames);
+
+private:
+
+     CIMOMHandle _cimom;
+
+};
+
+#endif
diff --git a/src/Providers/TestProviders/FaultyInstanceProvider/testclient/Makefile b/src/Providers/TestProviders/FaultyInstanceProvider/testclient/Makefile
new file mode 100644 (file)
index 0000000..425afb7
--- /dev/null
@@ -0,0 +1,68 @@
+#//%LICENSE////////////////////////////////////////////////////////////////
+#//
+#// Licensed to The Open Group (TOG) under one or more contributor license
+#// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+#// this work for additional information regarding copyright ownership.
+#// Each contributor licenses this file to you under the OpenPegasus Open
+#// Source License; you may not use this file except in compliance with the
+#// License.
+#//
+#// Permission is hereby granted, free of charge, to any person obtaining a
+#// copy of this software and associated documentation files (the "Software"),
+#// to deal in the Software without restriction, including without limitation
+#// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+#// and/or sell copies of the Software, and to permit persons to whom the
+#// Software is furnished to do so, subject to the following conditions:
+#//
+#// The above copyright notice and this permission notice shall be included
+#// in all copies or substantial portions of the Software.
+#//
+#// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+#// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+#// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+#// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+#// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+#// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#//
+#//////////////////////////////////////////////////////////////////////////
+ROOT = ../../../../..
+
+PEGASUS_ZOS_PROGRAM_OBJECT = yes
+
+DIR = Providers/TestProviders/FaultyInstanceProvider/testclient
+
+include $(ROOT)/mak/config.mak
+
+LIBRARIES = \
+    pegclient \
+    peggeneral \
+    pegcommon
+
+EXTRA_INCLUDES = $(SYS_INCLUDES)
+
+LOCAL_DEFINES = -DPEGASUS_INTERNALONLY
+
+PROGRAM = TestFaultyInstanceProviderClient
+
+SOURCES = TestFaultyInstanceProviderClient.cpp
+
+include $(ROOT)/mak/program.mak
+
+include $(ROOT)/mak/test.mak
+
+tests:
+
+poststarttests:
+
+runAvailabilityTest:
+# When tests are run through valgrind the client timeout
+# is disabled hence no point running these tests, since
+# the client will never timeout.
+ifndef PEGASUS_TEST_VALGRIND_LOG_DIR
+       @cimprovider -dm TestFaultyProviderModule
+       @cimprovider -em TestFaultyProviderModule
+       @cimprovider -dm TestGoodInstanceProviderModule
+       @cimprovider -em TestGoodInstanceProviderModule
+       $(PROGRAM)      
+endif
diff --git a/src/Providers/TestProviders/FaultyInstanceProvider/testclient/TestFaultyInstanceProviderClient.cpp b/src/Providers/TestProviders/FaultyInstanceProvider/testclient/TestFaultyInstanceProviderClient.cpp
new file mode 100644 (file)
index 0000000..60cb39d
--- /dev/null
@@ -0,0 +1,587 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%///////////////////////////////////////////////////////////////////////
+
+#include <cstdio>
+
+#include <Pegasus/Common/Thread.h>
+#include <Pegasus/Common/Config.h>
+#include <Pegasus/Common/Constants.h>
+#include <Pegasus/Common/Exception.h>
+#include <Pegasus/Common/ArrayInternal.h>
+#include <Pegasus/Common/AutoPtr.h>
+#include <Pegasus/Common/AtomicInt.h>
+#include <Pegasus/Common/PegasusAssert.h>
+#include <Pegasus/General/Stopwatch.h>
+#include <Pegasus/Common/System.h>
+#include <Pegasus/Common/Exception.h>
+#include <Pegasus/Client/CIMClient.h>
+#if defined(PEGASUS_OS_TYPE_UNIX)
+# include <unistd.h>
+# include <errno.h>
+# include <limits.h>
+#endif
+
+
+PEGASUS_USING_PEGASUS;
+PEGASUS_USING_STD;
+
+
+/*
+ * Here we test  the availability of cimserver even after it crosses
+ * its socket fd limit(max client connections) or a faulty provider crosses
+ * its thread limit.
+ *
+ * 1. The setup has a provider module with 1 faulty instance provider and one
+ * indication provider. The faulty provider does not respond correctly
+ * or respond after connection timeout or responds after the idle cleanup thread
+ * has been run by the cimserver. There is also a good instance provider which 
+ * serves the same class hierarchy as the faulty instance provider. The test 
+ * client inundates the cimserver with huge number of CIM requests for the 
+ * faulty provider and good provider on multiple connections causing the 
+ * cimserver to reach its thread/fd limit whichever  is lower.
+ * 2. The test client detects that cimserver crossed fd limit if it recieved
+ * CannotConnectException after few requests .
+ * OR
+ * 3. The test client detects that cimserver crossed thread limit if it 
+ * received CIMException after  few requests.Then the test client runs a test
+ * on sample instance provider which should succeed.
+ * 4. Then the test client waits for cimserver cleanup interval for cimserver to
+ * release the held resources (fds/threads) after which it executes a test on
+ * a sample provider which should succeed.
+ * 5. The indication provider is exercised at the same time when a request is
+ * sent to the faulty instance provider.
+ * 6. The above tests should run through CHO and should pass the leak test.
+ */
+#define DEFAULT_MAX_CIM_REQUESTS 2000
+#define MAX_CONNECTIONS 100 
+#define CONN_TIMEOUT 3
+#define EXPECTED_INSTANCENAMES 2
+#define CIMSERVER_CLEANUP_TIME 600
+
+static char * verbose = 0;
+static CIMException expectedNICIMException(CIM_ERR_FAILED);
+
+static AtomicInt  recievedNICIMExceptionCount(0);
+static AtomicInt  recievedNIConnTimeoutExceptionCount(0);
+static AtomicInt  recievedNICannotConnectExceptionCount(0);
+
+static const String NAMESPACE("test/TestProvider");
+static const String FAULTY_CLASSNAME("TST_FaultyInstance");
+static const String WELLBEHAVED_CLASSNAME("TST_Instance1");
+
+class T_Parms{
+public:
+    CIMClient* client;
+    long requestCount;
+    Uint32 uniqueID;
+};
+
+Thread * _runTestThreads(
+    CIMClient* client,
+    ThreadReturnType (PEGASUS_THREAD_CDECL *_executeFn)(void *),
+    Uint32 uniqueID,
+    long requestCount)
+{
+    // package parameters, create thread and run...
+    AutoPtr<T_Parms> parms(new T_Parms());
+
+    parms->client = client;
+    parms->uniqueID = uniqueID;
+    parms->requestCount = requestCount;
+    AutoPtr<Thread> t(new Thread(_executeFn, (void*)parms.release(), false));
+    // zzzzz... (1 second) zzzzz...
+    Threads::sleep(100);
+    t->run();
+    return t.release();
+}
+
+void _executeRequest(Array<CIMClient *>& clientConnections,
+    ThreadReturnType (PEGASUS_THREAD_CDECL *_executeFn)(void *),
+    long requests)
+{
+    // run tests
+    Array<Thread *> clientThreads;
+    Uint32 thdIndex = 0;
+   
+     //lets split the cim requests equally among client connections
+    long requestCount = (requests/clientConnections.size());
+
+    // start enumerateInstanceNames threads
+    for(Uint32 i = 0; i < clientConnections.size(); i++, thdIndex++)
+    {
+        clientThreads.append(
+            _runTestThreads(clientConnections[thdIndex],
+                _executeFn,
+                    thdIndex,
+                requestCount));
+    }
+
+    // wait for threads to terminate
+    for(Uint32 i=0; i< clientThreads.size(); i++)
+    {
+        clientThreads[i]->join();
+    }
+
+    // clean up threads
+    for(Uint32 i=0; i < clientThreads.size(); i++)
+    {
+        delete clientThreads[i];
+    }
+}
+
+bool TestWellbehavedInstanceProvider()
+{
+    bool result = false;
+
+    try
+    {
+        CIMClient client;
+        client.connectLocal();
+
+        Array<CIMObjectPath> cimInstanceNames =
+            client.enumerateInstanceNames(
+                NAMESPACE,
+                WELLBEHAVED_CLASSNAME);
+        if(cimInstanceNames.size() > 0)
+        {
+            result = true;
+        }
+     }
+     catch (Exception& e)
+     {
+         cout << "---- caught exception from test instance provider : "
+             << e.getMessage()<<endl;
+         result = false;
+     }
+
+     return result;
+}
+
+ThreadReturnType PEGASUS_THREAD_CDECL _createSubFunc(void *parm)
+{
+    // client for creating subscription on the good 
+    // provider which is part of the FaultyProviderModule.
+    CIMClient client;
+    client.connectLocal();
+
+   // create filter and handler
+    String queryFaulty01("SELECT * FROM CIM_AlertIndication");
+    String filterFaulty01("FilterFaulty01");
+
+    CIMInstance filterInstance (PEGASUS_CLASSNAME_INDFILTER);
+    filterInstance.addProperty (CIMProperty (CIMName
+        ("SystemCreationClassName"), System::getSystemCreationClassName ()));
+    filterInstance.addProperty (CIMProperty (CIMName ("SystemName"),
+        System::getFullyQualifiedHostName ()));
+    filterInstance.addProperty (CIMProperty (CIMName ("CreationClassName"),
+        PEGASUS_CLASSNAME_INDFILTER.getString ()));
+    filterInstance.addProperty (CIMProperty (CIMName ("Name"), filterFaulty01));
+    filterInstance.addProperty (CIMProperty (CIMName ("Query"), queryFaulty01));
+    filterInstance.addProperty (CIMProperty (CIMName ("QueryLanguage"),
+        String ("WQL")));
+    filterInstance.addProperty (CIMProperty (CIMName ("SourceNamespace"),
+        String(NAMESPACE)));
+
+    CIMObjectPath filterObjectPath;
+    try
+    {
+        filterObjectPath = client.createInstance(
+            NAMESPACE,
+            filterInstance);
+    }
+    catch(Exception& e)
+    {
+        cerr << "----- Error: Filter Instance Not Created: " <<
+           e.getMessage() << endl;
+        PEGASUS_TEST_ASSERT(false);
+    }
+
+    String handlerFaulty01("Handlerfaulty01");
+    String destination =String("http//localhost");
+
+    CIMInstance handlerInstance (PEGASUS_CLASSNAME_INDHANDLER_CIMXML);
+    handlerInstance.addProperty (CIMProperty (CIMName
+        ("SystemCreationClassName"), System::getSystemCreationClassName ()));
+    handlerInstance.addProperty (CIMProperty (CIMName ("SystemName"),
+        System::getFullyQualifiedHostName ()));
+    handlerInstance.addProperty (CIMProperty (CIMName ("CreationClassName"),
+        PEGASUS_CLASSNAME_INDHANDLER_CIMXML.getString ()));
+    handlerInstance.addProperty (CIMProperty (CIMName ("Name"), 
+        handlerFaulty01));
+    handlerInstance.addProperty (CIMProperty (CIMName ("Destination"),
+        destination));
+
+    CIMObjectPath handlerObjPath;
+    try
+    {
+        handlerObjPath = client.createInstance(
+            NAMESPACE,
+            handlerInstance);
+    }
+    catch(Exception& e)
+    {
+        cerr << "----- Error: Handler Instance Not Created: " <<
+            e.getMessage() << endl;
+        PEGASUS_TEST_ASSERT(false);
+    }
+
+    // Thread 1 : subscription creation
+    CIMInstance subscriptionInstance (PEGASUS_CLASSNAME_INDSUBSCRIPTION);
+    subscriptionInstance.addProperty (CIMProperty (CIMName ("Filter"),
+        filterObjectPath, 0, PEGASUS_CLASSNAME_INDFILTER));
+    subscriptionInstance.addProperty (CIMProperty (CIMName ("Handler"),
+        handlerObjPath, 0, PEGASUS_CLASSNAME_INDHANDLER_CIMXML));
+    subscriptionInstance.addProperty (CIMProperty
+        (CIMName ("SubscriptionState"), CIMValue ((Uint16) 2)));
+
+    CIMObjectPath subscriptionObjPath;
+    try
+    {
+        subscriptionObjPath = client.createInstance(
+            NAMESPACE,
+            subscriptionInstance);
+    }
+    catch(Exception& e)
+    {
+        cerr << "----- Error: Subscription Instance Not Created: " <<
+            e.getMessage() << endl;
+        PEGASUS_TEST_ASSERT(false);
+    }
+    cout << "Successfully created subscription instance" << endl;
+
+    // delete subscription
+    try
+    {
+        client.deleteInstance(NAMESPACE,subscriptionObjPath);
+        client.deleteInstance(NAMESPACE,filterObjectPath);
+        client.deleteInstance(NAMESPACE,handlerObjPath);
+    }
+    catch(Exception& e)
+    {
+        cerr << "----- Error: Subscription deletion failed : " <<
+            e.getMessage() << endl;
+        PEGASUS_TEST_ASSERT(false);
+    }
+    return ThreadReturnType(0);
+}
+
+ThreadReturnType PEGASUS_THREAD_CDECL _enumInstanceNamesFunc(void *parm)
+{
+    // client for enumerateInstanceNames request on the faulty
+    // provider.
+    CIMClient client;
+    client.connectLocal();
+    // Thread 2 : enumerate instance request to faulty provider.   
+    try
+    {
+        Array<CIMObjectPath> objs = client.enumerateInstanceNames(NAMESPACE,
+            FAULTY_CLASSNAME);
+    }
+    catch(Exception &e)
+    {
+        cout << "Caught exception while enumerating class " << 
+            FAULTY_CLASSNAME << ": " << e.getMessage() << endl;
+        return ThreadReturnType(0);
+    }
+
+    return ThreadReturnType(0);
+}
+
+bool TestIndicationProviderAndFaultyProvider()
+{
+    Thread t1(_createSubFunc, 0, false);
+    Thread t2(_enumInstanceNamesFunc, 0, false);
+
+    t1.run();
+
+    t2.run();
+   
+    t1.join();
+    t2.join();
+    return true;
+} 
+
+ThreadReturnType PEGASUS_THREAD_CDECL _executeNIonFaultyProvider(void *parm)
+{
+    Thread *my_thread = (Thread *)parm;
+    T_Parms *parms = (T_Parms *)my_thread->get_parm();
+    CIMClient *client = parms->client;
+    Uint32 uniqueID = parms->uniqueID;
+    long requestCount = parms->requestCount;
+    bool connectionAlreadyRefused=false;
+
+    long i=0;
+    for(i=0;i<requestCount;i++)
+    {
+        try
+        {
+            Array<CIMObjectPath> cimInstanceNames =
+                client->enumerateInstanceNames(NAMESPACE, FAULTY_CLASSNAME);
+
+           if(verbose)
+               cout<<"Request " << i << ": Faulty provider responded..!"<<endl;
+        }
+        catch (CIMException& e)
+        {
+            if(e.getCode() == expectedNICIMException.getCode())
+            {
+                recievedNICIMExceptionCount.inc();
+            }
+            else
+            {
+                cout << "---- NI  thread " << uniqueID
+                     <<" caught unexpected CIM exception: "<< e.getMessage()
+                     << endl;
+                break;
+            }
+        }
+
+        catch (ConnectionTimeoutException& e)
+        {
+            recievedNIConnTimeoutExceptionCount.inc();
+        }
+        catch (CannotConnectException& e)
+        {
+             //While testing its observed that because of huge number of
+             //requests and responses cimserver could be busy and unable to
+             //accept a aconnection and hence ignoring the exception once.
+            if(!connectionAlreadyRefused)
+            {
+                i--;
+                connectionAlreadyRefused=true;
+                Threads::sleep(1 * 1000);
+            }
+            else
+            { 
+                recievedNICannotConnectExceptionCount.inc();
+                if(verbose )
+                    cout << "---- NI  thread " << uniqueID 
+                         << " caught exception: "<< e.getMessage() << endl;
+                break;
+            }
+        }
+        catch(CIMClientMalformedHTTPException& e)
+        {
+            // This is the exception thrown on HP-UX if connection cannot be
+            // established.
+            if(!connectionAlreadyRefused)
+            {
+                i--;
+                connectionAlreadyRefused=true;
+                Threads::sleep(1 * 1000);
+            }
+            else
+            {
+                recievedNICannotConnectExceptionCount.inc();
+                if(verbose )
+                    cout << "---- NI  thread " << uniqueID 
+                         << " caught exception: "<< e.getMessage() << endl;
+                break;
+            }
+        }
+
+        catch (Exception& e)
+        {
+            cout << "---- NI  thread " << uniqueID 
+                 << " caught unexpected exception: "<< e.getMessage() << endl;
+
+            break;
+        }
+    }
+
+    if(verbose && (i >= requestCount))
+        cout<<"---- NI  thread " << uniqueID 
+            << " successfully completed"<<endl;
+    
+    delete parms;
+    return ThreadReturnType(0);
+}
+
+void TestCimserverAvailability()
+{
+   //runn a test on a test instance provider
+    bool resultWellbehavedProvider = TestWellbehavedInstanceProvider();
+    PEGASUS_TEST_ASSERT(resultWellbehavedProvider);    
+
+    TestIndicationProviderAndFaultyProvider();
+
+    Array<CIMClient *> clientConnections;
+
+    // declare the clients
+    CIMClient * tmpClient;
+
+    // Calculate the thread limit on the OS.
+    long maxThread(-1);
+    #if defined(PEGASUS_OS_TYPE_UNIX)
+        maxThread = sysconf(_SC_THREAD_THREADS_MAX);
+    #endif
+
+    // The maximum requests to be sent are derived from the maximum
+    // thread limit on the OS. The Faulty provider responds properly
+    // to some requests. Hence for the cimprovagt to reach its
+    // thread limit we have to inundate it with maxThread*2 requests.
+    long maxRequests;
+    maxThread == -1 ?
+        maxRequests = DEFAULT_MAX_CIM_REQUESTS:
+        maxRequests = maxThread * 2;
+
+    for(Uint32 i = 0; i < MAX_CONNECTIONS; i++)
+    {
+        tmpClient = new CIMClient();
+        tmpClient->setTimeout(CONN_TIMEOUT * 1000);
+        tmpClient->connectLocal();
+        clientConnections.append(tmpClient);
+    }
+
+    //initialize
+    recievedNICIMExceptionCount = 0;
+    recievedNIConnTimeoutExceptionCount = 0;
+    recievedNICannotConnectExceptionCount = 0;
+
+    // run tests
+    cout <<"Executing " << maxRequests
+        <<" NI requests for faulty provider on " <<MAX_CONNECTIONS 
+        <<" client connections for "
+        << (maxRequests/MAX_CONNECTIONS)*CONN_TIMEOUT
+        <<" sec."<<endl;
+
+    _executeRequest(clientConnections,
+        _executeNIonFaultyProvider,
+        maxRequests);
+
+   // clean up connections
+   for(Uint32 i=0; i< clientConnections.size(); i++)
+   {
+       delete clientConnections[i];
+   }
+
+   if(verbose)
+       cout<<"received CIM exceptions = "
+           <<recievedNICIMExceptionCount.get()<<endl
+           <<"received Connection Timeout exceptions = "
+           <<recievedNIConnTimeoutExceptionCount.get()<<endl
+           <<"received CannotConnect exceptions = "
+           <<recievedNICannotConnectExceptionCount.get()<<endl;
+
+   //we should have recieved either CIM exception(for crossing thread limit) or 
+   //cannot connect exceptions(for crossing fd limit) AND not both/none.
+   if(!(recievedNICIMExceptionCount.get() > 0) ^ 
+       (recievedNICannotConnectExceptionCount.get() > 0))
+   {
+       cout << "The test could have failed due to two reasons : " << endl
+           << "Reason 1 : The code did not behave as expected. " << endl
+           << "Reason 2 : The number of requests used to inundate the "
+           << "cimserver is insufficient." << endl; 
+   }
+
+   PEGASUS_TEST_ASSERT((recievedNICIMExceptionCount.get() > 0) ^ 
+       (recievedNICannotConnectExceptionCount.get() > 0));
+
+   //if cimserver reached its thread limit for the faulty provider
+   //before fd limit..then evaluate the results.
+   if(recievedNIConnTimeoutExceptionCount.get() == 0)
+   {
+       throw Exception(
+           "did not receive any conn timeout exceptions "
+           "for NI requests on faulty provider. ");
+   }
+   else
+   if(recievedNICIMExceptionCount.get() > 0)
+   {
+       cout<<"Faulty provider agent has reached its threadpool limit."<<endl;
+
+       //run a test on test instance provider
+       resultWellbehavedProvider = TestWellbehavedInstanceProvider();
+       PEGASUS_TEST_ASSERT(resultWellbehavedProvider);
+   }
+   else if(recievedNICannotConnectExceptionCount.get() > 0)
+   {
+       cout<<"cimserver may have reached its fd limit"
+           " before the thread limit"<<endl;
+   }
+   else
+   {
+       PEGASUS_TEST_ASSERT(false);
+   }
+
+   // wait for cim server to clean up disconnected clients' resources(threads 
+   // and fds).
+   cout<<"Waiting for clean up routine to initiate cleanup for " << 
+       CIMSERVER_CLEANUP_TIME<<" sec."<<endl;
+   Threads::sleep(CIMSERVER_CLEANUP_TIME * 1000);
+
+   //run a test on test instance provider
+   resultWellbehavedProvider = TestWellbehavedInstanceProvider();
+   if(resultWellbehavedProvider == false)
+   {
+       throw Exception(
+           "A cim request on well behaved test instance provider failed"
+           " after cimserver crossed its fd/thread limit");
+   }
+
+}
+
+int main(int argc, char** argv)
+{
+    verbose = getenv("PEGASUS_TEST_VERBOSE");
+
+    try
+    {
+        TestCimserverAvailability();
+    }
+    catch(const CIMException & e)
+    {
+        cout << "CIMException: " << e.getCode() << " "
+            << e.getMessage() << endl;
+        return(-1);
+    }
+    catch(const Exception & e)
+    {
+        cout << "Exception: " << e.getMessage() << endl;
+        return(-1);
+    }
+    catch(...)
+    {
+        cout << "unknown exception" << endl;
+        return(-1);
+    }
+
+    cout << argv[0] << " +++++ passed all tests" << endl;
+
+    return(0);
+}
+
+
index 6b921792b07c36f17c0e055e334e9ec436c0d150..e626f55bbffa594d9b5d11929c17a5f197249ef3 100644 (file)
@@ -84,6 +84,8 @@ repository:
        @ cimmofl "-R$(REPOSITORY_DIR)" "-N$(REPOSITORY_NAME)" "-M$(REPOSITORY_MODE)" "-n$(TESTPROVIDERNS)" TestChunkingStressProviderSchema.mof
        @ $(ECHO) +++++ Loading IndicationStressTest class definitions into $(TESTPROVIDERNS) namespace ...
        @ cimmofl "-R$(REPOSITORY_DIR)" "-N$(REPOSITORY_NAME)" "-M$(REPOSITORY_MODE)" "-n$(TESTPROVIDERNS)" IndicationStressTestProviderSchema.mof
+       @ $(ECHO) +++++ Loading TestFaultyProvider class definitions into $(TESTPROVIDERNS) namespace ...
+       @ cimmofl "-R$(REPOSITORY_DIR)" "-N$(REPOSITORY_NAME)" "-M$(REPOSITORY_MODE)" "-n$(TESTPROVIDERNS)" TestFaultyProviderSchema.mof
 
        @ $(ECHO) +++++ Registering TestInstanceProvider ...
        @ cimmofl "-R$(REPOSITORY_DIR)" "-N$(REPOSITORY_NAME)" "-M$(REPOSITORY_MODE)" "-n$(INTEROPNS)" TestInstanceProviderRegistration.mof
@@ -93,6 +95,10 @@ repository:
        @ cimmofl "-R$(REPOSITORY_DIR)" "-N$(REPOSITORY_NAME)" "-M$(REPOSITORY_MODE)" "-n$(INTEROPNS)" IndicationStressTestProviderR.mof
        @ $(ECHO) +++++ Registering IndicationStressTestConsumer Provider  ...
        @ cimmofl "-R$(REPOSITORY_DIR)" "-N$(REPOSITORY_NAME)" "-M$(REPOSITORY_MODE)" "-n$(INTEROPNS)" IndicationStressTestConsumerR.mof
+       @ $(ECHO) +++++ Registering TestFaultyProvider ...
+       @ cimmofl "-R$(REPOSITORY_DIR)" "-N$(REPOSITORY_NAME)" "-M$(REPOSITORY_MODE)" "-n$(INTEROPNS)" TestFaultyProviderRegistration.mof
+       @ $(ECHO) +++++ Registering TestGoodInstanceProvider ...
+       @ cimmofl "-R$(REPOSITORY_DIR)" "-N$(REPOSITORY_NAME)" "-M$(REPOSITORY_MODE)" "-n$(INTEROPNS)" TestGoodInstanceProviderRegistration.mof
 
        @ $(ECHO) +++++ Loading IndicationTestProvider class definitions into $(TESTPROVIDERNS) namespace ...
        @ cimmofl "-R$(REPOSITORY_DIR)" "-N$(REPOSITORY_NAME)" "-M$(REPOSITORY_MODE)" "-n$(TESTPROVIDERNS)" IndicationTestProvider.mof
diff --git a/src/Providers/TestProviders/Load/TestFaultyProviderRegistration.mof b/src/Providers/TestProviders/Load/TestFaultyProviderRegistration.mof
new file mode 100644 (file)
index 0000000..9414e59
--- /dev/null
@@ -0,0 +1,78 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+#pragma locale("en_US")
+
+instance of PG_ProviderModule
+{
+    Description = "A test provider to test cimom availability in the event of outstanding requests exceeding cimserver thread limit.";
+    Caption = "Pegasus thread limit test Provider Module";
+    Name = "TestFaultyProviderModule";
+    ModuleGroupName = "Faulty";
+    Vendor = "OpenPegasus";
+    Version = "2.5.0";
+    InterfaceType = "C++Default";
+    InterfaceVersion = "2.5.0";
+    Location = "TestFaultyProvider";
+};
+
+instance of PG_Provider
+{
+    ProviderModuleName = "TestFaultyProviderModule";
+    Name = "TestFaultyInstanceProvider";
+};
+
+instance of PG_ProviderCapabilities
+{
+    ProviderModuleName = "TestFaultyProviderModule";
+    ProviderName = "TestFaultyInstanceProvider";
+    CapabilityID = "001";
+    ClassName = "TST_FaultyInstance";
+    Namespaces = { "test/TestProvider" };
+    ProviderType = { 2 };
+    SupportedProperties = NULL;
+    SupportedMethods = NULL;
+};
+
+instance of PG_Provider
+{
+    ProviderModuleName = "TestFaultyProviderModule";
+    Name = "TestGoodIndicationProvider";
+};
+
+instance of PG_ProviderCapabilities
+{
+    ProviderModuleName = "TestFaultyProviderModule";
+    ProviderName = "TestGoodIndicationProvider";
+    CapabilityID = "002";
+    ClassName = "CIM_AlertIndication";
+    Namespaces = { "test/TestProvider" };
+    ProviderType = { 4 }; // Incication
+    SupportedProperties = NULL;
+    SupportedMethods = NULL;
+};
diff --git a/src/Providers/TestProviders/Load/TestFaultyProviderSchema.mof b/src/Providers/TestProviders/Load/TestFaultyProviderSchema.mof
new file mode 100644 (file)
index 0000000..e4abcd8
--- /dev/null
@@ -0,0 +1,48 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+#pragma locale("en_US")
+
+class TST_FaultyInstance
+{
+    [key]
+    string Name;
+
+    string s = "Faulty Instance Class";
+    uint64 n;
+    real64 f;
+    datetime d;
+
+};
+
+class TST_FaultyInstanceSub : TST_FaultyInstance
+{
+    uint64 sub;
+};
+
+
diff --git a/src/Providers/TestProviders/Load/TestGoodInstanceProviderRegistration.mof b/src/Providers/TestProviders/Load/TestGoodInstanceProviderRegistration.mof
new file mode 100644 (file)
index 0000000..0fef59e
--- /dev/null
@@ -0,0 +1,62 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+#pragma locale("en_US")
+
+instance of PG_ProviderModule
+{
+    Description = "A test provider used to test the cimserver availibility along with TestFaultyInstanceProvider";
+    Caption = "Pegasus Good Instance Provider Module";
+    Name = "TestGoodInstanceProviderModule";
+    Vendor = "OpenPegasus";
+    Version = "2.5.0";
+    InterfaceType = "C++Default";
+    InterfaceVersion = "2.5.0";
+    Location = "TestGoodInstanceProvider";
+};
+
+instance of PG_Provider
+{
+    ProviderModuleName = "TestGoodInstanceProviderModule";
+    Name = "TestGoodInstanceProvider";
+};
+
+instance of PG_ProviderCapabilities
+{
+    ProviderModuleName = "TestGoodInstanceProviderModule";
+    ProviderName = "TestGoodInstanceProvider";
+    CapabilityID = "001";
+    ClassName = "TST_FaultyInstanceSub";
+    Namespaces = { "test/TestProvider" };
+    ProviderType = { 2 }; // Instance
+    SupportedProperties = NULL;
+    SupportedMethods = NULL;
+};
+
+
+
index 514f5edd72783b8df5e69b3ad4069b3cdb1eeb4c..5a363622bda4e9f9ee0b7a022fc949eb52fe8025 100644 (file)
@@ -66,7 +66,11 @@ TEST_DIRS = \
        PerformanceTests \
         EmbeddedInstanceProvider \
         EmbeddedInstanceProvider/testClient \
-        TestModuleGrouping
+        TestModuleGrouping \
+       FaultyInstanceProvider \
+       FaultyInstanceProvider/testclient \
+       TestGoodInstanceProvider
+
 
 ifeq ($(PEGASUS_ENABLE_INTEROP_PROVIDER),true)
 TEST_DIRS += \
diff --git a/src/Providers/TestProviders/TestGoodInstanceProvider/Makefile b/src/Providers/TestProviders/TestGoodInstanceProvider/Makefile
new file mode 100644 (file)
index 0000000..6c37b38
--- /dev/null
@@ -0,0 +1,49 @@
+#//%LICENSE////////////////////////////////////////////////////////////////
+#//
+#// Licensed to The Open Group (TOG) under one or more contributor license
+#// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+#// this work for additional information regarding copyright ownership.
+#// Each contributor licenses this file to you under the OpenPegasus Open
+#// Source License; you may not use this file except in compliance with the
+#// License.
+#//
+#// Permission is hereby granted, free of charge, to any person obtaining a
+#// copy of this software and associated documentation files (the "Software"),
+#// to deal in the Software without restriction, including without limitation
+#// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+#// and/or sell copies of the Software, and to permit persons to whom the
+#// Software is furnished to do so, subject to the following conditions:
+#//
+#// The above copyright notice and this permission notice shall be included
+#// in all copies or substantial portions of the Software.
+#//
+#// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+#// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+#// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+#// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+#// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+#// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#//
+#//////////////////////////////////////////////////////////////////////////
+ROOT = ../../../..
+
+DIR = Providers/TestProviders/TestGoodInstanceProvider
+
+include $(ROOT)/mak/config.mak
+
+LIBRARY = TestGoodInstanceProvider
+
+LIBRARIES = \
+       pegprovider \
+       pegclient \
+       pegcommon
+
+SOURCES = \
+        TestGoodInstanceProviderMain.cpp \
+       TestGoodInstanceProvider.cpp
+       
+include $(ROOT)/mak/dynamic-library.mak
+
+tests:
+
diff --git a/src/Providers/TestProviders/TestGoodInstanceProvider/TestGoodInstanceProvider.cpp b/src/Providers/TestProviders/TestGoodInstanceProvider/TestGoodInstanceProvider.cpp
new file mode 100644 (file)
index 0000000..d694241
--- /dev/null
@@ -0,0 +1,159 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%///////////////////////////////////////////////////////////////////////
+
+#include <cstring>
+#include <Pegasus/Common/Config.h>
+#include <Pegasus/Provider/CIMInstanceProvider.h>
+
+#include "TestGoodInstanceProvider.h"
+
+PEGASUS_USING_STD;
+PEGASUS_NAMESPACE_BEGIN
+
+TestGoodInstanceProvider::TestGoodInstanceProvider()
+{
+}
+
+TestGoodInstanceProvider::~TestGoodInstanceProvider()
+{
+}
+
+void TestGoodInstanceProvider::initialize(CIMOMHandle& cimom)
+{
+    // save cimom handle
+    //_cimom = cimom;
+
+    char namebuf[20];
+    char pathbuf[45];
+    memset(namebuf, 0x00, sizeof(namebuf));
+    memset(pathbuf, 0x00, sizeof(pathbuf));
+
+    // create default instances
+    for (Uint32 i = 1; i <= 2; i++)
+    {
+        sprintf(namebuf, "%u", i);
+        sprintf(pathbuf, "TST_FaultyInstanceInstance.Name=\"%u\"", i);
+        {
+            CIMInstance instance("TST_FaultyInstanceInstance");
+
+            instance.addProperty(CIMProperty("name", String(namebuf)));
+            instance.addProperty(CIMProperty("s", String("specified")));
+            instance.addProperty(CIMProperty("n", Uint64(i)));
+            instance.addProperty(CIMProperty("f", Real64(Real64(i)+0.001)));
+            instance.addProperty(
+                CIMProperty("d", CIMDateTime::getCurrentDateTime()));
+            instance.addProperty(CIMProperty("sub", Uint64(i)));
+
+            instance.setPath(CIMObjectPath(pathbuf));
+
+            _instances.append(instance);
+        }
+    }
+}
+
+void TestGoodInstanceProvider::terminate()
+{
+    delete this;
+}
+
+void TestGoodInstanceProvider::getInstance(
+    const OperationContext& context,
+    const CIMObjectPath& instanceReference,
+    const Boolean includeQualifiers,
+    const Boolean includeClassOrigin,
+    const CIMPropertyList& propertyList,
+    InstanceResponseHandler& handler)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);
+}
+
+void TestGoodInstanceProvider::enumerateInstances(
+    const OperationContext& context,
+    const CIMObjectPath& ref,
+    const Boolean includeQualifiers,
+    const Boolean includeClassOrigin,
+    const CIMPropertyList& propertyList,
+    InstanceResponseHandler& handler)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);
+}
+
+void TestGoodInstanceProvider::enumerateInstanceNames(
+    const OperationContext& context,
+    const CIMObjectPath& classReference,
+    ObjectPathResponseHandler& handler)
+{
+    handler.processing();
+  
+    for (Uint32 i = 0, n = _instances.size(); i < n; i++)
+    {
+        try
+        {
+            handler.deliver(_instances[i].getPath());
+        }
+        catch (CIMException&)
+        {
+            // suppress error
+        }
+    }
+
+    handler.complete();
+}
+
+void TestGoodInstanceProvider::modifyInstance(
+    const OperationContext& context,
+    const CIMObjectPath& instanceReference,
+    const CIMInstance& instanceObject,
+    const Boolean includeQualifiers,
+    const CIMPropertyList& propertyList,
+    ResponseHandler& handler)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);
+}
+
+void TestGoodInstanceProvider::createInstance(
+    const OperationContext& context,
+    const CIMObjectPath& instanceReference,
+    const CIMInstance& instanceObject,
+    ObjectPathResponseHandler& handler)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);
+}
+
+void TestGoodInstanceProvider::deleteInstance(
+    const OperationContext& context,
+    const CIMObjectPath& instanceReference,
+    ResponseHandler& handler)
+{
+    throw CIMException(CIM_ERR_NOT_SUPPORTED);
+}
+
+PEGASUS_NAMESPACE_END
diff --git a/src/Providers/TestProviders/TestGoodInstanceProvider/TestGoodInstanceProvider.h b/src/Providers/TestProviders/TestGoodInstanceProvider/TestGoodInstanceProvider.h
new file mode 100644 (file)
index 0000000..d842f58
--- /dev/null
@@ -0,0 +1,99 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%///////////////////////////////////////////////////////////////////////
+
+#ifndef Pegasus_TestGoodInstanceProvider_h
+#define Pegasus_TestGoodInstanceProvider_h
+
+#include <Pegasus/Common/Config.h>
+#include <Pegasus/Common/AtomicInt.h>
+#include <Pegasus/Provider/CIMInstanceProvider.h>
+
+PEGASUS_NAMESPACE_BEGIN
+
+class TestGoodInstanceProvider :
+    public CIMInstanceProvider
+{
+public:
+    TestGoodInstanceProvider();
+    virtual ~TestGoodInstanceProvider();
+
+    // CIMProvider interface
+    virtual void initialize(CIMOMHandle& cimom);
+    virtual void terminate();
+
+    // CIMInstanceProvider interface
+    virtual void getInstance(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        const Boolean includeQualifiers,
+        const Boolean includeClassOrigin,
+        const CIMPropertyList& propertyList,
+        InstanceResponseHandler& handler);
+
+    virtual void enumerateInstances(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        const Boolean includeQualifiers,
+        const Boolean includeClassOrigin,
+        const CIMPropertyList& propertyList,
+        InstanceResponseHandler& handler);
+
+    virtual void enumerateInstanceNames(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        ObjectPathResponseHandler& handler);
+
+    virtual void modifyInstance(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        const CIMInstance& obj,
+        const Boolean includeQualifiers,
+        const CIMPropertyList& propertyList,
+        ResponseHandler& handler);
+
+    virtual void createInstance(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        const CIMInstance& obj,
+        ObjectPathResponseHandler& handler);
+
+    virtual void deleteInstance(
+        const OperationContext& context,
+        const CIMObjectPath& ref,
+        ResponseHandler& handler);
+
+protected:
+    Array<CIMInstance> _instances;
+};
+
+PEGASUS_NAMESPACE_END
+
+#endif
diff --git a/src/Providers/TestProviders/TestGoodInstanceProvider/TestGoodInstanceProviderMain.cpp b/src/Providers/TestProviders/TestGoodInstanceProvider/TestGoodInstanceProviderMain.cpp
new file mode 100644 (file)
index 0000000..081fcb3
--- /dev/null
@@ -0,0 +1,49 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%///////////////////////////////////////////////////////////////////////
+
+#include <Pegasus/Common/Config.h>
+
+#include "TestGoodInstanceProvider.h"
+
+PEGASUS_NAMESPACE_BEGIN
+
+extern "C"
+PEGASUS_EXPORT CIMProvider* PegasusCreateProvider(const String& providerName)
+{
+    if (String::equalNoCase(providerName, "TestGoodInstanceProvider"))
+    {
+        return new TestGoodInstanceProvider();
+    }
+
+    return 0;
+}
+
+PEGASUS_NAMESPACE_END
index 71b3665eb15b3d8b19fb9728e0739ada08a888fd..775227f7060107a355f2741626e4ed33e46c5e97 100755 (executable)
@@ -382,6 +382,9 @@ if [ "$PEGASUS_TEST_ENABLE_DEBUG_TRACE" = "true" ]; then
             -e "Test_IndicationProviderClass" \
             -e "idle connection" \
             -e "The repository throws the following exception: TestCMPI_Instance" \
+            -e "HTTPAcceptor: accept() failed.  errno: 24" \
+            -e "Socket write failed with error: Broken pipe (error code 32)" \
+            -e "arrived after the client disconnected." \
             -e "^$" \
             $traceFile > $PEGASUS_HOME/trace/trace.out