--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwsupport/commselements/rootserver/rootsrv/rootutil.cpp Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,2071 @@
+// Copyright (c) 2003-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
+ @internalComponent
+*/
+
+#include "rsstd.h"
+#include <elements/cfmacro.h>
+#include <cfmsgs.h>
+#include <cfshared.h>
+#include <cflog.h>
+#include <cfextras.h>
+#include "bindmgr.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_ElemRootServerrt, "ElemRootServerrt");
+#endif
+
+__CFLOG_STMT(_LIT8(KLogSubSysRS, "RootServer");) // subsystem name
+
+CNotifySuddenDeathContainer::CNotifySuddenDeathContainer(MNotifySuddenDeath* aNotifier):
+ iNotifier(aNotifier)
+ /** Constructor for Sudden Death notifier container
+
+ @param aNotifier The object to be notified of death
+ */
+ {
+ }
+
+void CNotifySuddenDeathContainer::Dequeue()
+ /** Dequeue
+
+ */
+ {
+ iLink.Deque();
+ }
+
+void CNotifySuddenDeathContainer::Notify(TInt aReason)
+ /** Notify of SuddenDeath
+
+ @param aReason The reason to associate with the Sudden Death event
+ */
+ {
+ iNotifier->SuddenDeath(aReason);
+ }
+
+CModuleUndertaker* CModuleUndertaker::NewL(MNotifySuddenDeath& aNotifier, RThread& aThread)
+ /** Creates new CModuleUndertaker object.
+ @param aNotifier The object to be notified of death.
+ @param aThread The thread to be monitored.
+ @return Pointer to the undertaker object.
+ */
+ {
+ CModuleUndertaker* pUndertaker = new (ELeave) CModuleUndertaker(aNotifier, aThread);
+ CActiveScheduler::Add(pUndertaker);
+ return pUndertaker;
+ }
+
+void CModuleUndertaker::Logon()
+ /** Logs on to thread.
+ Thread logon to monitor for death
+ */
+ {
+ iThread.Logon(iStatus);
+ SetActive();
+ }
+
+void CModuleUndertaker::DoCancel()
+ {
+ (void)iThread.LogonCancel(iStatus);
+ }
+
+void CModuleUndertaker::RunL()
+ /** Calls sudden death function on object registered for notification
+ */
+ {
+ LogThreadDeath();
+
+ TExitType type = iThread.ExitType();
+ TInt reason = iThread.ExitReason();
+
+ // Decide if the thread exit was expected or caused by an error.
+ if((iThread.ExitType() != EExitKill) || (reason != KErrNone))
+ {
+ // Looks like a panic or a forced kill/terminate happened to it.
+ reason = KErrRSSuddenViolentDeath;
+ }
+ else
+ {
+ reason = KErrRSSuddenDeath;
+ }
+
+ // Call the notifier.
+ iNotifier.SuddenDeath(reason);
+ }
+
+void CModuleUndertaker::LogThreadDeath()
+ {
+ #if defined _DEBUG || defined __CFLOG_ACTIVE || defined SYMBIAN_TRACE_ENABLE
+
+ RThread& deadThread = iThread;
+
+ TExitType type = deadThread.ExitType();
+ TInt reason = deadThread.ExitReason();
+
+ TName processName = RProcess().Name();
+ TPtrC processDisplayName = processName;
+ TInt pos = processName.Locate(L'[');
+ if(pos > 0)
+ {
+ // Strip off the UID and instance number.
+ processDisplayName.Set(processName.Left(pos));
+ }
+ TBuf8<KMaxName> processName8;
+ processName8.Copy(processDisplayName);
+
+ TName threadName = deadThread.Name();
+ TBuf8<KMaxName> threadName8;
+ threadName8.Copy(threadName);
+
+ TBuf8<KMaxExitCategoryName> cat8;
+ cat8.Copy(deadThread.ExitCategory());
+
+ if(type == EExitPending)
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("ERROR: CModuleUndertaker::RunL - the death of thread %S was reported but the exit type indicates that the thread is still running. The rootserver is probably in an unstable state."),
+ &threadName8);
+
+ __CF_BREAK_IF_DEBUGGER();
+ }
+ else
+ {
+ _LIT8(KExitNormalStr, "(Normal)");
+ _LIT8(KExitKillStr, "(Kill)");
+ _LIT8(KExitTerminateStr, "(Terminate)");
+ _LIT8(KExitPanicStr, "Panic:");
+
+ _LIT8(KKillNormalInfoFormatStr, "%S::%S Thread Died %S - Category: \"%S\", Reason: %d, Thread ID: %x, BTrace ID: 0x%x");
+ _LIT8(KKillCancelInfoFormatStr, "%S::%S Thread Died %S - Category: \"%S\", Reason: %d, Thread ID: %x, BTrace ID: 0x%x");
+ _LIT8(KKillErrorInfoFormatStr, "ERROR: %S::%S Thread Died %S - Category: \"%S\", Reason: %d, Thread ID: %x, BTrace ID: 0x%x");
+ _LIT8(KPanicInfoFormatStr, "ERROR: %S::%S Thread Died %S %S %d - Thread ID: %x, BTrace ID: 0x%x");
+
+ TPtrC8 type8;
+ TPtrC8 formatStr;
+
+ // Determine the reason why the thread exited and try to log as much information
+ // as possible if the exit was unexpected.
+ switch(type)
+ {
+ case EExitKill:
+ {
+ switch(reason)
+ {
+ case KErrNone:
+ type8.Set(KExitNormalStr);
+ formatStr.Set(KKillNormalInfoFormatStr);
+ break;
+ case KErrCancel:
+ type8.Set(KExitKillStr);
+ formatStr.Set(KKillCancelInfoFormatStr);
+ break;
+ default:
+ type8.Set(KExitKillStr);
+ formatStr.Set(KKillErrorInfoFormatStr);
+ break;
+ }
+ }
+ break;
+ case EExitTerminate:
+ type8.Set(KExitTerminateStr);
+ formatStr.Set(KKillErrorInfoFormatStr);
+ break;
+ case EExitPanic:
+ type8.Set(KExitPanicStr);
+ formatStr.Set(KPanicInfoFormatStr);
+ break;
+ default:
+ __ASSERT_DEBUG(false, User::Panic(KSpecAssert_ElemRootServerrt, 1)); // should never get here
+ break;
+ }
+
+ // Decide if the thread exit was expected or caused by an error.
+ #ifdef _DEBUG
+ if((deadThread.ExitType() != EExitKill) || ((reason != KErrNone) && (reason != KErrCancel)))
+ {
+ // Log unexpected thread exits to the debug port.
+ RDebug::Printf(reinterpret_cast<const char*>(formatStr.Ptr()), &processName8, &threadName8, &type8, &cat8, reason, TUint(deadThread.Id().Id()), deadThread.BTraceId());
+ }
+ #endif
+
+ // Log the thread's death to UTrace if available.
+ #ifdef SYMBIAN_TRACE_ENABLE
+ enum
+ {
+ KPrimaryFilter = 194, // server den
+ KMaxLogTextLength = 250
+ };
+
+ class TLogIgnoreOverflow8 : public TDes8Overflow
+ {
+ public:
+ void Overflow(TDes8& /*aDes*/) { }
+ };
+
+ // Format the log text into a buffer for UTrace.
+ TBuf8<KMaxLogTextLength> buf;
+ TLogIgnoreOverflow8 overflowHandler;
+ buf.AppendFormat(formatStr, &overflowHandler, &processName8, &threadName8, &type8, &cat8, reason, TUint(deadThread.Id().Id()), deadThread.BTraceId());
+
+ UTracePfAny(KPrimaryFilter, KText, ETrue, EFalse, buf.Length(), buf.Ptr(), buf.Length());
+ #endif
+
+ // Log the thread's death to CFlog if available.
+ __CFLOG_VAR((KLogSubSysRS, KLogCode, formatStr, &processName8, &threadName8, &type8, &cat8, reason, TUint(deadThread.Id().Id()), deadThread.BTraceId()));
+ }
+
+ #endif
+ }
+
+CModuleUndertaker::CModuleUndertaker(MNotifySuddenDeath& aNotifier, RThread& aThread)
+: CActive(EPriorityLow), // NB! lower priority than that of the session handlers to avoid race between undertaker & load handler
+ iNotifier(aNotifier),
+ iThread(aThread)
+ /** Constructor for ModuleUndertaker
+ */
+ {
+ }
+
+CModuleUndertaker::~CModuleUndertaker()
+ /** Destructor for ModuleUndertaker
+ */
+ {
+ Cancel();
+ }
+
+
+EXPORT_C CCommsProviderModule::CCommsProviderModule( RThread& aThread )
+ : CActive(EPriorityStandard)
+ , iState(EIdle)
+ , iThread(aThread)
+ , iNotifiers(_FOFF(CNotifySuddenDeathContainer, iLink))
+// Surplus initialisers left as documentation of intent
+//iUndertaker(NULL),
+ {}
+
+EXPORT_C CCommsProviderModule::~CCommsProviderModule()
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::~CCommsProviderModule: %S"), &iName);
+
+ iSend.Close();
+ iRecv.Close();
+
+ if(iHeapPtr)
+ {
+#if defined(SYMBIAN_C32ROOT_API_V3)
+#if !defined(ESOCKV3_TEMPORARY_PAIN_RELIEF)
+#ifdef _DEBUG
+ // If modules sharing a heap are unloaded in anything but LIFO order then
+ // they can't easily check for leaks (ie A marks heap, B loads, A unloads but
+ // doesn't check heap because it sees that someone else is using it, B unloads
+ // and doesn't check heap either. The real owner of the heap is the RootServer,
+ // so here we check the count and log leaked cells if any remain after the last
+ // user has unloaded.
+ // In _DEBUG builds we also execute a debugger breakpoint when cells remain,
+ // unless the module has been flagged as "unstable". A stable module sharing a
+ // heap with an unstable one might see this breakpoint but in general a leaky
+ // module should have a private heap to ensure cleanup.
+ RCFSharedHeap& heap = static_cast<RCFSharedHeap&>(*iHeapPtr);
+ if(heap.AccessCount() <= 2) //@todo worry more about why it's two
+ {
+ if(heap.Count() > 0)
+ {
+ __CFLOG_VAR( (KLogSubSysRSModule, KLogCode, _L8("~CCommsProviderModule: module '%S' heap(%08x) has %d cells remaining:"), &iName, &heap, heap.Count()) );
+ heap.LogAllocatedCells(KLogSubSysRSModule, KLogRSLeakTag);
+
+ // The configuration flags suppressing the panic: modules known to be unstable are not checked. These
+ // include all modules that have panicked (if they never had the chance to cleanup it isn't helpful
+ // to list "leaks")
+ const TUint32 noCheckCondition = TRSStartModuleParamContainer::KCF_UnstableModule;
+
+ // If not waivered by optional flags, call __DEBUGGER()
+ if( (iControlFlags & noCheckCondition)==0)
+ {
+ RProperty pubsub;
+ TInt res = pubsub.Attach(iRootServer->iProcessKey, iRootServer->iLeakKey.iUid);
+ //Does not leave before close therefore no need for cleanup stack
+ if (res == KErrNone)
+ {
+ TInt count;
+ res =pubsub.Get(count);
+ if (res == KErrNone)
+ {
+ ++count;
+ res =pubsub.Set(count);
+ }
+ }
+ pubsub.Close();
+ if (res != KErrNone)
+ {
+ __CFLOG_1(KLogSubSysRSModule, KLogRSLeakTag, _L8("Unable to report leaks. Error: %d"), res);
+ }
+ }
+ // As much as anything this log line is here to make it apparent that the breakpoint above was hit
+ // See the comment block above for more explanations.
+ __CFLOG_VAR( (KLogSubSysRSModule, KLogRSLeakTag, _L8("--- end of leaked cell log")) );
+ }
+ }
+#endif
+#endif
+#endif
+ iHeapPtr->Close();
+ }
+
+ if(iRootServer->FindCpm(iName))
+ {
+ iLink.Deque(); // Remove from list in Root Server
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::~CCommsProviderModule: removing %S from RS List"), &iName);
+ }
+
+ delete iUndertaker;
+
+ // Create a timer in case some other entity holds an open handle on the
+ // thread which prevents the kernel from destroying it. We timeout
+ // after one second.
+ TAutoClose<RTimer> timer;
+ if(timer.iObj.CreateLocal() == KErrNone)
+ {
+ // Ensure the thread has been destroyed by using a notification so that its unique name is available for
+ // reuse in case the module is reloaded soon afterwards.
+ TRequestStatus destructionStatus;
+ iThread.NotifyDestruction(destructionStatus);
+ iThread.Close();
+
+ enum{ KThreadDestructionTimeout = 1000000 };
+
+ TRequestStatus timerStatus;
+ timer.iObj.After(timerStatus, KThreadDestructionTimeout);
+
+ // Wait for the thread to be destroyed or for the timeout.
+ User::WaitForRequest(destructionStatus, timerStatus);
+ if(timerStatus.Int() == KRequestPending)
+ {
+ timer.iObj.Cancel();
+ User::WaitForRequest(timerStatus);
+ }
+ else
+ {
+ User::CancelMiscNotifier(destructionStatus);
+ User::WaitForRequest(destructionStatus);
+
+ __CFLOG_2(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::~CCommsProviderModule: %S thread has still not been destroyed after %fs"), &iName, KThreadDestructionTimeout / 1000.0);
+ }
+ }
+ else
+ {
+ iThread.Close();
+ }
+
+ // If a starting thread has been given the pointer then it's too dangerous to delete it here as might crash
+ // them - better to risk a small leak
+ if(iState != EStarting)
+ {
+ delete iThreadStartupInfo;
+ }
+#ifdef SYMBIAN_C32ROOT_API_V3
+ delete iIniData;
+#endif
+
+ // Remove from CActiveScheduler
+ if(IsAdded())
+ {
+ Deque();
+ }
+ // Remove from RootServer list of modules
+ if(iLink.iNext != NULL)
+ {
+ iLink.Deque();
+ }
+ }
+
+TInt CCommsProviderModule::CancelLoad()
+ /** Cancel Load. Marks whether an attempt to cancel load has happened
+ *
+ * @return KErrCancel if cancelation of the load module operation was initiated
+ * or KErrRSModuleAlreadyExist if the module's thread has started
+ * running and can no longer be canceled.
+ */
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule - CancelLoad %S"), &iName);
+
+ TInt result = KErrCancel;
+
+ // Check to see if the load module operation can be canceled or if the thread
+ // is already in the process of starting.
+ if((iState == EStarting) || (iState == ERunning))
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule - CancelLoad: %S module has already started running and can no longer be canceled"), &iName);
+
+ result = KErrRSModuleAlreadyExist;
+ }
+
+ return result;
+ }
+
+TInt CCommsProviderModule::CancelUnload(TRSUnLoadType aType)
+ /** Cancel unload. Marks whether an attempt to cancel an unload has happened
+ *
+ * @param aType The type of unload that was in progress
+ * @return KErrCancel if cancelation of the unload module operation was initiated
+ * or KErrRSModuleNotLoaded if the module's thread has started dying and
+ * can no longer be canceled.
+ */
+ {
+ #ifdef __CFLOG_ACTIVE
+ TPtrC8 unloadType = GetUnloadTypeName(aType);
+ __CFLOG_2(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule - CancelUnload: %S module has started an %S unload"), &iName, &unloadType);
+ #endif
+
+ TInt result = KErrCancel;
+
+ // Check to see if the unload module operation can be canceled or if the thread
+ // is already in the process of dying.
+ if(aType == EUnGraceful)
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule - CancelUnload: %S module has already started an EUnGraceful unload and can no longer be canceled"), &iName);
+
+ result = KErrRSModuleNotLoaded;
+ }
+ else
+ {
+ if(iState==EStopping)
+ {
+ iState=ERunning;
+ }
+ }
+
+ return result;
+ }
+
+void CCommsProviderModule::CreateThreadL()
+ /** Creates and sets up thread ready for initialisation
+ */
+ {
+ iUndertaker = CModuleUndertaker::NewL(*this, iThread);
+
+ TInt res = iLibrary.Load(iDll);
+ __CFLOG_STMT(TBuf8<KMaxFileName> fnam;)
+ __CFLOG_STMT(fnam.Copy(iDll);)
+
+
+ if (res!=KErrNone && res!=KErrAlreadyExists)
+ {
+ __CFLOG_2(KLogSubSysRS, KLogCode,
+ _L8("CModuleBase::CreateThreadL: Unable to load DLL %S: %d."),
+ &fnam, res);
+
+ User::Leave(res);
+ }
+
+ __CFLOG_1( KLogSubSysRS, KLogCode,
+ _L8("CModuleBase::CreateThreadL: Loaded module library %S."),
+ &fnam);
+
+ TUidType type = iLibrary.Type();
+ if ( ! UidMatch(type[1]) )
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,_L8("CModuleBase - UID mismatch for %S"), &fnam);
+ User::Leave(KErrRSInvalidUidType);
+ }
+
+ // If ordinal is set to 0, default to 1 (first)
+ if(iThreadFunctionOrdinal==0)
+ {
+ __CFLOG(KLogSubSysRS, KLogCode, _L8("CModuleBase - Using default ordinal: 1"));
+ iThreadFunctionOrdinal = 1;
+ }
+ __CFLOG_STMT(
+ else
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,_L8("CModuleBase - Using configured ordinal: %d"), iThreadFunctionOrdinal);
+ }
+ ); // __CFLOG_STMT
+
+ TThreadFunction libEntry=(TThreadFunction)iLibrary.Lookup(iThreadFunctionOrdinal);
+
+ if (libEntry==NULL)
+ {
+ User::Leave(KErrBadLibraryEntryPoint);
+ }
+
+ RCFChannel::TMsgQueues inputQueue;
+ RCFChannel::TMsgQueues outputQueue;
+
+ iSend.GetMsgQueues(inputQueue);
+ iRecv.GetMsgQueues(outputQueue);
+
+ iThreadStartupInfo = new(ELeave) CRSTransientModuleInfo(outputQueue, inputQueue, iHeapType, libEntry, iIniData, iPriority, iControlFlags);
+#ifdef SYMBIAN_C32ROOT_API_V3
+ iIniData = NULL; // iThreadStartupInfo now has ownership
+#endif
+
+ switch(iHeapType)
+ {
+ case EShareHeap:
+ iHeapPtr = iRootServer->FindHeap(iShareHeapWith);
+ if(iHeapPtr)
+ {
+ if(KErrNone!=iHeapPtr->Open())
+ {
+ __CFLOG(KLogSubSysRS, KLogWarning,
+ _L8("CCommsProviderModule::CreateThreadL - Couldn't open shared heap!"));
+ User::Leave(KErrRSUnableToOpenHeap); // Found the heap but couldn't open it
+ }
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::CreateThreadL: Shared heap address %x"), iHeapPtr);
+ }
+ else
+ {
+ __CFLOG(KLogSubSysRS, KLogWarning,
+ _L8("CCommsProviderModule - Couldn't find correct heap!"));
+ User::Leave(KErrRSUnableToFindHeap); // Couldn't find the required heap!
+ }
+ break;
+ case ENewHeap:
+ iHeapPtr = User::ChunkHeap(NULL,iMinHeapSize,iMaxHeapSize);
+ if(!iHeapPtr)
+ {
+ __CFLOG(KLogSubSysRS, KLogWarning,
+ _L8("CCommsProviderModule::CreateThreadL:Unable to create new heap"));
+ User::Leave(KErrRSNoNewHeapsAvailable);
+ }
+ else
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode, _L8("CCommsProviderModule::CreateThreadL: New heap address %x"), iHeapPtr);
+ }
+ break;
+ case EDefaultHeap:
+ __CFLOG(KLogSubSysRS, KLogCode, _L8("CCommsProviderModule::CreateThreadL: Using Default Heap."));
+ break; // iHeapPtr is left NULL
+ default:
+ __ASSERT_DEBUG(0, User::Panic(KSpecAssert_ElemRootServerrt, 2));
+ }
+
+ TName threadName;
+ threadName.Copy(iName);
+ res=CreateModuleThread(threadName, CRSTransientModuleInfo::ModuleThreadStartup,
+ iStackSize, iHeapPtr, iThreadStartupInfo);
+#if defined(SYMBIAN_C32ROOT_API_V3)
+#if !defined(ESOCKV3_TEMPORARY_PAIN_RELIEF)
+#if defined(C32ROOT_ALLOW_SUBSTITUTE_THREAD_NAMES)
+ // Reloading a module that has leaked a named resource will cause an already-exists
+ // error because the old thread hasn't been fully cleaned up. It can be helpful to get past
+ // this point in a debug build since if the resource in question is named it may later fail
+ // in a more specific fashion
+ if (res == KErrAlreadyExists)
+ {
+ // If not waivered by optional flags, call __DEBUGGER()
+ if( (iControlFlags & TRSStartModuleParamContainer::KCF_UnstableModule)==0)
+ {
+ __DEBUGGER();
+ }
+ TInt suffix = 0;
+ RProperty::Get(KUidSystemCategory, iRootServer->iDeathKey.iUid, suffix);
+ do
+ {
+ threadName.Copy(iName); // expand to Unicode
+ _LIT(KSubstituteNameFormat, "_%d");
+ threadName.AppendFormat(KSubstituteNameFormat, ++suffix);
+ __CFLOG_VAR( (KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::CreateThreadL - KErrAlreadyExists; trying with %S"), &threadName) );
+ res=CreateModuleThread(threadName, CRSTransientModuleInfo::ModuleThreadStartup,
+ iStackSize, iHeapPtr, iThreadStartupInfo);
+ } while(res == KErrAlreadyExists);
+ }
+#endif
+#endif
+#endif
+ if (res!=KErrNone)
+ {
+ __CFLOG_2(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::CreateThreadL:Unable to create thread %S error %d.."),
+ &iName, res);
+ User::Leave(res);
+ }
+
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::CreateThreadL: Created thread for %S."), &iName);
+
+ CActiveScheduler::Add(this);
+ }
+
+EXPORT_C void CCommsProviderModule::ConstructL(CRootServer* aRootServer,
+ const TRSStartModuleParams& aParams, HBufC8* aIniData)
+ /**
+ * Contruct module. Sets up module, creating comms channels and thread.
+ @param aRootServer The root server object
+ @param aParams The data needed to load module
+ @param aIniData The initialisation data for the module
+ */
+ {
+ __CFLOG_STMT(TBuf8<KMaxFileName> fnam;)
+ __CFLOG_STMT(fnam.Copy(aParams.iParams.iFilename);)
+ __CFLOG_4(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::ConstructL:%S,%S Pri:%d Stack:%d."),
+ &aParams.iParams.iName, &fnam, aParams.iParams.iPriority, aParams.iParams.iStackSize);
+
+ // Copy the essential information
+ iName.Copy(aParams.iParams.iName);
+ iDll.Copy(aParams.iParams.iFilename);
+ iPriority = aParams.iParams.iPriority;
+ iRootServer = aRootServer;
+ iIniData = aIniData;
+ iStackSize = aParams.iParams.iStackSize;
+ iHeapType = aParams.iParams.iHeapType;
+ iMinHeapSize = aParams.iParams.iMinHeapSize;
+ iMaxHeapSize = aParams.iParams.iMaxHeapSize;
+ iShareHeapWith = static_cast<const TCFModuleNameF&>(aParams.iParams.iShareHeapWith);
+ iThreadFunctionOrdinal = aParams.iParams.iThreadFunctionOrdinal;
+ iIsSticky = aParams.iParams.iIsSticky;
+ iIsServer = aParams.iParams.iIsServer;
+ iControlFlags = aParams.iParams.iControlFlags;
+
+ if(KErrNone!=iSend.Create(KCFMaxChannelQueues))
+ {
+ User::Leave(KErrRSUnableToCreateQueues);
+ }
+
+ if(KErrNone!=iRecv.Create(KCFMaxChannelQueues))
+ {
+ User::Leave(KErrRSUnableToCreateQueues);
+ }
+ }
+
+TInt CCommsProviderModule::Load(TRequestStatus& aStatus)
+ /** Initiates the loading of a module. Sets states and resumes thread
+ @param aStatus The status of the active object which will be completed on load
+ */
+ {
+ iState = EStarting;
+ iReqStatus = &aStatus;
+ aStatus = KRequestPending;
+
+ iThread.Rendezvous(iStatus);
+ iThread.Resume();
+ SetActive();
+
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::Load: Resumed thread %S."), &iName);
+
+ return KErrNone;
+ }
+
+TInt CCommsProviderModule::Unload()
+ /** Initiates the unloading of a module. Simply sets internal state
+ */
+ {
+
+ // We now attempt to send shutdowns to zombies - even though they failed to respond to
+ // some earlier request they may notice a shutdown, and it's much better that they shutdown
+ // politely than that an UnGraceful thread kill happens
+ if ( iState != ERunning && iState != EZombie )
+ {
+ return KErrRSModuleNotRunning;
+ }
+
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::UnLoading %S."), &iName);
+
+ iState = EStopping;
+
+ return KErrNone;
+ }
+
+TBool CCommsProviderModule::UidMatch(const TUid& aUid) const
+ /** Matches the Uid for a CPM
+ @param aUid The Uid to be checked
+ */
+ {
+ return ((aUid.iUid==KUidCommsServerModule)||(aUid.iUid==KUidCommsProviderModule));
+ }
+
+RThread CCommsProviderModule::GetThread() const
+ /** Return pointer to thread for a CPM
+ */
+ {
+ return iThread;
+ }
+
+#ifdef __CFLOG_ACTIVE
+const TText8* CCommsProviderModule::GetStateName() const
+ /** Returns a pointer to a text string identifying the module's current state
+ */
+ {
+ switch(iState)
+ {
+ case EIdle:
+ return _S8("Idle");
+ case EStarting:
+ return _S8("Starting");
+ case ERunning:
+ return _S8("Running");
+ case EStopping:
+ return _S8("Stopping");
+ case EZombie:
+ return _S8("Zombie");
+ case EDead:
+ return _S8("Dead");
+ default:
+ return _S8("<Unknown State>");
+ }
+ }
+#endif
+
+#if defined _DEBUG || defined __CFLOG_ACTIVE || defined SYMBIAN_TRACE_ENABLE
+const TText8* CCommsProviderModule::GetUnloadTypeName(RootServer::TRSUnLoadType aType)
+ /** Returns a pointer to a text string identifying the requested module unload type
+ */
+ {
+ // Determine the unload type.
+ switch(aType)
+ {
+ case EOptional:
+ return _S8("EOptional");
+ case EGraceful:
+ return _S8("EGraceful");
+ case EImmediate:
+ return _S8("EImmediate");
+ case EUnGraceful:
+ return _S8("EUnGraceful");
+ default:
+ return _S8("<Unknown Module Unload Type>");
+ }
+ }
+#endif
+
+void CCommsProviderModule::Inhume()
+ {
+ iState = EZombie;
+ }
+
+
+void CCommsProviderModule::RegisterSuddenDeathNotifierL(MNotifySuddenDeath* aNotifier)
+ /** Register a sudden death notifier.
+ Instantiates a container with the pointer to the notifier and
+ puts it in the TblQue list.
+ @param aNotifier The notifier to be registered.
+ */
+ {
+ __CFLOG(KLogSubSysRS, KLogCode, _L8("CCommsProviderModule - RegisterSuddenDeathNotifier"));
+ CNotifySuddenDeathContainer* pContainer = new (ELeave) CNotifySuddenDeathContainer(aNotifier);
+ iNotifiers.AddLast(*pContainer);
+ } //lint !e429 // custody taken of pContainer
+
+void CCommsProviderModule::UnregisterSuddenDeathNotifier(MNotifySuddenDeath* aNotifier)
+ /** Unregister a sudden death notifier.
+ Searches for container with a pointer to notifier being unregistered, and if found deletes
+ unlinks the container and deletes it. Failure to find such a notifier is not an error as this
+ is typically a clean-up behaviour.
+ @param aNotifier The notifier to be unregistered.
+ */
+ {
+ TDblQueIter<CNotifySuddenDeathContainer> notifierIter(iNotifiers);
+ CNotifySuddenDeathContainer *pContainer;
+
+ while((pContainer = notifierIter++)!=NULL)
+ {
+ if(pContainer->Match(aNotifier))
+ {
+ pContainer->Dequeue();
+ delete pContainer;
+ }
+ }
+ }
+
+EXPORT_C void CCommsProviderModule::SuddenDeath(TInt aDeathTypeErr)
+ /** Controls events on death of a module
+ Notifies Bind Manager of death event, so that it can clean up
+ aReason The reason associated with the death event
+ @param aDeathTypeErr xxx
+ */
+ {
+ #ifdef __CFLOG_ACTIVE
+ TPtrC8 stateName(GetStateName());
+ __CFLOG_2(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::SuddenDeath - %S module's thread died while module was in state: %S."), &iName, &stateName);
+ #endif
+
+ iExitReason = iThread.ExitReason();
+ if(aDeathTypeErr == KErrRSSuddenViolentDeath)
+ {
+ // Looks like a panic or a kill happened to it. Flag it as unstable to suppress the leak detection, since
+ // it never had a chance to clean-up
+ SetControlFlags(ControlFlags() | TRSStartModuleParamContainer::KCF_UnstableModule);
+ }
+ TInt result(KErrNone);
+ __CFLOG(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::SuddenDeath - BM::UnbindAlreadyDeadL called"));
+ TRAP(result, iRootServer->BindManager()->UnbindAlreadyDeadL(iStatus, iName));
+ SetActive();
+ if( result != KErrNone )
+ {
+ TRequestStatus *status = &iStatus;
+ User::RequestComplete(status, result);
+ }
+ if ( iState != EStopping )
+ {
+ iState = EZombie;
+ }
+ }
+
+
+void CCommsProviderModule::NotifyOfDeath(TInt aReason)
+ /** Controls notifications on death of a module
+ @param aReason The reason associated with the death event
+ */
+ {
+
+ TDblQueIter<CNotifySuddenDeathContainer> notifierIter(iNotifiers);
+ CNotifySuddenDeathContainer *pContainer;
+
+ while((pContainer = notifierIter++)!=NULL)
+ {
+ pContainer->Notify(aReason);
+ pContainer->Dequeue();
+ delete pContainer;
+ }
+ iNotifiers.Reset();
+ }
+
+EXPORT_C void CCommsProviderModule::RunL()
+ /** Handles each active object completion event differently
+ depending on the state of the module
+ */
+ {
+ #ifdef __CFLOG_ACTIVE
+ TPtrC8 stateName(GetStateName());
+ __CFLOG_3(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::RunL name: %S, state: %S, status: %d"),
+ &iName, &stateName, iStatus.Int());
+ #endif
+
+ TBool dieNow = EFalse;
+ switch(iState)
+ {
+ case EZombie:
+ dieNow = ETrue;
+ iRootServer->SuddenDeath(KErrRSSuddenDeath); // Notify Root Server
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::ModuleEndedL(%S) called"), &iName);
+ TRAPD(res, iRootServer->BindManager()->ModuleEndedL(iName)); // no use checking if this left...module is dead
+ iLink.Deque(); // Remove from list in Root Server
+ NotifyOfDeath(KErrRSSuddenDeath);
+ break;
+ case EIdle:
+ break;
+ case EStarting:
+ delete iThreadStartupInfo; // clean up startupinfo now, seeing as thread has rendezvoused
+ iThreadStartupInfo = NULL;
+ if (iStatus.Int()==KErrNone)
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::RunL - %S moving from Starting state to Running state"), &iName);
+ iState = ERunning;
+ iUndertaker->Logon(); // Monitor for thread death
+ }
+ else
+ {
+ __CFLOG_2(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::RunL - %S dying now due to error %d"), &iName, iStatus.Int());
+ dieNow = ETrue;
+ NotifyOfDeath(KErrRSSuddenDeath);
+ }
+
+ User::RequestComplete(iReqStatus, iStatus.Int()); // trigger session handler
+ break;
+ case ERunning:
+ break;
+ case EStopping:
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::RunL - %S dying now"), &iName);
+ dieNow = ETrue;
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::RunL - ModuleEndedL(%S)"),&iName);
+ TRAP(res, iRootServer->BindManager()->ModuleEndedL(iName));
+ __ASSERT_DEBUG(res==KErrNone, User::Panic(KSpecAssert_ElemRootServerrt, 3));
+ iLink.Deque(); // Remove from list in Root Server
+ iRootServer->SuddenDeath(KErrNone);
+ NotifyOfDeath(iExitReason);
+ break;
+ case EDead:
+ dieNow = ETrue;
+ break;
+ default:
+ __CFLOG_1(KLogSubSysRS, KLogCode, _L8("CCommsProviderModule::RunL() unexpected case <%d>!"), iState);
+ }
+
+ if (dieNow)
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CCommsProviderModule::RunL - %S deleting self"), &iName);
+ if (IsAdded())
+ {
+ Deque(); // Remove from active scheduler
+ }
+ iLibrary.Close(); //
+ delete this; // Disappear
+ }
+ }
+
+
+CSessionHandler::CSessionHandler(CRootServerSession* aSession, CBindManager* aBindMgr, const RMessage2& aMessage):
+ CActive(EPriorityStandard), iRequestCompleted(EFalse),
+ iSession(aSession), iBindMgr(aBindMgr), iState(ESHIdle), iMessage(aMessage)
+ /** Abstract base class to handle session requests
+ @param aSession The root server session
+ @param aBindMgr Pointer to the bind manager
+ @param aMessage The message which will be completed
+ */
+ {
+ RS_DETLOG((KLogSubSysRS, KLogCode, _L8("CSessionHandler(%X) - msgHdl = %x"), this, iMessage.Handle()));
+ CActiveScheduler::Add(this);
+ }
+
+CSessionHandler::~CSessionHandler()
+ {
+// Although sometimes useful this logging statement has to be left suppressed because sessions can be
+// deleted by the base CServer2 dtor, ie after CFLOG has been deleted by the RootServer dtor.
+// RS_DETLOG((KLogSubSysRS, KLogCode, _L8("~CSessionHandler(%X)"), this));
+ Cancel();
+ if (IsAdded())
+ {
+ Deque();
+ }
+ iLink.Deque();
+ }
+
+void CSessionHandler::SuddenDeath(TInt aError)
+ /** Only called if not over-ridden by derived class, but this
+ should never be the case.
+ @param aError The reason associated with the death event
+ */
+ {
+ (void) aError; // suppress error when not logging
+ __CFLOG_VAR((KLogSubSysRS, KLogCode, _L8("CSessionHandler::SuddenDeath(%d)"), aError));
+ User::Panic(RThread().Name(), KRSBadState); // derived class should override this for cases where it can legiarise
+ }
+
+CCommsProviderModule* CSessionHandler::GetModulePtr(const TCFModuleNameF& aName) const
+ /** Retrieves module pointer
+ @param aName The name to retrieve module pointer for
+ @return Pointer to module
+ */
+ {
+ CRootServer* rootServer = iSession->RootServer();
+ return rootServer->FindCpm( aName );
+ }
+
+void CSessionHandler::CompleteClientRequest(TInt aRequest)
+ /** Complete Request
+ @param aRequest The reason associated with the completion event
+ */
+ {
+ if (!iRequestCompleted)
+ {
+ RS_DETLOG((KLogSubSysRS, KLogCode, _L8("CSessionHandler(%X)::CompleteClientRequest(hdl %x = %d)"), this, iMessage.Handle(), aRequest));
+ iMessage.Complete(aRequest);
+ iRequestCompleted = ETrue;
+ }
+ }
+
+CSessionHandlerLoadCPM::CSessionHandlerLoadCPM(CRootServerSession* aSession, CBindManager* aBindMgr, const RMessage2& aMessage)
+ : CSessionHandler(aSession, aBindMgr, aMessage)
+ /** Constructor for Derived session handler
+ @param aSession The root server session
+ @param aBindMgr Pointer to Bind Manager
+ */
+ {
+ }
+
+CSessionHandlerLoadCPM::~CSessionHandlerLoadCPM()
+ /** Destructor for Derived session handler
+ */
+ {
+ delete iLoadCompletionNotificationWaiter;
+ }
+
+CSessionHandlerLoadCPM* CSessionHandlerLoadCPM::NewL(CRootServerSession* aSession, CBindManager* aBindMgr, const RMessage2& aMessage)
+ /** Create New instance of this session handler
+ @param aSession The root server session
+ @param aBindMgr Pointer to Bind Manager
+ */
+ {
+ CSessionHandlerLoadCPM* pSession = new(ELeave) CSessionHandlerLoadCPM(aSession, aBindMgr, aMessage);
+ CleanupStack::PushL(pSession);
+ pSession->ConstructL();
+ CleanupStack::Pop();
+ return pSession;
+ }
+
+CSessionHandler::TSHType CSessionHandlerLoadCPM::HandlerType()
+ /** Identifies the subclass type
+ */
+ {
+ return ESHTypeLoadCPM;
+ }
+
+TInt CSessionHandlerLoadCPM::Start()
+ /** Starts the load process
+ */
+ {
+ iState = ESHStarting;
+ TInt res = KErrNotFound;
+ CCommsProviderModule* modulePtr = GetModulePtr(iName);
+ if(modulePtr)
+ {
+ res = modulePtr->Load(iStatus);
+ SetActive();
+ }
+ return res;
+ }
+
+
+void CSessionHandlerLoadCPM::SetHandler(const TCFModuleNameF& aModule)
+ /** Set up this handler
+ @param aModule The name of the module handled
+ */
+ {
+ RS_DETLOG((KLogSubSysRS, KLogCode, _L8("CSessionHandlerLoadCPM - Setting up handler")));
+ iName = aModule;
+ }
+
+TBool CSessionHandlerLoadCPM::CancelHandler(TBool aCompleteRequest, TBool aWaitForCompletionIfUncancelable)
+ /** Cancel Handler attempts to cancel request
+ @param aCompleteRequest Whether to complete request or not
+ @param aWaitForCompletionIfUncancelable Whether to wait for completion in a nested active scheduler (option used during session cleanup)
+ @return Returns ETrue if the handler should be deleted by the caller or EFalse if the handler will delete itself
+ */
+ {
+ // Pretend message has already been completed if
+ // we are asked not to and it hasn't already
+ if ((!aCompleteRequest) && (!iRequestCompleted))
+ {
+ iRequestCompleted = ETrue;
+ }
+
+ TBool prevIsActive = IsActive();
+ TInt prevStatus = iStatus.Int();
+
+ Cancel();
+
+ // If the module's thread is already starting, reactivate the load handler
+ // because it is no longer possible to cancel the load operation and we
+ // need to let the load handler finish.
+ if(iStatus.Int() == KErrRSModuleAlreadyExist)
+ {
+ // We should not complete the request now if the cancel did not succeed
+ // regardless of the value of the aCompleteRequest parameter: the
+ // operation is still in progress.
+ aCompleteRequest = EFalse;
+
+ // Restore the previous state of our active object before cancellation was
+ // attempted.
+ iStatus = prevStatus;
+ if(prevIsActive)
+ {
+ SetActive();
+ }
+
+ // Check to see if we should wait for the uncancelable operation to
+ // complete. This is necessary if the session that initiated the operation
+ // is closing or else the handler will be orphaned and the completion signal
+ // will go astray.
+ if(aWaitForCompletionIfUncancelable)
+ {
+ __ASSERT_DEBUG(iLoadCompletionNotificationWaiter, User::Panic(KSpecAssert_ElemRootServerrt, 4));
+
+ // Start a nested scheduler to process the signals required to complete
+ // the operation. Not the neatest solution, but the least invasive.
+ // Otherwise CloseSession would be have to be broken into steps and
+ // restructured around an active object.
+ // CSessionHandlerLoadCPM::Cancel's semantics are arguably broken anyway
+ // since it is not guaranteed to work and doesn't wait for completion of
+ // the load module operation if it fails.
+ CActiveSchedulerWait* waiter = iLoadCompletionNotificationWaiter;
+ waiter->Start();
+
+ delete waiter;
+ }
+
+ return EFalse;
+ }
+
+ // Must complete the client AFTER we have canceled all unload operations.
+ if (aCompleteRequest)
+ {
+ CompleteClientRequest(iStatus.Int());
+ }
+
+ return ETrue;
+ }
+
+
+CSessionHandler* CSessionHandlerLoadCPM::MatchPending(const TCFModuleNameF& aModule)
+ /** Match a pending load
+ @param aModule The name of the loading module to be found
+ */
+ {
+ if ( aModule != iName )
+ {
+ return NULL;
+ }
+ else
+ {
+ __CFLOG(KLogSubSysRS, KLogCode, _L8("CSessionHandlerLoadCPM - Found match"));
+ return this;
+ }
+ }
+
+void CSessionHandlerLoadCPM::ConstructL()
+ {
+ // We preallocate this in case we need it since it is used in
+ // certain session cleanup situations.
+ iLoadCompletionNotificationWaiter = new(ELeave) CActiveSchedulerWait;
+ }
+
+void CSessionHandlerLoadCPM::CompleteClientRequest(TInt aRequest)
+ /** Complete Request
+ @param aRequest The reason associated with the completion event
+ */
+ {
+ if (!iRequestCompleted)
+ {
+ RS_DETLOG((KLogSubSysRS, KLogCode, _L8("CSessionHandlerLoadCPM(%X)::CompleteClientRequest(hdl %x = %d)"), this, iMessage.Handle(), aRequest));
+ iMessage.Complete(aRequest);
+ iRequestCompleted = ETrue;
+ }
+
+ // Complete a caller waiting in a nested scheduler for us to complete.
+ // This is necessary to handle the corner case where a load module
+ // operation was not cancelled in time and a session needs to wait for
+ // the handler to complete before the session is closed.
+ if(iLoadCompletionNotificationWaiter && iLoadCompletionNotificationWaiter->IsStarted())
+ {
+ iLoadCompletionNotificationWaiter->AsyncStop();
+
+ // Waiter is now responsible for deletion for safety - we will
+ // probably delete ourselves directly after this function call.
+ iLoadCompletionNotificationWaiter = NULL;
+ }
+ }
+
+void CSessionHandlerLoadCPM::RunL()
+ /** Handles different states of handler as load progresses
+ */
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerLoadCPM::RunL status %d"), iStatus.Int());
+ CCommsProviderModule* modulePtr = GetModulePtr(iName);
+
+ switch(iState)
+ {
+ case ESHStarting:
+ // We get here when the module's thread Rendezvous()s
+ if (iStatus.Int() == KErrNone)
+ {
+ iState = ESHLoading;
+ if(modulePtr)
+ {
+ RCFChannel::TMsgQueues inputQueue;
+ RCFChannel::TMsgQueues outputQueue;
+ modulePtr->GetSendChannel().GetMsgQueues(inputQueue);
+ modulePtr->GetRecvChannel().GetMsgQueues(outputQueue);
+ __CFLOG_1( KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerLoadCPM called BM::CreateModuleL(%S)" ),&iName);
+ TRAPD(res, iBindMgr->CreateModuleL(iStatus, modulePtr->GetName(),
+ inputQueue, outputQueue));
+ SetActive();
+ if (res != KErrNone)
+ {
+ __CFLOG_2(KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerLoadCPM::Load: Unable to register %S thread with BindMgr - will kill it: %d.."),
+ &iName, res);
+ // This is invidious - the thread lives but the bindmgr can't register it
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, res);
+ delete modulePtr;
+ }
+ }
+ }
+ else
+ {
+ // if rendezvous with !KErrNone, just complete, cos object is deleted
+ __CFLOG(KLogSubSysRS, KLogCode,_L8("CSessionHandlerLoadCPM::RunL bad rendezvous"));
+ CompleteClientRequest(iStatus.Int());
+ delete this;
+ }
+ break;
+ case ESHLoading:
+ if ( iStatus.Int() == KErrNone )
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerLoadCPM::RunL %S loaded sucessfully"),
+ &iName);
+ CompleteClientRequest( iStatus.Int());
+ delete this;
+ }
+ else
+ {
+ // load failed so we want to kill our thread!
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerLoadCPM::RunL %S load failed"),
+ &iName);
+ if(modulePtr)
+ {
+ // the thread has failed discovery so the client must
+ // decide whether it wants to kill the module as the rootserver
+ // now has a case of the living dead...
+ modulePtr->Inhume();
+ CompleteClientRequest(KErrRSZombie);
+ delete this;
+ }
+ else
+ {
+ // there is no valid module representation in the rootserver
+ // so this module must have had a sudden death after rendezvous
+ // and did not complete loading fully
+ CompleteClientRequest(KErrServerTerminated);
+ delete this;
+ }
+ }
+ break;
+ case ESHCompleting:
+ case ESHKilling:
+ case ESHIdle:
+ case ESHBinding:
+ case ESHUnBinding:
+ case ESHUnLoading:
+ default:
+ User::Panic(RThread().Name(), KRSBadState);
+ }
+ }
+
+void CSessionHandlerLoadCPM::DoCancel()
+ /** Attempt to cancel request
+ */
+ {
+ CCommsProviderModule* modulePtr = GetModulePtr(iName);
+ __ASSERT_DEBUG(modulePtr!=NULL, User::Panic(RThread().Name(), KRSModuleRefMissing));
+
+ TInt cancelLoadResult = KErrRSModuleUnknown;
+
+ if (modulePtr)
+ {
+ cancelLoadResult = modulePtr->CancelLoad();
+ }
+
+ if((cancelLoadResult == KErrCancel) || (cancelLoadResult == KErrRSModuleUnknown))
+ {
+ if(iBindMgr->Cancel(iStatus) != KErrNone)
+ {
+ TRequestStatus* pStatus = &iStatus;
+ User::RequestComplete(pStatus, cancelLoadResult);
+ }
+
+ // Must complete the client AFTER we have canceled all load operations.
+ CompleteClientRequest(KErrCancel);
+ }
+ else
+ {
+ TRequestStatus* pStatus = &iStatus;
+ User::RequestComplete(pStatus, cancelLoadResult);
+ }
+ }
+
+void CSessionHandlerLoadCPM::SuddenDeath(TInt aError)
+ /** Completes message on death of a module
+ @param aError The reason associated with the death event
+ */
+ {
+ __CFLOG(KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerLoadCPM - Notified of SuddenDeath"));
+ CompleteClientRequest(aError);
+ delete this;
+
+ }
+
+CSessionHandlerUnLoadCPM::CSessionHandlerUnLoadCPM(CRootServerSession* aSession, CBindManager* aBindMgr, const RMessage2& aMessage)
+ :CSessionHandler(aSession,aBindMgr,aMessage)
+ /** Constructor for Derived session handler
+ @param aSession The root server session
+ @param aBindMgr Pointer to Bind Manager
+ */
+ {
+ }
+
+CSessionHandlerUnLoadCPM::~CSessionHandlerUnLoadCPM()
+ /** Destructor for Derived session handler
+ */
+ {
+ delete iLoadCompletionNotificationWaiter;
+ }
+
+CSessionHandlerUnLoadCPM* CSessionHandlerUnLoadCPM::NewL(CRootServerSession* aSession, CBindManager* aBindMgr, const RMessage2& aMessage)
+ /** Create New instance of this session handler
+ @param aSession The root server session
+ @param aBindMgr Pointer to Bind Manager
+ */
+ {
+ CSessionHandlerUnLoadCPM* pSession = new(ELeave) CSessionHandlerUnLoadCPM(aSession, aBindMgr,aMessage);
+ CleanupStack::PushL(pSession);
+ pSession->ConstructL();
+ CleanupStack::Pop();
+ return pSession;
+ }
+
+CSessionHandler::TSHType CSessionHandlerUnLoadCPM::HandlerType()
+ /** Identifies the subclass type
+ */
+ {
+ return ESHTypeUnLoadCPM;
+ }
+
+TInt CSessionHandlerUnLoadCPM::Start()
+ /** Starts unload procedure
+ We have 2 types of unload: Graceful and Ungraceful.
+ Each unload works differently, but ultimately ends in the module
+ being removed
+ */
+ {
+ RS_DETLOG((KLogSubSysRS, KLogCode, _L8("CSessionHandlerUnLoadCPM(%X)::Start(%S)"), this, &iName));
+
+ CCommsProviderModule* modulePtr = GetModulePtr(iName);
+ // we have already checked it is running, so if we can't find it now...
+ __ASSERT_ALWAYS( modulePtr!=NULL, User::Panic(RThread().Name(), KRSModuleRefMissing));
+
+ TInt result;
+ switch(modulePtr->GetState())
+ {
+ case EStarting:
+ case EStopping:
+ // If it's an optional or graceful request then module needs to be in the running state
+ if(iType == EUnGraceful)
+ break;
+ delete this;
+ return KErrRSModuleNotRunning;
+ case EDead:
+ return KErrRSModuleNotRunning;
+ default:
+ // Reassure the tools that we're ignoring other values
+ break;
+ }
+
+ switch(iType)
+ {
+ case EOptional:
+ case EGraceful:
+ case EImmediate:
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8( "CSessionHandlerUnLoadCPM - BM::UnbindAllAndShutDownL(%S)"),
+ &iName );
+ // fire off the asynchronous request
+ TRAP(result, iBindMgr->UnbindAllAndShutDownL(iStatus, iName, iType));
+ SetActive();
+ if (result == KErrNone)
+ {
+ result = modulePtr->Unload();
+ // we have already checked module is running so...
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8( "CSessionHandlerUnLoadCPM - error %d"), result);
+ __ASSERT_DEBUG(result==KErrNone, User::Panic(RThread().Name(), KRSBindMgrError));
+ iState = ESHUnLoading;
+ }
+ else
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerUnLoadCPM - BM unable to unload %S gracefully"),
+ &iName);
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, result);
+ }
+ break;
+ case EUnGraceful:
+ iState = ESHKilling;
+ TRAPD( res, modulePtr->RegisterSuddenDeathNotifierL(this));
+ if (res!=KErrNone)
+ {
+ CompleteClientRequest(res);
+ delete this;
+ }
+ else
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerUnLoadCPM - Unloading %S ungracefully"),
+ &iName);
+ modulePtr->GetThread().Kill(KErrCancel);
+#ifdef SYMBIAN_C32ROOT_API_V3
+ // Any module whose thread is terminated must be regarded as unstable: no
+ // point in checking their cleanup when they had no chance to do any
+ modulePtr->SetControlFlags(modulePtr->ControlFlags() | TRSStartModuleParamContainer::KCF_UnstableModule);
+#endif
+ }
+ // this is all, cos we have already set in motion the events which
+ // will call our RunL and complete the message and clean up
+ break;
+ default:
+ User::Panic(RThread().Name(), KRSBadState);
+ }
+ return KErrNone;
+ }
+
+void CSessionHandlerUnLoadCPM::SetHandler(const TCFModuleNameF& aModule, TRSUnLoadType aType)
+ /**
+ @param aModule The name of the module handled
+ @param aType The type of unload - graceful/ungraceful
+ */
+ {
+ #ifdef __CFLOG_ACTIVE
+ TPtrC8 unloadType = CCommsProviderModule::GetUnloadTypeName(aType);
+ __CFLOG_1(KLogSubSysRS, KLogCode, _L8("CSessionHandlerUnLoadCPM - Setting up handler for an %S unload"), &unloadType);
+ #endif
+
+ iName = aModule;
+ iType = aType;
+ }
+
+TBool CSessionHandlerUnLoadCPM::CancelHandler(TBool aCompleteRequest, TBool aWaitForCompletionIfUncancelable)
+ /** Cancel handler attempts to cancel request
+ @param aCompleteRequest Whether to complete request or not
+ @param aWaitForCompletionIfUncancelable Whether to wait for completion in a nested active scheduler (option used during session cleanup)
+ @return Returns ETrue if the handler should be deleted by the caller or EFalse if the handler will delete itself
+ */
+ {
+ // Although sometimes useful this logging statement has to be left suppressed because sessions can be
+ // deleted by the base CServer2 dtor, ie after CFLOG has been deleted by the RootServer dtor.
+ //__CFLOG(KLogSubSysRS, KLogCode, _L8("CSessionHandlerUnLoadCPM::CancelHandler"));
+
+ // Pretend message has already been completed if
+ // we are asked not to and it hasn't already
+ if ((!aCompleteRequest) && (!iRequestCompleted))
+ {
+ iRequestCompleted = ETrue;
+ }
+
+ TBool prevIsActive = IsActive();
+ TInt prevStatus = iStatus.Int();
+
+ // We cannot place this code inside DoCancel because the handler may not be waiting for any
+ // operation to complete so DoCancel will not be called.
+ TInt cancelUnloadResult = KErrRSModuleUnknown;
+ CCommsProviderModule* module = GetModulePtr(iName);
+ if (module)
+ {
+ cancelUnloadResult = module->CancelUnload(iType);
+
+ if(cancelUnloadResult == KErrCancel)
+ {
+ module->UnregisterSuddenDeathNotifier(this);
+ }
+ }
+
+ // If the module unload is still cancelable, cancel any bind operations and
+ // complete the client.
+ if((cancelUnloadResult == KErrCancel) || (cancelUnloadResult == KErrRSModuleUnknown))
+ {
+ // Cancel any bind operations.
+ Cancel();
+
+ // Must complete the client request AFTER canceling any bind operations.
+ CompleteClientRequest(KErrCancel);
+ }
+
+ // Else, if the module's thread is already dying, reactivate the unload handler
+ // because it is no longer possible to cancel the unload operation and we need
+ // to let the unload handler finish.
+ else if(cancelUnloadResult == KErrRSModuleNotLoaded)
+ {
+ // We should not complete the request now if the cancel did not succeed
+ // regardless of the value of the aCompleteRequest parameter: the
+ // operation is still in progress.
+ aCompleteRequest = EFalse;
+
+ // Restore the previous state of our active object before cancellation was
+ // attempted.
+ iStatus = prevStatus;
+ if(prevIsActive)
+ {
+ SetActive();
+ }
+
+ // Check to see if we should wait for the uncancelable operation to
+ // complete. This is necessary if the session that initiated the operation
+ // is closing or else the handler will be orphaned and the completion signal
+ // will go astray.
+ if(aWaitForCompletionIfUncancelable)
+ {
+ __ASSERT_DEBUG(iLoadCompletionNotificationWaiter, User::Panic(KSpecAssert_ElemRootServerrt, 5));
+
+ // Start a nested scheduler to process the signals required to complete
+ // the operation. Not the neatest solution, but the least invasive.
+ // Otherwise CloseSession would be have to be broken into steps and
+ // restructured around an active object.
+ // CSessionHandlerUnLoadCPM::Cancel's semantics are arguably broken anyway
+ // since it is not guaranteed to work and doesn't wait for completion of
+ // the load module operation if it fails.
+ CActiveSchedulerWait* waiter = iLoadCompletionNotificationWaiter;
+ waiter->Start();
+
+ delete waiter;
+ }
+
+ return EFalse;
+ }
+
+ // Must complete the client AFTER we have canceled all unload operations.
+ if (aCompleteRequest)
+ {
+ CompleteClientRequest(iStatus.Int());
+ }
+
+ return ETrue;
+ }
+
+
+CSessionHandler* CSessionHandlerUnLoadCPM::MatchPending(const TCFModuleNameF& aModule)
+ /** Match a pending load
+ @param aModule The name of the loading module to be found
+ */
+ {
+ if (aModule != iName)
+ {
+ return NULL;
+ }
+ else
+ {
+ __CFLOG(KLogSubSysRS, KLogCode,_L8("CSessionHandlerUnLoadCPM - Found match"));
+ return this;
+ }
+ }
+
+void CSessionHandlerUnLoadCPM::ConstructL()
+ {
+ // We preallocate this in case we need it since it is used in
+ // certain session cleanup situations.
+ iLoadCompletionNotificationWaiter = new(ELeave) CActiveSchedulerWait;
+ }
+
+void CSessionHandlerUnLoadCPM::CompleteClientRequest(TInt aRequest)
+ /** Complete Request
+ @param aRequest The reason associated with the completion event
+ */
+ {
+ if (!iRequestCompleted)
+ {
+ RS_DETLOG((KLogSubSysRS, KLogCode, _L8("CSessionHandlerUnLoadCPM(%X)::CompleteClientRequest(hdl %x = %d)"), this, iMessage.Handle(), aRequest));
+ iMessage.Complete(aRequest);
+ iRequestCompleted = ETrue;
+ }
+
+ // Complete a caller waiting in a nested scheduler for us to complete.
+ // This is necessary to handle the corner case where an unload module
+ // operation was not cancelled in time and a session needs to wait for
+ // the handler to complete before the session is closed.
+ if(iLoadCompletionNotificationWaiter && iLoadCompletionNotificationWaiter->IsStarted())
+ {
+ iLoadCompletionNotificationWaiter->AsyncStop();
+
+ // Waiter is now responsible for deletion for safety - we will
+ // probably delete ourselves directly after this function call.
+ iLoadCompletionNotificationWaiter = NULL;
+ }
+ }
+
+void CSessionHandlerUnLoadCPM::RunL()
+ /** Deal with unloading as progresses through different states
+ */
+ {
+ // first time we come in here will be on a successful
+ // bindmgr request. we only ignore as we will be back in here
+ // after triggered from sudden death event
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerUnloadCPM::RunL status %d"), iStatus.Int());
+
+ CCommsProviderModule* module = GetModulePtr(iName);
+ switch(iState)
+ {
+ case ESHUnLoading:
+ if(iStatus.Int()==KErrNone)
+ {
+ iState = ESHKilling;
+ // if we get a valid pointer then we are not too late to get a notification
+ // of death from module. If we are too late, then module is already dead
+ // so we are happy and can complete message
+ if (module)
+ {
+ TRAPD(res, module->RegisterSuddenDeathNotifierL(this));
+ if(res!=KErrNone)
+ {
+ CompleteClientRequest(res);
+ delete this;
+ }
+ else
+ {
+ __CFLOG(KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerUnloadCPM::RunL now waiting for Sudden Death"));
+ }
+ }
+ else
+ {
+ // module already dead
+ CompleteClientRequest(iStatus.Int());
+ delete this;
+ }
+ }
+ else
+ {
+ // BM could not unload cleanly so return to client and let them decide
+ if (module)
+ {
+ module->CancelUnload(iType);
+ }
+ CompleteClientRequest(iStatus.Int());
+ delete this;
+ }
+ break;
+ case ESHKilling:
+ __CFLOG(KLogSubSysRS, KLogCode,_L8("CSessionHandlerUnloadCPM::RunL Successfully unloaded"));
+ CompleteClientRequest(iStatus.Int());
+ delete this;
+ break;
+ case ESHIdle:
+ __CFLOG_1(KLogSubSysRS, KLogCode,_L8("CSessionHandlerUnloadCPM::RunL Unbind request failed (%d)"), iStatus.Int());
+ CompleteClientRequest(iStatus.Int());
+ delete this;
+ break;
+ default:
+ User::Panic(RThread().Name(), KRSBadState);
+ }
+ }
+
+void CSessionHandlerUnLoadCPM::DoCancel()
+ /** Attempt to cancel request
+ */
+ {
+ if(iBindMgr->Cancel(iStatus) != KErrNone)
+ {
+ TRequestStatus* pStatus = &iStatus;
+ User::RequestComplete(pStatus, KErrCancel);
+ }
+ }
+
+void CSessionHandlerUnLoadCPM::SuddenDeath(TInt aError)
+ /** Completes message on death of a module
+ @param aError The reason associated with the death event
+ */
+ {
+ __CFLOG(KLogSubSysRS, KLogCode, _L8("CSessionHandlerUnLoadCPM - Notified of SuddenDeath"));
+ if(iType == EUnGraceful)
+ {
+ aError = KErrNone; // client requested this sudden death, so make it look less surprising
+ }
+ CompleteClientRequest(aError);
+ delete this;
+
+ }
+
+CSessionHandlerBinding::CSessionHandlerBinding(CRootServerSession* aSession, CBindManager* aBindMgr, const RMessage2& aMessage)
+ : CSessionHandler(aSession, aBindMgr,aMessage)
+ /** Constructor for Derived session handler
+ @param aSession The root server session
+ @param aBindMgr Pointer to Bind Manager
+ @param aMessage The message which will be completed
+ */
+ {
+ }
+
+CSessionHandlerBinding* CSessionHandlerBinding::NewL(CRootServerSession* aSession, CBindManager* aBindMgr, const RMessage2& aMessage)
+ /** Create New instance of this session handler
+ @param aSession The root server session
+ @param aBindMgr Pointer to Bind Manager
+ @param aMessage The message which will be completed
+ */
+ {
+ CSessionHandlerBinding* pSession = new(ELeave) CSessionHandlerBinding(aSession, aBindMgr,aMessage);
+ return pSession;
+ }
+
+CSessionHandler::TSHType CSessionHandlerBinding::HandlerType()
+ /** Identifies the subclass type
+ */
+ {
+ return ESHTypeBinding;
+ }
+
+TInt CSessionHandlerBinding::Start()
+ /** Starts Bind request
+ */
+ {
+ iState = ESHBinding;
+ __CFLOG(KLogSubSysRS, KLogCode,_L8("CSessionHandlerBinding - Call BM::BindSubModulesL"));
+ TRAPD(result, iBindMgr->BindSubmodulesL(iStatus, iBindType, iNameFrom, iNameTo, iForwardQLength, iReverseQLength));
+ SetActive();
+ if (result != KErrNone)
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,
+ _L8( "CSessionHandlerBinding - BM::BindSubmodulesL left with %d"), result);
+ // trigger our runL to deal with aftermath of leave
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, result);
+ }
+ return KErrNone;
+ }
+
+CSessionHandler* CSessionHandlerBinding::MatchPending(const TCFSubModuleAddress& aFrom,
+ const TCFSubModuleAddress& aTo)
+ /** Match a pending load
+ @param aFrom The name of one module involved
+ @param aTo The name of the other module involved
+ */
+ {
+
+ if ((iNameFrom == aFrom) && (iNameTo == aTo))
+ {
+ return this;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+void CSessionHandlerBinding::SetHandler(const TCFSubModuleAddress& aFrom,
+ const TCFSubModuleAddress& aTo, TRSBindType& aBindType,
+ TInt aForwardQLength, TInt aReverseQLength)
+ /** Set up this handler
+ @param aFrom The name of one module handled
+ @param aTo The name of the other module handled
+ @param aBindType The type of bind
+ @param aForwardQLength Number of slots in queue from->to
+ @param aReverseQLength Number of slots in queue to->from
+ */
+ {
+ iNameFrom = aFrom;
+ iNameTo = aTo;
+ iBindType = aBindType;
+ iForwardQLength = aForwardQLength;
+ iReverseQLength = aReverseQLength;
+ }
+
+TBool CSessionHandlerBinding::CancelHandler(TBool aCompleteRequest, const TBool /*aWaitForCompletionIfUncancelable*/)
+ /** Cancel Handler attempts to cancel request
+ @param aCompleteRequest Whether to complete request or not
+ @param aWaitForCompletionIfUncancelable Whether to wait for completion in a nested active scheduler (option used during session cleanup)
+ @return Returns ETrue if the handler should be deleted by the caller or EFalse if the handler will delete itself
+ */
+ {
+ // Pretend message has already been completed if
+ // we are asked not to complete it, and it hasn't already
+ iState = ESHCompleting;
+
+ if ((!aCompleteRequest) && (!iRequestCompleted))
+ {
+ iRequestCompleted = ETrue;
+ }
+
+// Although sometimes useful this logging statement has to be left suppressed because sessions can be
+// deleted by the base CServer2 dtor, ie after CFLOG has been deleted by the RootServer dtor.
+// __CFLOG(KLogSubSysRS, KLogCode,_L8("CSessionHandlerBinding - Cancel Handler"));
+
+ Cancel();
+
+ return ETrue;
+ }
+
+void CSessionHandlerBinding::RunL()
+ /** Handles the aftermath of a bind request. Fills TRSBindingInfo struct
+ with bind state for each sub-module involved
+ */
+ {
+ __CFLOG_1( KLogSubSysRS, KLogCode,_L8("CSessionHandlerBinding::RunL status %d"),
+ iStatus.Int() );
+
+ // Check completion code
+ TInt res=iStatus.Int() ;
+ if (res!=KErrNone)
+ {
+ CompleteClientRequest(res);
+ delete this;
+ return;
+ }
+
+ // Get BindInfo structure from client, we might need to put stuff in it
+ // and write it back before completing the client
+ TRSBindingInfo bindInfo;
+ res = iMessage.Read(0, bindInfo);
+ if (res!=KErrNone)
+ {
+ CompleteClientRequest(res);
+ delete this;
+ return;
+ }
+
+ CBindManager::TBindingInfo info;
+ TBool found=EFalse;
+ switch(iState)
+ {
+ case ESHBinding:
+ // Do while more bindings and match not found
+ res=iBindMgr->EnumerateBindings(iNameFrom, ETrue, info);
+ while( (KErrNone==res) && (!found))
+ {
+ if(EHierarchical==bindInfo.iParams.iType)
+ {
+ found = ((info.iSubModuleAddr2==iNameTo)&&(info.iSubModuleAddr1==iNameFrom));
+ }
+ else // if type == ECustom
+ {
+ found = (((info.iSubModuleAddr2==iNameTo)&&(info.iSubModuleAddr1==iNameFrom)) ||
+ ((info.iSubModuleAddr1==iNameTo)&&(info.iSubModuleAddr2==iNameFrom)) );
+ }
+
+ if(found)
+ {
+ __CFLOG(KLogSubSysRS, KLogCode,
+ _L8("CSessionHandlerBinding found a match in bind info"));
+ bindInfo.iParams.iState1 = info.iSubModuleState1;
+ bindInfo.iParams.iState2 = info.iSubModuleState2;
+ }
+ else // if not found
+ {
+ res=iBindMgr->EnumerateBindings(iNameFrom, EFalse, info);
+ }
+ }
+
+ // We succeeded bindingm but have no knowledge of the binding? ASSERT
+ __ASSERT_DEBUG(found, User::Panic(RThread().Name(), KRSBadState));
+
+ // Write the info struct back to client, complete the RMessage and delete this
+ res = iMessage.Write(0, bindInfo);
+ if (KErrNone==res)
+ {
+ res=iStatus.Int();
+ }
+
+ CompleteClientRequest(res);
+ delete this;
+ break;
+
+
+ case ESHCompleting:
+ CompleteClientRequest(iStatus.Int());
+ delete this;
+ break;
+ default:
+ User::Panic(RThread().Name(), KRSBadState);
+ }
+ }
+
+void CSessionHandlerBinding::DoCancel()
+ /** Attempt to cancel request
+ */
+ {
+ TInt res = iBindMgr->Cancel(iStatus);
+ if (res!=KErrNone)
+ {
+ TRequestStatus *status = &iStatus;
+ User::RequestComplete(status, KErrCancel);
+ }
+
+ // Must complete the client request AFTER canceling any bind operations.
+ CompleteClientRequest(KErrCancel);
+ }
+
+CSessionHandlerUnBinding::CSessionHandlerUnBinding(CRootServerSession* aSession, CBindManager* aBindMgr, const RMessage2& aMessage)
+ : CSessionHandler(aSession, aBindMgr,aMessage)
+ /** Constructor for Derived session handler
+ @param aSession The root server session
+ @param aBindMgr Pointer to Bind Manager
+ */
+ {
+ }
+
+CSessionHandlerUnBinding* CSessionHandlerUnBinding::NewL(CRootServerSession* aSession, CBindManager* aBindMgr, const RMessage2& aMessage)
+ /** Create New instance of this session handler
+ @param aSession The root server session
+ @param aBindMgr Pointer to Bind Manager
+ @param aMessage The message which will be completed
+ */
+ {
+ CSessionHandlerUnBinding* pSession = new(ELeave) CSessionHandlerUnBinding(aSession, aBindMgr,aMessage);
+ return pSession;
+ }
+
+CSessionHandler::TSHType CSessionHandlerUnBinding::HandlerType()
+ /** Identifies the subclass type
+ */
+ {
+ return ESHTypeUnBinding;
+ }
+
+TInt CSessionHandlerUnBinding::Start()
+ /** Starts the unbinding process
+ */
+ {
+ iState = ESHUnBinding;
+ __CFLOG(KLogSubSysRS, KLogCode,_L8("SessionHandlerUnBind - BM::UnbindSubmodulesL"));
+ TRAPD(result, iBindMgr->UnbindSubmodulesL(iStatus, iNameFrom, iNameTo));
+ SetActive();
+ if (result != KErrNone)
+ {
+ // trigger our runL to deal with aftermath of leave
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, result);
+ }
+ return KErrNone;
+ }
+
+CSessionHandler* CSessionHandlerUnBinding::MatchPending(const TCFSubModuleAddress& aFrom,
+ const TCFSubModuleAddress& aTo)
+ /** Match a pending load
+ @param aFrom The name of one module involved
+ @param aTo The name of the other module involved
+ */
+ {
+
+ if ((iNameFrom == aFrom) && (iNameTo == aTo))
+ {
+ return this;
+ }
+ else return NULL;
+
+ }
+
+void CSessionHandlerUnBinding::SetHandler(const TCFSubModuleAddress& aFrom,
+ const TCFSubModuleAddress& aTo)
+ /** Set up this handler
+ @param aFrom The name of one module handled
+ @param aTo The name of the other module handled
+ */
+ {
+ iNameFrom = aFrom;
+ iNameTo = aTo;
+ }
+
+TBool CSessionHandlerUnBinding::CancelHandler(TBool aCompleteRequest, const TBool /*aWaitForCompletionIfUncancelable*/)
+ /** Cancel Handler attempts to cancel request
+ @param aCompleteRequest Whether to complete request or not
+ @param aWaitForCompletionIfUncancelable Whether to wait for completion in a nested active scheduler (option used during session cleanup)
+ @return Returns ETrue if the handler should be deleted by the caller or EFalse if the handler will delete itself
+ */
+ {
+ iState = ESHCompleting;
+ // Pretend message has already been completed if
+ // we are asked not to and it hasn't already
+ if ((!aCompleteRequest) && (!iRequestCompleted))
+ {
+ iRequestCompleted = ETrue;
+ }
+
+// Although sometimes useful this logging statement has to be left suppressed because sessions can be
+// deleted by the base CServer2 dtor, ie after CFLOG has been deleted by the RootServer dtor.
+// __CFLOG( KLogSubSysRS, KLogCode,_L8("CSessionHandlerUnBinding - Cancel Handler"));
+
+ Cancel();
+
+ return ETrue;
+ }
+
+void CSessionHandlerUnBinding::RunL()
+ /** Handles aftermath of unbind, by completing the message
+ */
+ {
+ __CFLOG_1(KLogSubSysRS, KLogCode,_L8("CSessionHandlerUnBinding::RunL status %d"),
+ iStatus.Int());
+ CompleteClientRequest(iStatus.Int());
+ delete this;
+ }
+
+void CSessionHandlerUnBinding::DoCancel()
+ /** Attempt to cancel request
+ */
+ {
+ CompleteClientRequest(KErrCancel);
+ TInt res = iBindMgr->Cancel(iStatus);
+ if (res!=KErrNone)
+ {
+ TRequestStatus *status = &iStatus;
+ User::RequestComplete(status, KErrCancel);
+ }
+ }
+
+CRSTransientModuleInfo::CRSTransientModuleInfo(const RCFChannel::TMsgQueues& aTxQueues,
+ const RCFChannel::TMsgQueues& aRxQueues,
+ TRSHeapType aThreadHeapType,
+ TThreadFunction aLibEntry,
+ HBufC8* aIniDataOnRSHeap,
+ TThreadPriority aPriority,
+ TUint32 aControlFlags)
+: iThreadHeapType(aThreadHeapType),
+ iLibEntry(aLibEntry),
+ iIniDataOnRSHeap(aIniDataOnRSHeap),
+ iPriority(aPriority),
+ iControlFlags(aControlFlags)
+ {
+ iCFModuleInfo.iTxQueues=aTxQueues;
+ iCFModuleInfo.iRxQueues=aRxQueues;
+ }
+
+CRSTransientModuleInfo::~CRSTransientModuleInfo()
+ {
+ delete iIniDataOnRSHeap;
+ }
+
+TInt CRSTransientModuleInfo::ModuleThreadStartup(TAny* aArg)
+ {
+ CRSTransientModuleInfo* startupInfo = (CRSTransientModuleInfo*) aArg;
+
+ if (startupInfo->iControlFlags & TRSStartModuleParamContainer::KCF_ThreadAsSystem)
+ {
+ User::SetCritical( User::ESystemCritical);
+ }
+ else
+ {
+ User::SetCritical( User::ENotCritical);
+ }
+
+ RThread().SetPriority(startupInfo->iPriority);
+
+ // Duplicate the ini data into the new thread's heap.
+ // ** NOTE FOR CPM IMPLEMENTORS **
+ // It is an explicit responsibility to take ownership of the iIniData and to delete it
+ if(startupInfo->iIniDataOnRSHeap)
+ {
+ startupInfo->iCFModuleInfo.iIniData = startupInfo->iIniDataOnRSHeap->Alloc();
+ if(!startupInfo->iCFModuleInfo.iIniData )
+ {
+ return KErrNoMemory;
+ }
+ }
+ else
+ {
+ startupInfo->iCFModuleInfo.iIniData = startupInfo->iIniDataOnRSHeap;
+ }
+ return startupInfo->iLibEntry(&startupInfo->iCFModuleInfo);
+ }
+
+