commsfwsupport/commselements/meshmachine/src/mm_activities.cpp
changeset 0 dfb7c4ff071f
child 13 98a7181d2ce7
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18 */
       
    19 
       
    20 #include "mm_activities.h"
       
    21 #include <elements/mm_context.h>
       
    22 #include <elements/mm_states.h>
       
    23 #include <elements/nm_messages_base.h>
       
    24 #include <elements/nm_messages_child.h>
       
    25 #include <elements/nm_messages_errorrecovery.h>
       
    26 
       
    27 
       
    28 #ifdef _DEBUG
       
    29 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
       
    30 // (if it could happen through user error then you should give it an explicit, documented, category + code)
       
    31 _LIT(KSpecAssert_ElemMeshMachActC, "ElemMeshMachActC");
       
    32 #endif
       
    33 
       
    34 using namespace MeshMachine;
       
    35 using namespace Messages;
       
    36 using namespace Elements;
       
    37 using namespace NetStateMachine;
       
    38 
       
    39 //-=========================================================
       
    40 //
       
    41 //Panics
       
    42 //
       
    43 //-=========================================================
       
    44 _LIT (KMMActivityPanic,"MMActivityPanic");
       
    45 enum
       
    46 	{
       
    47 	EPanicCorruptedContext = 1,
       
    48 	EPanicNoPreallocatedSpace = 2
       
    49 	};
       
    50 
       
    51 //-=========================================================
       
    52 //
       
    53 //TNodeActivityIter
       
    54 //
       
    55 //-=========================================================
       
    56 const TNodeActivity* TNodeActivityIter::FetchActivity()
       
    57 	{
       
    58     const TNodeActivity* a = NULL;
       
    59     if (*iCurrentEntry)
       
    60     	{
       
    61     	a = &(*iCurrentEntry)();
       
    62     	++iCurrentEntry;
       
    63     	}
       
    64     else
       
    65     	{
       
    66     	if (NULL!=*(iCurrentEntry+1))
       
    67  		   	{
       
    68     		const TNodeActivityMap::TStaticNodeActivityMap& nextMapFn = (const TNodeActivityMap::TStaticNodeActivityMap&)*(iCurrentEntry+1);
       
    69     		iCurrentEntry = &nextMapFn().iFirstActivity;
       
    70     		a = FetchActivity();
       
    71     		}
       
    72     	}
       
    73     return a;
       
    74 	}
       
    75 
       
    76 //-=========================================================
       
    77 //
       
    78 //CNodeActivityBase
       
    79 //
       
    80 //-=========================================================
       
    81 EXPORT_C CNodeActivityBase* CNodeActivityBase::NewL(const TNodeActivity& aActivitySig, AMMNodeBase& aNode)
       
    82     {
       
    83     return new(ELeave)CNodeActivityBase(aActivitySig, aNode);
       
    84     }
       
    85 
       
    86 EXPORT_C CNodeActivityBase::CNodeActivityBase(const TNodeActivity& aActivitySig, AMMNodeBase& aNode)
       
    87 :	iNode(aNode),
       
    88 	iActivitySig(aActivitySig)
       
    89 	{
       
    90 	}
       
    91 
       
    92 EXPORT_C CNodeActivityBase::~CNodeActivityBase()
       
    93 	{
       
    94 	if(iError != KErrNone)
       
    95 		{
       
    96 		PostToOriginators(TEBase::TError(KickOffMessageId(), iError).CRef());
       
    97 		}
       
    98 
       
    99 	//If an activity constructed custom originator's interfaces, now it needs to clean them up
       
   100 	for (TInt i = iOriginators.Count() - 1; i >= 0; --i)
       
   101 		{
       
   102 		RemoveOriginator(i);
       
   103 		}
       
   104 
       
   105 	iOriginators.Close();
       
   106 	}
       
   107 
       
   108 EXPORT_C NetInterfaces::TInterfaceControl* CNodeActivityBase::DoFetchInterfaceControlL(TInt /*aInterfaceId*/)
       
   109 /** Allows to fetch an arbitrary interface instance from the client
       
   110 
       
   111 @internalTechnology
       
   112 */
       
   113 	{
       
   114 	return this; //as a base we assume are the control for any interface any derivative may implement
       
   115 	}
       
   116 
       
   117 //static
       
   118 const TStateTriple* CNodeActivityBase::Accept(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, TInt aTransitionTag)
       
   119     {
       
   120     const TStateTriple& first = aActivitySig.iFirstTriple;
       
   121 
       
   122     //in debug only(!) check if we are in the first triple as expected
       
   123     __ASSERT_DEBUG((&first-1)->iSCtor==NULL && (&first-1)->iTCtor==NULL, User::Panic(KSpecAssert_ElemMeshMachActC, 1));
       
   124 
       
   125     TBool accept = (aActivitySig.iKickOffMessageId == KNullMessageId
       
   126 		|| (aActivitySig.iKickOffMessageId == aContext.iMessage.MessageId().MessageId() &&
       
   127 			aActivitySig.iKickOffMessageRealm == aContext.iMessage.MessageId().Realm())
       
   128 		)
       
   129     	&& NetStateMachine::ACore::Accept(first, &aContext, aTransitionTag);
       
   130 
       
   131     //if the activity accepted the message and the first triple has a transition, we execute it here
       
   132     //NOTE that the first transition is called BEFORE the originator (sender of the message)
       
   133     //is added to the activity list
       
   134     if (accept && first.iTCtor)
       
   135     	{
       
   136     	TBuf8<KMaxStateClassByteSize> mem;
       
   137    		ACore::Do(first,&aContext,mem);
       
   138    		MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase:\tAccept->first transition [ANode=0x%08x] [Activity=%s] [Triple=%s]"),
       
   139    				&aContext.NodeId().Node(), aActivitySig.iName ? aActivitySig.iName : _S8("Undefined"), first.iName? first.iName : _S8("Undefined")));
       
   140     	}
       
   141 
       
   142 	if (accept && aContext.iReturn == KErrNone)
       
   143 		{
       
   144 		// MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase:\tAccept->accepted")));
       
   145 		return &first;
       
   146 		}
       
   147     return NULL;
       
   148     }
       
   149 
       
   150 EXPORT_C void CNodeActivityBase::StartL(TNodeContextBase& aContext, const XNodePeerId& aOriginator, const TStateTriple& aFirst)
       
   151 	{
       
   152 	__ASSERT_DEBUG(FindOriginator(aOriginator) == KErrNotFound, User::Panic(KSpecAssert_ElemMeshMachActC, 2));
       
   153   	iOriginators.AppendL(aOriginator);
       
   154 
       
   155 	MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext, (_L8("CNodeActivityBase %08x:\tStartL->starting activity"), this));
       
   156 	if (IsIdle())
       
   157 		{
       
   158 		NetStateMachine::ACore::Start(&aContext, aFirst);
       
   159 		MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext, (_L8("CNodeActivityBase %08x:\tStartL->activity started"), this));
       
   160 		}
       
   161 	}
       
   162 
       
   163 EXPORT_C TBool CNodeActivityBase::MatchSender(const TNodeContextBase& aContext) const
       
   164     {
       
   165     //The role of this method is to filter out all messages that 'this' should
       
   166     //not be bothered with. 'this' should be interested in messages coming from
       
   167     //what's set as iPostedToId or from one of the orginators. 
       
   168     //if the message's recipient specifies the activity id, then that
       
   169     //activity must much that of 'this'.
       
   170     TBool sender = iPostedToId.IsNull() || 
       
   171     			   aContext.iSender == iPostedToId || 
       
   172     			   FindOriginator(aContext.iSender) != KErrNotFound;
       
   173     const TNodeCtxId* recipient = address_cast<const TNodeCtxId>(&aContext.iRecipient);
       
   174     TBool activity = (recipient == NULL || ActivityId() == recipient->NodeCtx());
       
   175 
       
   176 #ifdef SYMBIAN_TRACE_ENABLE
       
   177 	//If didn't match, trace why.
       
   178 	if (!(sender && activity))
       
   179 		{
       
   180 		NM_LOG_START_BLOCK(KMeshMachineSubTag, _L8("CNodeActivityBase::MatchSender"));
       
   181 		if(!sender)
       
   182 			{
       
   183 			MESH_LOG((KMeshMachineSubTag(), _L8("CNodeActivityBase %08x:\tiPostedToId mismatch:"), this));
       
   184 			NM_LOG_ADDRESS(KMeshMachineSubTag(), iPostedToId);
       
   185 			NM_LOG_ADDRESS(KMeshMachineSubTag(), aContext.iSender);
       
   186 			MESH_LOG((KMeshMachineSubTag(), _L8("CNodeActivityBase %08x:\toriginators' mismatch:"), this));
       
   187 			for (TInt i = iOriginators.Count() - 1; i>=0; i--)
       
   188 		        {
       
   189 		        NM_LOG_ADDRESS(KMeshMachineSubTag(), iOriginators[i].RecipientId());
       
   190 		        }
       
   191 			}
       
   192 		if(!activity)
       
   193 			{
       
   194 			MESH_LOG((KMeshMachineSubTag(), _L8("CNodeActivityBase %08x:\tactivity mismatch [ours 0x%x, recipient 0x%x]"), this, ActivityId(), recipient->NodeCtx()));
       
   195 			}
       
   196 		NM_LOG_END_BLOCK(KMeshMachineSubTag(), KNullDesC8());
       
   197 		}
       
   198 #endif
       
   199 
       
   200     return sender && activity;
       
   201     }
       
   202 
       
   203 //static
       
   204 EXPORT_C TAny* CNodeActivityBase::BorrowPreallocatedSpace(AMMNodeBase& aNode, TUint aSize)
       
   205 	{
       
   206 	return aNode.BorrowPreallocatedSpace(aSize);
       
   207 	}
       
   208 
       
   209 EXPORT_C void CNodeActivityBase::ReturnPreallocatedSpace(TAny* aSpace)
       
   210 	{
       
   211 	return iNode.ReturnPreallocatedSpace(aSpace);
       
   212 	}
       
   213 
       
   214 EXPORT_C void CNodeActivityBase::AppendActivityL()
       
   215 	{
       
   216 	//Based on the fact that there can ever be only one preallocated activity active at a time
       
   217 	//it is sufficient to always maintain one reserved space in the activity array.
       
   218 	//NOTE: ReserveL() will not cause table expansion when the already allocated space is
       
   219 	//big enough to hold the new count = the array will not grow indefinietly.
       
   220 	iNode.iActivities.ReserveL(iNode.iActivities.Count() + iNode.MaxPreallocatedActivityCount() + 1); //Reserve for additional + potential preallocated)
       
   221 
       
   222 	//Can not fail now
       
   223 	__ASSERT_ALWAYS(iNode.iActivities.Append(this) == KErrNone, User::Panic(KMMActivityPanic, EPanicNoPreallocatedSpace));
       
   224 	}
       
   225 
       
   226 EXPORT_C void CNodeActivityBase::AppendPreallocatedActivity()
       
   227 	{
       
   228 	//Can not fail now
       
   229 	__ASSERT_ALWAYS(iNode.iActivities.Append(this) == KErrNone, User::Panic(KMMActivityPanic, EPanicNoPreallocatedSpace));
       
   230 	}
       
   231 
       
   232 EXPORT_C void CNodeActivityBase::InsertPreallocatedDestroyActivity()
       
   233 	{
       
   234 	//Can not fail now
       
   235 	__ASSERT_ALWAYS(iNode.iActivities.Insert(this, 0) == KErrNone, User::Panic(KMMActivityPanic, EPanicNoPreallocatedSpace));
       
   236 	}
       
   237 
       
   238 EXPORT_C TInt CNodeActivityBase::FindOriginator(const RNodeInterface& aPeerToFind) const
       
   239     {
       
   240 	for (TInt i = iOriginators.Count() - 1; i>=0; i--)
       
   241         {
       
   242         //When you see a panic here this is probably because your originator
       
   243         //stopped being a peer and this node failed to remove it from the activity originator's list.
       
   244         if (iOriginators[i] == aPeerToFind.RecipientId())
       
   245             {
       
   246 	        return i;
       
   247             }
       
   248         }
       
   249     return KErrNotFound;
       
   250     }
       
   251 
       
   252 EXPORT_C TInt CNodeActivityBase::FindOriginator(const TRuntimeCtxId& aPeerToFind) const
       
   253     {
       
   254 	for (TInt i = iOriginators.Count() - 1; i>=0; i--)
       
   255         {
       
   256         //When you see a panic here this is probably because your originator
       
   257         //stopped being a peer and this node failed to remove it from the activity originator's list.
       
   258         if (iOriginators[i] == aPeerToFind)
       
   259             {
       
   260 	        return i;
       
   261             }
       
   262         }
       
   263     return KErrNotFound;
       
   264 	}
       
   265 
       
   266 EXPORT_C TInt CNodeActivityBase::FindOriginator(const TNodePeerId& aOriginator) const
       
   267 	{
       
   268 	for (TInt i = iOriginators.Count() - 1; i>=0; i--)
       
   269         {
       
   270         //When you see a panic here this is probably because your originator
       
   271         //stopped being a peer and this node failed to remove it from the activity originator's list.
       
   272         if (iOriginators[i] == aOriginator)
       
   273             {
       
   274 	        return i;
       
   275             }
       
   276         }
       
   277     return KErrNotFound;
       
   278 	}
       
   279 
       
   280 EXPORT_C TUint16 CNodeActivityBase::ActivityId() const
       
   281 	{
       
   282 	return ActivitySigId();
       
   283 	}
       
   284 
       
   285 //You should use this function to remove originators to prevent memory leaking!
       
   286 EXPORT_C void CNodeActivityBase::RemoveOriginator(TInt aIndex)
       
   287 	{
       
   288 	__ASSERT_DEBUG(aIndex>=0 && aIndex<iOriginators.Count(), User::Panic(KSpecAssert_ElemMeshMachActC, 3));
       
   289 	iOriginators[aIndex].Destroy();
       
   290 	iOriginators.Remove(aIndex);
       
   291 	}
       
   292 
       
   293 EXPORT_C void CNodeActivityBase::SetIdle()
       
   294 	{
       
   295 	MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase %08x:\tSetIdle"), this));
       
   296 	NetStateMachine::ACore::SetIdle();
       
   297 	}
       
   298 
       
   299 EXPORT_C TBool CNodeActivityBase::Next(TNodeContextBase& aContext)
       
   300 	{
       
   301 	TBool nextRet = EFalse;
       
   302 	//Check if this is the same id we have recently sent to
       
   303 	TBool senderMatch = MatchSender(aContext);
       
   304 	MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext,
       
   305 	    (senderMatch ? _L8("CNodeActivityBase %08x:\tNext->match") : _L8("CNodeActivityBase %08x:\tNext->NO match"), this));
       
   306 
       
   307 	if (senderMatch)
       
   308 		{
       
   309 		nextRet = ACore::Next(&aContext);
       
   310 	    if(nextRet)
       
   311 			{
       
   312 	    	MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext, (_L8("CNodeActivityBase %08x:\tNext->transition"), this));
       
   313 			}
       
   314 		}
       
   315     return nextRet;
       
   316 	}
       
   317 
       
   318 EXPORT_C void CNodeActivityBase::Cancel(TNodeContextBase& aContext)
       
   319 	{//we expect KErrCancel be set as a result of the state cancelation
       
   320     MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase %08x:\tCancel(), iPostedToId %08x"), this, iPostedToId.Ptr() ? &iPostedToId.Node() : NULL));
       
   321 
       
   322 	if (!iPostedToId.IsNull())
       
   323 		{
       
   324 		RClientInterface::OpenPostMessageClose(TNodeCtxId(ActivityId(), iNode.Id()), iPostedToId, TEBase::TCancel().CRef());
       
   325 		}
       
   326     else
       
   327         {
       
   328     	NetStateMachine::ACore::Cancel(&aContext);
       
   329         }
       
   330 	SetError(KErrCancel);
       
   331 	}
       
   332 
       
   333 EXPORT_C TBool CNodeActivityBase::PostToOriginator(const TNodePeerId& aOriginator, const TSignalBase& aMessage) const
       
   334 	{
       
   335 	if (!(aOriginator.Flags() & TClientType::ELeaving))
       
   336 	    {
       
   337 	    aOriginator.PostMessage(TNodeCtxId(ActivityId(), iNode.Id()), aMessage);
       
   338 	    }
       
   339 	else
       
   340 		{
       
   341 		MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase:\tPostToOriginator - IGNORING POST!")));
       
   342 		return EFalse;
       
   343 		}
       
   344 	return ETrue;
       
   345 	}
       
   346 
       
   347 EXPORT_C TInt CNodeActivityBase::PostToOriginators(const TSignalBase& aMessage, TUint32 aFlagsToSet, TUint32 aFlagsToClear)
       
   348 	{
       
   349 	TInt msgSendCount=0;
       
   350 	for (TInt n = iOriginators.Count() - 1;n>=0; n--)
       
   351 		{
       
   352 		if (PostToOriginator(iOriginators[n], aMessage))
       
   353 			{
       
   354 			++msgSendCount;
       
   355 	    	iOriginators[n].Peer().SetFlags(aFlagsToSet);
       
   356 	    	iOriginators[n].Peer().ClearFlags(aFlagsToClear);
       
   357 			};
       
   358 		}
       
   359 	return msgSendCount;
       
   360 	}
       
   361 
       
   362 EXPORT_C void CNodeActivityBase::SetPostedTo(const TNodeId& aNodeId)
       
   363     {
       
   364     iPostedToId = aNodeId;
       
   365     }
       
   366 
       
   367 EXPORT_C void CNodeActivityBase::ClearPostedTo()
       
   368     {
       
   369     iPostedToId.SetNull();
       
   370     }
       
   371 
       
   372 EXPORT_C void CNodeActivityBase::PostRequestTo(const RNodeInterface& aRecipient, const TSignalBase& aMessage, const TBool aRecipientIdCritical)
       
   373 	{
       
   374 	aRecipient.PostMessage(TNodeCtxId(ActivityId(), iNode.Id()), aMessage);
       
   375 
       
   376 	// Provide the option for the identity of the receipient to be unimportant when the response arrives
       
   377 	iPostedToId = aRecipientIdCritical ? aRecipient.RecipientId() : TNodeId::NullId();
       
   378 	}
       
   379 
       
   380 //Avoid using this function, always prefer PostRequestTo(const RNodeInterface& aRecipient, const TNodeSignal& aMessage)
       
   381 EXPORT_C void CNodeActivityBase::PostRequestTo(const TNodeId& aRecipient, const TSignalBase& aMessage, const TBool aRecipientIdCritical)
       
   382 	{
       
   383 	RClientInterface::OpenPostMessageClose(TNodeCtxId(ActivityId(), iNode.Id()), aRecipient, aMessage);
       
   384 
       
   385 	// Provide the option for the identity of the receipient to be unimportant when the response arrives
       
   386 	iPostedToId = aRecipientIdCritical ? aRecipient : TNodeId::NullId();
       
   387 	}
       
   388 
       
   389 EXPORT_C TBool CNodeActivityBase::IsIdle() const
       
   390 	{
       
   391 	return NetStateMachine::ACore::IsIdle();
       
   392 	}
       
   393 
       
   394 EXPORT_C void CNodeActivityBase::Abort(TNodeContextBase& aContext, TBool aIsNodeBeingDestroyed)
       
   395     {
       
   396     MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase %08x:\tAbort"), this));
       
   397 
       
   398 	//the error message will be send by message post processing see AMMNodeBase::Received
       
   399    	aContext.iReturn = KErrAbort; //before so as the error could be overwritten
       
   400     NetStateMachine::ACore::Cancel(&aContext);
       
   401     if (aContext.iReturn != KErrNone)
       
   402         {
       
   403         TEBase::TError error(aContext.iMessage.MessageId(), aContext.iReturn);
       
   404        	for (TInt n = iOriginators.Count() - 1;n>=0; n--)
       
   405 			{
       
   406 			TNodePeerId& originator = iOriginators[n];
       
   407 			//In the "quiet mode", when the hosting node is being destroyed, we can not afford sending
       
   408 			//an error to the node as it would hit void.
       
   409    	        TBool canSend = !((aIsNodeBeingDestroyed && originator == aContext.NodeId())
       
   410    	        	|| aContext.iMessage.IsMessage<TEChild::TLeft>());
       
   411 			if (canSend)
       
   412 				{
       
   413 				PostToOriginator(originator, error);
       
   414 				}
       
   415 			RemoveOriginator(n); //Do not allow ~CNodeActivityBase to post as client's might be already gone
       
   416 			}
       
   417         }
       
   418     }
       
   419 
       
   420 //-=========================================================
       
   421 //
       
   422 //CNodeRetryActivity
       
   423 //
       
   424 //-=========================================================
       
   425 EXPORT_C CNodeRetryActivity::CNodeRetryActivity( const TNodeActivity& aActivitySig, AMMNodeBase& aNode )
       
   426 :	CNodeActivityBase(aActivitySig, aNode),
       
   427 	TIfStaticFetcherNearestInHierarchy(this)
       
   428 	{
       
   429 	}
       
   430 
       
   431 EXPORT_C CNodeActivityBase* CNodeRetryActivity::NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode )
       
   432     {
       
   433     return new(ELeave)CNodeRetryActivity(aActivitySig, aNode);
       
   434     }
       
   435 
       
   436 EXPORT_C TBool CNodeRetryActivity::IsIdle() const
       
   437 	{
       
   438 	return !IsWaiting() && CNodeActivityBase::IsIdle();
       
   439 	}
       
   440 
       
   441 EXPORT_C void CNodeRetryActivity::SetIdle()
       
   442 	{
       
   443 	iContextDesc.Close();
       
   444 	ClearIsWaiting();
       
   445 	ClearWillWait(); //Set this too in case this fn was invoked from within the serialised state ot transition
       
   446 	CNodeActivityBase::SetIdle();
       
   447 	}
       
   448 
       
   449 EXPORT_C TBool CNodeRetryActivity::Signal(TNodeContextBase& aContext)
       
   450 	{
       
   451 	return AActivitySemaphore::Signal(aContext);
       
   452 	}
       
   453 
       
   454 EXPORT_C void CNodeRetryActivity::ReturnInterfacePtrL(AContextStore*& aInterface)
       
   455     {
       
   456     aInterface = this;
       
   457     }
       
   458 
       
   459 EXPORT_C void CNodeRetryActivity::ReturnInterfacePtrL(AActivitySemaphore*& aInterface)
       
   460     {
       
   461     aInterface = this;
       
   462     }
       
   463 
       
   464 //-=========================================================
       
   465 //
       
   466 //CNodeParallelActivityBase
       
   467 //
       
   468 //-=========================================================
       
   469 // For custom activities to implement NewL
       
   470 EXPORT_C TUint CNodeParallelActivityBase::GetNextActivityCountL( const TNodeActivity& aActivitySig, const AMMNodeBase& aNode )
       
   471 	{
       
   472 	TInt c = 1, i = 0;
       
   473 	
       
   474 	const RPointerArray<CNodeActivityBase>& activities = aNode.Activities();
       
   475 	RArray<TInt> activityids;
       
   476 	CleanupClosePushL(activityids);
       
   477 
       
   478 	// collect the currently used ids
       
   479 	for (TInt i = 0; i < activities.Count(); i++)
       
   480 		{
       
   481 		TInt16 id = activities[i]->ActivityId();
       
   482 		if ((id&0xff) == aActivitySig.iId)
       
   483 			{
       
   484 			TInt8 uniqueid = id >> 8;
       
   485 			activityids.InsertInOrderL(uniqueid);
       
   486 			}
       
   487 		}
       
   488 
       
   489 	// find first available.
       
   490 	while (i < activityids.Count()
       
   491           && activityids[i] == c)
       
   492 		{
       
   493 		++i;
       
   494 		++c;
       
   495 		}
       
   496 	CleanupStack::PopAndDestroy(&activityids);
       
   497 
       
   498 	if(c > KActivityParallelRangeMax>>8)
       
   499 		{
       
   500 		User::Leave(KErrInUse);
       
   501 		}
       
   502     return c;
       
   503 	}
       
   504 
       
   505 EXPORT_C CNodeActivityBase* CNodeParallelActivityBase::NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode )
       
   506     {
       
   507 	TUint c = GetNextActivityCountL(aActivitySig,aNode);
       
   508     return new(ELeave)CNodeParallelActivityBase(aActivitySig, aNode, c);
       
   509     }
       
   510 
       
   511 EXPORT_C CNodeParallelActivityBase::CNodeParallelActivityBase(const TNodeActivity& aActivitySig, AMMNodeBase& aNode, TUint aNextActivityCount)
       
   512 :	CNodeActivityBase(aActivitySig, aNode),
       
   513     iActivityId((aNextActivityCount<<8)|aActivitySig.iId)
       
   514     {
       
   515     }
       
   516 
       
   517 EXPORT_C TUint16 CNodeParallelActivityBase::ActivityId() const
       
   518     {
       
   519     return iActivityId;
       
   520     }
       
   521 
       
   522 
       
   523 //-=========================================================
       
   524 //
       
   525 //CNodeParallelMessageStoreActivityBase
       
   526 //
       
   527 //-=========================================================
       
   528 EXPORT_C CNodeActivityBase* CNodeParallelMessageStoreActivityBase::NewL( const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode )
       
   529 	{
       
   530 	TUint c = GetNextActivityCountL(aActivitySig,aNode);
       
   531 	return new (ELeave) CNodeParallelMessageStoreActivityBase( aActivitySig, aNode, c);
       
   532 	}
       
   533 
       
   534 EXPORT_C CNodeParallelMessageStoreActivityBase::~CNodeParallelMessageStoreActivityBase()
       
   535 	{
       
   536 	}
       
   537 
       
   538 EXPORT_C Messages::TSignalBase& CNodeParallelMessageStoreActivityBase::Message()
       
   539 	{
       
   540 	ASSERT(iMsg);
       
   541 	return *iMsg;
       
   542 	}
       
   543 
       
   544 EXPORT_C void CNodeParallelMessageStoreActivityBase::StartL(TNodeContextBase& aContext, const Messages::XNodePeerId& aOriginator, const NetStateMachine::TStateTriple& aFirst)
       
   545 	{
       
   546 	SaveMessageL(aContext.iMessage);
       
   547 	CNodeParallelActivityBase::StartL(aContext, aOriginator, aFirst);
       
   548 	}
       
   549 
       
   550 void CNodeParallelMessageStoreActivityBase::SaveMessageL(Messages::TSignalBase& aMessage)
       
   551 	{
       
   552 	Meta::CMetaDataVirtualCtorInPlace* vctr = TlsGlobals::Get().VirtualCtor();
       
   553 	TPtrC8 ptr(iMsgBuf);
       
   554 	iMsg = static_cast<TSignalBase*>(vctr->New(aMessage.GetTypeId(), iMsgBuf));
       
   555 	if (iMsg == NULL)
       
   556 		{
       
   557 		User::Leave(KErrNotFound);
       
   558 		}
       
   559 	
       
   560 	iMsg->Copy(aMessage);
       
   561 	}
       
   562 
       
   563 EXPORT_C CNodeParallelMessageStoreActivityBase::CNodeParallelMessageStoreActivityBase( const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode, TUint aNextActivityCount )
       
   564 	: CNodeParallelActivityBase(aActivitySig, aNode, aNextActivityCount), iMsg(NULL)
       
   565 	{
       
   566 	}
       
   567 
       
   568 //-=========================================================
       
   569 //
       
   570 //CNodeRetryParallelActivity
       
   571 //
       
   572 //-=========================================================
       
   573 EXPORT_C CNodeRetryParallelActivity::CNodeRetryParallelActivity( const TNodeActivity& aActivitySig, AMMNodeBase& aNode, TUint aActivitiesCount )
       
   574 :	CNodeParallelActivityBase(aActivitySig, aNode, aActivitiesCount),
       
   575 	TIfStaticFetcherNearestInHierarchy(this)
       
   576 	{
       
   577 	}
       
   578 
       
   579 EXPORT_C CNodeActivityBase* CNodeRetryParallelActivity::NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode )
       
   580     {
       
   581 	TUint c = GetNextActivityCountL(aActivitySig,aNode);
       
   582     return new(ELeave)CNodeRetryParallelActivity(aActivitySig, aNode, c);
       
   583     }
       
   584 
       
   585 EXPORT_C TBool CNodeRetryParallelActivity::IsIdle() const
       
   586 	{
       
   587 	return !IsWaiting() && CNodeActivityBase::IsIdle();
       
   588 	}
       
   589 
       
   590 EXPORT_C void CNodeRetryParallelActivity::SetIdle()
       
   591 	{
       
   592 	iContextDesc.Close();
       
   593 	ClearIsWaiting();
       
   594 	ClearWillWait(); //Set this too in case this fn was invoked from within the serialised state ot transition
       
   595 	CNodeActivityBase::SetIdle();
       
   596 	}
       
   597 
       
   598 EXPORT_C TBool CNodeRetryParallelActivity::Signal(TNodeContextBase& aContext)
       
   599 	{
       
   600 	return AActivitySemaphore::Signal(aContext);
       
   601 	}
       
   602 
       
   603 EXPORT_C void CNodeRetryParallelActivity::ReturnInterfacePtrL(AContextStore*& aInterface)
       
   604     {
       
   605     aInterface = this;
       
   606     }
       
   607 
       
   608 EXPORT_C void CNodeRetryParallelActivity::ReturnInterfacePtrL(AActivitySemaphore*& aInterface)
       
   609     {
       
   610     aInterface = this;
       
   611     }
       
   612 
       
   613 //-=========================================================
       
   614 //
       
   615 //AContextStore
       
   616 //
       
   617 //-=========================================================
       
   618 EXPORT_C TInt AContextStore::StoreContext(const TNodeContextBase& aContext)
       
   619     {//doesn't actually store TNodeContextBase only the message since it assumes
       
   620     //that the transition context is the
       
   621     //template <class TNODE, class TDerivedContext = TNodeContextBase>
       
   622     //struct TNodeContext : public TDerivedContext
       
   623     //where TDerivedContext = TNodeContextBase is always TNodeContextBase
       
   624     //another type of context is not needed because all custom needs should be sorted by custom
       
   625     //activity class
       
   626     TInt error = KErrNone;
       
   627     TInt len = TRuntimeCtxId::KMaxInlineAddressSize + aContext.iMessage.Length();
       
   628     if (iContextDesc.MaxLength() < len)
       
   629         {
       
   630         iContextDesc.Close();
       
   631         error = iContextDesc.Create(len);
       
   632         }
       
   633     else
       
   634     	{
       
   635     	iContextDesc.Zero();
       
   636     	}
       
   637     if (KErrNone==error)
       
   638     	{
       
   639     	error = aContext.iSender.Store(iContextDesc); //would catch if iContextDesc has been allocated properly
       
   640     	}
       
   641     if (KErrNone==error)
       
   642     	{
       
   643     	error = aContext.iMessage.Store(iContextDesc); //would catch if iContextDesc has been allocated properly
       
   644     	}
       
   645     return error;
       
   646     }
       
   647 
       
   648 EXPORT_C TNodeContextBase* AContextStore::LoadContext(AMMNodeBase& aNode, CNodeActivityBase* aNodeActivity, TDes8& aCtxBuff, TDes8& aMsgBuff, const TNodeId& aDummy)
       
   649     {
       
   650     if (iContextDesc.Length() < sizeof(TNodeId))
       
   651         {
       
   652         return NULL;
       
   653         }
       
   654 
       
   655 	const TRuntimeCtxId* sender = reinterpret_cast<const TRuntimeCtxId*>(iContextDesc.Ptr());
       
   656 	TPtrC8 contextStore(iContextDesc.Ptr()+sender->Size(),iContextDesc.Length()-sender->Size());
       
   657 	TSignatureBase* msg = static_cast<TSignatureBase*>(TlsGlobals::Get().VirtualCtor()->New(contextStore, aMsgBuff));
       
   658 	if (!msg)
       
   659         {
       
   660 		return NULL;
       
   661         }
       
   662 
       
   663     //This assumes (as CNodeActivityBase::StoreContext) that the transition context is the
       
   664     //template <class TNODE, class TDerivedContext = TNodeContextBase>
       
   665     //struct TNodeContext : public TDerivedContext
       
   666     //where TDerivedContext = TNodeContextBase is always TNodeContextBase.
       
   667     //another type of context is not needed because all custom needs should be sorted by custom
       
   668     //activity class
       
   669     __ASSERT_DEBUG(aNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 4));
       
   670 	return ::new ((TUint8*)aCtxBuff.Ptr()) TNodeContextBase(aNode, *msg, *sender, aDummy, aNodeActivity);
       
   671     }
       
   672 
       
   673 EXPORT_C TBool AContextStore::IsStored() const
       
   674 	{
       
   675 	return iContextDesc.Length() >= sizeof(TNodeId);
       
   676 	}
       
   677 
       
   678 // Needs to be moved to error-recoverable activity class
       
   679 EXPORT_C const TNodeSignal::TMessageId& AContextStore::RetryingForMessageId() const
       
   680 	{
       
   681 	return iRetryingForMessageId;
       
   682 	}
       
   683 
       
   684 //Called only ever from ReceivedL
       
   685 EXPORT_C void AContextStore::Retry(CNodeActivityBase& aActivity, TNodeContextBase& aContext)
       
   686     {
       
   687 	TBuf8<__Align8(sizeof(TNodeContextBase))> ctxBuf;
       
   688 	TBuf8<__Align8(TSignalBase::KMaxInlineMessageSize + TSignalBase::KMaxUnstoredOverhead)> msgBuf;
       
   689 	TNodeContextBase* storedContext = LoadContext(aContext.iNode, &aActivity,ctxBuf, msgBuf, aContext.NodeId());
       
   690 
       
   691 	//If we are here the context has been stored. There is no reason why it could not be loaded now.
       
   692 	//The only reason would be that the message factory was unregistered since the context was stored
       
   693 	//which is a critical condition.
       
   694 	__ASSERT_ALWAYS(storedContext, User::Panic(KMMActivityPanic,EPanicCorruptedContext));
       
   695 
       
   696 	TEErrorRecovery::TErrorRecoveryResponse& msg = message_cast<TEErrorRecovery::TErrorRecoveryResponse>(aContext.iMessage);
       
   697     iRetryingForMessageId = msg.iErrResponse.iMessageId;
       
   698 	aActivity.ACore::DoCurrent(storedContext);
       
   699     aContext.Node().HandleMessageReturnValue(*storedContext);
       
   700     iContextDesc.Zero();
       
   701     }
       
   702 
       
   703 //-=========================================================
       
   704 //
       
   705 //AActivitySemaphore
       
   706 //
       
   707 //-=========================================================
       
   708 EXPORT_C void AActivitySemaphore::ParkTransitionL(const TNodeContextBase& aContext)
       
   709 	{
       
   710    	__ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 5));
       
   711    	AActivitySemaphore* as = static_cast<AActivitySemaphore*>(aContext.iNodeActivity->FetchExtInterfaceL(AActivitySemaphore::KInterfaceId));
       
   712     if (!as->IsWaiting())
       
   713     	{
       
   714     	User::LeaveIfError(as->StoreContext(aContext));
       
   715     	
       
   716         //The context has been stored along with the message. Must consume the message, otherwise
       
   717         //it will fall through and be seen by other activities or passthrough handling.    	
       
   718         aContext.iMessage.ClearMessageId();
       
   719         
       
   720 		as->SetIsWaiting();
       
   721 		as->SetIsTransition();
       
   722 	    MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("AActivitySemaphore:\tParkTransitionL->parked"));
       
   723 		}
       
   724 	as->SetWillWait();
       
   725     __ASSERT_DEBUG(as->IsWaiting(), User::Panic(KSpecAssert_ElemMeshMachActC, 6)); //Must be stored and waiting now
       
   726 	}
       
   727 
       
   728 EXPORT_C TInt AActivitySemaphore::ParkState(const TNodeContextBase& aContext)
       
   729 	{
       
   730    	__ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 7));
       
   731    	AActivitySemaphore* as = static_cast<AActivitySemaphore*>(aContext.iNodeActivity->FetchExtInterface(AActivitySemaphore::KInterfaceId));
       
   732     __ASSERT_DEBUG(as, User::Panic(KSpecAssert_ElemMeshMachActC, 8)); //State/transition mismatched with the activity object (activity doesn't support serialisation - wrong derivation?)
       
   733     if (!as->IsWaiting())
       
   734     	{
       
   735     	TInt error = as->StoreContext(aContext);
       
   736     	if (error!=KErrNone)
       
   737     		{
       
   738     		return error;
       
   739     		};
       
   740     	
       
   741     	//The context has been stored along with the message. Must consume the message, otherwise
       
   742     	//it will fall through and be seen by other activities or passthrough handling.
       
   743     	aContext.iMessage.ClearMessageId();
       
   744     	
       
   745 		as->SetIsWaiting();
       
   746     	as->ClearIsTransition();
       
   747     	MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("AActivitySemaphore:\tParkState->parked"));
       
   748     	}
       
   749     as->SetWillWait();
       
   750     __ASSERT_DEBUG(as->IsWaiting(), User::Panic(KSpecAssert_ElemMeshMachActC, 9)); //Must be stored and waiting now
       
   751     return KErrNone;
       
   752 	}
       
   753 
       
   754 EXPORT_C TInt AActivitySemaphore::UnparkState(const TNodeContextBase& aContext)
       
   755 	{
       
   756    	__ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 10));
       
   757    	AActivitySemaphore* as = static_cast<AActivitySemaphore*>(aContext.iNodeActivity->FetchExtInterface(AActivitySemaphore::KInterfaceId));
       
   758     __ASSERT_DEBUG(as, User::Panic(KSpecAssert_ElemMeshMachActC, 11)); //State/transition mismatched with the activity object (activity doesn't support serialisation - wrong derivation?)
       
   759     if (as->IsWaiting())
       
   760     	{
       
   761 		as->ClearIsWaiting();
       
   762     	MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("AActivitySemaphore:\tUnparkState->unparked"));
       
   763     	}
       
   764     as->ClearWillWait();
       
   765     __ASSERT_DEBUG(!as->IsWaiting(), User::Panic(KSpecAssert_ElemMeshMachActC, 12)); //Must be stored and waiting now
       
   766     return KErrNone;
       
   767 	}
       
   768 
       
   769 EXPORT_C void AActivitySemaphore::Wait()
       
   770 	{
       
   771 	MESH_LOG((KMeshMachineSubTag, _L8("AActivitySemaphore:\tWait->activity waiting")));
       
   772 	SetWillWait();
       
   773 	}
       
   774 
       
   775 EXPORT_C TBool AActivitySemaphore::Signal(TNodeContextBase& aContext)
       
   776     {
       
   777 	if (!(iFlags&KIsWaiting))
       
   778     	{
       
   779     	return EFalse;
       
   780     	}
       
   781 
       
   782     //aContext.iNodeActivity is us
       
   783    	TBuf8<__Align8(sizeof(TNodeContextBase))> ctxBuf;
       
   784    	TBuf8<__Align8(TSignalBase::KMaxInlineMessageSize + TSignalBase::KMaxUnstoredOverhead)> msgBuf;
       
   785    	TNodeCtxId dummy(aContext.ActivityId(), aContext.NodeId());
       
   786 	TNodeContextBase* storedContext = LoadContext(aContext.iNode,aContext.iNodeActivity,ctxBuf,msgBuf,dummy);
       
   787 	if (storedContext)
       
   788 		{
       
   789         ClearWillWait();
       
   790 		if (IsTransition())
       
   791 			{
       
   792 			//Transition stored
       
   793 			aContext.iNodeActivity->ACore::DoCurrent(storedContext);
       
   794 			}
       
   795 		else
       
   796 			{
       
   797 			//This is the state stored
       
   798 #ifdef _DEBUG
       
   799 			TBool hasRun = aContext.iNodeActivity->ACore::Next(storedContext);
       
   800 			__ASSERT_DEBUG(hasRun!=(iFlags & KWillWait), User::Panic(KSpecAssert_ElemMeshMachActC, 13));
       
   801 #else
       
   802 			aContext.iNodeActivity->ACore::Next(storedContext);
       
   803 #endif
       
   804 			}
       
   805 
       
   806 		if (!(iFlags & KWillWait))
       
   807     		{ //We have been run
       
   808     		ClearIsWaiting();
       
   809             iContextDesc.Zero();
       
   810             aContext.Node().HandleMessageReturnValue(*storedContext);
       
   811             return ETrue;
       
   812     		}
       
   813     	}
       
   814 
       
   815     return EFalse;
       
   816     }
       
   817 
       
   818