|
1 // Copyright (c) 2006-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_node.h" |
|
21 #include "mm_nodepeer.h" |
|
22 #include "mm_activities.h" |
|
23 #include <elements/mm_context_internal.h> |
|
24 #include <elements/mm_log.h> |
|
25 |
|
26 #include <elements/nm_messages_base.h> |
|
27 #include <elements/nm_messages_child.h> |
|
28 |
|
29 |
|
30 #ifdef _DEBUG |
|
31 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module |
|
32 // (if it could happen through user error then you should give it an explicit, documented, category + code) |
|
33 _LIT(KSpecAssert_ElemMeshMachNodC, "ElemMeshMachNodC"); |
|
34 #endif |
|
35 |
|
36 using namespace Messages; |
|
37 using namespace MeshMachine; |
|
38 using namespace NetStateMachine; |
|
39 |
|
40 //By default we reserve the space generously, to fit even a synchronised activity preallocating space for up to 4 originators. |
|
41 //Any node, hosting specific activities that may need the preallocation mechanism can choose a more optimal amounts. |
|
42 //For efficiency reasons it is strongly recommended that any node (or family of nodes) is revisited and an optimal |
|
43 //amount of space is specified (could be specified in the base class for those nodes or in every type of node separatelly). |
|
44 static const TUint KDefaultMaxPreallocatedActivityCount = 1; |
|
45 static const TUint KMaxPreallocatedActivitySize = sizeof(CNodeRetryParallelActivity) + sizeof(APreallocatedOriginators<4>); |
|
46 static const TUint KDefaultPreallocatedActivityBufferSize = KDefaultMaxPreallocatedActivityCount * KMaxPreallocatedActivitySize; |
|
47 |
|
48 //-========================================================= |
|
49 // |
|
50 //Panics |
|
51 // |
|
52 //-========================================================= |
|
53 _LIT (KMMNodePanic,"MMNodePanic"); |
|
54 enum |
|
55 { |
|
56 EPanicPreallocatedSpaceAlreadyTaken = 1, |
|
57 EPanicPreallocatedSpaceReturnedOther = 2, |
|
58 EPanicInvalidClientId = 3, |
|
59 EPanicOriginatorIsNotAPeer = 4, |
|
60 EPanicNotSynchronisedActivity = 5, |
|
61 }; |
|
62 |
|
63 //-========================================================= |
|
64 // |
|
65 //AMMNodeBase |
|
66 // |
|
67 //-========================================================= |
|
68 EXPORT_C AMMNodeBase::AMMNodeBase(const TNodeActivityMap& aActivityMap, const TNodeId& aNodeId) |
|
69 : ANodeBase(aNodeId), |
|
70 TIfStaticFetcherNearestInHierarchy(this), |
|
71 iActivityMap(aActivityMap), |
|
72 iPreallocatedSpace(NULL) |
|
73 { |
|
74 }; |
|
75 |
|
76 EXPORT_C void AMMNodeBase::ReturnInterfacePtrL(AMMNodeBase*& aInterface) |
|
77 { |
|
78 aInterface = this; |
|
79 } |
|
80 |
|
81 EXPORT_C TUint AMMNodeBase::CountActivities(TUint8 aActivitySigId) const |
|
82 { |
|
83 TInt i = iActivities.Count(); |
|
84 TUint count = 0; |
|
85 while (i>0) |
|
86 { |
|
87 CNodeActivityBase* a = iActivities[--i]; |
|
88 if (aActivitySigId == a->ActivitySigId() && !a->IsIdle()) |
|
89 { |
|
90 count++; |
|
91 } |
|
92 } |
|
93 return count; |
|
94 } |
|
95 |
|
96 EXPORT_C TUint AMMNodeBase::CountAllActivities(TUint8 aActivitySigId) const |
|
97 { |
|
98 TInt i = iActivities.Count(); |
|
99 TUint count = 0; |
|
100 while (i>0) |
|
101 { |
|
102 CNodeActivityBase* a = iActivities[--i]; |
|
103 if (aActivitySigId == a->ActivitySigId()) |
|
104 { |
|
105 count++; |
|
106 } |
|
107 } |
|
108 return count; |
|
109 } |
|
110 |
|
111 EXPORT_C TUint AMMNodeBase::CountAllActivities() const |
|
112 { |
|
113 return iActivities.Count(); |
|
114 } |
|
115 |
|
116 EXPORT_C const RPointerArray<CNodeActivityBase>& AMMNodeBase::Activities() const |
|
117 { |
|
118 return iActivities; |
|
119 } |
|
120 |
|
121 EXPORT_C void AMMNodeBase::ConstructL(TInt aSize) |
|
122 { |
|
123 //Preallocate space for preallocated activities |
|
124 if (aSize==KUseDefaultPreallocatedSize) |
|
125 { |
|
126 //Nodes will usually use the default parameter (-1) and rely on KDefaultPreallocatedActivityBufferSize. |
|
127 //We do not use KDefaultPreallocatedActivityBufferSize as the default argument to avoid publishing of |
|
128 //this constant or KDefaultMaxPreallocatedActivityCount/KMaxPreallocatedActivitySize (either can be |
|
129 //freely changed at any time). |
|
130 aSize = KDefaultPreallocatedActivityBufferSize; |
|
131 } |
|
132 |
|
133 if (aSize>0) |
|
134 { |
|
135 PreallocateSpaceL(aSize); |
|
136 } |
|
137 } |
|
138 |
|
139 EXPORT_C AMMNodeBase::~AMMNodeBase() |
|
140 { |
|
141 //We may still have some idle activities in the iActivities array. |
|
142 //This may be considered normal since there is no strict requirement |
|
143 //for a node to destroy all of them before going into destruction phase. |
|
144 //What is crutial however, is that there are no running activities left. |
|
145 |
|
146 |
|
147 for (TInt i = iActivities.Count() - 1; i >= 0; i--) |
|
148 { |
|
149 CNodeActivityBase* activity = iActivities[i]; |
|
150 if (activity->IsIdle()) |
|
151 { |
|
152 iActivities.Remove(i); |
|
153 activity->Destroy(); |
|
154 } |
|
155 else |
|
156 { |
|
157 MESH_LOG((KMeshMachineSubTag, _L8("ERROR: ~AMMNodeBase(%08x) - Running activity found! (%08x) %s (%d)"), |
|
158 this, activity, activity->ActivityName(), activity->ActivityId())); |
|
159 } |
|
160 } |
|
161 |
|
162 #ifdef _DEBUG |
|
163 for (TInt i = iActivities.Count() -1; i >= 0; i--) |
|
164 { |
|
165 CNodeActivityBase* activity = iActivities[i]; |
|
166 if (!activity->IsIdle()) |
|
167 { |
|
168 User::Invariant(); //Running activities still present! Please fix your node's cleanup! |
|
169 } |
|
170 } |
|
171 #endif |
|
172 |
|
173 for (TInt i = iActivities.Count() -1; i >= 0; i--) |
|
174 { |
|
175 CNodeActivityBase* activity = iActivities[i]; |
|
176 iActivities.Remove(i); |
|
177 activity->Destroy(); |
|
178 } |
|
179 iActivities.Close(); |
|
180 |
|
181 User::Free(iPreallocatedSpace); |
|
182 iPreallocatedSpace = NULL; |
|
183 |
|
184 } |
|
185 |
|
186 EXPORT_C void AMMNodeBase::RemoveClient(const TRuntimeCtxId& aClientId) |
|
187 { |
|
188 TNodeNullContext ctx(*this); |
|
189 RemoveClient(aClientId, ctx); |
|
190 } |
|
191 |
|
192 EXPORT_C void AMMNodeBase::RemoveClient(const TRuntimeCtxId& aClientId, TNodeContextBase& aContext) |
|
193 { |
|
194 TInt foundAt = 0; |
|
195 RNodeInterface* client = DoFindClient(aClientId, foundAt); |
|
196 __ASSERT_DEBUG(client, User::Panic(KMMNodePanic, EPanicInvalidClientId)); |
|
197 |
|
198 //here we need to cancel all activities originating aClientId (except the current one) |
|
199 __ASSERT_DEBUG(!client->RecipientId().IsNull(), User::Panic(KSpecAssert_ElemMeshMachNodC, 1)); |
|
200 AbortActivitiesOriginatedBy(aContext, client->RecipientId()); |
|
201 |
|
202 ANodeBase::RemoveClient(foundAt); |
|
203 if (aContext.iSender == aClientId) |
|
204 { |
|
205 aContext.iPeer = NULL; |
|
206 } |
|
207 } |
|
208 |
|
209 EXPORT_C CNodeActivityBase* AMMNodeBase::FindActivityById(TUint aActivityId) const |
|
210 { |
|
211 CNodeActivityBase* a = NULL; |
|
212 for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--) |
|
213 { |
|
214 CNodeActivityBase* comp = iActivities[i]; |
|
215 if (!comp->IsIdle() && comp->ActivityId() == aActivityId) |
|
216 { |
|
217 a = comp; |
|
218 } |
|
219 } |
|
220 return a; |
|
221 } |
|
222 |
|
223 EXPORT_C CNodeActivityBase* AMMNodeBase::FindAddressedActivity(const TNodeContextBase& aContext) const |
|
224 { |
|
225 const TNodeCtxId* recipient = address_cast<const TNodeCtxId>(&aContext.iRecipient); |
|
226 if (recipient==NULL) |
|
227 { |
|
228 return NULL; |
|
229 } |
|
230 |
|
231 CNodeActivityBase* a = NULL; |
|
232 for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--) |
|
233 { |
|
234 CNodeActivityBase* act = iActivities[i]; |
|
235 const TNodeId& postedTo = act->iPostedToId; |
|
236 if (!act->IsIdle() |
|
237 && (postedTo.IsNull() || aContext.iSender == postedTo) |
|
238 && (recipient->NodeCtx() == act->ActivityId())) |
|
239 { |
|
240 a = act; |
|
241 } |
|
242 } |
|
243 return a; |
|
244 } |
|
245 |
|
246 EXPORT_C void AMMNodeBase::Received(const TNodeSignal::TMessageId aNoPeerMsgIds[], TNodeContextBase& aContext) |
|
247 { |
|
248 aContext.iReturn = KErrNone; //Clear the return value. |
|
249 CNodeActivityBase* sendersActivity = NULL; |
|
250 if (!Accept(aContext, sendersActivity) && aContext.iReturn == KErrNone ) |
|
251 {//start new ones? but only if we know who sent a message or if it's a noPeer message |
|
252 //or if it's us sending message to ourselves |
|
253 |
|
254 //is it a message that must have a peer |
|
255 TBool noPeer = EFalse; |
|
256 for (const TNodeSignal::TMessageId* p = &aNoPeerMsgIds[0] ; !p->IsNull() ; ++p) |
|
257 { |
|
258 noPeer = (*p == aContext.iMessage.MessageId()); |
|
259 if (noPeer) |
|
260 { |
|
261 break; |
|
262 } |
|
263 } |
|
264 if (noPeer || aContext.IsPeer() || aContext.IsSelf()) |
|
265 { |
|
266 //At this stage we are about to add the peer to the activiy originators. |
|
267 //For all "peer requests" we must ensure the peer is in the client's list. |
|
268 //If this assertion fires, your environment is critically corrupted. |
|
269 //You must repair it by reconsidering your protocols. |
|
270 __ASSERT_ALWAYS(noPeer || aContext.iPeer!=NULL, User::Panic(KMMNodePanic, EPanicOriginatorIsNotAPeer)); |
|
271 TRAP(aContext.iReturn, StartNewActivitiesL(aContext, sendersActivity)); |
|
272 } |
|
273 else |
|
274 { |
|
275 //unknown sender => ignore the message |
|
276 NM_LOG_ADDRESS_EXT(KMeshMachineSubTag, aContext.iSender, _L8("AMMNodeBase:\tReceived() - Unknown sender. Message must have a peer => ignoring message")); |
|
277 } |
|
278 } |
|
279 else |
|
280 { |
|
281 __ASSERT_DEBUG(aContext.iMessage.MessageId().IsNull() || aContext.iReturn != KErrNone, User::Panic(KSpecAssert_ElemMeshMachNodC, 2)); //message must be processed |
|
282 } |
|
283 } |
|
284 |
|
285 EXPORT_C void AMMNodeBase::HandlePassThroughMessage(TNodeContextBase& aContext) |
|
286 { |
|
287 if (aContext.iMessage.IsMessage<TEBase::TCancel>()) |
|
288 { |
|
289 ASSERT(aContext.iNodeActivity == NULL); //by definition, since nobody accepted this; |
|
290 TInt originatorIndex = KErrNotFound; |
|
291 //Please note: |
|
292 //The same originator must not attempt to start more than one activities on the same node |
|
293 //(so there is only ever one activity on the node with the originator == that this TCancel is addressed to)! |
|
294 //In general one originator (identified by a unique channel id) must never originate more |
|
295 //than one activities at all. |
|
296 for (TInt i = 0; i < iActivities.Count(); i++) |
|
297 { |
|
298 if ((originatorIndex = iActivities[i]->FindOriginator(aContext.iSender)) != KErrNotFound) |
|
299 { |
|
300 aContext.iNodeActivity = iActivities[i]; |
|
301 break; |
|
302 } |
|
303 } |
|
304 |
|
305 if (aContext.iNodeActivity) |
|
306 { |
|
307 ASSERT(originatorIndex != KErrNotFound); |
|
308 if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator |
|
309 { |
|
310 aContext.iNodeActivity->Cancel(aContext); |
|
311 } |
|
312 else |
|
313 { |
|
314 // just tell this originator that we've stopped with respect to it.. otherwise keep running |
|
315 TEBase::TError err(TEBase::TCancel::Id(), KErrCancel); |
|
316 aContext.PostToSender(err); |
|
317 aContext.iNodeActivity->RemoveOriginator(originatorIndex); |
|
318 } |
|
319 } |
|
320 } |
|
321 else if (aContext.iReturn==KErrNone && !aContext.iMessage.MessageId().IsNull()) |
|
322 { //this is the pass-through message, forward to ..... |
|
323 //Find the activity being addressed, if any |
|
324 aContext.iNodeActivity = FindAddressedActivity(aContext); |
|
325 if (aContext.iNodeActivity) |
|
326 { //Peer message, forward to originators |
|
327 //aContext.iSender = Id(); |
|
328 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")); |
|
329 aContext.iNodeActivity->PostToOriginators(aContext.iMessage); |
|
330 if (aContext.iMessage.IsMessage<TEBase::TError>()) |
|
331 { |
|
332 //An activity received an error=>remove it from active array |
|
333 //This scenario will usually happen when there is no error activity on the node, |
|
334 //or when the error activity decides not to handle this particular error. |
|
335 aContext.iNodeActivity->SetIdle(); |
|
336 } |
|
337 aContext.iMessage.ClearMessageId(); |
|
338 } |
|
339 else |
|
340 { //A stray message |
|
341 //Please note that we should not implement forwarding for non-response messages here. |
|
342 //Any non-response message that needs forwarding should use TMessageDispatcher or other |
|
343 //supported mechanisms. |
|
344 NM_LOG_MESSAGE_EXT(KMeshMachineSubTag, aContext.iMessage, _L8("ERROR: AMMNodeBase::HandlePassThroughMessage - A stray message received!")); |
|
345 } |
|
346 } |
|
347 } |
|
348 |
|
349 |
|
350 EXPORT_C void AMMNodeBase::HandleMessageReturnValue(TNodeContextBase& aContext) |
|
351 { |
|
352 if (aContext.iReturn != KErrNone) |
|
353 { |
|
354 //keep the original activity in case no aCurrentActivity |
|
355 if(aContext.iNodeActivity && aContext.iNodeActivity->iOriginators.Count() > 0) |
|
356 { |
|
357 aContext.iNodeActivity->SetError(aContext.iReturn); |
|
358 // Mark the activity for destruction |
|
359 // When the activity is destroyed the Originators will be errored |
|
360 aContext.iNodeActivity->SetIdle(); |
|
361 } |
|
362 |
|
363 // Check to see if the node was unable to handle an error (e.g., an error recovery activity failed to start |
|
364 // because there was insufficient memory). If so, we manually error the activity and set it to idle causing |
|
365 // its originators to be errored. This is the most we can do if an error activity cannot be run. |
|
366 else if(aContext.iMessage.IsMessage<TEBase::TError>()) |
|
367 { |
|
368 CNodeActivityBase* activity = FindAddressedActivity(aContext); |
|
369 if(activity) |
|
370 { |
|
371 activity->SetError(static_cast<TEBase::TError&>(aContext.iMessage).iValue); |
|
372 // Mark the activity for destruction |
|
373 // When the activity is destroyed the Originators will be errored |
|
374 activity->SetIdle(); |
|
375 } |
|
376 } |
|
377 |
|
378 else |
|
379 { //No activity == single triple activity or an error from the first transition, so use the sender's message id. |
|
380 TEBase::TError err(aContext.iMessage.MessageId(), aContext.iReturn); |
|
381 aContext.PostToSender(err); |
|
382 } |
|
383 aContext.iReturn = KErrNone; |
|
384 aContext.iMessage.ClearMessageId(); |
|
385 } |
|
386 } |
|
387 |
|
388 |
|
389 //N.B. This function may delete the object pointed to by aCurrentActivity. |
|
390 //So don't use it after this function is called. |
|
391 //Also, it may delete the node itself, so don't use it after this function is called. |
|
392 EXPORT_C void AMMNodeBase::PostReceived(TNodeContextBase& aContext) |
|
393 { |
|
394 HandleMessageReturnValue(aContext); |
|
395 HandlePassThroughMessage(aContext); |
|
396 SignalActivities(); |
|
397 } |
|
398 |
|
399 void AMMNodeBase::SignalActivities() |
|
400 { |
|
401 TBool awoke = ETrue; |
|
402 TInt c = iActivities.Count(); |
|
403 TNodeNullContext context(*this); |
|
404 //Clean up.. |
|
405 while (awoke && c > 0) |
|
406 { |
|
407 awoke = EFalse; |
|
408 for (TInt i = c - 1 ; i>=0 ; --i) |
|
409 { |
|
410 //Signal to waiting activities if: |
|
411 //1) an event was received (& the state has potentialy changed as a result) |
|
412 //- remember that an activity does not have to get idle as a result of processing an event which changes the state!!!! |
|
413 //2) another waiting activity awoke == reacted to the signal (& the state has potentialy changed as a result) |
|
414 //If any signalled activity reacted, the state could change and all other activities need to be signalled again. |
|
415 context.iNodeActivity = iActivities[i]; |
|
416 awoke |= context.iNodeActivity->Signal(context); |
|
417 if(context.iNodeActivity->IsIdle()) |
|
418 { |
|
419 iActivities.Remove(i); |
|
420 context.iNodeActivity->Destroy(); |
|
421 context.iNodeActivity = NULL; |
|
422 // NOTE: if "aContext.iNodeActivity" is the destroy activity, then deleting |
|
423 // it will destroy the node (i.e. "this") as well, so don't put anything after this line ! |
|
424 if (c == 1) |
|
425 { |
|
426 // c == 1 means that we've just removed the last activity (also means i will be zero) |
|
427 // i == 0 means that this round of signalling parked activities has been completed |
|
428 // This is effectively safeguarding the access to iActivities which may or may not be |
|
429 // there (based on the note above). The destroy activity will always be placed at the |
|
430 // head of the list, and will therefore be the last to get processed. |
|
431 return; |
|
432 } |
|
433 } |
|
434 } |
|
435 c = iActivities.Count(); |
|
436 } |
|
437 } |
|
438 |
|
439 EXPORT_C void AMMNodeBase::AbortActivitiesOriginatedBy(TNodeContextBase& aContext, const TNodeId& aCommsId, TBool aIsNodeBeingDestroyed) |
|
440 { |
|
441 CNodeActivityBase* caller = aContext.iNodeActivity; |
|
442 TBool abortAll = aCommsId.IsNull(); |
|
443 |
|
444 for (TInt i = iActivities.Count() - 1; i>=0; i--) |
|
445 { |
|
446 aContext.iNodeActivity = iActivities[i]; |
|
447 if (caller != aContext.iNodeActivity) |
|
448 { |
|
449 if (abortAll) |
|
450 { |
|
451 //Abort the whole activity (Cancel it & error all originators) |
|
452 aContext.iNodeActivity->Abort(aContext,aIsNodeBeingDestroyed); |
|
453 } |
|
454 else |
|
455 { |
|
456 //Abort for one originator only (Cancel the activity if last originator & error just this one originator) |
|
457 TInt idx = aContext.iNodeActivity->FindOriginator(aCommsId); |
|
458 if (KErrNotFound!=idx) |
|
459 { |
|
460 if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator |
|
461 { |
|
462 aContext.iNodeActivity->SetError(KErrAbort); |
|
463 aContext.iNodeActivity->Cancel(aContext); |
|
464 } |
|
465 |
|
466 |
|
467 //In the "quiet mode", when the hosting node is being destroyed, we can not afford sending |
|
468 //an error to the node as it would hit void. |
|
469 TNodePeerId& originator = aContext.iNodeActivity->iOriginators[idx]; |
|
470 TBool canSend = !((aIsNodeBeingDestroyed && originator == aContext.NodeId()) |
|
471 || aContext.iMessage.IsMessage<TEChild::TLeft>()); |
|
472 if (canSend) |
|
473 { |
|
474 aContext.iNodeActivity->PostToOriginator(originator, TEBase::TError(aContext.iMessage.MessageId(), KErrAbort).CRef()); |
|
475 } |
|
476 |
|
477 |
|
478 aContext.iNodeActivity->RemoveOriginator(idx); |
|
479 } |
|
480 } |
|
481 } |
|
482 } |
|
483 aContext.iReturn = KErrNone; |
|
484 aContext.iNodeActivity = caller; |
|
485 } |
|
486 |
|
487 //This fn finds the (first) activity that has an originator matching that passed in |
|
488 EXPORT_C CNodeActivityBase* AMMNodeBase::FindActivityOriginatedBy(const TRuntimeCtxId& aPeerId) |
|
489 { |
|
490 for (TInt i = 0; i < iActivities.Count(); i++) |
|
491 { |
|
492 CNodeActivityBase* a = iActivities[i]; |
|
493 if (!a->IsIdle() |
|
494 && a->FindOriginator(aPeerId) != KErrNotFound) |
|
495 { |
|
496 return a; |
|
497 } |
|
498 } |
|
499 return NULL; |
|
500 } |
|
501 |
|
502 TBool AMMNodeBase::Accept(TNodeContextBase& aContext, CNodeActivityBase*& aFoundActivity) |
|
503 { |
|
504 // NM_LOG_MESSAGE_EXT(KMeshMachineSubTag, aContext.iMessage, _L8("AMMNodeBase:\tAccept")); |
|
505 |
|
506 //process the existing ones |
|
507 for (TInt i = 0; i < iActivities.Count(); i++) |
|
508 { |
|
509 CNodeActivityBase* a = aContext.iNodeActivity = iActivities[i]; |
|
510 if(a->Next(aContext)) |
|
511 { |
|
512 if (KErrNone == aContext.iReturn) |
|
513 { |
|
514 aContext.iMessage.ClearMessageId(); // message processed and value no longer needed |
|
515 } |
|
516 |
|
517 // If state went idle, aFoundActivity will be deleted later by PostReceived, |
|
518 // this gives us a chance to report error to originators if necessary. |
|
519 aFoundActivity = a; |
|
520 return ETrue; |
|
521 } |
|
522 |
|
523 if (a->FindOriginator(aContext.iSender) != KErrNotFound) |
|
524 { |
|
525 aFoundActivity = a; |
|
526 } |
|
527 } |
|
528 return EFalse; |
|
529 } |
|
530 |
|
531 void AMMNodeBase::StartNewActivitiesL(TNodeContextBase& aContext, CNodeActivityBase* aSendersActivity) |
|
532 { |
|
533 //new activity can only be started if the senders channel hasn't started any yet |
|
534 //but we need to check so that we can return an error |
|
535 TNodeActivityIter activityIter(iActivityMap); |
|
536 |
|
537 const TNodeActivity* activity; |
|
538 while (NULL!=(activity = activityIter++) && aContext.iReturn == KErrNone) |
|
539 { |
|
540 const TStateTriple* first; |
|
541 aContext.iNodeActivity = NULL; |
|
542 TInt i = iActivities.Count(); |
|
543 while (i>0 && !aContext.iNodeActivity) |
|
544 { |
|
545 if (activity->iId == iActivities[--i]->ActivityId()) |
|
546 { |
|
547 aContext.iNodeActivity = iActivities[i]; |
|
548 } |
|
549 } |
|
550 |
|
551 if ( (first = CNodeActivityBase::Accept( aContext, |
|
552 *activity, NetStateMachine::KExecuteAlways)) != NULL ) |
|
553 { //we do need to have a state here to go to otherwise we assume it is an activity |
|
554 //with one triple only |
|
555 if ((first+1)->iTCtor != NULL) |
|
556 { |
|
557 //is it any of the existing ones? |
|
558 if (aContext.iNodeActivity) |
|
559 { |
|
560 __ASSERT_DEBUG(aSendersActivity == NULL || aSendersActivity == aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachNodC, 3)); |
|
561 if (aSendersActivity == NULL) |
|
562 { |
|
563 XNodePeerId originator(aContext.iSender, aContext.iPeer); |
|
564 aContext.iNodeActivity->StartL(aContext, originator, *first); |
|
565 } |
|
566 } |
|
567 else |
|
568 { |
|
569 |
|
570 #ifdef SYMBIAN_TRACE_ENABLE |
|
571 if (aSendersActivity) |
|
572 { |
|
573 //The sender is already running an activity on this node. |
|
574 //There is no definitive reason why to disallow starting of a next one, |
|
575 //it is however a sign that something _may_ be going horribly wrong. |
|
576 |
|
577 //Usually, this is the case when the same originator sends several requests without |
|
578 //caring of the order in which they are going to be completed and the possibility of |
|
579 //cancelling them (there exist no way of targetting TCancel to more than one activity). |
|
580 |
|
581 //Also, an error activity may be starting and producing this warning (but please note that |
|
582 //error activity has no originators). |
|
583 |
|
584 //Please also see note in CNodeActivityBase::Next()! |
|
585 MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("WARNING: AMMNodeBase:\tStartNewActivitiesL - sender is starting an extra activity - TCancel will not work!")); |
|
586 TInt i = iActivities.Count(); |
|
587 MESH_LOG((KMeshMachineSubTag, _L8("\tThe sender has already started %d activities:"), i)); |
|
588 while (i>0) |
|
589 { |
|
590 if (iActivities[--i]->FindOriginator(aContext.iSender) >= 0) |
|
591 { |
|
592 MESH_LOG((KMeshMachineSubTag, _L8("\t(%08x) %s (%d)"), aSendersActivity, aSendersActivity->ActivityName(), aSendersActivity->ActivityId())); |
|
593 } |
|
594 } |
|
595 } |
|
596 #endif |
|
597 //create a new one then |
|
598 TRAPD(err, StartActivityL(aContext, *activity, *first)); |
|
599 if(err!=KErrNone) |
|
600 { |
|
601 MESH_LOG((KMeshMachineSubTag, |
|
602 _L8("ERROR: AMMNodeBase %08x:\tStartNewActivitiesL - Activity failed to start due to error %d!"), |
|
603 this, err)); |
|
604 |
|
605 User::Leave(err); |
|
606 } |
|
607 } |
|
608 } |
|
609 aContext.iMessage.ClearMessageId(); //message processed |
|
610 break;//only one activity can start since we have one activity per |
|
611 //channelId. (ChannelId == CommsId + activityId) |
|
612 } |
|
613 } |
|
614 } |
|
615 |
|
616 void AMMNodeBase::StartActivityL(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, const NetStateMachine::TStateTriple& aFirst) |
|
617 { |
|
618 CNodeActivityBase* a = aActivitySig.iCtor(aActivitySig,*this); |
|
619 if (iActivities.Find(a)==KErrNotFound) |
|
620 { |
|
621 //The activity did not add itself to the list in any special way, append it here |
|
622 CleanupStack::PushL(a); |
|
623 a->AppendActivityL(); |
|
624 CleanupStack::Pop(a); |
|
625 } |
|
626 //assign only after the activity is successfully appended |
|
627 aContext.iNodeActivity = a; |
|
628 |
|
629 //if StartL leaves the "a" will be removed from the array and deleted in ::PostReceived |
|
630 //since it will be idle |
|
631 XNodePeerId originator(aContext.iSender, aContext.iPeer); |
|
632 a->StartL(aContext, originator, aFirst); |
|
633 } |
|
634 |
|
635 void AMMNodeBase::PreallocateSpaceL(TUint aSize) |
|
636 { |
|
637 __ASSERT_DEBUG(aSize>0, User::Panic(KSpecAssert_ElemMeshMachNodC, 4)); |
|
638 // Reserve extra space for the maximum number of preallocated activities supported by this node |
|
639 // to ensure they can be added to the activities list while the system is out of memory. We also |
|
640 // add enough space for extra data strucures to store the free list - the caller cannot reserve this |
|
641 // space without knowledge of the preallocation implementation so we do this ourselves. |
|
642 TUint maxPreallocatedActivities = aSize / KMaxPreallocatedActivitySize; |
|
643 iActivities.ReserveL(iActivities.Count() + maxPreallocatedActivities); |
|
644 __ASSERT_DEBUG(iPreallocatedSpace==NULL, User::Panic(KSpecAssert_ElemMeshMachNodC, 5)); |
|
645 iPreallocatedSpace = User::AllocZL(aSize + sizeof(TUint) + maxPreallocatedActivities * sizeof(TAny*)); |
|
646 *reinterpret_cast<TUint*>(iPreallocatedSpace) = maxPreallocatedActivities; |
|
647 } |
|
648 |
|
649 TUint AMMNodeBase::MaxPreallocatedActivityCount() const |
|
650 { |
|
651 // Maximum number of activities that can be preallocated is stored at the beginning of the buffer. |
|
652 if(iPreallocatedSpace) |
|
653 { |
|
654 return *reinterpret_cast<TUint*>(iPreallocatedSpace); |
|
655 } |
|
656 return 0; |
|
657 } |
|
658 |
|
659 TAny* AMMNodeBase::GetPreallocatedCell(TUint aIndex) const |
|
660 { |
|
661 // Calculate the offset of the start of the preallocated space after the free list. |
|
662 TUint8* bufferStart = reinterpret_cast<TUint8*>(iPreallocatedSpace) + sizeof(TUint*) + MaxPreallocatedActivityCount() * sizeof(TAny*); |
|
663 |
|
664 return bufferStart + aIndex * KMaxPreallocatedActivitySize; |
|
665 } |
|
666 |
|
667 TAny* AMMNodeBase::BorrowPreallocatedSpace(TUint aSize) |
|
668 { |
|
669 MESH_LOG((KMeshMachineSubTag, _L8("AMMNodeBase %08x:\tBorrowPreallocatedSpace (%d)"),this,aSize)); |
|
670 |
|
671 __ASSERT_ALWAYS(iPreallocatedSpace, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken)); |
|
672 __ASSERT_ALWAYS(aSize <= KMaxPreallocatedActivitySize, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken)); |
|
673 |
|
674 #ifdef SYMBIAN_TRACE_ENABLE |
|
675 if(!iPreallocatedSpace) |
|
676 { |
|
677 MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tBorrowPreallocatedSpace - Preallocated space has not been allocated!"), this)); |
|
678 } |
|
679 if(aSize>KMaxPreallocatedActivitySize) |
|
680 { |
|
681 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)); |
|
682 } |
|
683 #endif |
|
684 |
|
685 TAny* ptr = NULL; |
|
686 TUint maxPreallocatedActivities = MaxPreallocatedActivityCount(); |
|
687 TAny** freeList = reinterpret_cast<TAny**>(reinterpret_cast<TUint8*>(iPreallocatedSpace) + sizeof(TUint)); |
|
688 TUint index = 0; |
|
689 |
|
690 // Search the free list to see if any space is available. |
|
691 for(; index < maxPreallocatedActivities; index ++) |
|
692 { |
|
693 if(!freeList[index]) |
|
694 { |
|
695 // This cell is now allocated to the calling activity. |
|
696 ptr = freeList[index] = GetPreallocatedCell(index); |
|
697 |
|
698 // Zero the cell so that any object allocated will have the expected initial zero fill. |
|
699 memset(ptr, 0, KMaxPreallocatedActivitySize); |
|
700 |
|
701 break; |
|
702 } |
|
703 } |
|
704 |
|
705 // Check to make sure a free cell was found. |
|
706 bool freeCellFound = index < maxPreallocatedActivities; |
|
707 if(!freeCellFound) |
|
708 { |
|
709 MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tBorrowPreallocatedSpace - All %d preallocation cells have been allocated!"), this, maxPreallocatedActivities)); |
|
710 __ASSERT_ALWAYS(freeCellFound, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken)); |
|
711 } |
|
712 |
|
713 return ptr; |
|
714 } |
|
715 |
|
716 void AMMNodeBase::ReturnPreallocatedSpace(TAny* aSpace) |
|
717 { |
|
718 MESH_LOG((KMeshMachineSubTag, _L8("AMMNodeBase %08x:\tReturnPreallocatedSpace"), this)); |
|
719 |
|
720 TUint maxPreallocatedActivities = MaxPreallocatedActivityCount(); |
|
721 TAny** freeList = reinterpret_cast<TAny**>(reinterpret_cast<TUint8*>(iPreallocatedSpace) + sizeof(TUint)); |
|
722 TUint index = 0; |
|
723 |
|
724 // Search the free list to return the cell. |
|
725 for(; index < maxPreallocatedActivities; index ++) |
|
726 { |
|
727 if(freeList[index] == aSpace) |
|
728 { |
|
729 // Mark this cell as free. |
|
730 freeList[index] = NULL; |
|
731 |
|
732 break; |
|
733 } |
|
734 } |
|
735 |
|
736 bool allocatedCellFound = index < maxPreallocatedActivities; |
|
737 if(!allocatedCellFound) |
|
738 { |
|
739 MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tReturnPreallocatedSpace - the returned pointer 0x%08X is invalid!"), this, aSpace)); |
|
740 __ASSERT_DEBUG(allocatedCellFound, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceReturnedOther)); |
|
741 } |
|
742 } |
|
743 |
|
744 |
|
745 //-========================================================= |
|
746 // |
|
747 //AMMNodeIdBase |
|
748 // |
|
749 //-========================================================= |
|
750 EXPORT_C const TNodeId& AMMNodeIdBase::NodeId() const |
|
751 { |
|
752 return Messages::ANodeId::Id(); |
|
753 } |
|
754 |
|
755 //-========================================================= |
|
756 // |
|
757 //XNodePeerId |
|
758 // |
|
759 //-========================================================= |
|
760 EXPORT_C XNodePeerId::XNodePeerId(const TRuntimeCtxId& aPeerId, RNodeInterface* aPeer, CBase* aInfo) |
|
761 : TNodePeerId(aPeerId, aPeer), |
|
762 iInfo(aInfo) |
|
763 { |
|
764 } |
|
765 |
|
766 EXPORT_C void XNodePeerId::Destroy() |
|
767 { |
|
768 delete iInfo; |
|
769 iInfo = NULL; |
|
770 } |
|
771 |
|
772 |