datacommsserver/esockserver/core_states/ss_corepractivities.cpp
branchRCL_3
changeset 12 8b5d60ce1e94
parent 4 928ed51ddc43
child 13 0b0e9fce0b58
--- a/datacommsserver/esockserver/core_states/ss_corepractivities.cpp	Fri Mar 12 15:49:41 2010 +0200
+++ b/datacommsserver/esockserver/core_states/ss_corepractivities.cpp	Mon Mar 15 12:45:15 2010 +0200
@@ -108,10 +108,51 @@
 NODEACTIVITY_END()
 }
 
+
+namespace PRDestroyOrphansActivity
+{
+DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityDestroyOrphans, PRDestroyOrphans, TCFMessage::TDestroyOrphans, CoreActivities::CDestroyOrphansActivity::New)
+    // Destroy non-Default Data clients first (as there can be references from non-Default Data clients to the Default Data client)
+    FIRST_NODEACTIVITY_ENTRY(MeshMachine::TAwaitingMessageState<TCFMessage::TDestroyOrphans>, PRStates::TOrphansOrNoTag)
+    NODEACTIVITY_ENTRY(KOrphans, PRStates::TDestroyFirstOrphan, MeshMachine::TAwaitingMessageState<Messages::TEChild::TLeft>, MeshMachine::TTag<KContinue>)
+    THROUGH_NODEACTIVITY_ENTRY(KContinue, PRStates::TProcessClientLeft, PRStates::TOrphansBackwardsOrNoTag)
+    ROUTING_NODEACTIVITY_ENTRY(KNoTag, CDestroyOrphansActivity::TNoTagOrNoClients)
+    LAST_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing)
+
+    // At this point, there are no Data or Control clients, so leave the Service Providers (if any) and destroy the node.
+    // (Can we just modify the above tuples so that they do not accept the very last TLeft, and thus leave it
+    // to MCPrDestroyActivity or PRClientLeftActivity to accept and do the destruction for us?).
+    
+    // If Control Provider is present, send a TIdle message.
+    THROUGH_NODEACTIVITY_ENTRY(KNoClients, CoreNetStates::TSendDataClientIdle, TNoTag)
+    // If Control Provider is present, terminate the activity (KNoTag), as
+    // Control Provider will send us a TDestroy in response to the TIdle message. 
+    ROUTING_NODEACTIVITY_ENTRY(KNoTag, CDestroyOrphansActivity::TControlProviderNoTagOrNoClients)
+    LAST_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing)
+
+    // No Control Provider - leave Service Providers (if any) and destroy the node.
+    ROUTING_NODEACTIVITY_ENTRY(KNoClients, CoreNetStates::TNoTagOrNoBearer)
+    THROUGH_NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TSendClientLeavingRequestToServiceProviders, TNoTag)
+    NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, MeshMachine::TAwaitingLeaveComplete, CDestroyOrphansActivity::TNoTagOrNoTagBackwards)
+
+    ROUTING_NODEACTIVITY_ENTRY(KNoBearer, TNoTag)
+    LAST_NODEACTIVITY_ENTRY(KNoTag, CDestroyOrphansActivity::TMarkNodeForDestruction)
+    // Node will be destroyed in CDestroyOrphansActivity::Destroy() 
+NODEACTIVITY_END()
+}
+
 namespace PRClientLeaveActivity
 {//This activity will wait for ECFActivityBinderRequest to complete
-DEFINE_EXPORT_NODEACTIVITY(ECFActivityClientLeave, PRClientLeave, TNodeSignal::TNullMessageId) //May be waiting for both messages
-NODEACTIVITY_ENTRY(KNoTag, PRStates::TProcessClientLeave, CoreStates::TAwaitingClientLeave, MeshMachine::TNoTag)
+DEFINE_EXPORT_NODEACTIVITY(ECFActivityClientLeave, PRClientLeave, Messages::TEPeer::TLeaveRequest) 
+    NODEACTIVITY_ENTRY(KNoTag, PRStates::TProcessClientLeave, MeshMachine::TAwaitingMessageState<TEPeer::TLeaveRequest>, MeshMachine::TNoTag)
+NODEACTIVITY_END()
+}
+
+namespace PRClientLeftActivity
+{
+//This activity waits for TLeft which is a response to destroy, shouldn't really be needed
+DEFINE_EXPORT_NODEACTIVITY(ECFActivityClientLeft, PRClientLeft, Messages::TEChild::TLeft)
+    NODEACTIVITY_ENTRY(KNoTag, PRStates::TProcessClientLeft, MeshMachine::TAwaitingMessageState<Messages::TEChild::TLeft>, MeshMachine::TNoTag)
 NODEACTIVITY_END()
 }
 
@@ -135,12 +176,9 @@
 DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityDestroy, PRDestroy, TEChild::TDestroy, CoreActivities::CDestroyActivity::New)
 	FIRST_NODEACTIVITY_ENTRY(MeshMachine::TAwaitingDestroy, CoreActivities::CDestroyActivity::TNoTagBlockedByActivitiesOrLeavingDataClient)
 
-    //Stop self first
-    NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TStopSelf, CoreNetStates::TAwaitingDataClientStopped, CoreStates::TNoTagOrNoClients)
-
-    //The node mustn't go out of scope with clients present. The node must get rid of them first.
-	NODEACTIVITY_ENTRY(KNoTag, CoreActivities::CDestroyActivity::TMakeClientsLeaveOrProcessClientLeave, CoreStates::TAwaitingClientLeave,  CDestroyActivity::TNoTagOrNoTagBackwards)
-	THROUGH_NODEACTIVITY_ENTRY(KNoTag, CoreActivities::CDestroyActivity::TProcessClientLeave, TTag<KNoClients>)
+    ROUTING_NODEACTIVITY_ENTRY(KNoTag, PRStates::TNonLeavingNoTagOrNoClients)
+    NODEACTIVITY_ENTRY(KNoTag, PRStates::TDestroyFirstClient, MeshMachine::TAwaitingMessageState<Messages::TEChild::TLeft>, MeshMachine::TTag<KContinue>)
+    THROUGH_NODEACTIVITY_ENTRY(KContinue, PRStates::TProcessClientLeft, PRStates::TNoTagBackwardsOrNoClients)
 
  	THROUGH_NODEACTIVITY_ENTRY(KNoClients, PRStates::TProcessDestroy, MeshMachine::TNoTag)
  	NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, MeshMachine::TAwaitingLeaveComplete, CoreActivities::CDestroyActivity::TNoTagOrNoTagBackwards)
@@ -296,6 +334,8 @@
 	THROUGH_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, CoreNetStates::TNoTagOrUnbindOnStop)
 
 	NODEACTIVITY_ENTRY(CoreNetStates::KUnbind, CoreNetStates::TSendClientLeavingRequestToServiceProvider, MeshMachine::TAwaitingLeaveComplete, MeshMachine::TNoTag)
+	// Note that if CMMCommsProviderBase::DestroyOrphanedDataClients() finds this activity running, it
+	// will do nothing and assume that destruction of orphans will be initiated below.
 	THROUGH_NODEACTIVITY_ENTRY(KNoTag, PRStates::TDestroyOrphanedDataClients, MeshMachine::TNoTag)
 	LAST_NODEACTIVITY_ENTRY(KNoTag, PRStates::TSendDataClientStopped)
 NODEACTIVITY_END()
@@ -632,7 +672,7 @@
 :	CNodeRetryActivity(aActivitySig, aNode),
 	APreallocatedOriginators<1>(iOriginators)
 	{
-	//Mark the provider for deletion, so that it's not served by the factory from now on.
+    //Mark the provider for deletion, so that it's not served by the factory from now on.
     static_cast<ESock::CMMCommsProviderBase&>(iNode).MarkMeForDeletion();
 	}
 
@@ -645,16 +685,6 @@
 	static_cast<ESock::CMMCommsProviderBase&>(iNode).DeleteMeNow();
 	}
 
-TBool CDestroyActivity::Next(TNodeContextBase& aContext)
-    {
-    if (aContext.iMessage.IsMessage<TEBase::TCancel>())
-        {  
-        return ETrue;
-        }
-    else
-        return CNodeActivityBase::Next(aContext);
-    }
-
 EXPORT_DEFINE_SMELEMENT(CDestroyActivity::TNoTagOrNoTagBackwards, NetStateMachine::MStateFork, PRStates::TContext)
 EXPORT_C TInt CDestroyActivity::TNoTagOrNoTagBackwards::TransitionTag()
     {
@@ -703,13 +733,18 @@
     __ASSERT_DEBUG(iContext.Node().GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EData, TCFClientType::EActive|TCFClientType::EActivating|TCFClientType::EStarting|TCFClientType::EStarted))==NULL,
     	User::Panic(KCorePrPanic, KPanicClientsStillPresent));
 
-   	TClientIter<TDefaultClientMatchPolicy> dciter = iContext.Node().GetClientIter<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EData),	TClientType(0, TCFClientType::ELeaving));
-   	RNodeInterface* dc = NULL;
-    while ((dc = dciter[0]) != NULL) //always inspect the first elem as we're invalidating the iterator with each hit.
-        {
-		dc->PostMessage(iContext.NodeId(), TEChild::TDestroy().CRef());
-		dc->SetFlags(TCFClientType::ELeaving);
-        }
+	iContext.Node().PostToClients<TDefaultClientMatchPolicy>(iContext.NodeId(),
+		TEChild::TDestroy().CRef(),
+		TClientType(TCFClientType::EData),
+		TClientType(0, TCFClientType::ELeaving|TCFClientType::EDefault),
+		TClientType::ELeaving
+		);
+	iContext.Node().PostToClients<TDefaultClientMatchPolicy>(iContext.NodeId(),
+		TEChild::TDestroy().CRef(),
+		TClientType(TCFClientType::EData),
+		TClientType(0, TCFClientType::ELeaving),
+		TClientType::ELeaving
+		);
 	}
 
 void CDestroyActivity::TMakeClientsLeaveOrProcessClientLeave::ProcessClientLeaveL()
@@ -718,6 +753,114 @@
     processClientLeave.DoL();
     }
 
+//-=========================================================
+//
+// Destroy Orphan Activity - will delete the node when destructed
+// if TMarkNodeForDestruction tuple has been called.
+//
+//-=========================================================
+
+CNodeActivityBase* CDestroyOrphansActivity::New(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
+    {
+    TAny* space = BorrowPreallocatedSpace(aNode, sizeof(CDestroyOrphansActivity));
+    CDestroyOrphansActivity* self = new (space) CDestroyOrphansActivity(aActivitySig, aNode);
+    self->InsertPreallocatedDestroyActivity(); //Destructing preallocated activity
+    return self;
+    }
+
+CDestroyOrphansActivity::CDestroyOrphansActivity(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
+  : MeshMachine::CNodeActivityBase(aActivitySig, aNode),
+          MeshMachine::APreallocatedOriginators<1>(iOriginators)
+    {
+    }
+
+CDestroyOrphansActivity::~CDestroyOrphansActivity() 
+    {
+    }
+
+void CDestroyOrphansActivity::Destroy() 
+    {
+    ReturnPreallocatedSpace(this);
+    if (DestroyFlag() && iNode.CountActivities(ECFActivityDestroy) == 0)
+        {
+        static_cast<ESock::CMMCommsProviderBase&>(iNode).MarkMeForDeletion();
+        this->~CDestroyOrphansActivity(); //Run the destructor
+        static_cast<ESock::CMMCommsProviderBase&>(iNode).DeleteMeNow();
+        }
+    else
+        {
+        this->~CDestroyOrphansActivity(); //Run the destructor
+        }
+    }
+
+void CDestroyOrphansActivity::SetDestroyFlag()
+    {
+    iDestroyFlag = ETrue;
+    }
+
+TBool CDestroyOrphansActivity::DestroyFlag() const
+    {
+    return iDestroyFlag;
+    }
+
+DEFINE_SMELEMENT(CDestroyOrphansActivity::TMarkNodeForDestruction, NetStateMachine::MStateTransition, CDestroyOrphansActivity::TContext)
+void CDestroyOrphansActivity::TMarkNodeForDestruction::DoL()
+/**
+Flag that the node should be destroyed when the activity completes.
+*/
+    {
+    CDestroyOrphansActivity* act = static_cast<CDestroyOrphansActivity*>(iContext.Activity());
+    ASSERT(act);
+    act->SetDestroyFlag();
+    }
+
+// This is a copy from CDestroyActivity.
+DEFINE_SMELEMENT(CDestroyOrphansActivity::TNoTagOrNoTagBackwards, NetStateMachine::MStateFork, CDestroyOrphansActivity::TContext)
+TInt CDestroyOrphansActivity::TNoTagOrNoTagBackwards::TransitionTag()
+    {
+    if (iContext.iMessage.IsMessage<TEChild::TLeft>())
+        {
+        TClientIter<TDefaultClientMatchPolicy> iter = iContext.Node().GetClientIter<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EData|TCFClientType::ECtrl));
+        __ASSERT_DEBUG(iter[0], User::Panic(KSpecAssert_ESockCrStaCPRAC, 7)); //One leaving client must still be there.
+        return iter[1] == NULL ?  MeshMachine::KNoTag : MeshMachine::KNoTag | NetStateMachine::EBackward;
+        }
+    else if (iContext.iMessage.IsMessage<TEPeer::TLeaveComplete>())
+        {
+        __ASSERT_DEBUG(iContext.Node().GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::ECtrl|TCFClientType::EData))==NULL,
+        User::Panic(KCorePrPanic, KPanicClientsStillPresent));
+        if (iContext.Node().GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EServProvider))==NULL)
+            {
+            return NetStateMachine::EForward | MeshMachine::KNoTag;
+            }
+        return NetStateMachine::EBackward | MeshMachine::KNoTag; //Loop back to the same triple (& remove the peer)
+        }
+    __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockCrStaCPRAC, 8));
+    return KNoTag;
+    }
+
+DEFINE_SMELEMENT(CDestroyOrphansActivity::TNoTagOrNoClients, NetStateMachine::MStateFork, CDestroyOrphansActivity::TContext)
+TInt CDestroyOrphansActivity::TNoTagOrNoClients::TransitionTag()
+/**
+If the Destroy activity is not running and there are no data/control clients, return KNoClients, else return KNoTag.
+*/
+    {
+    if (iContext.Node().CountActivities(ECFActivityDestroy))
+        {
+        return KNoTag;
+        }
+    CoreStates::TNoTagOrNoClients fork(iContext);
+    return fork.TransitionTag();
+    }
+
+
+DEFINE_SMELEMENT(CDestroyOrphansActivity::TControlProviderNoTagOrNoClients, NetStateMachine::MStateFork, CDestroyOrphansActivity::TContext)
+TInt CDestroyOrphansActivity::TControlProviderNoTagOrNoClients::TransitionTag()
+/**
+If there is a Control Provider, return KNoTag, else return KNoClients
+*/
+    {
+    return iContext.Node().ControlProvider() ? KNoTag : KNoClients;
+    }
 
 //-=========================================================
 //
@@ -794,8 +937,10 @@
     //If you are not providing a clean error handling solution for your activity,
     //please use IsBinding() before calling this API!
     __ASSERT_DEBUG(!iOriginator.IsNull(), User::Panic(KSpecAssert_ESockCrStaCPRAC, 10)); //The iOriginator must be set.
-    RClientInterface::OpenPostMessageClose(iOurNode, iOriginator, TCFDataClient::TBindToComplete(aError).CRef());
-    iOriginator.SetNull();
+    
+    RClientInterface::OpenPostMessageClose(iOurNode, iOriginator, TCFServiceProvider::TBindToComplete(aError).CRef());
+
+     iOriginator.SetNull();
     }
 
 EXPORT_DEFINE_SMELEMENT(ABindingActivity::TSendBindToComplete, NetStateMachine::MStateTransition, CoreStates::TContext)
@@ -807,18 +952,6 @@
     bindingActivity->ReplyToOriginator(iContext.iNodeActivity->Error());
 	}
 
-EXPORT_DEFINE_SMELEMENT(ABindingActivity::TSendBindToCompleteIfExpected, NetStateMachine::MStateTransition, CoreStates::TContext)
-EXPORT_C void ABindingActivity::TSendBindToCompleteIfExpected::DoL()
-	{
-    __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCorePrPanic, KPanicNoActivity));
-    __ASSERT_DEBUG(iContext.iNodeActivity->SupportsExtInterface(ABindingActivity::KInterfaceId), User::Panic(KSpecAssert_ESockCrStaCPRAC, 12));
-    ABindingActivity* bindingActivity = reinterpret_cast<ABindingActivity*>(iContext.iNodeActivity->FetchExtInterfaceL(ABindingActivity::KInterfaceId));
-    if (bindingActivity->IsBinding())
-	    {
-		bindingActivity->ReplyToOriginator(iContext.iNodeActivity->Error());
-	    }
-	}
-
 void ABindingActivity::FinalReplyToOriginator(TInt aError)
 /**
 Intended to be called from derived class destructors to arrange for a TBindToComplete reply to be sent
@@ -841,9 +974,11 @@
 DECLARE_DEFINE_ACTIVITY_MAP(coreActivitiesPR)
 	ACTIVITY_MAP_ENTRY(PRDataClientJoinActivity, PRDataClientJoin)
 	ACTIVITY_MAP_ENTRY(PRControlClientJoinActivity, PRControlClientJoin)
-	ACTIVITY_MAP_ENTRY(PRClientLeaveActivity, PRClientLeave)
+	ACTIVITY_MAP_ENTRY(PRClientLeftActivity, PRClientLeft)
+    ACTIVITY_MAP_ENTRY(PRClientLeaveActivity, PRClientLeave)
 	ACTIVITY_MAP_ENTRY(PRForwardStateChangeActivity, PRForwardStateChange)
 	ACTIVITY_MAP_ENTRY(PRBindToActivity, PRBindTo)
+	ACTIVITY_MAP_ENTRY(PRDestroyOrphansActivity, PRDestroyOrphans)
 ACTIVITY_MAP_END_BASE(CoreActivities,coreActivitiesAll)
 
 //Activity Map provided by CorePr to be used by SCprs.
@@ -894,6 +1029,7 @@
 	ACTIVITY_MAP_ENTRY(PRDataClientActiveActivity, PRDataClientActive)
     ACTIVITY_MAP_ENTRY(PRDataClientStatusChangeActivity, PRDataClientStatusChange)
     ACTIVITY_MAP_ENTRY(PRLegacyRMessage2HandlerActivity, PRLegacyRMessage2Handler)
+    ACTIVITY_MAP_ENTRY(PRDestroyActivity, PRDestroy)
 ACTIVITY_MAP_END_BASE(PRActivities,coreActivitiesPR)
 
 //Activity Map provided by CorePr to be used by TMs.
@@ -1319,18 +1455,20 @@
             //clients in at the current owner.
             for (TInt i = 0; i < iDataClients.Count(); i++)
                 {
-                if (!(iDataClients[i].iDataClient.Flags() & TCFClientType::EActive))
+                Messages::RNodeInterface& dataClient = iDataClients[i].iDataClient; 
+                if (!(dataClient.Flags() & TCFClientType::EActive))
                     {
 #ifndef __GCCXML__
-					//If the dataclient managed to report idle in the mean time, have him destroyed
-                    RClientInterface::OpenPostMessageClose(iNode.Id(), iDataClients[i].iDataClient.RecipientId(), TEChild::TDestroy().CRef());
+                    //If the dataclient managed to report idle in the mean time, have him destroyed
+                    RClientInterface::OpenPostMessageClose(iNode.Id(), dataClient.RecipientId(), TEChild::TDestroy().CRef());
+                    dataClient.SetFlags(TCFClientType::ELeaving);
 #endif
                     }
-                iDataClients[i].iDataClient.ClearFlags(TCFClientType::EActivating);
+                dataClient.ClearFlags(TCFClientType::EActivating);
 #ifndef __GCCXML__
                 //Simulate client leaving on the new owner.
-                RClientInterface::OpenPostMessageClose(iDataClients[i].iDataClient.RecipientId(), iDataClients[i].iNewOwner,
-                	TEChild::TLeft().CRef());
+                RClientInterface::OpenPostMessageClose(dataClient.RecipientId(), iDataClients[i].iNewOwner,
+                        TEChild::TLeft().CRef());
 #endif
                 }
             }
@@ -1711,19 +1849,23 @@
 
     intf->SendCustomFlowProvision();
 	}
-
+    
 EXPORT_DEFINE_SMELEMENT(CCommsBinderActivity::TAwaitingBindToComplete, NetStateMachine::MState, PRStates::TContext)
 EXPORT_C TBool CCommsBinderActivity::TAwaitingBindToComplete::Accept()
-	{
-	CoreNetStates::TAwaitingBindToComplete awaitingBindToComplete(iContext);
-	if (awaitingBindToComplete.Accept())
-		{
+	{   
+	TCFServiceProvider::TBindToComplete* bindToComplete = message_cast<TCFServiceProvider::TBindToComplete>(&iContext.iMessage); 
+	if (bindToComplete) 
+	    { 
+	    __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCorePrPanic, KPanicNoActivity)); 
+	    iContext.iNodeActivity->SetError(bindToComplete->iValue); 
+	    
 	    CCommsBinderActivity* binderActivity = reinterpret_cast<CCommsBinderActivity*>(iContext.iNodeActivity->FetchExtInterface(CCommsBinderActivity::KInterfaceId));
 	    __ASSERT_DEBUG(binderActivity, User::Panic(KSpecAssert_ESockCrStaCPRAC, 30));
 	    binderActivity->BindToComplete();
-		iContext.Node().DestroyOrphanedDataClients();
-		return ETrue;
-		}
+	    iContext.Node().DestroyOrphanedDataClients();
+	    return ETrue; 
+	    }
+
 	return EFalse;
 	}
 
@@ -1911,7 +2053,7 @@
                     TClientType(TCFClientType::ECtrl), TClientType(0, TCFClientType::ELeaving));
             RNodeInterface* ctrlClient = NULL;
 
-            while ( (ctrlClient = iter++) )
+            while ( (ctrlClient = iter++) != NULL )
                 {
                 // Let control clients know the node has gone down, other than those that originated Start (they will be errored by ~CNodeActivityBase)...
                 if (FindOriginator(*ctrlClient) >= 0)