persistentstorage/dbms/sdbms/SD_SRV.CPP
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/sdbms/SD_SRV.CPP	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,237 @@
+// Copyright (c) 1998-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:
+// DBMS server implementation
+// 
+//
+
+#include "SD_STD.H"
+#include "Sd_PlatDep.h"
+
+using namespace DBSC;
+
+//CDbmsActiveScheduler class just exposes the access to 
+//CActiveScheduler::Level() method, which is needed to 
+//make a decision when to call CDbmsActiveScheduler::Stop().
+class CDbmsActiveScheduler : public CActiveScheduler
+	{
+public:
+	inline TInt Level() const
+		{
+		return CActiveScheduler::Level();
+		}
+	};
+
+///////////////////////
+// Class CDbsServer
+inline CDbsServer::CDbsServer() :
+	CServer2(0, ESharableSessions), 
+	iSources(iCache),
+	iDbPropsFactory(iFs),
+	iDriveSpaceCol(iFs)
+	{
+	DbgPrint1(_L("###CDbsServer::CDbsServer(), Server ProcID=%d\n"), RDbProcess().Id());
+	}
+
+//"iCache.Hold(this,KDbsExitDelay)" statement will put CDbsServer instance in the cache, 
+//which ensures that CDbsServer instance will be automatically destroyed if nobody
+//uses it next KDbsExitDelay microseconds.
+CDbsServer* CDbsServer::NewL()
+	{
+	DbgPrint1(_L("###CDbsServer::NewL(), Server ProcId=%d\n"), RDbProcess().Id());
+	CDbsServer* self= new (ELeave) CDbsServer;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	self->iCache.Hold(self, KDbsExitDelay);		// the last thing we do here
+	//Intentional behaviour, resources freed after timeout only
+	//coverity[use_after_free]
+	return self;
+	}
+
+//
+// 2nd phase construction - ensure the timer and server objects are running
+//
+void CDbsServer::ConstructL()
+	{
+	DbgPrint1(_L("###CDbsServer::ConstructL(), Server ProcId=%d\n"), RDbProcess().Id());
+	__LEAVE_IF_ERROR(Dll::SetTls(this));
+	StartL(KDbsServerName);
+	__LEAVE_IF_ERROR(iFs.Connect());
+	iDbPropsFactory.OpenL();
+	//EDriveZ - Symbian OS ROM drive !?!?
+	iDbPropsFactory.GetPrivatePathL(EDriveZ, iFileName);
+	iPolicyProxy = CPolicyProxy::NewL(iFs,iFileName);
+	User::LeaveIfError(iCache.Open(ECacheSize, ETrue));	// create a timed cache
+	}
+
+//
+// Invoked via cache entry expiry (or cleanup)
+//
+CDbsServer::~CDbsServer()
+	{
+	DbgPrint1(_L("###CDbsServer::~CDbsServer(), Server ProcId=%d\n"), RDbProcess().Id());
+	iDriveSpaceCol.Close();
+	delete iPolicyProxy;
+	iDbPropsFactory.Close();
+	iCache.Close();
+	iSources.Close();
+	iFs.Close();
+	//Stop the scheduler if the nesting level > 0.
+	//Sometime it happens that more than one thread tries to run the server and you will have
+	//CDbmsActiveScheduler::Install() called multiple times. But you have to stop the 
+	//scheduler only once!
+	CDbmsActiveScheduler* scheduler = static_cast <CDbmsActiveScheduler*> (CActiveScheduler::Current());
+	if(scheduler->Level() > 0)
+		{
+		DbgPrint2(_L("###CDbsServer::~CDbsServer(), stop the scheduler, Server ProcId=%d, scheduler=%x\n"), RDbProcess().Id(), (TInt)scheduler);
+		CDbmsActiveScheduler::Stop();
+		}
+	}
+
+//
+// Creates a new client session. This should really check the version number.
+//
+CSession2* CDbsServer::NewSessionL(const TVersion& aVersion,const RMessage2&) const
+	{
+	if(!User::QueryVersionSupported(RDbs::Version(), aVersion))
+		{
+		__LEAVE(KErrNotSupported);
+		}
+	CSession2* session = new (ELeave) CDbsSession;
+	iCache.Release(*this);
+	return session;
+	}
+
+//
+// Returns the instance of the server
+//
+CDbsServer* CDbsServer::Instance()
+	{
+	return (CDbsServer*)Dll::Tls();
+	}
+
+//
+// initiates exit if the last client is closing
+//
+void CDbsServer::RemoveSession()
+	{
+	iSessionIter.SetToFirst();
+	iSessionIter++;
+	if(iSessionIter++ == 0)
+		{
+		iCache.Hold(this, KDbsExitDelay);
+		}
+	}
+
+//
+// Performs all server initialisation, in particular creation of the
+// scheduler and server.
+// Noting has to be leaved in the cleanup stack!
+// Both: DBMS server and the active scheduler will be destroyed
+// later. The active scheduler - in CDbsServer destructor.
+// CDbsServer instance - by iCache instance (RDbCache).
+static void CreateServerL()
+	{
+	DbgPrint1(_L("###DBMS-CreateServerL(), Server ProcId=%d\n"), RDbProcess().Id());
+	// naming the server thread after the server helps to debug panics
+	User::LeaveIfError(User::RenameThread(KDbsServerName));
+	// ensure the server thread has a handle on EDBMS.DLL
+	LoadDbmsLibraryL();
+
+	// create and install the active scheduler we need
+	CDbmsActiveScheduler* scheduler = new (ELeave) CDbmsActiveScheduler;
+	CleanupStack::PushL(scheduler);
+	CDbmsActiveScheduler::Install(scheduler);
+
+	// create the server
+	(void)CDbsServer::NewL();
+
+	CleanupStack::Pop(scheduler);
+
+	// Initialisation complete, now signal the client
+	RDbProcess::Rendezvous(KErrNone);
+	}
+
+//
+// Performs all server initialisation, in particular creation of the
+// scheduler and server and then run the scheduler
+//
+static void RunServerL()
+	{
+	DbgPrint1(_L("###DBMS-RunServerL(), Server ProcId=%d\n"), RDbProcess().Id());
+	::CreateServerL();
+	//After successfull creation CreateServerL() call leaves the active scheduler instance
+	//and the DBMS server instance in the heap - they will be destroyed later.
+	__UHEAP_MARK;
+	//Start the scheduler. The execution control is transferred to the curent
+	//active scheduler. The statement after "CDbmsActiveScheduler::Start();" will
+	//be reached after the stop of active scheduler.
+	CDbmsActiveScheduler::Start();
+	__UHEAP_MARKEND;
+	}
+
+//
+// Server process entry-point
+//
+EXPORT_C TInt Dbs::Run()
+	{
+	CTrapCleanup* cleanup = CTrapCleanup::New();
+	TInt err = KErrNoMemory;
+	if(cleanup)
+		{
+		TRAP(err, ::RunServerL());
+		delete cleanup;
+		}
+	DbgPrint2(_L("###Dbs::Run(), end, Server ProcId=%d, err=%d\n"), RDbProcess().Id(), err);
+	return err;
+	}
+	
+///////////////////////
+// Client called code
+
+//
+// Starts the DBMS server
+//
+TInt Dbs::Start()
+	{
+	DbgPrint1(_L("#-#Dbs::Start(), Client ProcId=%d\n"), RDbProcess().Id());
+	RDbProcess server;
+	TInt err = ::CreateDbmsProcess(server);
+	if(err != KErrNone)
+		{
+		DbgPrint2(_L("#-#Dbs::Start(), CreateDbmsProcess, Client ProcId=%d, err=%d\n"), RDbProcess().Id(), err);
+		return err;
+		}
+
+	TRequestStatus stat;
+	server.Rendezvous(stat);
+	if(stat != KRequestPending)
+		{
+		server.Kill(0);		// abort startup
+		}
+	else
+		{
+		server.Resume();	// logon OK - start the server
+		}
+	User::WaitForRequest(stat);		// wait for start or death
+
+	// we can't use the 'exit reason' if the server panicked as this
+	// is the panic 'reason' and may be '0' which cannot be distinguished
+	// from KErrNone
+	err = (server.ExitType() == EExitPanic) ? KErrGeneral : stat.Int();
+	server.Close();
+	DbgPrint2(_L("#-#Dbs::Start(), end, Client ProcId=%d, err=%d\n"), RDbProcess().Id(), err);
+	return err;
+	}
+