diff -r 000000000000 -r dfb7c4ff071f commsfwsupport/commselements/meshmachine/src/mm_node.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commsfwsupport/commselements/meshmachine/src/mm_node.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,772 @@ +// Copyright (c) 2006-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_node.h" +#include "mm_nodepeer.h" +#include "mm_activities.h" +#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_ElemMeshMachNodC, "ElemMeshMachNodC"); +#endif + +using namespace Messages; +using namespace MeshMachine; +using namespace NetStateMachine; + +//By default we reserve the space generously, to fit even a synchronised activity preallocating space for up to 4 originators. +//Any node, hosting specific activities that may need the preallocation mechanism can choose a more optimal amounts. +//For efficiency reasons it is strongly recommended that any node (or family of nodes) is revisited and an optimal +//amount of space is specified (could be specified in the base class for those nodes or in every type of node separatelly). +static const TUint KDefaultMaxPreallocatedActivityCount = 1; +static const TUint KMaxPreallocatedActivitySize = sizeof(CNodeRetryParallelActivity) + sizeof(APreallocatedOriginators<4>); +static const TUint KDefaultPreallocatedActivityBufferSize = KDefaultMaxPreallocatedActivityCount * KMaxPreallocatedActivitySize; + +//-========================================================= +// +//Panics +// +//-========================================================= +_LIT (KMMNodePanic,"MMNodePanic"); +enum + { + EPanicPreallocatedSpaceAlreadyTaken = 1, + EPanicPreallocatedSpaceReturnedOther = 2, + EPanicInvalidClientId = 3, + EPanicOriginatorIsNotAPeer = 4, + EPanicNotSynchronisedActivity = 5, + }; + +//-========================================================= +// +//AMMNodeBase +// +//-========================================================= +EXPORT_C AMMNodeBase::AMMNodeBase(const TNodeActivityMap& aActivityMap, const TNodeId& aNodeId) +: ANodeBase(aNodeId), + TIfStaticFetcherNearestInHierarchy(this), + iActivityMap(aActivityMap), + iPreallocatedSpace(NULL) + { + }; + +EXPORT_C void AMMNodeBase::ReturnInterfacePtrL(AMMNodeBase*& aInterface) + { + aInterface = this; + } + +EXPORT_C TUint AMMNodeBase::CountActivities(TUint8 aActivitySigId) const + { + TInt i = iActivities.Count(); + TUint count = 0; + while (i>0) + { + CNodeActivityBase* a = iActivities[--i]; + if (aActivitySigId == a->ActivitySigId() && !a->IsIdle()) + { + count++; + } + } + return count; + } + +EXPORT_C TUint AMMNodeBase::CountAllActivities(TUint8 aActivitySigId) const + { + TInt i = iActivities.Count(); + TUint count = 0; + while (i>0) + { + CNodeActivityBase* a = iActivities[--i]; + if (aActivitySigId == a->ActivitySigId()) + { + count++; + } + } + return count; + } + +EXPORT_C TUint AMMNodeBase::CountAllActivities() const + { + return iActivities.Count(); + } + +EXPORT_C const RPointerArray& AMMNodeBase::Activities() const + { + return iActivities; + } + +EXPORT_C void AMMNodeBase::ConstructL(TInt aSize) + { + //Preallocate space for preallocated activities + if (aSize==KUseDefaultPreallocatedSize) + { + //Nodes will usually use the default parameter (-1) and rely on KDefaultPreallocatedActivityBufferSize. + //We do not use KDefaultPreallocatedActivityBufferSize as the default argument to avoid publishing of + //this constant or KDefaultMaxPreallocatedActivityCount/KMaxPreallocatedActivitySize (either can be + //freely changed at any time). + aSize = KDefaultPreallocatedActivityBufferSize; + } + + if (aSize>0) + { + PreallocateSpaceL(aSize); + } + } + +EXPORT_C AMMNodeBase::~AMMNodeBase() + { + //We may still have some idle activities in the iActivities array. + //This may be considered normal since there is no strict requirement + //for a node to destroy all of them before going into destruction phase. + //What is crutial however, is that there are no running activities left. + + + for (TInt i = iActivities.Count() - 1; i >= 0; i--) + { + CNodeActivityBase* activity = iActivities[i]; + if (activity->IsIdle()) + { + iActivities.Remove(i); + activity->Destroy(); + } + else + { + MESH_LOG((KMeshMachineSubTag, _L8("ERROR: ~AMMNodeBase(%08x) - Running activity found! (%08x) %s (%d)"), + this, activity, activity->ActivityName(), activity->ActivityId())); + } + } + +#ifdef _DEBUG + for (TInt i = iActivities.Count() -1; i >= 0; i--) + { + CNodeActivityBase* activity = iActivities[i]; + if (!activity->IsIdle()) + { + User::Invariant(); //Running activities still present! Please fix your node's cleanup! + } + } +#endif + + for (TInt i = iActivities.Count() -1; i >= 0; i--) + { + CNodeActivityBase* activity = iActivities[i]; + iActivities.Remove(i); + activity->Destroy(); + } + iActivities.Close(); + + User::Free(iPreallocatedSpace); + iPreallocatedSpace = NULL; + + } + +EXPORT_C void AMMNodeBase::RemoveClient(const TRuntimeCtxId& aClientId) + { + TNodeNullContext ctx(*this); + RemoveClient(aClientId, ctx); + } + +EXPORT_C void AMMNodeBase::RemoveClient(const TRuntimeCtxId& aClientId, TNodeContextBase& aContext) + { + TInt foundAt = 0; + RNodeInterface* client = DoFindClient(aClientId, foundAt); + __ASSERT_DEBUG(client, User::Panic(KMMNodePanic, EPanicInvalidClientId)); + + //here we need to cancel all activities originating aClientId (except the current one) + __ASSERT_DEBUG(!client->RecipientId().IsNull(), User::Panic(KSpecAssert_ElemMeshMachNodC, 1)); + AbortActivitiesOriginatedBy(aContext, client->RecipientId()); + + ANodeBase::RemoveClient(foundAt); + if (aContext.iSender == aClientId) + { + aContext.iPeer = NULL; + } + } + +EXPORT_C CNodeActivityBase* AMMNodeBase::FindActivityById(TUint aActivityId) const + { + CNodeActivityBase* a = NULL; + for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--) + { + CNodeActivityBase* comp = iActivities[i]; + if (!comp->IsIdle() && comp->ActivityId() == aActivityId) + { + a = comp; + } + } + return a; + } + +EXPORT_C CNodeActivityBase* AMMNodeBase::FindAddressedActivity(const TNodeContextBase& aContext) const + { + const TNodeCtxId* recipient = address_cast(&aContext.iRecipient); + if (recipient==NULL) + { + return NULL; + } + + CNodeActivityBase* a = NULL; + for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--) + { + CNodeActivityBase* act = iActivities[i]; + const TNodeId& postedTo = act->iPostedToId; + if (!act->IsIdle() + && (postedTo.IsNull() || aContext.iSender == postedTo) + && (recipient->NodeCtx() == act->ActivityId())) + { + a = act; + } + } + return a; + } + +EXPORT_C void AMMNodeBase::Received(const TNodeSignal::TMessageId aNoPeerMsgIds[], TNodeContextBase& aContext) + { + aContext.iReturn = KErrNone; //Clear the return value. + CNodeActivityBase* sendersActivity = NULL; + if (!Accept(aContext, sendersActivity) && aContext.iReturn == KErrNone ) + {//start new ones? but only if we know who sent a message or if it's a noPeer message + //or if it's us sending message to ourselves + + //is it a message that must have a peer + TBool noPeer = EFalse; + for (const TNodeSignal::TMessageId* p = &aNoPeerMsgIds[0] ; !p->IsNull() ; ++p) + { + noPeer = (*p == aContext.iMessage.MessageId()); + if (noPeer) + { + break; + } + } + if (noPeer || aContext.IsPeer() || aContext.IsSelf()) + { + //At this stage we are about to add the peer to the activiy originators. + //For all "peer requests" we must ensure the peer is in the client's list. + //If this assertion fires, your environment is critically corrupted. + //You must repair it by reconsidering your protocols. + __ASSERT_ALWAYS(noPeer || aContext.iPeer!=NULL, User::Panic(KMMNodePanic, EPanicOriginatorIsNotAPeer)); + TRAP(aContext.iReturn, StartNewActivitiesL(aContext, sendersActivity)); + } + else + { + //unknown sender => ignore the message + NM_LOG_ADDRESS_EXT(KMeshMachineSubTag, aContext.iSender, _L8("AMMNodeBase:\tReceived() - Unknown sender. Message must have a peer => ignoring message")); + } + } + else + { + __ASSERT_DEBUG(aContext.iMessage.MessageId().IsNull() || aContext.iReturn != KErrNone, User::Panic(KSpecAssert_ElemMeshMachNodC, 2)); //message must be processed + } + } + +EXPORT_C void AMMNodeBase::HandlePassThroughMessage(TNodeContextBase& aContext) + { + if (aContext.iMessage.IsMessage()) + { + ASSERT(aContext.iNodeActivity == NULL); //by definition, since nobody accepted this; + TInt originatorIndex = KErrNotFound; + //Please note: + //The same originator must not attempt to start more than one activities on the same node + //(so there is only ever one activity on the node with the originator == that this TCancel is addressed to)! + //In general one originator (identified by a unique channel id) must never originate more + //than one activities at all. + for (TInt i = 0; i < iActivities.Count(); i++) + { + if ((originatorIndex = iActivities[i]->FindOriginator(aContext.iSender)) != KErrNotFound) + { + aContext.iNodeActivity = iActivities[i]; + break; + } + } + + if (aContext.iNodeActivity) + { + ASSERT(originatorIndex != KErrNotFound); + if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator + { + aContext.iNodeActivity->Cancel(aContext); + } + else + { + // just tell this originator that we've stopped with respect to it.. otherwise keep running + TEBase::TError err(TEBase::TCancel::Id(), KErrCancel); + aContext.PostToSender(err); + aContext.iNodeActivity->RemoveOriginator(originatorIndex); + } + } + } + else if (aContext.iReturn==KErrNone && !aContext.iMessage.MessageId().IsNull()) + { //this is the pass-through message, forward to ..... + //Find the activity being addressed, if any + aContext.iNodeActivity = FindAddressedActivity(aContext); + if (aContext.iNodeActivity) + { //Peer message, forward to originators + //aContext.iSender = Id(); + NM_LOG_MESSAGE_EXT(KMeshMachineSubTag, aContext.iMessage, _L8("AMMNodeBase::HandlePassThroughMessage - message not served by the node but matching activity found=>SEND TO ACTIVITY'S ORIGINATORS")); + aContext.iNodeActivity->PostToOriginators(aContext.iMessage); + if (aContext.iMessage.IsMessage()) + { + //An activity received an error=>remove it from active array + //This scenario will usually happen when there is no error activity on the node, + //or when the error activity decides not to handle this particular error. + aContext.iNodeActivity->SetIdle(); + } + aContext.iMessage.ClearMessageId(); + } + else + { //A stray message + //Please note that we should not implement forwarding for non-response messages here. + //Any non-response message that needs forwarding should use TMessageDispatcher or other + //supported mechanisms. + NM_LOG_MESSAGE_EXT(KMeshMachineSubTag, aContext.iMessage, _L8("ERROR: AMMNodeBase::HandlePassThroughMessage - A stray message received!")); + } + } + } + + +EXPORT_C void AMMNodeBase::HandleMessageReturnValue(TNodeContextBase& aContext) + { + if (aContext.iReturn != KErrNone) + { + //keep the original activity in case no aCurrentActivity + if(aContext.iNodeActivity && aContext.iNodeActivity->iOriginators.Count() > 0) + { + aContext.iNodeActivity->SetError(aContext.iReturn); + // Mark the activity for destruction + // When the activity is destroyed the Originators will be errored + aContext.iNodeActivity->SetIdle(); + } + + // Check to see if the node was unable to handle an error (e.g., an error recovery activity failed to start + // because there was insufficient memory). If so, we manually error the activity and set it to idle causing + // its originators to be errored. This is the most we can do if an error activity cannot be run. + else if(aContext.iMessage.IsMessage()) + { + CNodeActivityBase* activity = FindAddressedActivity(aContext); + if(activity) + { + activity->SetError(static_cast(aContext.iMessage).iValue); + // Mark the activity for destruction + // When the activity is destroyed the Originators will be errored + activity->SetIdle(); + } + } + + else + { //No activity == single triple activity or an error from the first transition, so use the sender's message id. + TEBase::TError err(aContext.iMessage.MessageId(), aContext.iReturn); + aContext.PostToSender(err); + } + aContext.iReturn = KErrNone; + aContext.iMessage.ClearMessageId(); + } + } + + +//N.B. This function may delete the object pointed to by aCurrentActivity. +//So don't use it after this function is called. +//Also, it may delete the node itself, so don't use it after this function is called. +EXPORT_C void AMMNodeBase::PostReceived(TNodeContextBase& aContext) + { + HandleMessageReturnValue(aContext); + HandlePassThroughMessage(aContext); + SignalActivities(); + } + +void AMMNodeBase::SignalActivities() + { + TBool awoke = ETrue; + TInt c = iActivities.Count(); + TNodeNullContext context(*this); + //Clean up.. + while (awoke && c > 0) + { + awoke = EFalse; + for (TInt i = c - 1 ; i>=0 ; --i) + { + //Signal to waiting activities if: + //1) an event was received (& the state has potentialy changed as a result) + //- remember that an activity does not have to get idle as a result of processing an event which changes the state!!!! + //2) another waiting activity awoke == reacted to the signal (& the state has potentialy changed as a result) + //If any signalled activity reacted, the state could change and all other activities need to be signalled again. + context.iNodeActivity = iActivities[i]; + awoke |= context.iNodeActivity->Signal(context); + if(context.iNodeActivity->IsIdle()) + { + iActivities.Remove(i); + context.iNodeActivity->Destroy(); + context.iNodeActivity = NULL; + // NOTE: if "aContext.iNodeActivity" is the destroy activity, then deleting + // it will destroy the node (i.e. "this") as well, so don't put anything after this line ! + if (c == 1) + { + // c == 1 means that we've just removed the last activity (also means i will be zero) + // i == 0 means that this round of signalling parked activities has been completed + // This is effectively safeguarding the access to iActivities which may or may not be + // there (based on the note above). The destroy activity will always be placed at the + // head of the list, and will therefore be the last to get processed. + return; + } + } + } + c = iActivities.Count(); + } + } + +EXPORT_C void AMMNodeBase::AbortActivitiesOriginatedBy(TNodeContextBase& aContext, const TNodeId& aCommsId, TBool aIsNodeBeingDestroyed) + { + CNodeActivityBase* caller = aContext.iNodeActivity; + TBool abortAll = aCommsId.IsNull(); + + for (TInt i = iActivities.Count() - 1; i>=0; i--) + { + aContext.iNodeActivity = iActivities[i]; + if (caller != aContext.iNodeActivity) + { + if (abortAll) + { + //Abort the whole activity (Cancel it & error all originators) + aContext.iNodeActivity->Abort(aContext,aIsNodeBeingDestroyed); + } + else + { + //Abort for one originator only (Cancel the activity if last originator & error just this one originator) + TInt idx = aContext.iNodeActivity->FindOriginator(aCommsId); + if (KErrNotFound!=idx) + { + if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator + { + aContext.iNodeActivity->SetError(KErrAbort); + aContext.iNodeActivity->Cancel(aContext); + } + + + //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. + TNodePeerId& originator = aContext.iNodeActivity->iOriginators[idx]; + TBool canSend = !((aIsNodeBeingDestroyed && originator == aContext.NodeId()) + || aContext.iMessage.IsMessage()); + if (canSend) + { + aContext.iNodeActivity->PostToOriginator(originator, TEBase::TError(aContext.iMessage.MessageId(), KErrAbort).CRef()); + } + + + aContext.iNodeActivity->RemoveOriginator(idx); + } + } + } + } + aContext.iReturn = KErrNone; + aContext.iNodeActivity = caller; + } + +//This fn finds the (first) activity that has an originator matching that passed in +EXPORT_C CNodeActivityBase* AMMNodeBase::FindActivityOriginatedBy(const TRuntimeCtxId& aPeerId) + { + for (TInt i = 0; i < iActivities.Count(); i++) + { + CNodeActivityBase* a = iActivities[i]; + if (!a->IsIdle() + && a->FindOriginator(aPeerId) != KErrNotFound) + { + return a; + } + } + return NULL; + } + +TBool AMMNodeBase::Accept(TNodeContextBase& aContext, CNodeActivityBase*& aFoundActivity) + { +// NM_LOG_MESSAGE_EXT(KMeshMachineSubTag, aContext.iMessage, _L8("AMMNodeBase:\tAccept")); + + //process the existing ones + for (TInt i = 0; i < iActivities.Count(); i++) + { + CNodeActivityBase* a = aContext.iNodeActivity = iActivities[i]; + if(a->Next(aContext)) + { + if (KErrNone == aContext.iReturn) + { + aContext.iMessage.ClearMessageId(); // message processed and value no longer needed + } + + // If state went idle, aFoundActivity will be deleted later by PostReceived, + // this gives us a chance to report error to originators if necessary. + aFoundActivity = a; + return ETrue; + } + + if (a->FindOriginator(aContext.iSender) != KErrNotFound) + { + aFoundActivity = a; + } + } + return EFalse; + } + +void AMMNodeBase::StartNewActivitiesL(TNodeContextBase& aContext, CNodeActivityBase* aSendersActivity) + { + //new activity can only be started if the senders channel hasn't started any yet + //but we need to check so that we can return an error + TNodeActivityIter activityIter(iActivityMap); + + const TNodeActivity* activity; + while (NULL!=(activity = activityIter++) && aContext.iReturn == KErrNone) + { + const TStateTriple* first; + aContext.iNodeActivity = NULL; + TInt i = iActivities.Count(); + while (i>0 && !aContext.iNodeActivity) + { + if (activity->iId == iActivities[--i]->ActivityId()) + { + aContext.iNodeActivity = iActivities[i]; + } + } + + if ( (first = CNodeActivityBase::Accept( aContext, + *activity, NetStateMachine::KExecuteAlways)) != NULL ) + { //we do need to have a state here to go to otherwise we assume it is an activity + //with one triple only + if ((first+1)->iTCtor != NULL) + { + //is it any of the existing ones? + if (aContext.iNodeActivity) + { + __ASSERT_DEBUG(aSendersActivity == NULL || aSendersActivity == aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachNodC, 3)); + if (aSendersActivity == NULL) + { + XNodePeerId originator(aContext.iSender, aContext.iPeer); + aContext.iNodeActivity->StartL(aContext, originator, *first); + } + } + else + { + +#ifdef SYMBIAN_TRACE_ENABLE + if (aSendersActivity) + { + //The sender is already running an activity on this node. + //There is no definitive reason why to disallow starting of a next one, + //it is however a sign that something _may_ be going horribly wrong. + + //Usually, this is the case when the same originator sends several requests without + //caring of the order in which they are going to be completed and the possibility of + //cancelling them (there exist no way of targetting TCancel to more than one activity). + + //Also, an error activity may be starting and producing this warning (but please note that + //error activity has no originators). + + //Please also see note in CNodeActivityBase::Next()! + MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("WARNING: AMMNodeBase:\tStartNewActivitiesL - sender is starting an extra activity - TCancel will not work!")); + TInt i = iActivities.Count(); + MESH_LOG((KMeshMachineSubTag, _L8("\tThe sender has already started %d activities:"), i)); + while (i>0) + { + if (iActivities[--i]->FindOriginator(aContext.iSender) >= 0) + { + MESH_LOG((KMeshMachineSubTag, _L8("\t(%08x) %s (%d)"), aSendersActivity, aSendersActivity->ActivityName(), aSendersActivity->ActivityId())); + } + } + } +#endif + //create a new one then + TRAPD(err, StartActivityL(aContext, *activity, *first)); + if(err!=KErrNone) + { + MESH_LOG((KMeshMachineSubTag, + _L8("ERROR: AMMNodeBase %08x:\tStartNewActivitiesL - Activity failed to start due to error %d!"), + this, err)); + + User::Leave(err); + } + } + } + aContext.iMessage.ClearMessageId(); //message processed + break;//only one activity can start since we have one activity per + //channelId. (ChannelId == CommsId + activityId) + } + } + } + +void AMMNodeBase::StartActivityL(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, const NetStateMachine::TStateTriple& aFirst) + { + CNodeActivityBase* a = aActivitySig.iCtor(aActivitySig,*this); + if (iActivities.Find(a)==KErrNotFound) + { + //The activity did not add itself to the list in any special way, append it here + CleanupStack::PushL(a); + a->AppendActivityL(); + CleanupStack::Pop(a); + } + //assign only after the activity is successfully appended + aContext.iNodeActivity = a; + + //if StartL leaves the "a" will be removed from the array and deleted in ::PostReceived + //since it will be idle + XNodePeerId originator(aContext.iSender, aContext.iPeer); + a->StartL(aContext, originator, aFirst); + } + +void AMMNodeBase::PreallocateSpaceL(TUint aSize) + { + __ASSERT_DEBUG(aSize>0, User::Panic(KSpecAssert_ElemMeshMachNodC, 4)); + // Reserve extra space for the maximum number of preallocated activities supported by this node + // to ensure they can be added to the activities list while the system is out of memory. We also + // add enough space for extra data strucures to store the free list - the caller cannot reserve this + // space without knowledge of the preallocation implementation so we do this ourselves. + TUint maxPreallocatedActivities = aSize / KMaxPreallocatedActivitySize; + iActivities.ReserveL(iActivities.Count() + maxPreallocatedActivities); + __ASSERT_DEBUG(iPreallocatedSpace==NULL, User::Panic(KSpecAssert_ElemMeshMachNodC, 5)); + iPreallocatedSpace = User::AllocZL(aSize + sizeof(TUint) + maxPreallocatedActivities * sizeof(TAny*)); + *reinterpret_cast(iPreallocatedSpace) = maxPreallocatedActivities; + } + +TUint AMMNodeBase::MaxPreallocatedActivityCount() const + { + // Maximum number of activities that can be preallocated is stored at the beginning of the buffer. + if(iPreallocatedSpace) + { + return *reinterpret_cast(iPreallocatedSpace); + } + return 0; + } + +TAny* AMMNodeBase::GetPreallocatedCell(TUint aIndex) const + { + // Calculate the offset of the start of the preallocated space after the free list. + TUint8* bufferStart = reinterpret_cast(iPreallocatedSpace) + sizeof(TUint*) + MaxPreallocatedActivityCount() * sizeof(TAny*); + + return bufferStart + aIndex * KMaxPreallocatedActivitySize; + } + +TAny* AMMNodeBase::BorrowPreallocatedSpace(TUint aSize) + { + MESH_LOG((KMeshMachineSubTag, _L8("AMMNodeBase %08x:\tBorrowPreallocatedSpace (%d)"),this,aSize)); + + __ASSERT_ALWAYS(iPreallocatedSpace, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken)); + __ASSERT_ALWAYS(aSize <= KMaxPreallocatedActivitySize, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken)); + + #ifdef SYMBIAN_TRACE_ENABLE + if(!iPreallocatedSpace) + { + MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tBorrowPreallocatedSpace - Preallocated space has not been allocated!"), this)); + } + if(aSize>KMaxPreallocatedActivitySize) + { + MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tBorrowPreallocatedSpace - Size exceeds maximum limit for a single allocation (%d was requested but only %d is available)!"), this, aSize, KMaxPreallocatedActivitySize)); + } + #endif + + TAny* ptr = NULL; + TUint maxPreallocatedActivities = MaxPreallocatedActivityCount(); + TAny** freeList = reinterpret_cast(reinterpret_cast(iPreallocatedSpace) + sizeof(TUint)); + TUint index = 0; + + // Search the free list to see if any space is available. + for(; index < maxPreallocatedActivities; index ++) + { + if(!freeList[index]) + { + // This cell is now allocated to the calling activity. + ptr = freeList[index] = GetPreallocatedCell(index); + + // Zero the cell so that any object allocated will have the expected initial zero fill. + memset(ptr, 0, KMaxPreallocatedActivitySize); + + break; + } + } + + // Check to make sure a free cell was found. + bool freeCellFound = index < maxPreallocatedActivities; + if(!freeCellFound) + { + MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tBorrowPreallocatedSpace - All %d preallocation cells have been allocated!"), this, maxPreallocatedActivities)); + __ASSERT_ALWAYS(freeCellFound, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken)); + } + + return ptr; + } + +void AMMNodeBase::ReturnPreallocatedSpace(TAny* aSpace) + { + MESH_LOG((KMeshMachineSubTag, _L8("AMMNodeBase %08x:\tReturnPreallocatedSpace"), this)); + + TUint maxPreallocatedActivities = MaxPreallocatedActivityCount(); + TAny** freeList = reinterpret_cast(reinterpret_cast(iPreallocatedSpace) + sizeof(TUint)); + TUint index = 0; + + // Search the free list to return the cell. + for(; index < maxPreallocatedActivities; index ++) + { + if(freeList[index] == aSpace) + { + // Mark this cell as free. + freeList[index] = NULL; + + break; + } + } + + bool allocatedCellFound = index < maxPreallocatedActivities; + if(!allocatedCellFound) + { + MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tReturnPreallocatedSpace - the returned pointer 0x%08X is invalid!"), this, aSpace)); + __ASSERT_DEBUG(allocatedCellFound, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceReturnedOther)); + } + } + + +//-========================================================= +// +//AMMNodeIdBase +// +//-========================================================= +EXPORT_C const TNodeId& AMMNodeIdBase::NodeId() const + { + return Messages::ANodeId::Id(); + } + +//-========================================================= +// +//XNodePeerId +// +//-========================================================= +EXPORT_C XNodePeerId::XNodePeerId(const TRuntimeCtxId& aPeerId, RNodeInterface* aPeer, CBase* aInfo) +: TNodePeerId(aPeerId, aPeer), + iInfo(aInfo) + { + } + +EXPORT_C void XNodePeerId::Destroy() + { + delete iInfo; + iInfo = NULL; + } + +