--- /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 <elements/mm_context_internal.h>
+#include <elements/mm_log.h>
+
+#include <elements/nm_messages_base.h>
+#include <elements/nm_messages_child.h>
+
+
+#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<CNodeActivityBase>& 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<const TNodeCtxId>(&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<TEBase::TCancel>())
+ {
+ 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<TEBase::TError>())
+ {
+ //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<TEBase::TError>())
+ {
+ CNodeActivityBase* activity = FindAddressedActivity(aContext);
+ if(activity)
+ {
+ activity->SetError(static_cast<TEBase::TError&>(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<TEChild::TLeft>());
+ 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<TUint*>(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<TUint*>(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<TUint8*>(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<TAny**>(reinterpret_cast<TUint8*>(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<TAny**>(reinterpret_cast<TUint8*>(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;
+ }
+
+