commsfwsupport/commselements/rootserver/rootsrv/rootutil.cpp
changeset 0 dfb7c4ff071f
--- /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);
+	}
+
+