|
1 // Copyright (c) 2007-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_activities.h" |
|
21 #include <elements/mm_context.h> |
|
22 #include <elements/mm_states.h> |
|
23 #include <elements/nm_messages_base.h> |
|
24 #include <elements/nm_messages_child.h> |
|
25 #include <elements/nm_messages_errorrecovery.h> |
|
26 |
|
27 |
|
28 #ifdef _DEBUG |
|
29 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module |
|
30 // (if it could happen through user error then you should give it an explicit, documented, category + code) |
|
31 _LIT(KSpecAssert_ElemMeshMachActC, "ElemMeshMachActC"); |
|
32 #endif |
|
33 |
|
34 using namespace MeshMachine; |
|
35 using namespace Messages; |
|
36 using namespace Elements; |
|
37 using namespace NetStateMachine; |
|
38 |
|
39 //-========================================================= |
|
40 // |
|
41 //Panics |
|
42 // |
|
43 //-========================================================= |
|
44 _LIT (KMMActivityPanic,"MMActivityPanic"); |
|
45 enum |
|
46 { |
|
47 EPanicCorruptedContext = 1, |
|
48 EPanicNoPreallocatedSpace = 2 |
|
49 }; |
|
50 |
|
51 //-========================================================= |
|
52 // |
|
53 //TNodeActivityIter |
|
54 // |
|
55 //-========================================================= |
|
56 const TNodeActivity* TNodeActivityIter::FetchActivity() |
|
57 { |
|
58 const TNodeActivity* a = NULL; |
|
59 if (*iCurrentEntry) |
|
60 { |
|
61 a = &(*iCurrentEntry)(); |
|
62 ++iCurrentEntry; |
|
63 } |
|
64 else |
|
65 { |
|
66 if (NULL!=*(iCurrentEntry+1)) |
|
67 { |
|
68 const TNodeActivityMap::TStaticNodeActivityMap& nextMapFn = (const TNodeActivityMap::TStaticNodeActivityMap&)*(iCurrentEntry+1); |
|
69 iCurrentEntry = &nextMapFn().iFirstActivity; |
|
70 a = FetchActivity(); |
|
71 } |
|
72 } |
|
73 return a; |
|
74 } |
|
75 |
|
76 //-========================================================= |
|
77 // |
|
78 //CNodeActivityBase |
|
79 // |
|
80 //-========================================================= |
|
81 EXPORT_C CNodeActivityBase* CNodeActivityBase::NewL(const TNodeActivity& aActivitySig, AMMNodeBase& aNode) |
|
82 { |
|
83 return new(ELeave)CNodeActivityBase(aActivitySig, aNode); |
|
84 } |
|
85 |
|
86 EXPORT_C CNodeActivityBase::CNodeActivityBase(const TNodeActivity& aActivitySig, AMMNodeBase& aNode) |
|
87 : iNode(aNode), |
|
88 iActivitySig(aActivitySig) |
|
89 { |
|
90 } |
|
91 |
|
92 EXPORT_C CNodeActivityBase::~CNodeActivityBase() |
|
93 { |
|
94 if(iError != KErrNone) |
|
95 { |
|
96 PostToOriginators(TEBase::TError(KickOffMessageId(), iError).CRef()); |
|
97 } |
|
98 |
|
99 //If an activity constructed custom originator's interfaces, now it needs to clean them up |
|
100 for (TInt i = iOriginators.Count() - 1; i >= 0; --i) |
|
101 { |
|
102 RemoveOriginator(i); |
|
103 } |
|
104 |
|
105 iOriginators.Close(); |
|
106 } |
|
107 |
|
108 EXPORT_C NetInterfaces::TInterfaceControl* CNodeActivityBase::DoFetchInterfaceControlL(TInt /*aInterfaceId*/) |
|
109 /** Allows to fetch an arbitrary interface instance from the client |
|
110 |
|
111 @internalTechnology |
|
112 */ |
|
113 { |
|
114 return this; //as a base we assume are the control for any interface any derivative may implement |
|
115 } |
|
116 |
|
117 //static |
|
118 const TStateTriple* CNodeActivityBase::Accept(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, TInt aTransitionTag) |
|
119 { |
|
120 const TStateTriple& first = aActivitySig.iFirstTriple; |
|
121 |
|
122 //in debug only(!) check if we are in the first triple as expected |
|
123 __ASSERT_DEBUG((&first-1)->iSCtor==NULL && (&first-1)->iTCtor==NULL, User::Panic(KSpecAssert_ElemMeshMachActC, 1)); |
|
124 |
|
125 TBool accept = (aActivitySig.iKickOffMessageId == KNullMessageId |
|
126 || (aActivitySig.iKickOffMessageId == aContext.iMessage.MessageId().MessageId() && |
|
127 aActivitySig.iKickOffMessageRealm == aContext.iMessage.MessageId().Realm()) |
|
128 ) |
|
129 && NetStateMachine::ACore::Accept(first, &aContext, aTransitionTag); |
|
130 |
|
131 //if the activity accepted the message and the first triple has a transition, we execute it here |
|
132 //NOTE that the first transition is called BEFORE the originator (sender of the message) |
|
133 //is added to the activity list |
|
134 if (accept && first.iTCtor) |
|
135 { |
|
136 TBuf8<KMaxStateClassByteSize> mem; |
|
137 ACore::Do(first,&aContext,mem); |
|
138 MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase:\tAccept->first transition [ANode=0x%08x] [Activity=%s] [Triple=%s]"), |
|
139 &aContext.NodeId().Node(), aActivitySig.iName ? aActivitySig.iName : _S8("Undefined"), first.iName? first.iName : _S8("Undefined"))); |
|
140 } |
|
141 |
|
142 if (accept && aContext.iReturn == KErrNone) |
|
143 { |
|
144 // MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase:\tAccept->accepted"))); |
|
145 return &first; |
|
146 } |
|
147 return NULL; |
|
148 } |
|
149 |
|
150 EXPORT_C void CNodeActivityBase::StartL(TNodeContextBase& aContext, const XNodePeerId& aOriginator, const TStateTriple& aFirst) |
|
151 { |
|
152 __ASSERT_DEBUG(FindOriginator(aOriginator) == KErrNotFound, User::Panic(KSpecAssert_ElemMeshMachActC, 2)); |
|
153 iOriginators.AppendL(aOriginator); |
|
154 |
|
155 MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext, (_L8("CNodeActivityBase %08x:\tStartL->starting activity"), this)); |
|
156 if (IsIdle()) |
|
157 { |
|
158 NetStateMachine::ACore::Start(&aContext, aFirst); |
|
159 MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext, (_L8("CNodeActivityBase %08x:\tStartL->activity started"), this)); |
|
160 } |
|
161 } |
|
162 |
|
163 EXPORT_C TBool CNodeActivityBase::MatchSender(const TNodeContextBase& aContext) const |
|
164 { |
|
165 //The role of this method is to filter out all messages that 'this' should |
|
166 //not be bothered with. 'this' should be interested in messages coming from |
|
167 //what's set as iPostedToId or from one of the orginators. |
|
168 //if the message's recipient specifies the activity id, then that |
|
169 //activity must much that of 'this'. |
|
170 TBool sender = iPostedToId.IsNull() || |
|
171 aContext.iSender == iPostedToId || |
|
172 FindOriginator(aContext.iSender) != KErrNotFound; |
|
173 const TNodeCtxId* recipient = address_cast<const TNodeCtxId>(&aContext.iRecipient); |
|
174 TBool activity = (recipient == NULL || ActivityId() == recipient->NodeCtx()); |
|
175 |
|
176 #ifdef SYMBIAN_TRACE_ENABLE |
|
177 //If didn't match, trace why. |
|
178 if (!(sender && activity)) |
|
179 { |
|
180 NM_LOG_START_BLOCK(KMeshMachineSubTag, _L8("CNodeActivityBase::MatchSender")); |
|
181 if(!sender) |
|
182 { |
|
183 MESH_LOG((KMeshMachineSubTag(), _L8("CNodeActivityBase %08x:\tiPostedToId mismatch:"), this)); |
|
184 NM_LOG_ADDRESS(KMeshMachineSubTag(), iPostedToId); |
|
185 NM_LOG_ADDRESS(KMeshMachineSubTag(), aContext.iSender); |
|
186 MESH_LOG((KMeshMachineSubTag(), _L8("CNodeActivityBase %08x:\toriginators' mismatch:"), this)); |
|
187 for (TInt i = iOriginators.Count() - 1; i>=0; i--) |
|
188 { |
|
189 NM_LOG_ADDRESS(KMeshMachineSubTag(), iOriginators[i].RecipientId()); |
|
190 } |
|
191 } |
|
192 if(!activity) |
|
193 { |
|
194 MESH_LOG((KMeshMachineSubTag(), _L8("CNodeActivityBase %08x:\tactivity mismatch [ours 0x%x, recipient 0x%x]"), this, ActivityId(), recipient->NodeCtx())); |
|
195 } |
|
196 NM_LOG_END_BLOCK(KMeshMachineSubTag(), KNullDesC8()); |
|
197 } |
|
198 #endif |
|
199 |
|
200 return sender && activity; |
|
201 } |
|
202 |
|
203 //static |
|
204 EXPORT_C TAny* CNodeActivityBase::BorrowPreallocatedSpace(AMMNodeBase& aNode, TUint aSize) |
|
205 { |
|
206 return aNode.BorrowPreallocatedSpace(aSize); |
|
207 } |
|
208 |
|
209 EXPORT_C void CNodeActivityBase::ReturnPreallocatedSpace(TAny* aSpace) |
|
210 { |
|
211 return iNode.ReturnPreallocatedSpace(aSpace); |
|
212 } |
|
213 |
|
214 EXPORT_C void CNodeActivityBase::AppendActivityL() |
|
215 { |
|
216 //Based on the fact that there can ever be only one preallocated activity active at a time |
|
217 //it is sufficient to always maintain one reserved space in the activity array. |
|
218 //NOTE: ReserveL() will not cause table expansion when the already allocated space is |
|
219 //big enough to hold the new count = the array will not grow indefinietly. |
|
220 iNode.iActivities.ReserveL(iNode.iActivities.Count() + iNode.MaxPreallocatedActivityCount() + 1); //Reserve for additional + potential preallocated) |
|
221 |
|
222 //Can not fail now |
|
223 __ASSERT_ALWAYS(iNode.iActivities.Append(this) == KErrNone, User::Panic(KMMActivityPanic, EPanicNoPreallocatedSpace)); |
|
224 } |
|
225 |
|
226 EXPORT_C void CNodeActivityBase::AppendPreallocatedActivity() |
|
227 { |
|
228 //Can not fail now |
|
229 __ASSERT_ALWAYS(iNode.iActivities.Append(this) == KErrNone, User::Panic(KMMActivityPanic, EPanicNoPreallocatedSpace)); |
|
230 } |
|
231 |
|
232 EXPORT_C void CNodeActivityBase::InsertPreallocatedDestroyActivity() |
|
233 { |
|
234 //Can not fail now |
|
235 __ASSERT_ALWAYS(iNode.iActivities.Insert(this, 0) == KErrNone, User::Panic(KMMActivityPanic, EPanicNoPreallocatedSpace)); |
|
236 } |
|
237 |
|
238 EXPORT_C TInt CNodeActivityBase::FindOriginator(const RNodeInterface& aPeerToFind) const |
|
239 { |
|
240 for (TInt i = iOriginators.Count() - 1; i>=0; i--) |
|
241 { |
|
242 //When you see a panic here this is probably because your originator |
|
243 //stopped being a peer and this node failed to remove it from the activity originator's list. |
|
244 if (iOriginators[i] == aPeerToFind.RecipientId()) |
|
245 { |
|
246 return i; |
|
247 } |
|
248 } |
|
249 return KErrNotFound; |
|
250 } |
|
251 |
|
252 EXPORT_C TInt CNodeActivityBase::FindOriginator(const TRuntimeCtxId& aPeerToFind) const |
|
253 { |
|
254 for (TInt i = iOriginators.Count() - 1; i>=0; i--) |
|
255 { |
|
256 //When you see a panic here this is probably because your originator |
|
257 //stopped being a peer and this node failed to remove it from the activity originator's list. |
|
258 if (iOriginators[i] == aPeerToFind) |
|
259 { |
|
260 return i; |
|
261 } |
|
262 } |
|
263 return KErrNotFound; |
|
264 } |
|
265 |
|
266 EXPORT_C TInt CNodeActivityBase::FindOriginator(const TNodePeerId& aOriginator) const |
|
267 { |
|
268 for (TInt i = iOriginators.Count() - 1; i>=0; i--) |
|
269 { |
|
270 //When you see a panic here this is probably because your originator |
|
271 //stopped being a peer and this node failed to remove it from the activity originator's list. |
|
272 if (iOriginators[i] == aOriginator) |
|
273 { |
|
274 return i; |
|
275 } |
|
276 } |
|
277 return KErrNotFound; |
|
278 } |
|
279 |
|
280 EXPORT_C TUint16 CNodeActivityBase::ActivityId() const |
|
281 { |
|
282 return ActivitySigId(); |
|
283 } |
|
284 |
|
285 //You should use this function to remove originators to prevent memory leaking! |
|
286 EXPORT_C void CNodeActivityBase::RemoveOriginator(TInt aIndex) |
|
287 { |
|
288 __ASSERT_DEBUG(aIndex>=0 && aIndex<iOriginators.Count(), User::Panic(KSpecAssert_ElemMeshMachActC, 3)); |
|
289 iOriginators[aIndex].Destroy(); |
|
290 iOriginators.Remove(aIndex); |
|
291 } |
|
292 |
|
293 EXPORT_C void CNodeActivityBase::SetIdle() |
|
294 { |
|
295 MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase %08x:\tSetIdle"), this)); |
|
296 NetStateMachine::ACore::SetIdle(); |
|
297 } |
|
298 |
|
299 EXPORT_C TBool CNodeActivityBase::Next(TNodeContextBase& aContext) |
|
300 { |
|
301 TBool nextRet = EFalse; |
|
302 //Check if this is the same id we have recently sent to |
|
303 TBool senderMatch = MatchSender(aContext); |
|
304 MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext, |
|
305 (senderMatch ? _L8("CNodeActivityBase %08x:\tNext->match") : _L8("CNodeActivityBase %08x:\tNext->NO match"), this)); |
|
306 |
|
307 if (senderMatch) |
|
308 { |
|
309 nextRet = ACore::Next(&aContext); |
|
310 if(nextRet) |
|
311 { |
|
312 MESH_LOG_ACTIVITY_EXT(KMeshMachineSubTag, this, &aContext, (_L8("CNodeActivityBase %08x:\tNext->transition"), this)); |
|
313 } |
|
314 } |
|
315 return nextRet; |
|
316 } |
|
317 |
|
318 EXPORT_C void CNodeActivityBase::Cancel(TNodeContextBase& aContext) |
|
319 {//we expect KErrCancel be set as a result of the state cancelation |
|
320 MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase %08x:\tCancel(), iPostedToId %08x"), this, iPostedToId.Ptr() ? &iPostedToId.Node() : NULL)); |
|
321 |
|
322 if (!iPostedToId.IsNull()) |
|
323 { |
|
324 RClientInterface::OpenPostMessageClose(TNodeCtxId(ActivityId(), iNode.Id()), iPostedToId, TEBase::TCancel().CRef()); |
|
325 } |
|
326 else |
|
327 { |
|
328 NetStateMachine::ACore::Cancel(&aContext); |
|
329 } |
|
330 SetError(KErrCancel); |
|
331 } |
|
332 |
|
333 EXPORT_C TBool CNodeActivityBase::PostToOriginator(const TNodePeerId& aOriginator, const TSignalBase& aMessage) const |
|
334 { |
|
335 if (!(aOriginator.Flags() & TClientType::ELeaving)) |
|
336 { |
|
337 aOriginator.PostMessage(TNodeCtxId(ActivityId(), iNode.Id()), aMessage); |
|
338 } |
|
339 else |
|
340 { |
|
341 MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase:\tPostToOriginator - IGNORING POST!"))); |
|
342 return EFalse; |
|
343 } |
|
344 return ETrue; |
|
345 } |
|
346 |
|
347 EXPORT_C TInt CNodeActivityBase::PostToOriginators(const TSignalBase& aMessage, TUint32 aFlagsToSet, TUint32 aFlagsToClear) |
|
348 { |
|
349 TInt msgSendCount=0; |
|
350 for (TInt n = iOriginators.Count() - 1;n>=0; n--) |
|
351 { |
|
352 if (PostToOriginator(iOriginators[n], aMessage)) |
|
353 { |
|
354 ++msgSendCount; |
|
355 iOriginators[n].Peer().SetFlags(aFlagsToSet); |
|
356 iOriginators[n].Peer().ClearFlags(aFlagsToClear); |
|
357 }; |
|
358 } |
|
359 return msgSendCount; |
|
360 } |
|
361 |
|
362 EXPORT_C void CNodeActivityBase::SetPostedTo(const TNodeId& aNodeId) |
|
363 { |
|
364 iPostedToId = aNodeId; |
|
365 } |
|
366 |
|
367 EXPORT_C void CNodeActivityBase::ClearPostedTo() |
|
368 { |
|
369 iPostedToId.SetNull(); |
|
370 } |
|
371 |
|
372 EXPORT_C void CNodeActivityBase::PostRequestTo(const RNodeInterface& aRecipient, const TSignalBase& aMessage, const TBool aRecipientIdCritical) |
|
373 { |
|
374 aRecipient.PostMessage(TNodeCtxId(ActivityId(), iNode.Id()), aMessage); |
|
375 |
|
376 // Provide the option for the identity of the receipient to be unimportant when the response arrives |
|
377 iPostedToId = aRecipientIdCritical ? aRecipient.RecipientId() : TNodeId::NullId(); |
|
378 } |
|
379 |
|
380 //Avoid using this function, always prefer PostRequestTo(const RNodeInterface& aRecipient, const TNodeSignal& aMessage) |
|
381 EXPORT_C void CNodeActivityBase::PostRequestTo(const TNodeId& aRecipient, const TSignalBase& aMessage, const TBool aRecipientIdCritical) |
|
382 { |
|
383 RClientInterface::OpenPostMessageClose(TNodeCtxId(ActivityId(), iNode.Id()), aRecipient, aMessage); |
|
384 |
|
385 // Provide the option for the identity of the receipient to be unimportant when the response arrives |
|
386 iPostedToId = aRecipientIdCritical ? aRecipient : TNodeId::NullId(); |
|
387 } |
|
388 |
|
389 EXPORT_C TBool CNodeActivityBase::IsIdle() const |
|
390 { |
|
391 return NetStateMachine::ACore::IsIdle(); |
|
392 } |
|
393 |
|
394 EXPORT_C void CNodeActivityBase::Abort(TNodeContextBase& aContext, TBool aIsNodeBeingDestroyed) |
|
395 { |
|
396 MESH_LOG((KMeshMachineSubTag, _L8("CNodeActivityBase %08x:\tAbort"), this)); |
|
397 |
|
398 //the error message will be send by message post processing see AMMNodeBase::Received |
|
399 aContext.iReturn = KErrAbort; //before so as the error could be overwritten |
|
400 NetStateMachine::ACore::Cancel(&aContext); |
|
401 if (aContext.iReturn != KErrNone) |
|
402 { |
|
403 TEBase::TError error(aContext.iMessage.MessageId(), aContext.iReturn); |
|
404 for (TInt n = iOriginators.Count() - 1;n>=0; n--) |
|
405 { |
|
406 TNodePeerId& originator = iOriginators[n]; |
|
407 //In the "quiet mode", when the hosting node is being destroyed, we can not afford sending |
|
408 //an error to the node as it would hit void. |
|
409 TBool canSend = !((aIsNodeBeingDestroyed && originator == aContext.NodeId()) |
|
410 || aContext.iMessage.IsMessage<TEChild::TLeft>()); |
|
411 if (canSend) |
|
412 { |
|
413 PostToOriginator(originator, error); |
|
414 } |
|
415 RemoveOriginator(n); //Do not allow ~CNodeActivityBase to post as client's might be already gone |
|
416 } |
|
417 } |
|
418 } |
|
419 |
|
420 //-========================================================= |
|
421 // |
|
422 //CNodeRetryActivity |
|
423 // |
|
424 //-========================================================= |
|
425 EXPORT_C CNodeRetryActivity::CNodeRetryActivity( const TNodeActivity& aActivitySig, AMMNodeBase& aNode ) |
|
426 : CNodeActivityBase(aActivitySig, aNode), |
|
427 TIfStaticFetcherNearestInHierarchy(this) |
|
428 { |
|
429 } |
|
430 |
|
431 EXPORT_C CNodeActivityBase* CNodeRetryActivity::NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode ) |
|
432 { |
|
433 return new(ELeave)CNodeRetryActivity(aActivitySig, aNode); |
|
434 } |
|
435 |
|
436 EXPORT_C TBool CNodeRetryActivity::IsIdle() const |
|
437 { |
|
438 return !IsWaiting() && CNodeActivityBase::IsIdle(); |
|
439 } |
|
440 |
|
441 EXPORT_C void CNodeRetryActivity::SetIdle() |
|
442 { |
|
443 iContextDesc.Close(); |
|
444 ClearIsWaiting(); |
|
445 ClearWillWait(); //Set this too in case this fn was invoked from within the serialised state ot transition |
|
446 CNodeActivityBase::SetIdle(); |
|
447 } |
|
448 |
|
449 EXPORT_C TBool CNodeRetryActivity::Signal(TNodeContextBase& aContext) |
|
450 { |
|
451 return AActivitySemaphore::Signal(aContext); |
|
452 } |
|
453 |
|
454 EXPORT_C void CNodeRetryActivity::ReturnInterfacePtrL(AContextStore*& aInterface) |
|
455 { |
|
456 aInterface = this; |
|
457 } |
|
458 |
|
459 EXPORT_C void CNodeRetryActivity::ReturnInterfacePtrL(AActivitySemaphore*& aInterface) |
|
460 { |
|
461 aInterface = this; |
|
462 } |
|
463 |
|
464 //-========================================================= |
|
465 // |
|
466 //CNodeParallelActivityBase |
|
467 // |
|
468 //-========================================================= |
|
469 // For custom activities to implement NewL |
|
470 EXPORT_C TUint CNodeParallelActivityBase::GetNextActivityCountL( const TNodeActivity& aActivitySig, const AMMNodeBase& aNode ) |
|
471 { |
|
472 TInt c = 1, i = 0; |
|
473 |
|
474 const RPointerArray<CNodeActivityBase>& activities = aNode.Activities(); |
|
475 RArray<TInt> activityids; |
|
476 CleanupClosePushL(activityids); |
|
477 |
|
478 // collect the currently used ids |
|
479 for (TInt i = 0; i < activities.Count(); i++) |
|
480 { |
|
481 TInt16 id = activities[i]->ActivityId(); |
|
482 if ((id&0xff) == aActivitySig.iId) |
|
483 { |
|
484 TInt8 uniqueid = id >> 8; |
|
485 activityids.InsertInOrderL(uniqueid); |
|
486 } |
|
487 } |
|
488 |
|
489 // find first available. |
|
490 while (i < activityids.Count() |
|
491 && activityids[i] == c) |
|
492 { |
|
493 ++i; |
|
494 ++c; |
|
495 } |
|
496 CleanupStack::PopAndDestroy(&activityids); |
|
497 |
|
498 if(c > KActivityParallelRangeMax>>8) |
|
499 { |
|
500 User::Leave(KErrInUse); |
|
501 } |
|
502 return c; |
|
503 } |
|
504 |
|
505 EXPORT_C CNodeActivityBase* CNodeParallelActivityBase::NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode ) |
|
506 { |
|
507 TUint c = GetNextActivityCountL(aActivitySig,aNode); |
|
508 return new(ELeave)CNodeParallelActivityBase(aActivitySig, aNode, c); |
|
509 } |
|
510 |
|
511 EXPORT_C CNodeParallelActivityBase::CNodeParallelActivityBase(const TNodeActivity& aActivitySig, AMMNodeBase& aNode, TUint aNextActivityCount) |
|
512 : CNodeActivityBase(aActivitySig, aNode), |
|
513 iActivityId((aNextActivityCount<<8)|aActivitySig.iId) |
|
514 { |
|
515 } |
|
516 |
|
517 EXPORT_C TUint16 CNodeParallelActivityBase::ActivityId() const |
|
518 { |
|
519 return iActivityId; |
|
520 } |
|
521 |
|
522 |
|
523 //-========================================================= |
|
524 // |
|
525 //CNodeParallelMessageStoreActivityBase |
|
526 // |
|
527 //-========================================================= |
|
528 EXPORT_C CNodeActivityBase* CNodeParallelMessageStoreActivityBase::NewL( const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode ) |
|
529 { |
|
530 TUint c = GetNextActivityCountL(aActivitySig,aNode); |
|
531 return new (ELeave) CNodeParallelMessageStoreActivityBase( aActivitySig, aNode, c); |
|
532 } |
|
533 |
|
534 EXPORT_C CNodeParallelMessageStoreActivityBase::~CNodeParallelMessageStoreActivityBase() |
|
535 { |
|
536 } |
|
537 |
|
538 EXPORT_C Messages::TSignalBase& CNodeParallelMessageStoreActivityBase::Message() |
|
539 { |
|
540 ASSERT(iMsg); |
|
541 return *iMsg; |
|
542 } |
|
543 |
|
544 EXPORT_C void CNodeParallelMessageStoreActivityBase::StartL(TNodeContextBase& aContext, const Messages::XNodePeerId& aOriginator, const NetStateMachine::TStateTriple& aFirst) |
|
545 { |
|
546 SaveMessageL(aContext.iMessage); |
|
547 CNodeParallelActivityBase::StartL(aContext, aOriginator, aFirst); |
|
548 } |
|
549 |
|
550 void CNodeParallelMessageStoreActivityBase::SaveMessageL(Messages::TSignalBase& aMessage) |
|
551 { |
|
552 Meta::CMetaDataVirtualCtorInPlace* vctr = TlsGlobals::Get().VirtualCtor(); |
|
553 TPtrC8 ptr(iMsgBuf); |
|
554 iMsg = static_cast<TSignalBase*>(vctr->New(aMessage.GetTypeId(), iMsgBuf)); |
|
555 if (iMsg == NULL) |
|
556 { |
|
557 User::Leave(KErrNotFound); |
|
558 } |
|
559 |
|
560 iMsg->Copy(aMessage); |
|
561 } |
|
562 |
|
563 EXPORT_C CNodeParallelMessageStoreActivityBase::CNodeParallelMessageStoreActivityBase( const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode, TUint aNextActivityCount ) |
|
564 : CNodeParallelActivityBase(aActivitySig, aNode, aNextActivityCount), iMsg(NULL) |
|
565 { |
|
566 } |
|
567 |
|
568 //-========================================================= |
|
569 // |
|
570 //CNodeRetryParallelActivity |
|
571 // |
|
572 //-========================================================= |
|
573 EXPORT_C CNodeRetryParallelActivity::CNodeRetryParallelActivity( const TNodeActivity& aActivitySig, AMMNodeBase& aNode, TUint aActivitiesCount ) |
|
574 : CNodeParallelActivityBase(aActivitySig, aNode, aActivitiesCount), |
|
575 TIfStaticFetcherNearestInHierarchy(this) |
|
576 { |
|
577 } |
|
578 |
|
579 EXPORT_C CNodeActivityBase* CNodeRetryParallelActivity::NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode ) |
|
580 { |
|
581 TUint c = GetNextActivityCountL(aActivitySig,aNode); |
|
582 return new(ELeave)CNodeRetryParallelActivity(aActivitySig, aNode, c); |
|
583 } |
|
584 |
|
585 EXPORT_C TBool CNodeRetryParallelActivity::IsIdle() const |
|
586 { |
|
587 return !IsWaiting() && CNodeActivityBase::IsIdle(); |
|
588 } |
|
589 |
|
590 EXPORT_C void CNodeRetryParallelActivity::SetIdle() |
|
591 { |
|
592 iContextDesc.Close(); |
|
593 ClearIsWaiting(); |
|
594 ClearWillWait(); //Set this too in case this fn was invoked from within the serialised state ot transition |
|
595 CNodeActivityBase::SetIdle(); |
|
596 } |
|
597 |
|
598 EXPORT_C TBool CNodeRetryParallelActivity::Signal(TNodeContextBase& aContext) |
|
599 { |
|
600 return AActivitySemaphore::Signal(aContext); |
|
601 } |
|
602 |
|
603 EXPORT_C void CNodeRetryParallelActivity::ReturnInterfacePtrL(AContextStore*& aInterface) |
|
604 { |
|
605 aInterface = this; |
|
606 } |
|
607 |
|
608 EXPORT_C void CNodeRetryParallelActivity::ReturnInterfacePtrL(AActivitySemaphore*& aInterface) |
|
609 { |
|
610 aInterface = this; |
|
611 } |
|
612 |
|
613 //-========================================================= |
|
614 // |
|
615 //AContextStore |
|
616 // |
|
617 //-========================================================= |
|
618 EXPORT_C TInt AContextStore::StoreContext(const TNodeContextBase& aContext) |
|
619 {//doesn't actually store TNodeContextBase only the message since it assumes |
|
620 //that the transition context is the |
|
621 //template <class TNODE, class TDerivedContext = TNodeContextBase> |
|
622 //struct TNodeContext : public TDerivedContext |
|
623 //where TDerivedContext = TNodeContextBase is always TNodeContextBase |
|
624 //another type of context is not needed because all custom needs should be sorted by custom |
|
625 //activity class |
|
626 TInt error = KErrNone; |
|
627 TInt len = TRuntimeCtxId::KMaxInlineAddressSize + aContext.iMessage.Length(); |
|
628 if (iContextDesc.MaxLength() < len) |
|
629 { |
|
630 iContextDesc.Close(); |
|
631 error = iContextDesc.Create(len); |
|
632 } |
|
633 else |
|
634 { |
|
635 iContextDesc.Zero(); |
|
636 } |
|
637 if (KErrNone==error) |
|
638 { |
|
639 error = aContext.iSender.Store(iContextDesc); //would catch if iContextDesc has been allocated properly |
|
640 } |
|
641 if (KErrNone==error) |
|
642 { |
|
643 error = aContext.iMessage.Store(iContextDesc); //would catch if iContextDesc has been allocated properly |
|
644 } |
|
645 return error; |
|
646 } |
|
647 |
|
648 EXPORT_C TNodeContextBase* AContextStore::LoadContext(AMMNodeBase& aNode, CNodeActivityBase* aNodeActivity, TDes8& aCtxBuff, TDes8& aMsgBuff, const TNodeId& aDummy) |
|
649 { |
|
650 if (iContextDesc.Length() < sizeof(TNodeId)) |
|
651 { |
|
652 return NULL; |
|
653 } |
|
654 |
|
655 const TRuntimeCtxId* sender = reinterpret_cast<const TRuntimeCtxId*>(iContextDesc.Ptr()); |
|
656 TPtrC8 contextStore(iContextDesc.Ptr()+sender->Size(),iContextDesc.Length()-sender->Size()); |
|
657 TSignatureBase* msg = static_cast<TSignatureBase*>(TlsGlobals::Get().VirtualCtor()->New(contextStore, aMsgBuff)); |
|
658 if (!msg) |
|
659 { |
|
660 return NULL; |
|
661 } |
|
662 |
|
663 //This assumes (as CNodeActivityBase::StoreContext) that the transition context is the |
|
664 //template <class TNODE, class TDerivedContext = TNodeContextBase> |
|
665 //struct TNodeContext : public TDerivedContext |
|
666 //where TDerivedContext = TNodeContextBase is always TNodeContextBase. |
|
667 //another type of context is not needed because all custom needs should be sorted by custom |
|
668 //activity class |
|
669 __ASSERT_DEBUG(aNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 4)); |
|
670 return ::new ((TUint8*)aCtxBuff.Ptr()) TNodeContextBase(aNode, *msg, *sender, aDummy, aNodeActivity); |
|
671 } |
|
672 |
|
673 EXPORT_C TBool AContextStore::IsStored() const |
|
674 { |
|
675 return iContextDesc.Length() >= sizeof(TNodeId); |
|
676 } |
|
677 |
|
678 // Needs to be moved to error-recoverable activity class |
|
679 EXPORT_C const TNodeSignal::TMessageId& AContextStore::RetryingForMessageId() const |
|
680 { |
|
681 return iRetryingForMessageId; |
|
682 } |
|
683 |
|
684 //Called only ever from ReceivedL |
|
685 EXPORT_C void AContextStore::Retry(CNodeActivityBase& aActivity, TNodeContextBase& aContext) |
|
686 { |
|
687 TBuf8<__Align8(sizeof(TNodeContextBase))> ctxBuf; |
|
688 TBuf8<__Align8(TSignalBase::KMaxInlineMessageSize + TSignalBase::KMaxUnstoredOverhead)> msgBuf; |
|
689 TNodeContextBase* storedContext = LoadContext(aContext.iNode, &aActivity,ctxBuf, msgBuf, aContext.NodeId()); |
|
690 |
|
691 //If we are here the context has been stored. There is no reason why it could not be loaded now. |
|
692 //The only reason would be that the message factory was unregistered since the context was stored |
|
693 //which is a critical condition. |
|
694 __ASSERT_ALWAYS(storedContext, User::Panic(KMMActivityPanic,EPanicCorruptedContext)); |
|
695 |
|
696 TEErrorRecovery::TErrorRecoveryResponse& msg = message_cast<TEErrorRecovery::TErrorRecoveryResponse>(aContext.iMessage); |
|
697 iRetryingForMessageId = msg.iErrResponse.iMessageId; |
|
698 aActivity.ACore::DoCurrent(storedContext); |
|
699 aContext.Node().HandleMessageReturnValue(*storedContext); |
|
700 iContextDesc.Zero(); |
|
701 } |
|
702 |
|
703 //-========================================================= |
|
704 // |
|
705 //AActivitySemaphore |
|
706 // |
|
707 //-========================================================= |
|
708 EXPORT_C void AActivitySemaphore::ParkTransitionL(const TNodeContextBase& aContext) |
|
709 { |
|
710 __ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 5)); |
|
711 AActivitySemaphore* as = static_cast<AActivitySemaphore*>(aContext.iNodeActivity->FetchExtInterfaceL(AActivitySemaphore::KInterfaceId)); |
|
712 if (!as->IsWaiting()) |
|
713 { |
|
714 User::LeaveIfError(as->StoreContext(aContext)); |
|
715 |
|
716 //The context has been stored along with the message. Must consume the message, otherwise |
|
717 //it will fall through and be seen by other activities or passthrough handling. |
|
718 aContext.iMessage.ClearMessageId(); |
|
719 |
|
720 as->SetIsWaiting(); |
|
721 as->SetIsTransition(); |
|
722 MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("AActivitySemaphore:\tParkTransitionL->parked")); |
|
723 } |
|
724 as->SetWillWait(); |
|
725 __ASSERT_DEBUG(as->IsWaiting(), User::Panic(KSpecAssert_ElemMeshMachActC, 6)); //Must be stored and waiting now |
|
726 } |
|
727 |
|
728 EXPORT_C TInt AActivitySemaphore::ParkState(const TNodeContextBase& aContext) |
|
729 { |
|
730 __ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 7)); |
|
731 AActivitySemaphore* as = static_cast<AActivitySemaphore*>(aContext.iNodeActivity->FetchExtInterface(AActivitySemaphore::KInterfaceId)); |
|
732 __ASSERT_DEBUG(as, User::Panic(KSpecAssert_ElemMeshMachActC, 8)); //State/transition mismatched with the activity object (activity doesn't support serialisation - wrong derivation?) |
|
733 if (!as->IsWaiting()) |
|
734 { |
|
735 TInt error = as->StoreContext(aContext); |
|
736 if (error!=KErrNone) |
|
737 { |
|
738 return error; |
|
739 }; |
|
740 |
|
741 //The context has been stored along with the message. Must consume the message, otherwise |
|
742 //it will fall through and be seen by other activities or passthrough handling. |
|
743 aContext.iMessage.ClearMessageId(); |
|
744 |
|
745 as->SetIsWaiting(); |
|
746 as->ClearIsTransition(); |
|
747 MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("AActivitySemaphore:\tParkState->parked")); |
|
748 } |
|
749 as->SetWillWait(); |
|
750 __ASSERT_DEBUG(as->IsWaiting(), User::Panic(KSpecAssert_ElemMeshMachActC, 9)); //Must be stored and waiting now |
|
751 return KErrNone; |
|
752 } |
|
753 |
|
754 EXPORT_C TInt AActivitySemaphore::UnparkState(const TNodeContextBase& aContext) |
|
755 { |
|
756 __ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachActC, 10)); |
|
757 AActivitySemaphore* as = static_cast<AActivitySemaphore*>(aContext.iNodeActivity->FetchExtInterface(AActivitySemaphore::KInterfaceId)); |
|
758 __ASSERT_DEBUG(as, User::Panic(KSpecAssert_ElemMeshMachActC, 11)); //State/transition mismatched with the activity object (activity doesn't support serialisation - wrong derivation?) |
|
759 if (as->IsWaiting()) |
|
760 { |
|
761 as->ClearIsWaiting(); |
|
762 MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("AActivitySemaphore:\tUnparkState->unparked")); |
|
763 } |
|
764 as->ClearWillWait(); |
|
765 __ASSERT_DEBUG(!as->IsWaiting(), User::Panic(KSpecAssert_ElemMeshMachActC, 12)); //Must be stored and waiting now |
|
766 return KErrNone; |
|
767 } |
|
768 |
|
769 EXPORT_C void AActivitySemaphore::Wait() |
|
770 { |
|
771 MESH_LOG((KMeshMachineSubTag, _L8("AActivitySemaphore:\tWait->activity waiting"))); |
|
772 SetWillWait(); |
|
773 } |
|
774 |
|
775 EXPORT_C TBool AActivitySemaphore::Signal(TNodeContextBase& aContext) |
|
776 { |
|
777 if (!(iFlags&KIsWaiting)) |
|
778 { |
|
779 return EFalse; |
|
780 } |
|
781 |
|
782 //aContext.iNodeActivity is us |
|
783 TBuf8<__Align8(sizeof(TNodeContextBase))> ctxBuf; |
|
784 TBuf8<__Align8(TSignalBase::KMaxInlineMessageSize + TSignalBase::KMaxUnstoredOverhead)> msgBuf; |
|
785 TNodeCtxId dummy(aContext.ActivityId(), aContext.NodeId()); |
|
786 TNodeContextBase* storedContext = LoadContext(aContext.iNode,aContext.iNodeActivity,ctxBuf,msgBuf,dummy); |
|
787 if (storedContext) |
|
788 { |
|
789 ClearWillWait(); |
|
790 if (IsTransition()) |
|
791 { |
|
792 //Transition stored |
|
793 aContext.iNodeActivity->ACore::DoCurrent(storedContext); |
|
794 } |
|
795 else |
|
796 { |
|
797 //This is the state stored |
|
798 #ifdef _DEBUG |
|
799 TBool hasRun = aContext.iNodeActivity->ACore::Next(storedContext); |
|
800 __ASSERT_DEBUG(hasRun!=(iFlags & KWillWait), User::Panic(KSpecAssert_ElemMeshMachActC, 13)); |
|
801 #else |
|
802 aContext.iNodeActivity->ACore::Next(storedContext); |
|
803 #endif |
|
804 } |
|
805 |
|
806 if (!(iFlags & KWillWait)) |
|
807 { //We have been run |
|
808 ClearIsWaiting(); |
|
809 iContextDesc.Zero(); |
|
810 aContext.Node().HandleMessageReturnValue(*storedContext); |
|
811 return ETrue; |
|
812 } |
|
813 } |
|
814 |
|
815 return EFalse; |
|
816 } |
|
817 |
|
818 |