commsprocess/commsrootserverconfig/configurator/src/c32start.cpp
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commsprocess/commsrootserverconfig/configurator/src/c32start.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,1584 @@
+// 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:
+// Implementation of the root server startup confguration process
+// 
+//
+
+#include "c32start.h"
+#include <f32file.h>
+#include "c32cmi.h"
+#include <rserror.h>
+#include <cfextras.h>
+	#include <ssm/ssmdomaindefs.h>
+#include <rsshared.h>				// for TRSAddMBufAllocInfoContainer
+	#include "c32startserv.h"
+	#include <c32startshared.h>
+
+#include <es_mbman.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_RootSrvc32start, "RootSrvc32start.");
+#endif
+
+
+/**
+@file
+Implements the reference Comms Configurator
+
+@publishedPartner
+@released
+*/
+
+/** Local Flogger instance for debug logging. We can't use the tidier __FLOG_DECLARATION_VARIABLE macro because
+the need for a statement terminator causes a warning for WINSCW UREL
+*/
+#if defined(__FLOG_ACTIVE)
+RFileLogger __logger__;
+#endif
+
+static void Fault(TConfiguratorServerPanic aFault)
+    /** Panic the configurator server
+     @param aFault Fault code as defined in cs_std.h
+     @internalComponent
+     */
+    {
+    User::Panic(KRsConfiguratorServerName, aFault);
+    }
+
+/** Name of application.
+*/
+_LIT(KC32Start, "C32Start");
+_LIT8(KAbbreviatedC32Start, "C32:");
+
+/** Configuration file wildcard
+*/
+_LIT(KC32WildCard, "*.cmi");
+/** Configuration process global settings
+*/
+_LIT(KC32StartIniFile, "c32start.ini");
+/** Global section in configuration process settings
+*/
+_LIT8(KC32StartIniGlobalSection, "Global");
+
+/** Optional global setting for the size of the MBuf pool, in bytes 
+*/ 	 
+_LIT8(KC32StartMBufPoolSize, "MBufPoolSize");
+	
+/** Optional (but highly recommended) setting to specify mbuf size allocation information; mbuf size, initial allocation, growth rate, auto growth.
+*/
+_LIT8(KC32StartMBufSizeAllocInfo, "MBufSizeAllocInfo");
+/** Optional global override for the TestMode, in which the failure to reload a shutdown or
+crashed critical module is logged, rather than causing the phone to reboot.
+*/
+_LIT8(KC32StartTestMode, "TestMode");
+
+/** PANICs which can occur in this module.
+*/
+enum TC32StartPanics
+     {
+     /** There was a problem when wanting to load a module.
+     */
+     EPanicLoad,
+     /** When starting, the system property that must be created
+     by the configurator was already created.
+     */
+     EPanicPubSub,
+     /** Unable to get value of the Rootserver Death Property.
+     */
+     EDeathWatch,
+     /** Out of memory.
+     */
+     ENoMemory,
+     /** SystemCritical module died and any attempt made at resurrection
+	 failed. Category text will include start of module's name.
+     */
+     ECriticalModuleDeath
+     };
+
+/** Source of PANICs from this application.
+*/
+_LIT(KPanicSource, "C32Start");
+
+CBindingRef::CBindingRef(RRootServ& aRootServer, CCommsProcessStarter& aStartConfigProcess,
+							   const TRSBindingInfo& aBinding)
+: CActive(EPriorityStandard),
+  iRootServer(aRootServer),
+  iStartProcess(aStartConfigProcess),
+  iState(ENotBound),
+  iBindInfo(aBinding)
+/**
+C'tor
+*/
+	{
+	CActiveScheduler::Add(this);
+	}
+
+TInt CBindingRef::BindIfReady()
+/** Bind a submodule if it is ready to be bound.
+*/
+	{
+		
+	if(iState==EBound || iState==EBindFailed)
+		{
+		// We don't attempt to reapply bindings once they've failed; the usual case is
+		// that they've timed-out, so they may complete later and by re-requesting them
+		// we'd risk generating unwanted multiple bindings.
+		return KErrRSAlreadyBound;
+		}
+
+	CModuleRef* pModule = NULL;
+	CModuleRef* qModule = NULL;
+	TInt res = KErrNotReady; // assume the worst
+	// While enumerating the CMI files it may be that a binding refers to a module not yet described; once
+	// we start loading modules then all bindings will be fully defined. So if a module can't be found by
+	// name we return ERSSubModuleUnknown to flag the configuration error
+	qModule = iStartProcess.GetModule(FromModule().Module());
+	if(!qModule)
+		{
+		__FLOG_1(_L8("BindIfReady(): first module %S (involved in binding) is unknown"), &FromModule().Module());
+		
+		return KErrRSSubModuleUnknown;
+		}
+	if(qModule->State()==ELoaded)
+		{
+		pModule = iStartProcess.GetModule(ToModule().Module());
+		if(!pModule)
+			{
+			__FLOG_1(_L8("BindIfReady(): second module %S (involved in binding) is unknown"), &ToModule().Module());
+		
+			return KErrRSSubModuleUnknown;
+			}
+		if(pModule->State() == ELoaded && (iState !=EBinding || iState == ENotBound ))
+			{
+			// track bindings of either end
+			pModule->IncrementBindings();
+			qModule->IncrementBindings();
+			iState = EBinding;
+			SetPriority(EPriorityHigh);
+			iBindInfo.iParams.iState1 = KErrNone;
+			iBindInfo.iParams.iState2 = KErrNone;
+			__FLOG_2(_L8("BindIfReady() - binding %S to %S"), &qModule->Name(), &pModule->Name());
+			iRootServer.Bind(iStatus, iBindInfo);
+			SetActive();
+			res = KErrNone;
+			}
+		else if(pModule->State() == ELoadFailed)
+			{
+			// second named module in binding failed to load, SetState(EBindInComplete)
+			SetState(EBindInComplete);
+			__FLOG_2(_L8("BindIfReady(): second module %S (involved in binding) failed to load, first module %S loaded, SetState(EBindInComplete)"), &pModule->Name(), &qModule->Name());
+			RDebug::Printf("WARNING: second module %S (involved in binding) failed to load, first module %S loaded, SetState(EBindInComplete)", &pModule->Name(), &qModule->Name());
+			__DEBUGGER();
+			}
+		}
+	else if(qModule->State() == ELoadFailed)
+		{
+		// first named module in binding failed to load, SetState(EBindInComplete)
+		SetState(EBindInComplete);
+		__FLOG_1(_L8("BindIfReady(): first named module %S in binding failed to load, SetState(EBindInComplete) "), &qModule->Name());
+		RDebug::Printf("WARNING: first named module %S in binding failed to load, SetState(EBindInComplete)", &qModule->Name());
+		__DEBUGGER();
+		}
+
+	if(iState == EBindInComplete)
+		{
+		// inComplete Binding, check if any of the modules is being OnDemand loaded (iRMessage != NULL)
+		// if the module is tried for 'Load' complete message with KErrRSEitherModuleInBindingFailedToLoad
+		if(qModule->State() != ENotLoaded)
+			{
+			qModule->MaybeCompleteMessage(KErrRSEitherModuleInBindingFailedToLoad);
+			}
+		pModule = iStartProcess.GetModule(ToModule().Module());
+		if(pModule)
+			{
+			if(pModule->State() != ENotLoaded)
+				{
+				pModule->MaybeCompleteMessage(KErrRSEitherModuleInBindingFailedToLoad);
+				}
+			}
+		}
+	return res;
+	}
+
+
+void CBindingRef::RunL()
+/** This function is invoked on completion of a bind
+and is used to trigger further bindings by calling NotifyBindCompletion
+in the controller object which will deal with correct behaviour.
+*/
+	{
+	if(iStatus.Int()==KErrNone)
+		{
+		iState = EBound;
+		__FLOG(_L8("CBindingRef completed with KErrNone."));
+		UpdateCompletedBinding(iStatus.Int());
+		}
+	else
+		{
+		iState = EBindFailed;
+		if(iStatus.Int()==KErrRSAlreadyBound)
+			{
+			__FLOG(_L8("CBindingRef completed with KErrRSAlreadyBound. This is usually OK if configurator was SoftBooted, e.g. during testing."));
+			UpdateCompletedBinding(iStatus.Int());
+			}
+		else
+			{
+			__FLOG_1(_L8("CBindingRef completed with %d"), iStatus.Int());
+			UpdateCompletedBinding(iStatus.Int());
+			}
+		}
+	iStartProcess.NotifyBindCompletion(*this);
+	}
+
+CBindingRef::~CBindingRef()
+/** Destructor of CBindingRef. Removes self from list of CBindingRef objects.
+*/
+	{
+	Deque();
+	}
+
+void CBindingRef::DoCancel()
+	{
+	TRSSubModuleAddress subMod1(iBindInfo.iParams.iAddress1);
+	TRSSubModuleAddress subMod2(iBindInfo.iParams.iAddress2);
+	iRootServer.CancelBind(subMod1, subMod2);
+	}
+
+const TCFSubModuleAddress& CBindingRef::FromModule() const
+/**
+@return Reference to a Submodule address.
+*/
+	{
+	return iBindInfo.iParams.iAddress1;
+	}
+
+const TCFSubModuleAddress& CBindingRef::ToModule() const
+/**
+@return Reference to a Submodule address.
+*/
+	{
+	return iBindInfo.iParams.iAddress2;
+	}
+
+void CBindingRef::UpdateCompletedBinding(TInt aReturnValue)
+	{
+	CModuleRef* pModule = iStartProcess.GetModule(FromModule().Module());
+	if(pModule)
+		{
+		pModule->UpdateCompletedBinding(aReturnValue);
+		}
+	pModule = iStartProcess.GetModule(ToModule().Module());
+	if(pModule)
+		{
+		pModule->UpdateCompletedBinding(aReturnValue);
+		}
+	}
+
+CModuleRef* CModuleRef::NewLC(RRootServ& aRootServer,
+							  CCommsProcessStarter& aCommsProcess,
+							  C32CmiData& aModuleCMIData)
+/** Create instance of CModuleRef.
+@param aRootServer The rootserver API.
+@param aCommsProcess The controller object.
+@param aModuleCMIData The object containing the ini data for the module.
+@return A pointer to the new instance.
+*/
+	{
+	CModuleRef* pModule=new(ELeave) CModuleRef(aRootServer, aCommsProcess);
+	CleanupStack::PushL(pModule);
+	pModule->ConstructL(aModuleCMIData);
+	return pModule;
+	}
+
+CModuleRef::CModuleRef(RRootServ& aRootServer,CCommsProcessStarter& aCommsProcess)
+	:	CActive(EPriorityStandard),
+		iRootServer(aRootServer),
+		iCommsProcess(aCommsProcess)
+/** C'tor
+@param aRootServer The rootserver API.
+@param aCommsProcess The controller object.
+*/
+	{}
+
+void CModuleRef::ConstructL(C32CmiData& aModuleCMIData)
+/** Second phase construction, sets data members.
+@param aModuleCMIData The object containing the ini data for the module
+@leave KErrNoMemory
+*/
+	{
+	if(aModuleCMIData.IsServer())
+		{
+		iType = EServerModule;
+		}
+	else
+		{
+		iType = EProviderModule;
+		}
+	iState = ENotLoaded;
+	iScaledStartupState = aModuleCMIData.ScaledStartupState();
+	iIniData = aModuleCMIData.IniDataL();
+	iSystemCritical = aModuleCMIData.SystemCritical();
+	iSystemCriticalAfterInit = aModuleCMIData.SystemCriticalAfterInit();
+	iParams.iParams.iName.Copy(aModuleCMIData.Name());
+	iParams.iParams.iFilename.Copy(aModuleCMIData.FileName());
+	iParams.iParams.iPriority = aModuleCMIData.Priority();
+	iParams.iParams.iStackSize = aModuleCMIData.StackSize();
+	iParams.iParams.iHeapType = aModuleCMIData.HeapOption();
+    iParams.iParams.iMinHeapSize = aModuleCMIData.MinHeapSize();
+    iParams.iParams.iMaxHeapSize = aModuleCMIData.MaxHeapSize();
+	iParams.iParams.iThreadFunctionOrdinal = aModuleCMIData.ThreadFuncOrdinal();
+	iParams.iParams.iShareHeapWith.Copy(aModuleCMIData.SharedHeapName());
+	iParams.iParams.iIsSticky = aModuleCMIData.IsSticky();
+	iParams.iParams.iIsServer = aModuleCMIData.IsServer();
+
+	// DEF040831 - Experience has demonstrated that test code frequently triggers
+	// the demise of a server, deliberately or otherwise.
+	//
+	// CMI files are only suppressed by test code. In such a state we don't
+	// panic about module deaths even when they're labelled as SystemCritical
+	// since test code also manipulates these. On a real device only the
+	// configurator (eg this current process) should ever be manipulating the
+	// RootServer state
+	//
+	// DEF068506 - Determine whether to turn off this option (specified by the .CMI files) based on 'TestMode'
+	// defined in the C32Start.ini. This is generally done by tests temporarily replacing the original .ini file at runtime.
+	iParams.iParams.iControlFlags = aModuleCMIData.ControlFlags();
+	if (iCommsProcess.InTestMode())
+		{
+		__FLOG(_L8("CModuleRef::ConstructL - TestMode set."));
+		iParams.iParams.iControlFlags &= ~TRSStartModuleParamContainer::KCF_ThreadAsSystem;
+		}
+
+	iConfigParams.iGroupName.Copy(aModuleCMIData.GroupName());
+	iConfigParams.iOnDemand = aModuleCMIData.IsOnDemand();
+
+
+	CActiveScheduler::Add(this);
+	}
+
+CModuleRef::~CModuleRef()
+/** D'tor. Dequeues the instance.
+*/
+	{
+	delete iIniData;
+	Deque();
+	}
+
+void CModuleRef::UpdateCompletedBinding(TInt aReturnValue)
+	{
+	IncrementCompletedBindings();
+	MaybeCompleteMessage(aReturnValue);
+	}
+
+void CModuleRef::Load()
+/** Attempts to load the module with the Rootserver.
+*/
+	{
+	__ASSERT_ALWAYS(!IsActive(), User::Panic(KPanicSource, EPanicLoad));
+	__ASSERT_ALWAYS(iState==ENotLoaded || iState==ELoadFailed, User::Panic(KPanicSource, EPanicLoad));
+
+	__FLOG_1(_L8("CModuleRef::LoadingCPM - %S"), &iParams.iParams.iName);
+
+	iState = ELoading;
+
+	SetPriority(EPriorityHigh);
+
+	iRootServer.LoadCpm(iStatus, iParams, *iIniData);
+	SetActive();
+	}
+
+TBool CModuleRef::Resurrect()
+/** Called when the Root Server publishes the death of this module. In an extended-feature configurator this
+may attempt to reload and rebind the module. This reference implementation simply returns that resurrection failed.
+@return EFalse if the module could not be reloaded.
+*/
+	{
+	return EFalse;
+	}
+
+
+TBool CModuleRef::operator==(const TCFModuleNameF& aModuleName) const
+	{
+   	return Name() == aModuleName;
+ 	}
+
+void CModuleRef::RunL()
+/** Calls NotifyLoadCompletion on CCommsProcessStarter.
+*/
+	{
+	const TInt result=iStatus.Int();
+	if(result==KErrNone)
+		{
+		if (iState == ELoading)
+			{
+			iState = ELoaded;
+			if(!iHasBinding)
+				{
+				__FLOG_1(_L8("Comms Provider Module (%S) loaded successfully, has no bindings - Complete msg"), &iParams.iParams.iName);
+				MaybeCompleteMessage(result);
+				}
+			iCommsProcess.NotifyLoadCompletion(*this);
+			}
+		else if(iState == EUnLoading)
+			{
+			iState = ENotLoaded;
+			UnBindCpm();
+			__FLOG_2(_L8("Comms ProviderModule (%S) unloaded successfully state (%d) - Complete msg"), &iParams.iParams.iName, iState);
+			MaybeCompleteMessage(result);
+			}
+		}
+
+	else
+		{
+		if(iState == ELoading)
+			{
+			__FLOG_2(_L8("Comms Provider Module load operation failed with (%d) - state (%d) - Complete msg"), result, iState);
+			}
+			else if(iState == EUnLoading)
+				{
+				__FLOG_2(_L8("Comms Provider Module unload operation failed with (%d) - state (%d) - Complete msg"), result, iState);
+				}
+		else
+			{
+			__FLOG_2(_L8("Comms Provider Module operation failed with (%d) - state (%d) - Complete msg"), result, iState);
+			}
+		MaybeCompleteMessage(result);
+		if(result==KErrRSModuleAlreadyExist)
+			{
+			__FLOG_1(_L8("Comms Provider Module %S load failed with KErrRSModuleAlreadyExist. This is usually OK if configurator was SoftBooted, e.g. during testing."), &iParams.iParams.iName);
+			iState = ELoaded;
+			iCommsProcess.NotifyLoadCompletion(*this);
+			}
+		else
+			{
+			if (iState == ELoading)
+				{
+				__FLOG_2(_L8("Comms Provider Module %S NOT loaded. Error: %d"), &iParams.iParams.iName, iStatus.Int());
+				iState = ELoadFailed;
+				iCommsProcess.NotifyLoadCompletion(*this);
+				}
+			else if (iState == EUnLoading)
+				{
+				__FLOG_2(_L8("Comms Provider Module %S NOT Unloaded. Error: %d"), &iParams.iParams.iName, iStatus.Int());
+				iState = ELoaded;
+				}
+			}
+		}
+	}
+
+void CModuleRef::DoCancel()
+	{
+	iRootServer.CancelLoadCpm(iParams.iParams.iName);
+	}
+
+TInt CModuleRef::CompareScaledStartupState(const CModuleRef& aModule1, const CModuleRef& aModule2)
+	{
+	// Rely upon 2s-complement maths & the comparative closeness of values to avoid explicit comparisons
+	return (TInt32) aModule1.ScaledStartupState() - (TInt32) aModule2.ScaledStartupState();
+	}
+
+void CModuleRef::MaybeCompleteMessage(TInt aReturnValue)
+	{
+	// only complete msg for module which has RMessage set on OnDemand Loading/Unloading NOT on
+	// OnDemand property of module
+	if (!iRMessage.IsNull())
+		{
+		if(iNumBindings == iCompletedBindings && iRMessage.Function() == CSLoadCpm)
+			{
+			iRMessage.Complete(aReturnValue);
+			}
+		else if (iRMessage.Function() == CSUnloadCpm)
+			{
+			iRMessage.Complete(aReturnValue);
+			}
+		}
+	}
+
+void CModuleRef::UnBindCpm()
+	/**Sets the iState of CBindinRef to ENotBound once UnLoadCpm is successful
+	*/
+	{
+	RPointerArray<CBindingRef>& bindings = iCommsProcess.GetBindingList();
+	for(TInt i=0; i<bindings.Count(); i++)
+		{
+		if(Name() == bindings[i]->FromModule().Module())
+			{
+			bindings[i]->SetState(ENotBound);
+			}
+		}
+	}
+
+void CModuleRef::UnLoadCpm(const TCFModuleNameF& aModuleName,TRSUnLoadType aType)
+	{
+	iState = EUnLoading;
+
+	SetPriority(EPriorityHigh);
+
+	iRootServer.UnloadCpm(iStatus, aModuleName, aType);
+	SetActive();
+	}
+
+void CModuleRef::CancelLoadCpm(const TCFModuleNameF& aModuleName)
+	{
+	iRootServer.CancelLoadCpm(aModuleName);
+	}
+
+void CModuleRef::CancelUnLoadCpm(const TCFModuleNameF& aModuleName)
+	{
+	iRootServer.CancelUnloadCpm(aModuleName);
+	}
+
+CDeathWatcher::CDeathWatcher(CCommsProcessStarter& aStartConfigProcess)
+: CActive(EPriorityStandard),
+  iStartProcess(aStartConfigProcess)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CDeathWatcher::~CDeathWatcher()
+	{
+	Cancel();
+	iDeathProperty.Close();
+	}
+
+void CDeathWatcher::DoCancel()
+	{
+	iDeathProperty.Cancel();
+	}
+
+void CDeathWatcher::RunL()
+	{
+	TInt deathReason = iStatus.Int();
+	iDeathProperty.Subscribe(iStatus);
+	SetActive();
+	TInt deathCount;
+	TInt result = iDeathProperty.Get(deathCount);
+	if(result != KErrNone)
+		{
+		__FLOG_1(_L8("Error %d upon Get of death property"), result);
+		User::Panic(KC32Start, EDeathWatch);
+		}
+	iStartProcess.NotifySuddenDeath(deathCount, deathReason);
+	}
+
+CDeathWatcher* CDeathWatcher::NewL(CCommsProcessStarter& aStartConfigProcess)
+	{
+	CDeathWatcher* self = new(ELeave) CDeathWatcher(aStartConfigProcess);
+	self->Construct();
+	return self;
+	}
+
+void CDeathWatcher::Construct()
+	{
+	TInt result = iDeathProperty.Attach(KUidSystemCategory,KUidC32RootModuleDeathKey.iUid);
+	if(result != KErrNone)
+		{
+		__FLOG_1(_L8("Error %d upon attach to death property"), result);
+		User::Panic(KC32Start, EDeathWatch);
+		}
+	iDeathProperty.Subscribe(iStatus);
+	SetActive();
+	}
+
+
+CStartupStateObserver::CStartupStateObserver(CCommsProcessStarter& aStarter)
+: CDmDomain(KDmHierarchyIdStartup, KSM2GenMiddlewareDomain3),
+  iStarter(aStarter)
+	{
+	}
+
+
+CStartupStateObserver* CStartupStateObserver::NewL(CCommsProcessStarter& aStarter)
+	{
+	CStartupStateObserver* self = new(ELeave) CStartupStateObserver(aStarter);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CStartupStateObserver::~CStartupStateObserver()
+	{
+	Cancel();
+	}
+
+void CStartupStateObserver::RunL()
+	{
+	iStarter.NotifyStartupStateChange();
+	}
+
+#ifdef SYMBIAN_ZERO_COPY_NETWORKING
+CCommsProcessStarter::CCommsProcessStarter(RRootServ& aRootServer, RProperty& aProperty)
+:
+  iRootServer(aRootServer),
+  iConfigurationProperty(aProperty)
+#else
+CCommsProcessStarter::CCommsProcessStarter(RRootServ& aRootServer, RProperty& aProperty)
+:
+  iRootServer(aRootServer),
+  iConfigurationProperty(aProperty),
+  iInitMBufPoolSize(KMBufDefaultHeapSize),
+  iMaxMBufPoolSize(KMBufDefaultHeapSize)
+#endif // SYMBIAN_ZERO_COPY_NETWORKING
+/** C'tor. derived from CBase, hence member zero initialized
+@param aRootServer The rootserver API.
+@param aProperty The property through which to publish level information.
+*/
+    {
+    }
+
+CCommsProcessStarter* CCommsProcessStarter::NewLC(RRootServ& aRootServer, RProperty& aProperty)
+	{
+	CCommsProcessStarter* self = new(ELeave) CCommsProcessStarter(aRootServer, aProperty);
+	CleanupStack::PushL(self);
+	TRAPD(err, self->iStartupStateObserver = CStartupStateObserver::NewL(*self));
+	if(err != KErrNone)
+		{
+		// The likely cause of this is that the system has no domains defined & in fact is running a legacy starter.
+		__FLOG_1(_L8("CCommsProcessStarter - domain observer construction failed (err %d); going immediately to fully-booted state"), err);
+		}
+	return self;
+	}
+
+CCommsProcessStarter::~CCommsProcessStarter()
+/** D'tor.
+*/
+    {
+	iModules.ResetAndDestroy();
+	iBindings.ResetAndDestroy();
+	delete iDeathWatcher;
+	delete iStartupStateObserver;
+	iRootServer.Close();
+    delete iConfiguratorServer;
+    }
+
+TBool CCommsProcessStarter::ConfigurationComplete() const
+	{
+	return iUnloadedModuleIdx >= iModules.Count();
+	}
+
+void CCommsProcessStarter::NotifySuddenDeath(TInt aDeathCount, TInt aDeathStatus)
+/** Runs when the Rootserver publish the deathcount.
+*/
+	{
+	if(aDeathCount > iDeathCount)
+		{
+		iDeathCount = aDeathCount;
+		if(aDeathStatus != KErrServerTerminated)
+			{
+			__FLOG_1(_L8("CCommsProcessStarter::NotifySuddenDeath - DeathCount: %d"), iDeathCount);
+			// At least one module just died - enumerate the current modules to determine
+			// which have died, and for each of these pass control to its death handler,
+			// which may attempt to reload it with some suitable algorithm to prevent
+			// endless looping (etc). If the death handler doesn't resurrect it and it
+			// was marked as SystemCritical then we have to reboot the RootServer. This
+			// is done to clear up all process-owned artifacts (eg old thread names,
+			// semaphores) which could be blocking a restart.
+			TRSModuleInfo modInfo;
+			for(int i = iModules.Count() - 1; i >= 0; --i)
+				{
+				CModuleRef* mod = iModules[i];
+				if((mod->State() != ENotLoaded) && (iRootServer.GetModuleInfo(mod->Name(), modInfo) != KErrNone ||
+					modInfo.iParams.iState == EZombie ||
+					modInfo.iParams.iState == EDead))
+				{
+				if(!mod->Resurrect() && !InTestMode() && (mod->SystemCritical() || (mod->SystemCriticalAfterInit() && ConfigurationComplete())))
+					{
+						// if SystemCriticalAfterInit then will not reboot as problem could be due to corrupt system files
+						// in c drive, hence best let the phone to continue and allow a master reset.
+
+						// Here we do the RS reboot in the most brutal way possible, by rebooting
+						// the whole OS.
+						// In principle all we need is to kill and respawn the Root Server, since
+						// that will usually release all conflicting resources. However it's possible that
+						// other processes are sharing these too, in which case we'll end up having to do
+						// a full reboot anyway. A worthwhile improvement could be falling all the way
+						// out of InitConfiguratorL() with some "reboot" code to trigger us to
+						// republish the progress to the base state, relaunch the RS, and restart the
+						// whole load and configuration process, and only opt for a device reboot if
+						// this second chance fails.
+						// However this will add significant testing load (risk of endless loops) so
+						// it is excluded from the scope of this reference implementation.
+						_LIT16(KSystemCriticalMsg1, "%S: A thread specified as Critical, i.e. in its .cmi file, has exited and cannot be restarted.");
+						_LIT8 (KSystemCriticalMsg2, "\t\"%s\" thread at fault. The system will now reboot!");
+						_LIT8 (KSystemCriticalMsg3, "\t\"%s=1\", that would switch off this behaviour for testing, was not specified in file:");
+						_LIT16(KSystemCriticalMsg4, "\t\t\"\\private\\101F7988\\%S\"");
+
+						RDebug::Print (KSystemCriticalMsg1, &KC32Start);
+						RDebug::Printf(reinterpret_cast<const char*>(KSystemCriticalMsg2().Ptr()), mod->Name().Ptr());
+						RDebug::Printf(reinterpret_cast<const char*>(KSystemCriticalMsg3().Ptr()), KC32StartTestMode().Ptr());
+						RDebug::Print (KSystemCriticalMsg4, &KC32StartIniFile);
+
+						User::SetCritical(User::ESystemPermanent);
+						TBuf8<KMaxExitCategoryName> panicCategory(KAbbreviatedC32Start);
+						panicCategory.Append(mod->Name().Left(KMaxExitCategoryName - KAbbreviatedC32Start().Length()));
+						TBuf<KMaxExitCategoryName> unicodePanicCategory;
+						unicodePanicCategory.Copy(panicCategory);
+						User::Panic(unicodePanicCategory, ECriticalModuleDeath);
+						}
+					}
+				}
+
+			}
+// surely this is legacy of pre-pubsub?
+//		else
+//			{
+//			__FLOG_1(_L8("CCommsProcessStarter::NotifySuddenDeath - Root Server has died. Error: %d."), iStatus.Int());
+//			Shutdown();
+//			}
+		}
+	else
+		{
+		__FLOG(_L8("CCommsProcessStarter::NotifySuddenDeath - Signalled to shutdown."));	//@todo - check whether the double pub of status really done by RS shutting down?
+		Shutdown();
+		}
+	}
+
+CModuleRef* CCommsProcessStarter::GetModule(const TCFModuleNameF& aModuleName) const
+/**
+@param aModule Name of a module to search for.
+@return Pointer to an instance with matching name or NULL.
+*/
+	{
+	for(TInt i=0; i<iModules.Count(); i++)
+		{
+		if(*iModules[i] == aModuleName)
+			{
+			return iModules[i];
+			}
+		}
+	return NULL;
+	}
+
+
+void CCommsProcessStarter::NotifyLoadCompletion(CModuleRef& /*aModule*/)
+/** Called by each CModuleRef when they have finished loading, and calls
+bindIfReady() on them.
+*/
+	{
+	iModulesLoading--;
+	iModulesLoaded++;
+
+
+	if(!iModulesLoading)	// if all at this level are done then can process the next level
+		{
+		__FLOG(_L8("no more pending at current level. Trying binds."));
+		iBindCount = 0;
+		TInt result;
+		for(TInt i=0; i<iBindings.Count(); i++)
+			{
+			 result = iBindings[i]->BindIfReady();
+			if(result == KErrNone)
+				{
+				iBindCount++;
+				}
+			else if(result == KErrRSSubModuleUnknown)
+				{
+				// This is a definite configuration error - the binding refers to a module
+				// that wasn't described in any CMI file. We delete the binding and proceed -
+				// although such a configuration error is panic worthy this is too likely to
+				// make the phone useless
+				__FLOG_STMT(
+					{
+					TCFFullModuleName __FullModName1;
+					iBindings[i]->ToModule().Printable(__FullModName1);
+					TCFFullModuleName __FullModName2;
+					iBindings[i]->FromModule().Printable(__FullModName2);
+					__FLOG_VA( (_L8("CONFIGURATION ERROR: binding %S - %S failed with ERSSubModuleUnknown"), &__FullModName1, &__FullModName2) );
+					}
+					);
+				__DEBUGGER();
+				iBindings.Remove(i);
+				--i;	// balance the loop
+				}
+			}
+		if(iBindCount==0)
+			{
+		    ContinueLoading();
+			}
+		}
+	}
+
+void CCommsProcessStarter::NotifyBindCompletion(CBindingRef& /*aBinding*/)
+/** If this was the last binding, ascends to next level.
+*/
+	{
+	iBindCount--;
+
+	if(iBindCount==0)
+		{
+		ContinueLoading();
+		}
+	}
+
+
+
+void CCommsProcessStarter::NotifyStartupStateChange()
+	{
+	__ASSERT_DEBUG(iStartupStateObserver, User::Panic(KSpecAssert_RootSrvc32start, 1));
+
+	iNeedToAckLastState = ETrue;
+	// Upper bound for the next tranche of scaled start-up states
+	iScaledStartupState = ((iStartupStateObserver->GetState() + 1) * (TUint) KC32StartupStateScalingFactor) - 1;
+	ContinueLoading();
+	}
+
+void CCommsProcessStarter::PrintSummary()
+/** In debug mode this prints information of loaded modules and bindings.
+*/
+    {
+#ifdef __FLOG_ACTIVE
+	// Enumerate all modules
+	TCFModuleNameF name;
+	TRSIter modulePos;
+
+	// NB: ABove we set eReset to true, the rootserver will set it to false
+	// for next run, so we never ned to worry about it being a wrong value.
+	// the loop just run to end of entries as if by magic.
+	while(iRootServer.EnumerateModules(modulePos, name) == KErrNone)
+		{
+		TRSModuleInfo info;
+		// Get more information
+		TInt result = iRootServer.GetModuleInfo(name, info);
+		if(result==KErrNone)
+			{
+			__FLOG_STMT(TBuf8<KMaxFileName> fnam;)
+			__FLOG_STMT(fnam.Copy(info.iParams.iDll);)
+			__FLOG_3(_L8("Module: \"%S\" from \"%S\". State: %d."),
+				&name, &fnam, info.iParams.iState);
+
+			// Enumerating submodules for this module
+			TRSIter subModulePos;
+			TCFSubModuleName subname;
+			while(KErrNone==iRootServer.EnumerateSubModules(name, subModulePos, subname))
+				{
+				__FLOG_2(_L8("  Submodule: \"%S:%S\""), &name, &subname);
+				// Enumerate bindings for this module
+				TRSBindingInfo binding;
+				TRSIter bindPos;
+				TCFSubModuleAddress addr(name,subname);
+
+				while(KErrNone==iRootServer.EnumerateBindings(addr, bindPos, binding))
+					{
+					if(subname == binding.iParams.iAddress1.SubModule())
+					    {
+						__FLOG_5(_L8("    Binding: \"%S:%S\", status(%d,%d), typ=%d."),
+						    &binding.iParams.iAddress2.Module(),
+							&binding.iParams.iAddress2.SubModule(),
+							binding.iParams.iState1,
+							binding.iParams.iState2,
+							binding.iParams.iType);
+					    }
+					else
+					    {
+						__FLOG_5(_L8("    Binding: \"%S:%S\", status(%d,%d), typ=%d."),
+						    &binding.iParams.iAddress1.Module(),
+							&binding.iParams.iAddress1.SubModule(),
+							binding.iParams.iState1,
+							binding.iParams.iState2,
+							binding.iParams.iType);
+					    }
+					}
+				}
+			}
+		}
+	__FLOG(_L8("*** End of configuration summary ***"));
+#endif
+    }
+
+void CCommsProcessStarter::Shutdown()
+	{
+	__FLOG(_L8("Shutting down"));
+	CActiveScheduler::Stop();
+ 	}
+
+
+/** Start loading all modules with a scaled startup state below the
+current level and which haven't yet been tried.
+*/
+void CCommsProcessStarter::ContinueLoading()
+	{
+	const TInt modulesCount = iModules.Count();
+	__FLOG_6(_L8("ContinueLoading: Scaled start-up state 0x%x (%u), %d loads pending, %d binds pending, load pos %d of %d"), iScaledStartupState, iScaledStartupState, iModulesLoading, iBindCount, iUnloadedModuleIdx, modulesCount);
+
+	if(iModulesLoading > 0 || iBindCount > 0)
+		{
+		return;	// as these complete they'll attempt to continue loading
+		}
+
+	if (iNeedToAckLastState)
+		{
+		iNeedToAckLastState = EFalse;
+		iStartupStateObserver->RequestTransitionNotification();
+		iStartupStateObserver->AcknowledgeLastState(KErrNone);
+		if (iScaledStartupState >= KC32HighStartSequenceScaleBase)
+			{
+			//The SuDHSC has transitioned past our startup state
+			//so we are not interested in state change information anymore
+			delete iStartupStateObserver;
+			iStartupStateObserver = NULL;
+			__FLOG(_L8("iStartupStateObserver observation ended"));
+			}
+		}
+
+	CModuleRef* mod = NULL;
+	TUint32 firstModScaledState = 0;
+	TBool allModsOnDemand = ETrue;	// all mods encountered in this loop have been skipped as OnDemand
+	
+	if(iUnloadedModuleIdx < modulesCount)
+		{
+		mod = iModules[iUnloadedModuleIdx];
+		}
+	while(iUnloadedModuleIdx < modulesCount && 
+		((mod = iModules[iUnloadedModuleIdx])->ScaledStartupState() == firstModScaledState || allModsOnDemand))
+		{
+			// Not all modules load now, as there are modules with OnDemand=1
+			// if ((module is NOT loaded) AND (EITHER (OnDemand module being loaded (RMessage set)) OR (boot-time module)))
+			// msg will be set for module only if OnDemand loading is requested
+			if(mod->State()==ENotLoaded && ((mod->IsOnDemand() && !mod->Message().IsNull()) || !mod->IsOnDemand()))
+				{
+				mod->Load();
+				if(allModsOnDemand)
+					{
+					allModsOnDemand = EFalse;	// this one wasn't!
+					firstModScaledState = mod->ScaledStartupState();	// can only simultaneously command the load of others with the exact same sequence
+					}
+				++iModulesLoading;		// this must be subtracted as each module load completes
+				}
+			++iUnloadedModuleIdx;
+			}
+
+
+	if(iUnloadedModuleIdx == modulesCount && allModsOnDemand)
+		{
+		// All currently loadable modules have loaded and bound, however unless no
+		// OnDemand modules are present we keep listening for startup state changes 
+		// as it's possible that an OnDemand load request will occur that still 
+		// needs correct startup sequencing. However we're can declare ourself
+		// "booted" and dump the summary
+		
+		if(iPublicationLevel < EPublishedComplete)
+			{
+			// set the sequence to max and publish it
+			iPublicationLevel = EPublishedComplete;
+			iConfigurationProperty.Set(EConfigurationComplete);
+
+			}
+#if defined _DEBUG || defined __FLOG_ACTIVE || defined SYMBIAN_TRACE_ENABLE
+		if(!iSummaryAlreadyPrinted)
+			{
+			iSummaryAlreadyPrinted = ETrue;
+			
+			_LIT8(KAllModulesStarted, "ESockSvr startup modules loaded! (%d of %d)");
+			
+			#ifdef _DEBUG
+				RDebug::Printf(reinterpret_cast<const char*>(TPtrC8(KAllModulesStarted).Ptr()), iModulesLoaded, modulesCount);
+			#endif
+				
+			// Log the modules startup message 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(KAllModulesStarted, &overflowHandler, iModulesLoaded, modulesCount);
+
+				UTracePfAny(KPrimaryFilter, KText, ETrue, EFalse, buf.Length(), buf.Ptr(), buf.Length());
+			#endif
+			
+			__FLOG_2(KAllModulesStarted, iModulesLoaded, modulesCount);
+			
+    	    PrintSummary();
+			}
+#endif
+		}
+	else if(iPublicationLevel < EPublishedCore && firstModScaledState >= KC32CoreComponentsStartedScaled)
+		{
+		iPublicationLevel = EPublishedCore;
+		iConfigurationProperty.Set(ECoreComponentsStarted);
+
+		}
+	}
+
+
+void CCommsProcessStarter::LoadOnDemandModule(CModuleRef& aModule)
+	/** This is called when there is request for on demand load of a module.
+	Compares the Scaled Startup State of OnDemand module with scaled state of module in the list (iModules) which
+	is being currently loaded, if current scaled startup state has already passed wrt the scaled startup state of
+	OnDemand requested module, this sets the iUnloadedModuleIdx to index (in iModules) of MIN scaled startup
+	state of current and OnDemand requested module
+	*/
+	{
+	__FLOG_1(_L8("CCommsProcessStarter::LoadOnDemandModule(%S)"), &aModule.Name());
+
+	const TUint32 modScaledState = aModule.ScaledStartupState();//Scaled start up state of requested module
+	if(iUnloadedModuleIdx!=0)
+		{
+		const TUint32 currentModScaledState = iModules[iUnloadedModuleIdx-1]->ScaledStartupState();//Scaled start up state of last module loaded.
+
+		if(currentModScaledState >= modScaledState)
+			{
+			TInt minIndex;
+			for(minIndex=0;minIndex<iUnloadedModuleIdx;minIndex++)
+				{
+				// since iModules are added in order of scaled startup state, finding index this way
+				// will not skip any to-be-loaded modules
+				if(iModules[minIndex] == &aModule)
+					{
+					break;
+					}
+				}
+			iUnloadedModuleIdx = minIndex;	// set the index
+			}
+		}
+
+	ContinueLoading();
+
+	}
+
+// private MBufSizeAllocInfo defaults
+// - 128 mbuf size is mandatory since their exists some (poorly writen) legacy code that assumes the existance of mbufs with this size
+static const TInt KMBuf_MBufSize = 128;
+static const TInt KMBuf_InitialAllocation = 128;
+static const TInt KMBuf_MinGrowth = 64;
+static const TInt KMBuf_GrowthThreshold = 40;
+
+void CCommsProcessStarter::ReadConfigAndStartAllL(const TDesC& aCMISuppressions)
+/** Initiate the loading of comms server modules and
+comms provider modules.  We publish a property with
+the state of configuration we have reached to allow waiting
+StartC32() to complete when we indicate we are finished by
+publishing CONFIGURED to our property.
+@param aCMISuppressions List of .cmi files to ignore should they exist.
+*/
+	{
+	__FLOG(_L8("CBindingRef::ReadConfigAndStartAllL"));
+
+	// start the configurator server
+	TRAPD(err, iConfiguratorServer = CRsConfiguratorServer::NewL(*this));
+	__FLOG_1(_L8(" Create ConfiguratorServer returned %d."), err);
+	__ASSERT_ALWAYS(err == KErrNone || err == KErrAlreadyExists , Fault(EPanicConfigServer));
+
+	TAutoClose<RFs> fs;
+	TInt result;
+	if(KErrNone!=(result=fs.iObj.Connect()))
+		{
+		__FLOG(_L8("Unable to connect to the File Server"));
+		User::Leave(result);
+		}
+	fs.PushL();
+
+	TBuf<KMaxPath> privatePath;
+	User::LeaveIfError(fs.iObj.PrivatePath(privatePath));
+
+	__FLOG_STMT(TBuf8<KMaxPath> fpath;)
+	__FLOG_STMT(fpath.Copy(privatePath);)
+	__FLOG_1(_L8("Using .CMI search path: %S"), &fpath);
+
+	// Find the (optional) c32start.ini configuration file across all drive
+	TFindFile ff(fs.iObj);
+	CDir* iniFileList;
+	TParse fullentry;
+	result = ff.FindWildByDir(KC32StartIniFile, privatePath, iniFileList);
+	CleanupStack::PushL(iniFileList);
+#ifdef SYMBIAN_ZERO_COPY_NETWORKING
+	TInt initTotalPoolSize = 0;
+	TInt overAllCeiling = 0;
+#endif
+	RArray<TRSAddMBufAllocInfoContainer> mBufAllocSizeInfo;
+	if (KErrNone == result)
+		{
+		// Read global configuration options
+		fullentry.Set((*iniFileList)[0].iName, &ff.File(), NULL);
+		C32ParseIniFile* globalConfigFile = C32ParseIniFile::NewL(fullentry.FullName(), fs);
+
+		TPtrC8 mBufCfg;
+		// read mbuf pool size
+
+		globalConfigFile->FindVar(KC32StartIniGlobalSection, KC32StartMBufPoolSize, mBufCfg);
+#ifdef  SYMBIAN_ZERO_COPY_NETWORKING		
+      	SplitInt(mBufCfg, initTotalPoolSize);
+        SplitInt(mBufCfg, overAllCeiling);
+#else
+ 		SplitInt(mBufCfg, iInitMBufPoolSize);
+  		SplitInt(mBufCfg, iMaxMBufPoolSize);
+#endif  // SYMBIAN_ZERO_COPY_NETWORKING      
+		// read mbuf size alloc info entries
+		TRSAddMBufAllocInfoContainer allocInfo;
+		for (TInt i = 1 ;; i++)	// the first missing key enumeration (starting from 1) aborts the loop
+			{
+			if (globalConfigFile->FindVar(KC32StartIniGlobalSection, KC32StartMBufSizeAllocInfo, mBufCfg, i) == EFalse)
+				break;
+			if (SplitUint(mBufCfg, allocInfo.iMBufSize)  || SplitUint(mBufCfg, allocInfo.iInitialAllocation) ||
+				SplitUint(mBufCfg, allocInfo.iMinGrowth) || SplitUint(mBufCfg, allocInfo.iGrowthThreshold))
+				{
+				__FLOG_1(_L("CCommsProcessStarter::ReadConfigAndStartAllL() Error! - failed to parse MBufSizeAllocInfo=%d"), i);
+				continue;
+				}
+#ifdef  SYMBIAN_ZERO_COPY_NETWORKING				
+			allocInfo.iPoolCeiling = 0;
+			(void)SplitUint(mBufCfg, allocInfo.iPoolCeiling); // If it is not set we will set the value based on the overall pool ceiling
+#endif // SYMBIAN_ZERO_COPY_NETWORKING			
+			mBufAllocSizeInfo.AppendL(allocInfo);
+			}
+		
+		
+		
+		// read test mode flag
+		globalConfigFile->FindVar(KC32StartIniGlobalSection, KC32StartTestMode, iTestMode);
+
+		delete globalConfigFile;
+		}
+#ifdef  SYMBIAN_ZERO_COPY_NETWORKING			
+	if(overAllCeiling > 0)
+		{
+		TBool needPoolCeilingAssign = EFalse;
+		// Check we have the pool ceiling value for every entry
+		// If pool ceiling is missing in some entry we will align them based on the overall pool size
+		for(TInt i = 0; i < mBufAllocSizeInfo.Count(); ++i)
+			{
+			if(mBufAllocSizeInfo[i].iPoolCeiling == 0)	
+				{
+				__FLOG_0(_L("CCommsProcessStarter::ReadConfigAndStartAllL() Error! - One of the pool ceiling value is wrong. Initializing to default"));
+				needPoolCeilingAssign = ETrue;
+				break;					
+				}
+			}
+		if(needPoolCeilingAssign)
+			{
+			TInt poolSize = overAllCeiling / mBufAllocSizeInfo.Count();
+			for(TInt i = 0; i < mBufAllocSizeInfo.Count(); ++i)
+				{
+				mBufAllocSizeInfo[i].iPoolCeiling = poolSize/mBufAllocSizeInfo[i].iMBufSize;
+				}
+			}
+		}
+#endif // SYMBIAN_ZERO_COPY_NETWORKING		
+	
+	
+	// if no valid mbuf size alloc info entry, then assign a default value
+	if (mBufAllocSizeInfo.Count() == 0)
+		{
+		__FLOG(_L("CCommsProcessStarter::ReadConfigAndStartAllL() Warning! - no valid MBufSizeAllocInfoX entry found, assigning default value instead"));
+		TRSAddMBufAllocInfoContainer allocInfo;
+		allocInfo.iMBufSize = KMBuf_MBufSize;
+		allocInfo.iInitialAllocation = KMBuf_InitialAllocation;
+		allocInfo.iMinGrowth = KMBuf_MinGrowth;
+		allocInfo.iGrowthThreshold = KMBuf_GrowthThreshold;
+#ifdef  SYMBIAN_ZERO_COPY_NETWORKING		
+		allocInfo.iPoolCeiling = overAllCeiling/KMBuf_MBufSize;
+#endif // SYMBIAN_ZERO_COPY_NETWORKING		
+		mBufAllocSizeInfo.AppendL(allocInfo);
+		}
+
+	CleanupStack::PopAndDestroy(iniFileList);
+	__FLOG(iTestMode? _L("In test mode: termination of system-critical CPMs tolerated") : _L("In normal mode") );
+
+	// Generate a list of config files (*.CMI in the *\system\data directory, ie searches all drives
+	// available drives, ending with Z:)
+	CommsFW::COwnEntryList* cmiList = new(ELeave) CommsFW::COwnEntryList(6);
+	CleanupStack::PushL(cmiList);
+
+#ifdef SYMBIAN_NETWORKING_CFTRANSPORT
+	cmiList->UniqueWildScanAcrossDrivesL(privatePath, KC32WildCard);		// masking of CMI files on basis of module names Y->A:Z
+#else
+	cmiList->WildScanAcrossDrivesL(privatePath, KC32WildCard);		// masking of CMI files on basis of module names Y->A:Z
+#endif
+
+	if(cmiList->Count()==0)
+		{
+		__FLOG(_L8("Unable find any CMI files"));
+		}
+
+	// ************************************* checks to ensure we don;t get race conditions
+	TCFModuleNameF name;
+	TRSIter modulePos;
+	TInt totalModules = 0;
+	while((result = iRootServer.EnumerateModules(modulePos, name)) == KErrNone)
+		{
+		++totalModules;
+		}
+	__ASSERT_DEBUG(result == KErrEof, User::Panic(KSpecAssert_RootSrvc32start, 2));
+	if(totalModules == cmiList->Count())
+		{
+		// we found the same number of servers running in rootserver as
+		// we expected to load, so rootserver has already been configured
+		__FLOG(_L8("root server found to be configured already"));
+		// we must set the property, just to put us into the right state
+		iConfigurationProperty.Set(EConfigurationComplete);
+		CleanupStack::PopAndDestroy(cmiList);
+		fs.Pop();
+		return;	// because rootserver is already configured
+		}
+	// ********************************** end of starting check
+
+	// before starting load get the death watcher ready to catch any collateral damage
+	iDeathWatcher = CDeathWatcher::NewL(*this);
+#ifndef SYMBIAN_ZERO_COPY_NETWORKING
+  	// Configure the MBuf pool size
+  	__FLOG_2(_L8("Setting MBufPoolSize(Init:%d Max:%d)"), iInitMBufPoolSize, iMaxMBufPoolSize);
+  	result = iRootServer.SetMBufPoolSize(iInitMBufPoolSize, iMaxMBufPoolSize);
+  	if(result==KErrInUse)
+  		{
+  		__FLOG(_L8("SetMBufPoolSize failed with KErrInUse. This is usually OK if configurator was SoftBooted, e.g. during testing."));
+  		}
+  	else if(result != KErrNone)
+  		{
+  		__FLOG_1(_L8("SetMBufPoolSize failed with err %d"), result);
+  		}
+#endif // SYMBIAN_ZERO_COPY_NETWORKING
+
+	// configure the mbuf size allocation info - via a message between the configurator to rootserver
+    for (int i = 0; i < mBufAllocSizeInfo.Count(); i++)
+		{
+		__FLOG_4(_L8("Setting MBufSizeAllocInfo; mbufSize=%d initialAlloc=%d minGrowth=%d growthTrigger=%d"),
+			mBufAllocSizeInfo[i].iMBufSize, mBufAllocSizeInfo[i].iInitialAllocation, mBufAllocSizeInfo[i].iMinGrowth,
+			mBufAllocSizeInfo[i].iGrowthThreshold);
+		result = iRootServer.AddMBufAllocInfo(mBufAllocSizeInfo[i]);
+		if (result != KErrNone)
+			{
+			__FLOG_1(_L8("AddMBufAllocInfo failed with err %d"), result);
+			}
+		}
+
+	// set the mbuf size allocation commit flag - via a message between the configurator to rootserver
+//	result = iRootServer.SetMBufSizeAllocCommit();
+//	if (result != KErrNone)
+//		{
+//		__FLOG_1(_L8("SetMBufSizeAllocCommit failed with err %d"), result);
+//		}
+
+	__FLOG_STMT(TBuf<KMaxFileName> nam;)
+	C32CmiData* pIniData;
+	CModuleRef* pModule;
+	TRSBindingInfo binding;
+	TLinearOrder<CModuleRef> scaledStartupStateSort(CModuleRef::CompareScaledStartupState);
+
+	// We have a list of filenames, process them...
+	for (TInt i=0; i<cmiList->Count(); i++)
+		{
+		const TDesC& cmiEntry = (*cmiList)[i].iName;
+		fullentry.Set(cmiEntry, &ff.File(), NULL);
+
+		// Test whether it's a suppressed file
+		const TPtrC ptrc = fullentry.NameAndExt();
+		TInt pos = aCMISuppressions.FindF(ptrc);
+		if(pos >= 0)
+			{
+			__FLOG_1(_L("Skipping .CMI file %S due to explicit suppression."), &cmiEntry);
+			continue;
+			}
+		__FLOG_STMT(nam.Copy(fullentry.FullName());)
+		__FLOG_1(_L("Processing .CMI file %S."), &nam);
+
+			TRAP(result,
+			 pIniData = C32CmiData::NewL(fullentry.FullName(), fs);
+			 CleanupStack::PushL(pIniData);
+			 pModule=CModuleRef::NewLC(iRootServer, *this, *pIniData);
+			 if(KErrNone!=(result=iModules.InsertInOrderAllowRepeats(pModule, scaledStartupStateSort)))
+				 {
+				 __FLOG_2(_L("Unable to add %S configuration to task list, error %d."), &nam, result);
+				 User::Leave(result);
+				 }
+			__FLOG_1(_L8("...ModuleName=\"%S\""), &pModule->Name());
+			 CleanupStack::Pop(pModule);
+
+			 while(pIniData->NextBindingL(binding))
+				 {
+				 CBindingRef* pBinding = new(ELeave) CBindingRef(iRootServer, *this, binding);
+				 if(KErrNone!=(result=iBindings.Append(pBinding)))
+					 {
+					 __FLOG_1(_L8("Unable to add binding to task list, error %d."), result);
+					 delete pBinding;
+					 User::Leave(result);
+					 }
+				 }
+			 CleanupStack::PopAndDestroy(pIniData);
+ 			); //)TRAP	//lint !e429	// custody taken of pBinding
+
+		__FLOG_STMT(
+			if(KErrNone!=result)
+				{
+				__FLOG_2(_L("Unable to use .CMI file %S, error %d."), &nam, result);
+				__DEBUGGER();
+				}
+			);
+		}
+#ifdef _DEBUG
+	// Duplicate module configurations can arise from incomplete edits, backup copies, or having a .CMI present on
+	// multiple drive letters. Although these are reported as "load failed with KErrRSModuleAlreadyExist" this is
+	// too subtle to help most users understand why a module loads with the wrong configuration, etc. Hence this
+	// UDEB-only sanity check & diagnostic slap.
+	for(TInt i = iModules.Count() - 1; i >= 1; --i)	// modules are sorted by start order so no optimised search available
+		{
+		const CModuleRef& mod1(*iModules[i]);
+		for(TInt j = i - 1; j >= 0; --j)
+			{
+			if(mod1.Name() == iModules[j]->Name())
+				{
+				__FLOG_1(_L8("Duplicate \"%S\" module found. Only the first will successfully load (if any do). To find the files containing the duplicates search this log file for \"ModuleName=\""), &mod1.Name() );
+				// You hit this breakpoint because two or more .CMI files described a module with the same name.
+				// Configurations with duplicate modules can arise from incomplete edits, backup copies, or having a .CMI present on
+				// multiple drive letters. Enable the "C32Start" category in "c:\logs\commsdbg.ini" and re-run, then study the output
+				// in "c:\logs\log.txt" (path can be overridden through the .ini file). If you can't find commsdbg.ini look for advice
+				// on enabling logging through the "Comms Debug Utility"
+				__DEBUGGER();
+				continue;	// gratuitous, just to try to ensure the execution point in the debugger is close to the above breakpoint instruction
+				}
+			}
+		}
+#endif
+	CleanupStack::PopAndDestroy(cmiList);
+	fs.Pop();
+
+	iModulesLoading = 0;
+	iUnloadedModuleIdx = 0;
+	iPublicationLevel = EUnpublished;
+	if(iStartupStateObserver)
+		{
+		// Prime the change notification pump
+		NotifyStartupStateChange();
+		}
+	else
+		{
+		// No start-up observation possible, so fake the system fully-booted state
+		iScaledStartupState = 0x7FFFFFFF;
+		}
+
+#ifdef __FLOG_ACTIVE
+	// Log summary of CMI files in their startup order including the simple states they tie to.
+	_LIT( KCMISummaryLogMsg, "CCommsProcessStarter::ReadConfigAndStartAllL: CMI Load Order" );
+	__FLOG_0( KCMISummaryLogMsg );
+	RDebug::Print( KCMISummaryLogMsg );
+
+	// CMI names are ASCII so we have to use 8-bit.
+	_LIT8( KCMISummaryLogEntry, "\t%S\t[SystemCritical(%d), SystemCriticalAfterInit(%d), ScaledStartupState(%08x), GroupName(%S), IsOnDemand(%d)]" );
+	for( TInt i = 0; i < iModules.Count(); i ++ )
+		{
+		const CModuleRef& mod = *iModules[i];
+
+		// Generate the log entry using Format - RDebug::Print does not seem to cope with ASCII strings properly.
+		TBuf8<sizeof( KCMISummaryLogEntry ) + KMaxFileName + 8> entry;
+		entry.Format( KCMISummaryLogEntry, &mod.Name(), mod.SystemCritical(), mod.SystemCriticalAfterInit(), mod.ScaledStartupState()
+		, &mod.GroupName(), mod.IsOnDemand()
+		);
+
+		__FLOG_0( entry );
+		RDebug::RawPrint( entry );
+		}
+#endif
+
+	RDebug::Printf("\n");
+
+	ContinueLoading();
+	}
+
+// split/extract the first integer from the descriptor, the descriptor is incremented afterwards
+TBool CCommsProcessStarter::SplitInt(TPtrC8 &aDes, TInt& aValue) const
+	{
+	// locate the start of number
+	TLex8 lex(aDes);
+	while (!lex.Eos() &&!lex.Peek().IsDigit())
+		lex.Inc();
+
+	// extract the number & increment descriptor
+	TInt result = lex.Val(aValue);
+	aDes.Set(lex.Remainder());
+
+	return result;
+	}
+
+// split/extract the first integer from the descriptor, the descriptor is incremented afterwards
+TBool CCommsProcessStarter::SplitUint(TPtrC8 &aDes, TUint& aValue) const
+	{
+	// locate the start of number
+	TLex8 lex(aDes);
+	while (!lex.Eos() &&!lex.Peek().IsDigit())
+		lex.Inc();
+
+	// extract the number & increment descriptor
+	TInt result = lex.Val(aValue);
+	aDes.Set(lex.Remainder());
+
+	return result;
+	}
+
+static TInt InitConfiguratorL(CCommsProcessStarter*& pCCommsStartProcess, RRootServ& aRootServer, RProperty& aProperty, const TDesC& aCMISuppressions)
+/** Start the Rootserver and initiates the process of loading modules and bindings.
+*/
+    {
+	// There are 3 normal possibilities:
+	//	(1) C32EXE process is not running - we must launch it, wait for rendezvous, then connect
+	//	(2) C32EXE process is running but has yet to start the RS server - since we can't reliably distinguish
+	//		this from #1 we launch another and wait for it to exit when it can't start the server. At this
+	//		point we can try connecting to it.
+	//	(3) RS is running and connects us.
+	// After this we're connected. We may not be the only instance of C32START doing this so we ask the RS
+	// if we are "the configurator" (thanks to its protected server it's a true singleton, so we can trust
+	// its answer to be authoratative). If we aren't then we exit; anyone who launched us can now watch
+	// the KUidC32StartPropertyKey to monitor the "the configurator's" progress.
+
+    TBool alreadyRunning = aRootServer.Connect() == KErrNone;
+
+    //If we couldnt connect, we need to launch c32exe.exe
+    if(!alreadyRunning)
+		{
+		__FLOG(_L8("As expected, Root Server has to be started by us"));
+		RProcess rootServerExe;
+		TInt result = rootServerExe.Create(KRootServerExe, KNullDesC);
+		if (result == KErrNone)
+			{
+			__FLOG(_L8("Starting RS/c32exe.exe."));
+			TRequestStatus status;
+			rootServerExe.SetPriority(KRootServerDefaultPriority);
+			rootServerExe.Rendezvous(status);
+			rootServerExe.Resume();
+			__FLOG(_L8("wait for RS to complete init."));
+
+			User::WaitForRequest(status);
+			rootServerExe.Close();
+			}
+		else
+			{
+			__FLOG_1(_L8("Launching RS had error %d"), result);
+			}
+
+		__FLOG(_L8("RS has completed init and is ready for connection."));
+
+	    result = aRootServer.Connect();
+	    if(result!=KErrNone)
+			{
+			__FLOG(_L8("Unable to connect to Root Server!"));
+			User::Leave(result);
+			}
+		else
+			{
+			__FLOG(_L8("Successfully connected to Root Server."));
+			}
+		}
+	else
+		{
+		}
+
+	// Now we have RS connection, ask it whether we're "the configurator". If not then we bow
+	// out immediately; anyone who launched us can now be watching the starting publications
+	// from "The Configurator"
+	if(!aRootServer.IsCallerConfigurationAuthority())
+		{
+		__FLOG(_L8("RootServer reports existing configurator; terminating to let it do the real work"));
+		User::Leave(KErrAlreadyExists);
+		}
+
+	pCCommsStartProcess = CCommsProcessStarter::NewLC(aRootServer, aProperty);
+	__FLOG_STMT(
+		if(alreadyRunning)
+			{
+			__FLOG(_L8("RootServer already running! Current config:"));			
+			pCCommsStartProcess->PrintSummary();
+			}
+		);
+
+    pCCommsStartProcess->ReadConfigAndStartAllL(aCMISuppressions);
+	CleanupStack::Pop(pCCommsStartProcess);
+	return KErrNone;
+    }
+
+TInt E32Main()
+/** Life starts here!
+*/
+    {
+
+	// Renaming is very cosmetic so we ignore the result
+    (void)RThread::RenameMe(KC32Start);
+	(void)RProcess::RenameMe(KC32Start);
+
+    TInt result;
+	RProperty configurationProperty;
+	// publish initial property state to indicate we have started configuration
+
+	TSecurityPolicy readPolicy(ECapability_None);
+	TSecurityPolicy writePolicy(ECapabilityWriteDeviceData);
+	result = configurationProperty.Define(KUidSystemCategory, KUidC32StartPropertyKey.iUid, RProperty::EInt, readPolicy, writePolicy);
+	__ASSERT_ALWAYS(result == KErrNone || result == KErrAlreadyExists, User::Panic(KPanicSource, EPanicPubSub));
+	result = configurationProperty.Attach(KUidSystemCategory, KUidC32StartPropertyKey.iUid);
+	__ASSERT_ALWAYS(result == KErrNone, User::Panic(KPanicSource, EPanicPubSub));
+
+	__UHEAP_MARK;
+
+	__FLOG_OPEN(KSubsys, KComponent);
+	__FLOG(_L8("| - - - - - - - - - - C32Start New - - - - - - - - - - - - - |"));
+
+	CTrapCleanup* cleanupStack = CTrapCleanup::New();
+	if(!cleanupStack)
+		{
+		__FLOG(_L8("Out Of Memory initializing"));
+		return KErrNoMemory;
+		}
+	CActiveScheduler* pA = new CActiveScheduler;
+	__ASSERT_ALWAYS(pA != NULL, User::Panic(KPanicSource, ENoMemory));
+	CActiveScheduler::Install(pA);
+
+	// Fetch the list of CMI suppressions
+    TInt suppressionBufLength;
+	suppressionBufLength = User::CommandLineLength();
+	HBufC* suppressionBuf = HBufC::NewMax(suppressionBufLength);
+	__ASSERT_ALWAYS(suppressionBuf != NULL, User::Panic(KPanicSource, ENoMemory));
+	TPtr suppressions = suppressionBuf->Des();
+	User::CommandLine(suppressions);
+
+	RRootServ rootServerSession;
+	CCommsProcessStarter* pCCommsStartProcess = NULL;
+
+	// we indicate we are running and busy configuring so caller can start watching the progress property
+	RProcess::Rendezvous(KErrNone);	// we indicate we are done as property is important to caller!
+
+    TRAP(result, result = InitConfiguratorL(pCCommsStartProcess, rootServerSession, configurationProperty, suppressions));
+
+	delete suppressionBuf;
+	if(result==KErrNone)
+		{
+		CActiveScheduler::Start();
+		}
+	else if(result != KErrAlreadyExists)
+		{
+		__FLOG_1(_L8("InitConfiguratorL error %d"), result);
+		User::Panic(KPanicSource, result);	// as specified in the design we panic here not in CSCP
+		}
+
+	delete pCCommsStartProcess;
+	CActiveScheduler::Install(NULL);
+	delete pA;
+	delete cleanupStack;
+	configurationProperty.Close();	
+
+	__FLOG(_L8("| - - - - - - - - C32Start Finished - - - - - - - - - - |"));
+	__FLOG_CLOSE;
+
+	__UHEAP_MARKEND;
+
+	return KErrNone;
+	}