diff -r 000000000000 -r dfb7c4ff071f commsfwsupport/commselements/meshmachine/src/mm_activities.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commsfwsupport/commselements/meshmachine/src/mm_activities.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,818 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +/** + @file +*/ + +#include "mm_activities.h" +#include +#include +#include +#include +#include + + +#ifdef _DEBUG +// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module +// (if it could happen through user error then you should give it an explicit, documented, category + code) +_LIT(KSpecAssert_ElemMeshMachActC, "ElemMeshMachActC"); +#endif + +using namespace MeshMachine; +using namespace Messages; +using namespace Elements; +using namespace NetStateMachine; + +//-========================================================= +// +//Panics +// +//-========================================================= +_LIT (KMMActivityPanic,"MMActivityPanic"); +enum + { + EPanicCorruptedContext = 1, + EPanicNoPreallocatedSpace = 2 + }; + +//-========================================================= +// +//TNodeActivityIter +// +//-========================================================= +const TNodeActivity* TNodeActivityIter::FetchActivity() + { + const TNodeActivity* a = NULL; + if (*iCurrentEntry) + { + a = &(*iCurrentEntry)(); + ++iCurrentEntry; + } + else + { + if (NULL!=*(iCurrentEntry+1)) + { + const TNodeActivityMap::TStaticNodeActivityMap& nextMapFn = (const TNodeActivityMap::TStaticNodeActivityMap&)*(iCurrentEntry+1); + iCurrentEntry = &nextMapFn().iFirstActivity; + a = FetchActivity(); + } + } + return a; + } + +//-========================================================= +// +//CNodeActivityBase +// +//-========================================================= +EXPORT_C CNodeActivityBase* CNodeActivityBase::NewL(const TNodeActivity& aActivitySig, AMMNodeBase& aNode) + { + return new(ELeave)CNodeActivityBase(aActivitySig, aNode); + } + +EXPORT_C CNodeActivityBase::CNodeActivityBase(const TNodeActivity& aActivitySig, AMMNodeBase& aNode) +: iNode(aNode), + iActivitySig(aActivitySig) + { + } + +EXPORT_C CNodeActivityBase::~CNodeActivityBase() + { + if(iError != KErrNone) + { + PostToOriginators(TEBase::TError(KickOffMessageId(), iError).CRef()); + } + + //If an activity constructed custom originator's interfaces, now it needs to clean them up + for (TInt i = iOriginators.Count() - 1; i >= 0; --i) + { + RemoveOriginator(i); + } + + iOriginators.Close(); + } + +EXPORT_C NetInterfaces::TInterfaceControl* CNodeActivityBase::DoFetchInterfaceControlL(TInt /*aInterfaceId*/) +/** Allows to fetch an arbitrary interface instance from the client + +@internalTechnology +*/ + { + return this; //as a base we assume are the control for any interface any derivative may implement + } + +//static +const TStateTriple* CNodeActivityBase::Accept(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, TInt aTransitionTag) + { + const TStateTriple& first = aActivitySig.iFirstTriple; + + //in debug only(!) check if we are in the first triple as expected + __ASSERT_DEBUG((&first-1)->iSCtor==NULL && (&first-1)->iTCtor==NULL, User::Panic(KSpecAssert_ElemMeshMachActC, 1)); + + TBool accept = (aActivitySig.iKickOffMessageId == KNullMessageId + || (aActivitySig.iKickOffMessageId == aContext.iMessage.MessageId().MessageId() && + aActivitySig.iKickOffMessageRealm == aContext.iMessage.MessageId().Realm()) + ) + && NetStateMachine::ACore::Accept(first, &aContext, aTransitionTag); + + //if the activity accepted the message and the first triple has a transition, we execute it here + //NOTE that the first transition is called BEFORE the originator (sender of the message) + //is added to the activity list + if (accept && first.iTCtor) + { + TBuf8 mem; + ACore::Do(first,&aContext,mem); + MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase:\tAccept->first transition [ANode=0x%08x] [Activity=%s] [Triple=%s]"), + &aContext.NodeId().Node(), aActivitySig.iName ? aActivitySig.iName : _S8("Undefined"), first.iName? first.iName : _S8("Undefined"))); + } + + if (accept && aContext.iReturn == KErrNone) + { + // MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase:\tAccept->accepted"))); + return &first; + } + return NULL; + } + +EXPORT_C void CNodeActivityBase::StartL(TNodeContextBase& aContext, const XNodePeerId& aOriginator, const TStateTriple& aFirst) + { + __ASSERT_DEBUG(FindOriginator(aOriginator) == KErrNotFound, User::Panic(KSpecAssert_ElemMeshMachActC, 2)); + iOriginators.AppendL(aOriginator); + + MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext, (_L8("CNodeActivityBase %08x:\tStartL->starting activity"), this)); + if (IsIdle()) + { + NetStateMachine::ACore::Start(&aContext, aFirst); + MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext, (_L8("CNodeActivityBase %08x:\tStartL->activity started"), this)); + } + } + +EXPORT_C TBool CNodeActivityBase::MatchSender(const TNodeContextBase& aContext) const + { + //The role of this method is to filter out all messages that 'this' should + //not be bothered with. 'this' should be interested in messages coming from + //what's set as iPostedToId or from one of the orginators. + //if the message's recipient specifies the activity id, then that + //activity must much that of 'this'. + TBool sender = iPostedToId.IsNull() || + aContext.iSender == iPostedToId || + FindOriginator(aContext.iSender) != KErrNotFound; + const TNodeCtxId* recipient = address_cast(&aContext.iRecipient); + TBool activity = (recipient == NULL || ActivityId() == recipient->NodeCtx()); + +#ifdef SYMBIAN_TRACE_ENABLE + //If didn't match, trace why. + if (!(sender && activity)) + { + NM_LOG_START_BLOCK(KMeshMachineSubTag, _L8("CNodeActivityBase::MatchSender")); + if(!sender) + { + MESH_LOG((KMeshMachineSubTag(), _L8("CNodeActivityBase %08x:\tiPostedToId mismatch:"), this)); + NM_LOG_ADDRESS(KMeshMachineSubTag(), iPostedToId); + NM_LOG_ADDRESS(KMeshMachineSubTag(), aContext.iSender); + MESH_LOG((KMeshMachineSubTag(), _L8("CNodeActivityBase %08x:\toriginators' mismatch:"), this)); + for (TInt i = iOriginators.Count() - 1; i>=0; i--) + { + NM_LOG_ADDRESS(KMeshMachineSubTag(), iOriginators[i].RecipientId()); + } + } + if(!activity) + { + MESH_LOG((KMeshMachineSubTag(), _L8("CNodeActivityBase %08x:\tactivity mismatch [ours 0x%x, recipient 0x%x]"), this, ActivityId(), recipient->NodeCtx())); + } + NM_LOG_END_BLOCK(KMeshMachineSubTag(), KNullDesC8()); + } +#endif + + return sender && activity; + } + +//static +EXPORT_C TAny* CNodeActivityBase::BorrowPreallocatedSpace(AMMNodeBase& aNode, TUint aSize) + { + return aNode.BorrowPreallocatedSpace(aSize); + } + +EXPORT_C void CNodeActivityBase::ReturnPreallocatedSpace(TAny* aSpace) + { + return iNode.ReturnPreallocatedSpace(aSpace); + } + +EXPORT_C void CNodeActivityBase::AppendActivityL() + { + //Based on the fact that there can ever be only one preallocated activity active at a time + //it is sufficient to always maintain one reserved space in the activity array. + //NOTE: ReserveL() will not cause table expansion when the already allocated space is + //big enough to hold the new count = the array will not grow indefinietly. + iNode.iActivities.ReserveL(iNode.iActivities.Count() + iNode.MaxPreallocatedActivityCount() + 1); //Reserve for additional + potential preallocated) + + //Can not fail now + __ASSERT_ALWAYS(iNode.iActivities.Append(this) == KErrNone, User::Panic(KMMActivityPanic, EPanicNoPreallocatedSpace)); + } + +EXPORT_C void CNodeActivityBase::AppendPreallocatedActivity() + { + //Can not fail now + __ASSERT_ALWAYS(iNode.iActivities.Append(this) == KErrNone, User::Panic(KMMActivityPanic, EPanicNoPreallocatedSpace)); + } + +EXPORT_C void CNodeActivityBase::InsertPreallocatedDestroyActivity() + { + //Can not fail now + __ASSERT_ALWAYS(iNode.iActivities.Insert(this, 0) == KErrNone, User::Panic(KMMActivityPanic, EPanicNoPreallocatedSpace)); + } + +EXPORT_C TInt CNodeActivityBase::FindOriginator(const RNodeInterface& aPeerToFind) const + { + for (TInt i = iOriginators.Count() - 1; i>=0; i--) + { + //When you see a panic here this is probably because your originator + //stopped being a peer and this node failed to remove it from the activity originator's list. + if (iOriginators[i] == aPeerToFind.RecipientId()) + { + return i; + } + } + return KErrNotFound; + } + +EXPORT_C TInt CNodeActivityBase::FindOriginator(const TRuntimeCtxId& aPeerToFind) const + { + for (TInt i = iOriginators.Count() - 1; i>=0; i--) + { + //When you see a panic here this is probably because your originator + //stopped being a peer and this node failed to remove it from the activity originator's list. + if (iOriginators[i] == aPeerToFind) + { + return i; + } + } + return KErrNotFound; + } + +EXPORT_C TInt CNodeActivityBase::FindOriginator(const TNodePeerId& aOriginator) const + { + for (TInt i = iOriginators.Count() - 1; i>=0; i--) + { + //When you see a panic here this is probably because your originator + //stopped being a peer and this node failed to remove it from the activity originator's list. + if (iOriginators[i] == aOriginator) + { + return i; + } + } + return KErrNotFound; + } + +EXPORT_C TUint16 CNodeActivityBase::ActivityId() const + { + return ActivitySigId(); + } + +//You should use this function to remove originators to prevent memory leaking! +EXPORT_C void CNodeActivityBase::RemoveOriginator(TInt aIndex) + { + __ASSERT_DEBUG(aIndex>=0 && aIndexmatch") : _L8("CNodeActivityBase %08x:\tNext->NO match"), this)); + + if (senderMatch) + { + nextRet = ACore::Next(&aContext); + if(nextRet) + { + MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext, (_L8("CNodeActivityBase %08x:\tNext->transition"), this)); + } + } + return nextRet; + } + +EXPORT_C void CNodeActivityBase::Cancel(TNodeContextBase& aContext) + {//we expect KErrCancel be set as a result of the state cancelation + MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase %08x:\tCancel(), iPostedToId %08x"), this, iPostedToId.Ptr() ? &iPostedToId.Node() : NULL)); + + if (!iPostedToId.IsNull()) + { + RClientInterface::OpenPostMessageClose(TNodeCtxId(ActivityId(), iNode.Id()), iPostedToId, TEBase::TCancel().CRef()); + } + else + { + NetStateMachine::ACore::Cancel(&aContext); + } + SetError(KErrCancel); + } + +EXPORT_C TBool CNodeActivityBase::PostToOriginator(const TNodePeerId& aOriginator, const TSignalBase& aMessage) const + { + if (!(aOriginator.Flags() & TClientType::ELeaving)) + { + aOriginator.PostMessage(TNodeCtxId(ActivityId(), iNode.Id()), aMessage); + } + else + { + MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase:\tPostToOriginator - IGNORING POST!"))); + return EFalse; + } + return ETrue; + } + +EXPORT_C TInt CNodeActivityBase::PostToOriginators(const TSignalBase& aMessage, TUint32 aFlagsToSet, TUint32 aFlagsToClear) + { + TInt msgSendCount=0; + for (TInt n = iOriginators.Count() - 1;n>=0; n--) + { + if (PostToOriginator(iOriginators[n], aMessage)) + { + ++msgSendCount; + iOriginators[n].Peer().SetFlags(aFlagsToSet); + iOriginators[n].Peer().ClearFlags(aFlagsToClear); + }; + } + return msgSendCount; + } + +EXPORT_C void CNodeActivityBase::SetPostedTo(const TNodeId& aNodeId) + { + iPostedToId = aNodeId; + } + +EXPORT_C void CNodeActivityBase::ClearPostedTo() + { + iPostedToId.SetNull(); + } + +EXPORT_C void CNodeActivityBase::PostRequestTo(const RNodeInterface& aRecipient, const TSignalBase& aMessage, const TBool aRecipientIdCritical) + { + aRecipient.PostMessage(TNodeCtxId(ActivityId(), iNode.Id()), aMessage); + + // Provide the option for the identity of the receipient to be unimportant when the response arrives + iPostedToId = aRecipientIdCritical ? aRecipient.RecipientId() : TNodeId::NullId(); + } + +//Avoid using this function, always prefer PostRequestTo(const RNodeInterface& aRecipient, const TNodeSignal& aMessage) +EXPORT_C void CNodeActivityBase::PostRequestTo(const TNodeId& aRecipient, const TSignalBase& aMessage, const TBool aRecipientIdCritical) + { + RClientInterface::OpenPostMessageClose(TNodeCtxId(ActivityId(), iNode.Id()), aRecipient, aMessage); + + // Provide the option for the identity of the receipient to be unimportant when the response arrives + iPostedToId = aRecipientIdCritical ? aRecipient : TNodeId::NullId(); + } + +EXPORT_C TBool CNodeActivityBase::IsIdle() const + { + return NetStateMachine::ACore::IsIdle(); + } + +EXPORT_C void CNodeActivityBase::Abort(TNodeContextBase& aContext, TBool aIsNodeBeingDestroyed) + { + MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase %08x:\tAbort"), this)); + + //the error message will be send by message post processing see AMMNodeBase::Received + aContext.iReturn = KErrAbort; //before so as the error could be overwritten + NetStateMachine::ACore::Cancel(&aContext); + if (aContext.iReturn != KErrNone) + { + TEBase::TError error(aContext.iMessage.MessageId(), aContext.iReturn); + for (TInt n = iOriginators.Count() - 1;n>=0; n--) + { + TNodePeerId& originator = iOriginators[n]; + //In the "quiet mode", when the hosting node is being destroyed, we can not afford sending + //an error to the node as it would hit void. + TBool canSend = !((aIsNodeBeingDestroyed && originator == aContext.NodeId()) + || aContext.iMessage.IsMessage()); + if (canSend) + { + PostToOriginator(originator, error); + } + RemoveOriginator(n); //Do not allow ~CNodeActivityBase to post as client's might be already gone + } + } + } + +//-========================================================= +// +//CNodeRetryActivity +// +//-========================================================= +EXPORT_C CNodeRetryActivity::CNodeRetryActivity( const TNodeActivity& aActivitySig, AMMNodeBase& aNode ) +: CNodeActivityBase(aActivitySig, aNode), + TIfStaticFetcherNearestInHierarchy(this) + { + } + +EXPORT_C CNodeActivityBase* CNodeRetryActivity::NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode ) + { + return new(ELeave)CNodeRetryActivity(aActivitySig, aNode); + } + +EXPORT_C TBool CNodeRetryActivity::IsIdle() const + { + return !IsWaiting() && CNodeActivityBase::IsIdle(); + } + +EXPORT_C void CNodeRetryActivity::SetIdle() + { + iContextDesc.Close(); + ClearIsWaiting(); + ClearWillWait(); //Set this too in case this fn was invoked from within the serialised state ot transition + CNodeActivityBase::SetIdle(); + } + +EXPORT_C TBool CNodeRetryActivity::Signal(TNodeContextBase& aContext) + { + return AActivitySemaphore::Signal(aContext); + } + +EXPORT_C void CNodeRetryActivity::ReturnInterfacePtrL(AContextStore*& aInterface) + { + aInterface = this; + } + +EXPORT_C void CNodeRetryActivity::ReturnInterfacePtrL(AActivitySemaphore*& aInterface) + { + aInterface = this; + } + +//-========================================================= +// +//CNodeParallelActivityBase +// +//-========================================================= +// For custom activities to implement NewL +EXPORT_C TUint CNodeParallelActivityBase::GetNextActivityCountL( const TNodeActivity& aActivitySig, const AMMNodeBase& aNode ) + { + TInt c = 1, i = 0; + + const RPointerArray& activities = aNode.Activities(); + RArray activityids; + CleanupClosePushL(activityids); + + // collect the currently used ids + for (TInt i = 0; i < activities.Count(); i++) + { + TInt16 id = activities[i]->ActivityId(); + if ((id&0xff) == aActivitySig.iId) + { + TInt8 uniqueid = id >> 8; + activityids.InsertInOrderL(uniqueid); + } + } + + // find first available. + while (i < activityids.Count() + && activityids[i] == c) + { + ++i; + ++c; + } + CleanupStack::PopAndDestroy(&activityids); + + if(c > KActivityParallelRangeMax>>8) + { + User::Leave(KErrInUse); + } + return c; + } + +EXPORT_C CNodeActivityBase* CNodeParallelActivityBase::NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode ) + { + TUint c = GetNextActivityCountL(aActivitySig,aNode); + return new(ELeave)CNodeParallelActivityBase(aActivitySig, aNode, c); + } + +EXPORT_C CNodeParallelActivityBase::CNodeParallelActivityBase(const TNodeActivity& aActivitySig, AMMNodeBase& aNode, TUint aNextActivityCount) +: CNodeActivityBase(aActivitySig, aNode), + iActivityId((aNextActivityCount<<8)|aActivitySig.iId) + { + } + +EXPORT_C TUint16 CNodeParallelActivityBase::ActivityId() const + { + return iActivityId; + } + + +//-========================================================= +// +//CNodeParallelMessageStoreActivityBase +// +//-========================================================= +EXPORT_C CNodeActivityBase* CNodeParallelMessageStoreActivityBase::NewL( const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode ) + { + TUint c = GetNextActivityCountL(aActivitySig,aNode); + return new (ELeave) CNodeParallelMessageStoreActivityBase( aActivitySig, aNode, c); + } + +EXPORT_C CNodeParallelMessageStoreActivityBase::~CNodeParallelMessageStoreActivityBase() + { + } + +EXPORT_C Messages::TSignalBase& CNodeParallelMessageStoreActivityBase::Message() + { + ASSERT(iMsg); + return *iMsg; + } + +EXPORT_C void CNodeParallelMessageStoreActivityBase::StartL(TNodeContextBase& aContext, const Messages::XNodePeerId& aOriginator, const NetStateMachine::TStateTriple& aFirst) + { + SaveMessageL(aContext.iMessage); + CNodeParallelActivityBase::StartL(aContext, aOriginator, aFirst); + } + +void CNodeParallelMessageStoreActivityBase::SaveMessageL(Messages::TSignalBase& aMessage) + { + Meta::CMetaDataVirtualCtorInPlace* vctr = TlsGlobals::Get().VirtualCtor(); + TPtrC8 ptr(iMsgBuf); + iMsg = static_cast(vctr->New(aMessage.GetTypeId(), iMsgBuf)); + if (iMsg == NULL) + { + User::Leave(KErrNotFound); + } + + iMsg->Copy(aMessage); + } + +EXPORT_C CNodeParallelMessageStoreActivityBase::CNodeParallelMessageStoreActivityBase( const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode, TUint aNextActivityCount ) + : CNodeParallelActivityBase(aActivitySig, aNode, aNextActivityCount), iMsg(NULL) + { + } + +//-========================================================= +// +//CNodeRetryParallelActivity +// +//-========================================================= +EXPORT_C CNodeRetryParallelActivity::CNodeRetryParallelActivity( const TNodeActivity& aActivitySig, AMMNodeBase& aNode, TUint aActivitiesCount ) +: CNodeParallelActivityBase(aActivitySig, aNode, aActivitiesCount), + TIfStaticFetcherNearestInHierarchy(this) + { + } + +EXPORT_C CNodeActivityBase* CNodeRetryParallelActivity::NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode ) + { + TUint c = GetNextActivityCountL(aActivitySig,aNode); + return new(ELeave)CNodeRetryParallelActivity(aActivitySig, aNode, c); + } + +EXPORT_C TBool CNodeRetryParallelActivity::IsIdle() const + { + return !IsWaiting() && CNodeActivityBase::IsIdle(); + } + +EXPORT_C void CNodeRetryParallelActivity::SetIdle() + { + iContextDesc.Close(); + ClearIsWaiting(); + ClearWillWait(); //Set this too in case this fn was invoked from within the serialised state ot transition + CNodeActivityBase::SetIdle(); + } + +EXPORT_C TBool CNodeRetryParallelActivity::Signal(TNodeContextBase& aContext) + { + return AActivitySemaphore::Signal(aContext); + } + +EXPORT_C void CNodeRetryParallelActivity::ReturnInterfacePtrL(AContextStore*& aInterface) + { + aInterface = this; + } + +EXPORT_C void CNodeRetryParallelActivity::ReturnInterfacePtrL(AActivitySemaphore*& aInterface) + { + aInterface = this; + } + +//-========================================================= +// +//AContextStore +// +//-========================================================= +EXPORT_C TInt AContextStore::StoreContext(const TNodeContextBase& aContext) + {//doesn't actually store TNodeContextBase only the message since it assumes + //that the transition context is the + //template + //struct TNodeContext : public TDerivedContext + //where TDerivedContext = TNodeContextBase is always TNodeContextBase + //another type of context is not needed because all custom needs should be sorted by custom + //activity class + TInt error = KErrNone; + TInt len = TRuntimeCtxId::KMaxInlineAddressSize + aContext.iMessage.Length(); + if (iContextDesc.MaxLength() < len) + { + iContextDesc.Close(); + error = iContextDesc.Create(len); + } + else + { + iContextDesc.Zero(); + } + if (KErrNone==error) + { + error = aContext.iSender.Store(iContextDesc); //would catch if iContextDesc has been allocated properly + } + if (KErrNone==error) + { + error = aContext.iMessage.Store(iContextDesc); //would catch if iContextDesc has been allocated properly + } + return error; + } + +EXPORT_C TNodeContextBase* AContextStore::LoadContext(AMMNodeBase& aNode, CNodeActivityBase* aNodeActivity, TDes8& aCtxBuff, TDes8& aMsgBuff, const TNodeId& aDummy) + { + if (iContextDesc.Length() < sizeof(TNodeId)) + { + return NULL; + } + + const TRuntimeCtxId* sender = reinterpret_cast(iContextDesc.Ptr()); + TPtrC8 contextStore(iContextDesc.Ptr()+sender->Size(),iContextDesc.Length()-sender->Size()); + TSignatureBase* msg = static_cast(TlsGlobals::Get().VirtualCtor()->New(contextStore, aMsgBuff)); + if (!msg) + { + return NULL; + } + + //This assumes (as CNodeActivityBase::StoreContext) that the transition context is the + //template + //struct TNodeContext : public TDerivedContext + //where TDerivedContext = TNodeContextBase is always TNodeContextBase. + //another type of context is not needed because all custom needs should be sorted by custom + //activity class + __ASSERT_DEBUG(aNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 4)); + return ::new ((TUint8*)aCtxBuff.Ptr()) TNodeContextBase(aNode, *msg, *sender, aDummy, aNodeActivity); + } + +EXPORT_C TBool AContextStore::IsStored() const + { + return iContextDesc.Length() >= sizeof(TNodeId); + } + +// Needs to be moved to error-recoverable activity class +EXPORT_C const TNodeSignal::TMessageId& AContextStore::RetryingForMessageId() const + { + return iRetryingForMessageId; + } + +//Called only ever from ReceivedL +EXPORT_C void AContextStore::Retry(CNodeActivityBase& aActivity, TNodeContextBase& aContext) + { + TBuf8<__Align8(sizeof(TNodeContextBase))> ctxBuf; + TBuf8<__Align8(TSignalBase::KMaxInlineMessageSize + TSignalBase::KMaxUnstoredOverhead)> msgBuf; + TNodeContextBase* storedContext = LoadContext(aContext.iNode, &aActivity,ctxBuf, msgBuf, aContext.NodeId()); + + //If we are here the context has been stored. There is no reason why it could not be loaded now. + //The only reason would be that the message factory was unregistered since the context was stored + //which is a critical condition. + __ASSERT_ALWAYS(storedContext, User::Panic(KMMActivityPanic,EPanicCorruptedContext)); + + TEErrorRecovery::TErrorRecoveryResponse& msg = message_cast(aContext.iMessage); + iRetryingForMessageId = msg.iErrResponse.iMessageId; + aActivity.ACore::DoCurrent(storedContext); + aContext.Node().HandleMessageReturnValue(*storedContext); + iContextDesc.Zero(); + } + +//-========================================================= +// +//AActivitySemaphore +// +//-========================================================= +EXPORT_C void AActivitySemaphore::ParkTransitionL(const TNodeContextBase& aContext) + { + __ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 5)); + AActivitySemaphore* as = static_cast(aContext.iNodeActivity->FetchExtInterfaceL(AActivitySemaphore::KInterfaceId)); + if (!as->IsWaiting()) + { + User::LeaveIfError(as->StoreContext(aContext)); + + //The context has been stored along with the message. Must consume the message, otherwise + //it will fall through and be seen by other activities or passthrough handling. + aContext.iMessage.ClearMessageId(); + + as->SetIsWaiting(); + as->SetIsTransition(); + MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("AActivitySemaphore:\tParkTransitionL->parked")); + } + as->SetWillWait(); + __ASSERT_DEBUG(as->IsWaiting(), User::Panic(KSpecAssert_ElemMeshMachActC, 6)); //Must be stored and waiting now + } + +EXPORT_C TInt AActivitySemaphore::ParkState(const TNodeContextBase& aContext) + { + __ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 7)); + AActivitySemaphore* as = static_cast(aContext.iNodeActivity->FetchExtInterface(AActivitySemaphore::KInterfaceId)); + __ASSERT_DEBUG(as, User::Panic(KSpecAssert_ElemMeshMachActC, 8)); //State/transition mismatched with the activity object (activity doesn't support serialisation - wrong derivation?) + if (!as->IsWaiting()) + { + TInt error = as->StoreContext(aContext); + if (error!=KErrNone) + { + return error; + }; + + //The context has been stored along with the message. Must consume the message, otherwise + //it will fall through and be seen by other activities or passthrough handling. + aContext.iMessage.ClearMessageId(); + + as->SetIsWaiting(); + as->ClearIsTransition(); + MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("AActivitySemaphore:\tParkState->parked")); + } + as->SetWillWait(); + __ASSERT_DEBUG(as->IsWaiting(), User::Panic(KSpecAssert_ElemMeshMachActC, 9)); //Must be stored and waiting now + return KErrNone; + } + +EXPORT_C TInt AActivitySemaphore::UnparkState(const TNodeContextBase& aContext) + { + __ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 10)); + AActivitySemaphore* as = static_cast(aContext.iNodeActivity->FetchExtInterface(AActivitySemaphore::KInterfaceId)); + __ASSERT_DEBUG(as, User::Panic(KSpecAssert_ElemMeshMachActC, 11)); //State/transition mismatched with the activity object (activity doesn't support serialisation - wrong derivation?) + if (as->IsWaiting()) + { + as->ClearIsWaiting(); + MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("AActivitySemaphore:\tUnparkState->unparked")); + } + as->ClearWillWait(); + __ASSERT_DEBUG(!as->IsWaiting(), User::Panic(KSpecAssert_ElemMeshMachActC, 12)); //Must be stored and waiting now + return KErrNone; + } + +EXPORT_C void AActivitySemaphore::Wait() + { + MESH_LOG((KMeshMachineSubTag, _L8("AActivitySemaphore:\tWait->activity waiting"))); + SetWillWait(); + } + +EXPORT_C TBool AActivitySemaphore::Signal(TNodeContextBase& aContext) + { + if (!(iFlags&KIsWaiting)) + { + return EFalse; + } + + //aContext.iNodeActivity is us + TBuf8<__Align8(sizeof(TNodeContextBase))> ctxBuf; + TBuf8<__Align8(TSignalBase::KMaxInlineMessageSize + TSignalBase::KMaxUnstoredOverhead)> msgBuf; + TNodeCtxId dummy(aContext.ActivityId(), aContext.NodeId()); + TNodeContextBase* storedContext = LoadContext(aContext.iNode,aContext.iNodeActivity,ctxBuf,msgBuf,dummy); + if (storedContext) + { + ClearWillWait(); + if (IsTransition()) + { + //Transition stored + aContext.iNodeActivity->ACore::DoCurrent(storedContext); + } + else + { + //This is the state stored +#ifdef _DEBUG + TBool hasRun = aContext.iNodeActivity->ACore::Next(storedContext); + __ASSERT_DEBUG(hasRun!=(iFlags & KWillWait), User::Panic(KSpecAssert_ElemMeshMachActC, 13)); +#else + aContext.iNodeActivity->ACore::Next(storedContext); +#endif + } + + if (!(iFlags & KWillWait)) + { //We have been run + ClearIsWaiting(); + iContextDesc.Zero(); + aContext.Node().HandleMessageReturnValue(*storedContext); + return ETrue; + } + } + + return EFalse; + } + +