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