23 #include <elements/mm_context_internal.h> |
23 #include <elements/mm_context_internal.h> |
24 #include <elements/mm_log.h> |
24 #include <elements/mm_log.h> |
25 |
25 |
26 #include <elements/nm_messages_base.h> |
26 #include <elements/nm_messages_base.h> |
27 #include <elements/nm_messages_child.h> |
27 #include <elements/nm_messages_child.h> |
28 |
|
29 |
28 |
30 #ifdef _DEBUG |
29 #ifdef _DEBUG |
31 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module |
30 // 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) |
31 // (if it could happen through user error then you should give it an explicit, documented, category + code) |
33 _LIT(KSpecAssert_ElemMeshMachNodC, "ElemMeshMachNodC"); |
32 _LIT(KSpecAssert_ElemMeshMachNodC, "ElemMeshMachNodC"); |
230 |
229 |
231 CNodeActivityBase* a = NULL; |
230 CNodeActivityBase* a = NULL; |
232 for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--) |
231 for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--) |
233 { |
232 { |
234 CNodeActivityBase* act = iActivities[i]; |
233 CNodeActivityBase* act = iActivities[i]; |
235 const TNodeId& postedTo = act->iPostedToId; |
234 const TNodeId& postedTo = act->PostedToNodeId(); |
236 if (!act->IsIdle() |
235 if (!act->IsIdle() |
237 && (postedTo.IsNull() || aContext.iSender == postedTo) |
236 && (postedTo.IsNull() || aContext.iSender == postedTo) |
238 && (recipient->NodeCtx() == act->ActivityId())) |
237 && (recipient->NodeCtx() == act->ActivityId())) |
239 { |
238 { |
240 a = act; |
239 a = act; |
428 context.iNodeActivity = NULL; |
427 context.iNodeActivity = NULL; |
429 } |
428 } |
430 } |
429 } |
431 } |
430 } |
432 |
431 |
|
432 |
433 EXPORT_C void AMMNodeBase::AbortActivitiesOriginatedBy(TNodeContextBase& aContext, const TNodeId& aCommsId, TBool aIsNodeBeingDestroyed) |
433 EXPORT_C void AMMNodeBase::AbortActivitiesOriginatedBy(TNodeContextBase& aContext, const TNodeId& aCommsId, TBool aIsNodeBeingDestroyed) |
434 { |
434 { |
435 CNodeActivityBase* caller = aContext.iNodeActivity; |
435 CNodeActivityBase* caller = aContext.iNodeActivity; |
436 TBool abortAll = aCommsId.IsNull(); |
436 TBool abortAll = aCommsId.IsNull(); |
437 |
437 |
438 for (TInt i = iActivities.Count() - 1; i>=0; i--) |
438 for (TInt i = iActivities.Count() - 1; i>=0; i--) |
439 { |
439 { |
440 aContext.iNodeActivity = iActivities[i]; |
440 aContext.iNodeActivity = iActivities[i]; |
|
441 |
|
442 if (!abortAll && aContext.iNodeActivity->PostedToNodeId() == aCommsId) |
|
443 {//clear postedto if a leaver has been set as a postedto at any of the running activities. |
|
444 //No other messages will ever come from the leaver and it is not gonna be safe to forward TCancels |
|
445 //to the leaver, so at least postedto must be cleared to avoid the crash. It could be speculated that |
|
446 //if the postedto is still set, then either the postedto node failed to respond or the local activity failed to |
|
447 //clear postedto when it had responded. Worth putting a speculative ASSERT here to catch misdeeds. |
|
448 |
|
449 //clearing postedto shouldn't be done in here (AbortActivitiesOriginatedBy), but I (RZ) have expressed my disrespect to the |
|
450 //this method before and the suggestion that it should go (replaced by a CancelActivitiesOriginatedBy). |
|
451 //So instead of introducing another method that loops through activities i decided to piggyback the function in an |
|
452 //existing method. Note that the final logic should be based on RNodeInterfaces and not TNodeIds. |
|
453 aContext.iNodeActivity->ClearPostedTo(); |
|
454 } |
441 |
455 |
442 // We dont want to abort already idle activities or they may error. |
456 // We dont want to abort already idle activities or they may error. |
443 if(aContext.iNodeActivity->IsIdle()) |
457 if(aContext.iNodeActivity->IsIdle()) |
444 { |
458 { |
445 continue; |
459 continue; |
456 { |
470 { |
457 //Abort for one originator only (Cancel the activity if last originator & error just this one originator) |
471 //Abort for one originator only (Cancel the activity if last originator & error just this one originator) |
458 TInt idx = aContext.iNodeActivity->FindOriginator(aCommsId); |
472 TInt idx = aContext.iNodeActivity->FindOriginator(aCommsId); |
459 if (KErrNotFound!=idx) |
473 if (KErrNotFound!=idx) |
460 { |
474 { |
|
475 TBool canSend = ETrue; |
461 if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator |
476 if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator |
462 { |
477 { |
463 aContext.iNodeActivity->SetError(KErrAbort); |
478 aContext.iNodeActivity->SetError(KErrAbort); |
464 aContext.iNodeActivity->Cancel(aContext); |
479 aContext.iNodeActivity->Cancel(aContext); |
|
480 //This is a workaround for CCommsBinderRequest. The proper fix is to abolish the concept of aborting activities. |
|
481 //Aborting activities is a bad idea as an aborted activity isn't given a chance to perform graceful cleanup. |
|
482 //Today activities get aborted because their orinators urgently leave. I.e.: they are trully leaving now! Last orders! |
|
483 //It is then incorrect to leave the activity d'tor to finish the wrap up - because the node will be gone by then. |
|
484 //So whether and when to send an error must be decided here, by this generic code that has no clue on the subtleties |
|
485 //of individual activities. If there is no abort - there is urgent leavers. They send TLeaveRequest and they politely |
|
486 //wait for the completion and all this code is unnecessary. |
|
487 canSend = (aContext.iNodeActivity->Error() != KErrNone); |
465 } |
488 } |
466 |
489 |
467 |
|
468 //In the "quiet mode", when the hosting node is being destroyed, we can not afford sending |
490 //In the "quiet mode", when the hosting node is being destroyed, we can not afford sending |
469 //an error to the node as it would hit void. |
491 //an error to the node as it would hit void. |
470 TNodePeerId& originator = aContext.iNodeActivity->iOriginators[idx]; |
492 TNodePeerId& originator = aContext.iNodeActivity->iOriginators[idx]; |
471 TBool canSend = !((aIsNodeBeingDestroyed && originator == aContext.NodeId()) |
493 canSend &= !((aIsNodeBeingDestroyed && originator == aContext.NodeId()) |
472 || aContext.iMessage.IsMessage<TEChild::TLeft>()); |
494 || aContext.iMessage.IsMessage<TEChild::TLeft>()); |
473 if (canSend) |
495 if (canSend) |
474 { |
496 { |
475 aContext.iNodeActivity->PostToOriginator(originator, TEBase::TError(aContext.iMessage.MessageId(), KErrAbort).CRef()); |
497 aContext.iNodeActivity->PostToOriginator(originator, TEBase::TError(aContext.iMessage.MessageId(), KErrAbort).CRef()); |
476 } |
498 } |
477 |
499 aContext.iNodeActivity->RemoveOriginator(idx); |
478 |
|
479 aContext.iNodeActivity->RemoveOriginator(idx); |
|
480 } |
500 } |
481 } |
501 } |
482 } |
502 } |
483 } |
503 } |
484 aContext.iReturn = KErrNone; |
504 aContext.iReturn = KErrNone; |
614 } |
634 } |
615 } |
635 } |
616 |
636 |
617 void AMMNodeBase::StartActivityL(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, const NetStateMachine::TStateTriple& aFirst) |
637 void AMMNodeBase::StartActivityL(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, const NetStateMachine::TStateTriple& aFirst) |
618 { |
638 { |
619 CNodeActivityBase* a = aActivitySig.iCtor(aActivitySig,*this); |
639 CNodeActivityBase* nodeActivity; |
620 if (iActivities.Find(a)==KErrNotFound) |
640 // Activity is based on one of 2 declarations. One of which has an extra member. In the case of the instance |
|
641 // with a second member the activities Ctor will point to this second member. Since the first member is a TNodeActivity |
|
642 // We can compare the activities Ctor pointer to the address of the second member to assess which type of declarations |
|
643 // this is. |
|
644 |
|
645 if (aActivitySig.iFlags & TNodeActivity::EContextCtor) |
|
646 { // TNodeActivity's iCtor is a pointer to Activity Ctor |
|
647 nodeActivity = ((TNodeActivity::TStaticActivityContextCtor)aActivitySig.iCtor)(aActivitySig,aContext); |
|
648 } |
|
649 else |
|
650 { // TNodeActivity's iCtor is a pointer to activity constructor |
|
651 nodeActivity = ((TNodeActivity::TStaticActivityCtor)aActivitySig.iCtor)(aActivitySig,*this); |
|
652 } |
|
653 |
|
654 if (iActivities.Find(nodeActivity)==KErrNotFound) |
621 { |
655 { |
622 //The activity did not add itself to the list in any special way, append it here |
656 //The activity did not add itself to the list in any special way, append it here |
623 CleanupStack::PushL(a); |
657 CleanupStack::PushL(nodeActivity); |
624 a->AppendActivityL(); |
658 nodeActivity->AppendActivityL(); |
625 CleanupStack::Pop(a); |
659 CleanupStack::Pop(nodeActivity); |
626 } |
660 } |
|
661 |
627 //assign only after the activity is successfully appended |
662 //assign only after the activity is successfully appended |
628 aContext.iNodeActivity = a; |
663 aContext.iNodeActivity = nodeActivity; |
629 |
664 |
630 //if StartL leaves the "a" will be removed from the array and deleted in ::PostReceived |
665 //if StartL leaves the "a" will be removed from the array and deleted in ::PostReceived |
631 //since it will be idle |
666 //since it will be idle |
632 XNodePeerId originator(aContext.iSender, aContext.iPeer); |
667 XNodePeerId originator(aContext.iSender, aContext.iPeer); |
633 a->StartL(aContext, originator, aFirst); |
668 nodeActivity->StartL(aContext, originator, aFirst); |
634 } |
669 } |
635 |
670 |
636 void AMMNodeBase::PreallocateSpaceL(TUint aSize) |
671 void AMMNodeBase::PreallocateSpaceL(TUint aSize) |
637 { |
672 { |
638 __ASSERT_DEBUG(aSize>0, User::Panic(KSpecAssert_ElemMeshMachNodC, 4)); |
673 __ASSERT_DEBUG(aSize>0, User::Panic(KSpecAssert_ElemMeshMachNodC, 4)); |