commsfwsupport/commselements/meshmachine/src/mm_node.cpp
changeset 40 34fc115b8742
parent 22 592244873960
child 65 41cc8e7ff496
equal deleted inserted replaced
34:6646e488a904 40:34fc115b8742
    23 #include <elements/mm_context_internal.h>
    23 #include <elements/mm_context_internal.h>
    24 #include <elements/mm_log.h>
    24 #include <elements/mm_log.h>
    25 
    25 
    26 #include <elements/nm_messages_base.h>
    26 #include <elements/nm_messages_base.h>
    27 #include <elements/nm_messages_child.h>
    27 #include <elements/nm_messages_child.h>
    28 
       
    29 
    28 
    30 #ifdef _DEBUG
    29 #ifdef _DEBUG
    31 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
    30 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
    32 // (if it could happen through user error then you should give it an explicit, documented, category + code)
    31 // (if it could happen through user error then you should give it an explicit, documented, category + code)
    33 _LIT(KSpecAssert_ElemMeshMachNodC, "ElemMeshMachNodC");
    32 _LIT(KSpecAssert_ElemMeshMachNodC, "ElemMeshMachNodC");
   230 
   229 
   231 	CNodeActivityBase* a = NULL;
   230 	CNodeActivityBase* a = NULL;
   232 	for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--)
   231 	for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--)
   233 		{
   232 		{
   234 		CNodeActivityBase* act = iActivities[i];
   233 		CNodeActivityBase* act = iActivities[i];
   235 		const TNodeId& postedTo = act->iPostedToId;
   234 		const TNodeId& postedTo = act->PostedToNodeId();
   236 		if (!act->IsIdle()
   235 		if (!act->IsIdle()
   237 			&& (postedTo.IsNull() || aContext.iSender == postedTo)
   236 			&& (postedTo.IsNull() || aContext.iSender == postedTo)
   238 				&& (recipient->NodeCtx() == act->ActivityId()))
   237 				&& (recipient->NodeCtx() == act->ActivityId()))
   239 			{
   238 			{
   240 			a = act;
   239 			a = act;
   428 			context.iNodeActivity = NULL;
   427 			context.iNodeActivity = NULL;
   429 			}
   428 			}
   430 		}
   429 		}
   431 	}
   430 	}
   432 
   431 
       
   432 
   433 EXPORT_C void AMMNodeBase::AbortActivitiesOriginatedBy(TNodeContextBase& aContext, const TNodeId& aCommsId, TBool aIsNodeBeingDestroyed)
   433 EXPORT_C void AMMNodeBase::AbortActivitiesOriginatedBy(TNodeContextBase& aContext, const TNodeId& aCommsId, TBool aIsNodeBeingDestroyed)
   434     {
   434     {
   435     CNodeActivityBase* caller = aContext.iNodeActivity;
   435     CNodeActivityBase* caller = aContext.iNodeActivity;
   436     TBool abortAll = aCommsId.IsNull();
   436     TBool abortAll = aCommsId.IsNull();
   437 
   437 
   438     for (TInt i = iActivities.Count() - 1; i>=0; i--)
   438     for (TInt i = iActivities.Count() - 1; i>=0; i--)
   439         {
   439         {
   440         aContext.iNodeActivity = iActivities[i];
   440         aContext.iNodeActivity = iActivities[i];
       
   441         
       
   442         if (!abortAll && aContext.iNodeActivity->PostedToNodeId() == aCommsId)
       
   443             {//clear postedto if a leaver has been set as a postedto at any of the running activities.
       
   444              //No other messages will ever come from the leaver and it is not gonna be safe to forward TCancels
       
   445              //to the leaver, so at least postedto must be cleared to avoid the crash. It could be speculated that
       
   446              //if the postedto is still set, then either the postedto node failed to respond or the local activity failed to
       
   447              //clear postedto when it had responded. Worth putting a speculative ASSERT here to catch misdeeds. 
       
   448         
       
   449              //clearing postedto shouldn't be done in here (AbortActivitiesOriginatedBy), but I (RZ) have expressed my disrespect to the
       
   450              //this method before and the suggestion that it should go (replaced by a CancelActivitiesOriginatedBy).
       
   451              //So instead of introducing another method that  loops through activities i decided to piggyback the function in an 
       
   452              //existing method. Note that the final logic should be based on RNodeInterfaces and not TNodeIds.
       
   453             aContext.iNodeActivity->ClearPostedTo();
       
   454             }
   441 		
   455 		
   442 		// We dont want to abort already idle activities or they may error.		
   456 		// We dont want to abort already idle activities or they may error.		
   443 		if(aContext.iNodeActivity->IsIdle())
   457 		if(aContext.iNodeActivity->IsIdle())
   444 			{
   458 			{
   445 			continue;
   459 			continue;
   456       	        {
   470       	        {
   457       	        //Abort for one originator only (Cancel the activity if last originator & error just this one originator)
   471       	        //Abort for one originator only (Cancel the activity if last originator & error just this one originator)
   458       	        TInt idx = aContext.iNodeActivity->FindOriginator(aCommsId);
   472       	        TInt idx = aContext.iNodeActivity->FindOriginator(aCommsId);
   459       	        if (KErrNotFound!=idx)
   473       	        if (KErrNotFound!=idx)
   460       	        	{
   474       	        	{
       
   475                     TBool canSend = ETrue;
   461 					if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator
   476 					if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator
   462 						{
   477 						{
   463 						aContext.iNodeActivity->SetError(KErrAbort);
   478 						aContext.iNodeActivity->SetError(KErrAbort);
   464            	        	aContext.iNodeActivity->Cancel(aContext);
   479            	        	aContext.iNodeActivity->Cancel(aContext);
       
   480            	        	//This is a workaround for CCommsBinderRequest. The proper fix is to abolish the concept of aborting activities.
       
   481                         //Aborting activities is a bad idea as an aborted activity isn't given a chance to perform graceful cleanup.
       
   482            	        	//Today activities get aborted because their orinators urgently leave. I.e.: they are trully leaving now! Last orders!
       
   483            	        	//It is then incorrect to leave the activity d'tor to finish the wrap up - because the node will be gone by then.
       
   484            	        	//So whether and when to send an error must be decided here, by this generic code that has no clue on the subtleties
       
   485            	        	//of individual activities. If there is no abort - there is urgent leavers. They send TLeaveRequest and they politely
       
   486            	        	//wait for the completion and all this code is unnecessary.
       
   487            	        	canSend = (aContext.iNodeActivity->Error() != KErrNone);
   465 						}
   488 						}
   466 					
   489                     
   467     					
       
   468                     //In the "quiet mode", when the hosting node is being destroyed, we can not afford sending
   490                     //In the "quiet mode", when the hosting node is being destroyed, we can not afford sending
   469                     //an error to the node as it would hit void.
   491                     //an error to the node as it would hit void.
   470                     TNodePeerId& originator = aContext.iNodeActivity->iOriginators[idx];
   492                     TNodePeerId& originator = aContext.iNodeActivity->iOriginators[idx];
   471                     TBool canSend = !((aIsNodeBeingDestroyed && originator == aContext.NodeId())
   493                     canSend &= !((aIsNodeBeingDestroyed && originator == aContext.NodeId())
   472                         || aContext.iMessage.IsMessage<TEChild::TLeft>());
   494                         || aContext.iMessage.IsMessage<TEChild::TLeft>()); 
   473                     if (canSend)
   495                     if (canSend)
   474                         {
   496                         {
   475                         aContext.iNodeActivity->PostToOriginator(originator, TEBase::TError(aContext.iMessage.MessageId(), KErrAbort).CRef());
   497                         aContext.iNodeActivity->PostToOriginator(originator, TEBase::TError(aContext.iMessage.MessageId(), KErrAbort).CRef());
   476                         }
   498                         }
   477     					
   499                     aContext.iNodeActivity->RemoveOriginator(idx);
   478 
       
   479 	 	        	aContext.iNodeActivity->RemoveOriginator(idx);
       
   480       	        	}
   500       	        	}
   481       	        }
   501       	        }
   482             }
   502             }
   483         }
   503         }
   484     aContext.iReturn = KErrNone;
   504     aContext.iReturn = KErrNone;
   614         }
   634         }
   615     }
   635     }
   616 
   636 
   617 void AMMNodeBase::StartActivityL(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, const NetStateMachine::TStateTriple& aFirst)
   637 void AMMNodeBase::StartActivityL(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, const NetStateMachine::TStateTriple& aFirst)
   618     {
   638     {
   619     CNodeActivityBase* a = aActivitySig.iCtor(aActivitySig,*this);
   639 	CNodeActivityBase* nodeActivity;
   620     if (iActivities.Find(a)==KErrNotFound)
   640 	// Activity is based on one of 2 declarations. One of which has an extra member. In the case of the instance
       
   641 	// with a second member the activities Ctor will point to this second member. Since the first member is a TNodeActivity
       
   642 	// We can compare the activities Ctor pointer to the address of the second member to assess which type of declarations
       
   643 	// this is.
       
   644 	
       
   645 	if (aActivitySig.iFlags & TNodeActivity::EContextCtor)
       
   646 		{ // TNodeActivity's iCtor is a pointer to Activity Ctor
       
   647 		nodeActivity = ((TNodeActivity::TStaticActivityContextCtor)aActivitySig.iCtor)(aActivitySig,aContext);
       
   648 		}
       
   649 	else
       
   650 		{ // TNodeActivity's iCtor is a pointer to activity constructor
       
   651 		nodeActivity = ((TNodeActivity::TStaticActivityCtor)aActivitySig.iCtor)(aActivitySig,*this);
       
   652 		}
       
   653 
       
   654     if (iActivities.Find(nodeActivity)==KErrNotFound)
   621     	{
   655     	{
   622     	//The activity did not add itself to the list in any special way, append it here
   656     	//The activity did not add itself to the list in any special way, append it here
   623 	    CleanupStack::PushL(a);
   657 	    CleanupStack::PushL(nodeActivity);
   624    		a->AppendActivityL();
   658    		nodeActivity->AppendActivityL();
   625 	    CleanupStack::Pop(a);
   659 	    CleanupStack::Pop(nodeActivity);
   626 		}
   660 		}
       
   661 
   627 	//assign only after the activity is successfully appended
   662 	//assign only after the activity is successfully appended
   628 	aContext.iNodeActivity = a;
   663 	aContext.iNodeActivity = nodeActivity;
   629 
   664 
   630     //if StartL leaves the "a" will be removed from the array and deleted in ::PostReceived
   665     //if StartL leaves the "a" will be removed from the array and deleted in ::PostReceived
   631     //since it will be idle
   666     //since it will be idle
   632     XNodePeerId originator(aContext.iSender, aContext.iPeer);
   667     XNodePeerId originator(aContext.iSender, aContext.iPeer);
   633     a->StartL(aContext, originator, aFirst);
   668     nodeActivity->StartL(aContext, originator, aFirst);
   634     }
   669     }
   635 
   670 
   636 void AMMNodeBase::PreallocateSpaceL(TUint aSize)
   671 void AMMNodeBase::PreallocateSpaceL(TUint aSize)
   637 	{
   672 	{
   638 	__ASSERT_DEBUG(aSize>0, User::Panic(KSpecAssert_ElemMeshMachNodC, 4));
   673 	__ASSERT_DEBUG(aSize>0, User::Panic(KSpecAssert_ElemMeshMachNodC, 4));