diff -r 000000000000 -r 08ec8eefde2f persistentstorage/dbms/sdbms/SD_SRV.CPP --- /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 (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; + } +