sl@0: // Copyright (c) 1997-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: // Implements the Flogger server side sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalComponent sl@0: */ sl@0: sl@0: #include "comsdbgsvr.h" sl@0: #include "comsdbgwriter.h" sl@0: #include "comsdbgstd.h" sl@0: #include "comsdbgmessages.h" sl@0: sl@0: _LIT8(KOOMErrorString, "#Logs may be lost out of memory!! Further OOM conditions may not be recorded.\r\n"); sl@0: _LIT8(KThreadDiedString, "#Something caused the secondary thread in comsdbgutil to die.\r\n"); sl@0: _LIT8(KIniFileProblem, "#There is a problem with the ini file\r\n"); sl@0: _LIT8(KIniFileUpdate, "#Ini file changes detected and noted.\r\n"); sl@0: _LIT(KFloggerSecondaryThreadName, "Comsdbg2"); sl@0: sl@0: sl@0: sl@0: sl@0: sl@0: // sl@0: // CFileLoggerServer class definition sl@0: // sl@0: sl@0: sl@0: CFileLoggerServer* CFileLoggerServer::NewL() sl@0: { sl@0: sl@0: CFileLoggerServer* r=new(ELeave) CFileLoggerServer(); sl@0: CleanupStack::PushL(r); sl@0: r->ConstructL(); sl@0: r->StartL(KFLoggerServerName); sl@0: CleanupStack::Pop(); sl@0: return r; sl@0: } sl@0: sl@0: CFileLoggerServer::CFileLoggerServer() sl@0: : CServer2(EPriorityNormal,ESharableSessions) sl@0: {} sl@0: sl@0: void CFileLoggerServer::ConstructL() sl@0: /** sl@0: * sl@0: * @note Constructs the secondary thread, passing through a pointer to the log queue. sl@0: * Constructs the file parser object and parses the file, attempting to copy the sl@0: * file from the ROM if it is not found on C drive. sl@0: * Constructs the time beat. sl@0: * Performs the first UpdateMedia to ensure a media is set. sl@0: */ sl@0: { sl@0: User::LeaveIfError(iCriticalSection.CreateLocal()); sl@0: User::LeaveIfError(iCompletionSemaphore.CreateLocal(0)); sl@0: User::LeaveIfError(iFs.Connect()); sl@0: sl@0: #if defined (__WINS__) sl@0: iDebugWriter = CDebugPortProtocol::NewL(); sl@0: #endif sl@0: sl@0: User::LeaveIfError(iLogMessageArray.Append(NULL)); sl@0: iPreAllocatedErrorMessage = CLogCommentMessage::NewL(KOOMErrorString); sl@0: iArrayHasSpaceForWrite = ETrue; sl@0: sl@0: TInt err(KErrNone); sl@0: TPtrC iniFile(_L("")); sl@0: sl@0: /* We first check whether KFloggerIniFile (commsdbg.ini) exists, sl@0: if it does we use that one, otherwise we use the old KFloggerIniOldFile sl@0: (comsdbg.ini) instead (or rather, we try), else copy the default ini file. */ sl@0: TFindFile ff(iFs); sl@0: sl@0: err = ff.FindByDir(KFloggerIniFile, KFloggerIniDir); sl@0: sl@0: if(err != KErrNone) sl@0: { sl@0: // KFloggerIniFile was not there, lets use KFloggerIniOldFile sl@0: err = ff.FindByDir(KFloggerIniOldFile, KFloggerIniDir); sl@0: } sl@0: sl@0: if (err == KErrNone) sl@0: { sl@0: // found the ini file to use, hold on to its name and location sl@0: iniFile.Set (ff.File ()); sl@0: } sl@0: else sl@0: { sl@0: // couldn't find an ini file with the new or old name, lets use ini file in the resource dir sl@0: err = ff.FindByDir(KFloggerIniFile, KFloggerIniRscDir); sl@0: sl@0: // Get the correct system drive letter in a buffer. sl@0: TChar sysDriveLetter = RFs::GetSystemDriveChar(); sl@0: TBuf<1> sysDriveLetterBuf; sl@0: sysDriveLetterBuf.Fill( sysDriveLetter, 1 ); sl@0: sl@0: // Get the full path to the default ini file including the system drive letter. sl@0: TBuf dfltIniFullPath( KFloggerDfltIniPartialPath ); sl@0: dfltIniFullPath.Insert( 0, sysDriveLetterBuf ); sl@0: sl@0: if(err == KErrNone) sl@0: { sl@0: //only ini file is the default one in z:\resource sl@0: CFileMan* fileMan = CFileMan::NewL(iFs); sl@0: err = fileMan->Copy(KFloggerIniInROM, dfltIniFullPath, CFileMan::ERecurse); sl@0: if (err==KErrNone) sl@0: { sl@0: err = fileMan->Attribs(dfltIniFullPath,0,KEntryAttReadOnly,TTime(0)); sl@0: iniFile.Set (dfltIniFullPath); sl@0: } sl@0: delete fileMan; sl@0: } sl@0: else sl@0: { sl@0: // Get the full path to the old ini file including the system drive letter. sl@0: TBuf dfltIniOldIniFullPath( KFloggerIniOldFilePartialPath ); sl@0: dfltIniOldIniFullPath.Insert( 0, sysDriveLetterBuf ); sl@0: sl@0: // watch ini file, even tho it isnt there sl@0: // also create another file watched to watch for the old file for backward compatibility sl@0: iniFile.Set(dfltIniFullPath); sl@0: iIniOldFileWatcher = CIniFileWatcher::NewL(iFs, *this, dfltIniOldIniFullPath); sl@0: } sl@0: } sl@0: sl@0: iIniFileParser = CIniFileParser::NewL(iFs); sl@0: if (err==KErrNone) //error getting the ini file or setting attributes sl@0: { sl@0: err=iIniFileParser->ParseIniFile(iniFile); sl@0: } sl@0: else sl@0: { sl@0: // no default ini file to copy either, so lets just pretend there is an empty file sl@0: err = KErrNone; sl@0: } sl@0: sl@0: // create and set in motion the second thread sl@0: // we can only create the second thread thread once we know whether we are running sl@0: // synchronous or not. If we still don't know, then we'll force it to false. sl@0: // When flogger first starts, the flush setting is not known because the ini file sl@0: // parsing may fail. However, once client's start calling this function, we must sl@0: // decide whether to flush or not since it is not easy to switch from sl@0: // non-flushing to flushing. Thus, instead, the first time this function sl@0: // is called, we make a decision sl@0: iIniFileParser->FinaliseFlushSetting(); sl@0: TBool currentFlushSetting; sl@0: iIniFileParser->FlushingOn(currentFlushSetting); sl@0: // the second thread needs to have been created before we need to place anything sl@0: // into the log queue, since the 2nd thread contains the semaphore we are using sl@0: // to count the # of mesgs in the queue. sl@0: iSecondaryThread = CSecondaryThread::NewL(*this,currentFlushSetting); sl@0: sl@0: // update the media regardless of whether the parsing worked sl@0: // since we need to get the default set if needs be. sl@0: UpdateMediaL(); sl@0: sl@0: if (err!=KErrNone) //Problem with ini file reading. Stick a message in the log... sl@0: { sl@0: CLogCommentMessage* message = CLogCommentMessage::NewL(KIniFileProblem); sl@0: err = AppendAndGiveOwnership(message); sl@0: if (err != KErrNone) sl@0: { sl@0: delete message; sl@0: User::Leave(err); sl@0: } sl@0: } sl@0: sl@0: iIniFileWatcher = CIniFileWatcher::NewL(iFs, *this, iniFile); sl@0: iTimeManager = CTimeManager::NewL(*this); sl@0: } sl@0: sl@0: void CFileLoggerServer::UpdateMediaL() sl@0: { sl@0: CMediaUpdateMessage* message = new(ELeave) CMediaUpdateMessage(*iIniFileParser); sl@0: CleanupStack::PushL(message); sl@0: if (AppendAndGiveOwnership(message)!=KErrNone) //Problem => Leave media as it was. sl@0: { sl@0: CleanupStack::Pop(message); sl@0: delete message; sl@0: return; sl@0: } sl@0: CleanupStack::Pop(message); sl@0: } sl@0: sl@0: CFileLoggerServer::~CFileLoggerServer() sl@0: { sl@0: delete iSecondaryThread; sl@0: delete iTimeManager; sl@0: delete iIniFileWatcher; sl@0: delete iIniOldFileWatcher; sl@0: delete iIniFileParser; sl@0: delete iPreAllocatedErrorMessage; sl@0: iFs.Close(); sl@0: iCriticalSection.Close(); sl@0: iCompletionSemaphore.Close(); sl@0: iLogMessageArray.ResetAndDestroy(); sl@0: #if defined (__WINS__) sl@0: delete iDebugWriter; sl@0: #endif sl@0: } sl@0: sl@0: sl@0: CSession2* CFileLoggerServer::NewSessionL(const TVersion &aVersion ,const RMessage2& /*aMessage*/) const sl@0: /** sl@0: * Create a new server session. Check that client is using current or older interface and make a new session. sl@0: * @note Called by kernel after RFileLogger::DoConnect(). sl@0: */ sl@0: { sl@0: sl@0: TVersion v(KFLogSrvMajorVersionNumber,KFLogSrvMinorVersionNumber,KFLogSrvBuildVersionNumber); sl@0: if (!User::QueryVersionSupported(v,aVersion)) sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: return CFileLogSession::NewL(*(const_cast(this)), *iIniFileParser); sl@0: } sl@0: sl@0: void CFileLoggerServer::RePrepareForOOML() sl@0: /** sl@0: * Called to ensure there is space for the OOM error msg in log queue. sl@0: */ sl@0: { sl@0: if (!iPreAllocatedErrorMessage) sl@0: { sl@0: iPreAllocatedErrorMessage = CLogCommentMessage::NewL(KOOMErrorString); sl@0: } sl@0: //Must reserve 1 space in array for error handling or leave. sl@0: User::LeaveIfError(iLogMessageArray.Append(NULL)); sl@0: //We've got everything we need should we hit an OOM to guarentee we can get an error in the log. sl@0: iArrayHasSpaceForWrite=ETrue; sl@0: } sl@0: sl@0: TInt CFileLoggerServer::AppendAndGiveOwnership(CLogMessageBase* aMessage) sl@0: /** sl@0: * Append a log package to the queue end. sl@0: * @note Entry only allowed for primary (producer) thread. sl@0: * @note If win32 and debug port logging on, package is written immediately to the debug port as well. sl@0: * @note If no space has been allocated for the OOM error msg, then this is done first. sl@0: * @note If flushing (synchronous) operation then waits for completion. sl@0: @return KErrNoMemory sl@0: */ sl@0: { sl@0: iCriticalSection.Wait(); sl@0: #if defined (__WINS__) sl@0: if (iIniFileParser->Win32DebugEnabled()) sl@0: { sl@0: aMessage->Invoke(*iDebugWriter); sl@0: } sl@0: #endif sl@0: TInt err(KErrNone); sl@0: if (!iArrayHasSpaceForWrite) //We ran into low memmory a while ago, time to get set up again. sl@0: //iArrayHasSpaceForWrite==ETrue <==> 1 free slot in the array sl@0: //iArrayHasSpaceForWrite==EFalse <==> 0 free slots in the array sl@0: //Above MUST be true or we'll go horribly wrong!! sl@0: //RePrepareForOOML must be done in CS since we'll be mucking about with the array. sl@0: { sl@0: TRAP(err, RePrepareForOOML()); sl@0: if (err!=KErrNone) sl@0: { sl@0: iCriticalSection.Signal(); sl@0: return err; sl@0: } sl@0: } sl@0: //If we get to here then we must have 1 space in the array. First try to expand sl@0: //then if that works stick the message in the array, otherwise return error. sl@0: if ((err = iLogMessageArray.Append(NULL))==KErrNone) sl@0: { sl@0: const TInt arrayCount(iLogMessageArray.Count()); sl@0: iLogMessageArray[arrayCount-2] = aMessage; sl@0: iSecondaryThread->SignalRequestSemaphore(); sl@0: } sl@0: iCriticalSection.Signal(); sl@0: sl@0: if (err==KErrNone) sl@0: { sl@0: TBool flushSetting; sl@0: iIniFileParser->FlushingOn(flushSetting); sl@0: sl@0: if (flushSetting == EFlushOn) sl@0: { sl@0: iCompletionSemaphore.Wait(); // one for each signal of the request semaphore sl@0: } sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: void CFileLoggerServer::PutOOMErrorInLog() sl@0: { sl@0: //Best attempt to put error in log, if there's no space then we can't sl@0: //We don't try to allocate space in the array. The reasons for this are left as sl@0: //an excercise to whomever is unfortunate enough to be trying to debug this. sl@0: //Basically, this is the only place the last slot of the array can ever be filled, sl@0: //so if iArrayHasSpaceForWrite==EFalse we're guaranteed to have got an error in the sl@0: //log already earlier on, and since sl@0: //in the AppendAndGiveOwnership method we fail if we cant realocate the error message sl@0: //we're guarenteed that the last line in the log is and error message already. sl@0: if (iArrayHasSpaceForWrite) sl@0: { sl@0: iCriticalSection.Wait(); sl@0: const TInt arrayCount(iLogMessageArray.Count()); sl@0: iLogMessageArray[arrayCount-1] = iPreAllocatedErrorMessage; sl@0: iPreAllocatedErrorMessage=NULL; sl@0: iArrayHasSpaceForWrite=EFalse; sl@0: iCriticalSection.Signal(); sl@0: iSecondaryThread->SignalRequestSemaphore(); sl@0: sl@0: TBool flushSetting; sl@0: iIniFileParser->FlushingOn(flushSetting); sl@0: sl@0: if (flushSetting == EFlushOn) sl@0: { sl@0: iCompletionSemaphore.Wait(); // one for each signal of the request semaphore sl@0: } sl@0: sl@0: } sl@0: sl@0: } sl@0: sl@0: sl@0: void CFileLoggerServer::GetFirstMessageAndTakeOwnership(CLogMessageBase*& aMessage) sl@0: /* sl@0: * Remove the message at the head of the log queue. sl@0: * @note Entry only allowed for secondary (consumer) thread. sl@0: * @note Blocks if no messages in the log queue. sl@0: */ sl@0: sl@0: { sl@0: // Wait on the request semaphore, since we are using that to communicate the number of sl@0: // outstanding log items in the queue. sl@0: User::WaitForAnyRequest(); sl@0: iCriticalSection.Wait(); sl@0: aMessage = iLogMessageArray[0]; sl@0: iLogMessageArray.Remove(0); sl@0: iCriticalSection.Signal(); sl@0: } sl@0: sl@0: sl@0: sl@0: void CFileLoggerServer::SignalCompletionSemaphore() sl@0: // signal the completion semaphore. Called by the slave/consumer thread when it is sl@0: // done with the current message. Since the slave thread doesn't know if flushing sl@0: // is on, it will call this regardless of whether we actually need to signal the sl@0: // semphore or not. sl@0: { sl@0: sl@0: TBool flushSetting; sl@0: iIniFileParser->FlushingOn(flushSetting); sl@0: sl@0: if (flushSetting == EFlushOn) sl@0: { sl@0: iCompletionSemaphore.Signal(); sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: TInt CFileLoggerServer::RunError(TInt aError) sl@0: /** sl@0: * Leave has occured in CFileLogSession::ServiceL. sl@0: * Usually this is because the appending of the message to the queue has failed sl@0: * due to the queue being filled. sl@0: */ sl@0: { sl@0: PutOOMErrorInLog(); sl@0: return CServer2::RunError(aError); sl@0: } sl@0: sl@0: sl@0: void CFileLoggerServer::IniFileChanged(TDesC &aIniFile) sl@0: /** sl@0: Called by the file watcher when the ini file changes. sl@0: Any OOM problems are ignored sl@0: */ sl@0: { sl@0: CLogCommentMessage* message = NULL; sl@0: TRAPD(err, message = CLogCommentMessage::NewL(KIniFileUpdate)) sl@0: if ((err == KErrNone) && (message)) sl@0: { sl@0: err = AppendAndGiveOwnership(message); sl@0: if (err != KErrNone) sl@0: { sl@0: delete message; sl@0: } sl@0: } sl@0: err = iIniFileParser->ParseIniFile (aIniFile); sl@0: sl@0: // update media regardless of success, since we may want to sl@0: // set the default media. update media will only leave if memory full. sl@0: // in which case we cant output an error msg anyway. sl@0: TRAPD(err2, UpdateMediaL()); sl@0: sl@0: if (err!=KErrNone) //problem parsing ini file, leave settings as they are and carry on. sl@0: { sl@0: CLogCommentMessage* message = NULL; sl@0: TRAP(err, message = CLogCommentMessage::NewL(KIniFileProblem)) sl@0: if ((err == KErrNone) && (message)) sl@0: { sl@0: err = AppendAndGiveOwnership(message); sl@0: if (err != KErrNone) sl@0: { sl@0: delete message; sl@0: } sl@0: } sl@0: return; sl@0: } sl@0: else if (err2 != KErrNone) sl@0: { sl@0: // memory full, but cant even output msg to say this sl@0: } sl@0: sl@0: sl@0: //Ignore error. Above can only fail due to OOM, so carry on regardless. sl@0: CSession2* p=NULL; sl@0: iSessionIter.SetToFirst(); sl@0: while ((p=iSessionIter++)!=NULL) sl@0: { sl@0: static_cast(p)->IniFileChanged(); sl@0: } sl@0: } sl@0: sl@0: #ifdef _DEBUG sl@0: void CFileLoggerServer::__DbgKillTimeManager() sl@0: { sl@0: delete iTimeManager; sl@0: iTimeManager=NULL; sl@0: } sl@0: #endif //_DEBUG sl@0: // sl@0: // CFileLogSession class definition sl@0: // sl@0: sl@0: CFileLogSession* CFileLogSession::NewL(MLogArrayAccess& aArrayAccess, const MIniFlushModeAndLogValidQuery& aLogValidQuery) sl@0: /** sl@0: * Construct new server end of session. sl@0: * @note Only called from CFileLoggerServer::NewSessionL() sl@0: */ sl@0: { sl@0: sl@0: CFileLogSession* self = new(ELeave) CFileLogSession(aArrayAccess, aLogValidQuery); sl@0: return self; sl@0: } sl@0: sl@0: CFileLogSession::CFileLogSession(MLogArrayAccess& aArrayAccess, const MIniFlushModeAndLogValidQuery& aLogValidQuery) sl@0: : iArrayAccess(aArrayAccess), iFlushModeLogValidQuery(aLogValidQuery), iLogValid(KLoggingOnOffDefault) sl@0: {} sl@0: sl@0: sl@0: CFileLogSession::~CFileLogSession() sl@0: { sl@0: } sl@0: sl@0: void CFileLogSession::ServiceL(const RMessage2& aMessage) sl@0: /** sl@0: * Processes message from client-side (RFileLogger) sl@0: * @note Most messages result in logs being added to the queue. If sl@0: * synchronous logging is on, this function will wait until the queue is then emptied. sl@0: */ sl@0: { sl@0: RThread clientThread; sl@0: TBool flushOn; sl@0: iFlushModeLogValidQuery.FlushingOn(flushOn); sl@0: sl@0: // All of the common & performance-critical requests need the client thread id. Note that RFileLogger sl@0: // sessions are shareable; the thread now logging may be other than that which created the session sl@0: User::LeaveIfError(aMessage.Client(clientThread)); sl@0: iThreadId = clientThread.Id(); sl@0: sl@0: sl@0: sl@0: switch(aMessage.Function()) sl@0: { sl@0: case EStaticWriteToLog: sl@0: { sl@0: aMessage.ReadL(0, iSubsystem); sl@0: aMessage.ReadL(1, iComponent); sl@0: if (iFlushModeLogValidQuery.LogValid(iSubsystem, iComponent)) sl@0: { sl@0: HBufC8* stringOnHeap = HBufC8::NewLC(aMessage.Int3()); sl@0: TPtr8 ptrToString(stringOnHeap->Des()); sl@0: aMessage.ReadL(2, ptrToString); sl@0: if (!flushOn) sl@0: { sl@0: //We're done with the client now, so we can complete its request. sl@0: aMessage.Complete(KErrNone); sl@0: } sl@0: CLogStringMessage* logMessage = new(ELeave) CLogStringMessage(stringOnHeap, iSubsystem, iComponent, iThreadId); sl@0: CleanupStack::Pop(stringOnHeap); sl@0: TInt err = iArrayAccess.AppendAndGiveOwnership(logMessage); sl@0: if(err != KErrNone) sl@0: { sl@0: delete logMessage; sl@0: User::Leave(err); sl@0: } sl@0: if (flushOn) sl@0: { sl@0: aMessage.Complete(KErrNone); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: //We've done with the client now, so we can complete it's request. sl@0: aMessage.Complete(KErrNone); sl@0: } sl@0: break; sl@0: } sl@0: case EClearLog: sl@0: { sl@0: CheckClientHasSetTagsL(aMessage); sl@0: CClearLogMessage* clearLogMessage = new(ELeave) CClearLogMessage(clientThread.FullName()); sl@0: TInt err = iArrayAccess.AppendAndGiveOwnership(clearLogMessage); sl@0: if(err != KErrNone) sl@0: { sl@0: delete clearLogMessage; sl@0: User::Leave(err); sl@0: } sl@0: aMessage.Complete(KErrNone); sl@0: break; sl@0: } sl@0: case ESetLogTag: sl@0: { sl@0: aMessage.ReadL(0, iSubsystem); sl@0: aMessage.ReadL(1, iComponent); sl@0: iSetLogMessage = aMessage; sl@0: SetLoggingOnOffInClient(); sl@0: aMessage.Complete(KErrNone); sl@0: break; sl@0: } sl@0: case EWriteToLog: sl@0: { sl@0: CheckClientHasSetTagsL(aMessage); sl@0: HBufC8* stringOnHeap = HBufC8::NewLC(aMessage.Int1()); sl@0: TPtr8 ptrToString(stringOnHeap->Des()); sl@0: aMessage.ReadL(0, ptrToString); sl@0: if (!flushOn) sl@0: { sl@0: //We're done with the client now, so we can complete its request. sl@0: aMessage.Complete(KErrNone); sl@0: } sl@0: CLogStringMessage* logMessage = new(ELeave) CLogStringMessage(stringOnHeap, iSubsystem, iComponent, iThreadId); sl@0: CleanupStack::Pop(stringOnHeap);//Above call takes ownership of stringOnHeap sl@0: TInt err = iArrayAccess.AppendAndGiveOwnership(logMessage); sl@0: if(err != KErrNone) sl@0: { sl@0: delete logMessage; sl@0: User::Leave(err); sl@0: } sl@0: if (flushOn) sl@0: { sl@0: aMessage.Complete(KErrNone); sl@0: } sl@0: sl@0: break; sl@0: } sl@0: case EWriteBinary: sl@0: { sl@0: CheckClientHasSetTagsL(aMessage); sl@0: HBufC8* stringOnHeap = HBufC8::NewLC(aMessage.Int1()); sl@0: TPtr8 ptrToString(stringOnHeap->Des()); sl@0: aMessage.ReadL(0, ptrToString); sl@0: CLogBinaryString* logMessage = new(ELeave) CLogBinaryString(stringOnHeap, iSubsystem, iComponent); sl@0: CleanupStack::Pop(stringOnHeap);//Above call takes ownership of stringOnHeap sl@0: if (!flushOn) sl@0: { sl@0: //We're done with the client now, so we can complete its request. sl@0: aMessage.Complete(KErrNone); sl@0: } sl@0: sl@0: TInt err = iArrayAccess.AppendAndGiveOwnership(logMessage); sl@0: if(err != KErrNone) sl@0: { sl@0: delete logMessage; sl@0: User::Leave(err); sl@0: } sl@0: if (flushOn) sl@0: { sl@0: aMessage.Complete(KErrNone); sl@0: } sl@0: break; sl@0: } sl@0: #ifdef _DEBUG //These methods are only accessible in debug. sl@0: case EShutDownServer: sl@0: { sl@0: CActiveScheduler::Stop(); sl@0: aMessage.Complete(KErrNone); sl@0: break; sl@0: } sl@0: case ESetHeapFailure: sl@0: { sl@0: //we need to stop the timer otherwise server will sl@0: //keep allocing when we're doing heap failure test which makes the test fail. sl@0: const_cast(static_cast(Server()))->__DbgKillTimeManager(); sl@0: __UHEAP_FAILNEXT(aMessage.Int0()); sl@0: aMessage.Complete(KErrNone); sl@0: break; sl@0: } sl@0: #endif //_DEBUG sl@0: default: sl@0: { sl@0: aMessage.Panic(KFloggerServerPanic, EBadMessageFunction); sl@0: } sl@0: } sl@0: clientThread.Close(); sl@0: } sl@0: sl@0: void CFileLogSession::CheckClientHasSetTagsL(const RMessage2& aMessage) sl@0: /** sl@0: * Ensure for a connection that the client has set the tags, otherwise panic. sl@0: * @param aMessage the current client message in progress sl@0: * @note Tags are kept server side so that we don't need to store the tags in the client and pass them through with each request. sl@0: */ sl@0: sl@0: { sl@0: if (iSetLogMessage.IsNull()) sl@0: { sl@0: aMessage.Panic(KFloggerPanic, ESetLogTagsNotCalled); //Client ain't called set log tags. sl@0: User::Leave(KErrGeneral); sl@0: } sl@0: sl@0: } sl@0: sl@0: void CFileLogSession::SetLoggingOnOffInClient() sl@0: { sl@0: const TBool currentLoggingOnOffState = iLogValid; sl@0: iLogValid = iFlushModeLogValidQuery.LogValid(iSubsystem, iComponent); sl@0: if (currentLoggingOnOffState!=iLogValid) //Logging on/off has changed. Set state in client sl@0: { sl@0: // ignore the error returned sl@0: (void)iSetLogMessage.Write(2, TPckgBuf(iLogValid)); sl@0: } sl@0: } sl@0: sl@0: void CFileLogSession::IniFileChanged() sl@0: //We only need to update clients that have called SetLogTags sl@0: //We don't update clients that are using the static API client side. sl@0: { sl@0: if (!iSetLogMessage.IsNull()) sl@0: { sl@0: SetLoggingOnOffInClient(); sl@0: } sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////// sl@0: sl@0: CSecondaryThread* CSecondaryThread::NewL(MLogArrayAccess& aArrayAccess, TBool aFlushOn) sl@0: { sl@0: CSecondaryThread* self = new(ELeave) CSecondaryThread(aArrayAccess,aFlushOn); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: CSecondaryThread::CSecondaryThread(MLogArrayAccess& aArrayAccess, TBool aFlushOn) sl@0: : CActive(EPriorityHigh), iArrayAccess(aArrayAccess), iFlushingOn(aFlushOn) sl@0: {} sl@0: sl@0: void CSecondaryThread::RunL() sl@0: /** sl@0: * Runs when second thread dies, and simply restarts it again. sl@0: * @note On death a thread-death message is placed in the queue so that sl@0: * a user is aware this happened. sl@0: * @note StartSecondaryThread issues a request to be informed of thread death, sl@0: * so starts active object again. sl@0: */ sl@0: { sl@0: StartSecondaryThreadL(ETrue); sl@0: } sl@0: sl@0: void CSecondaryThread::DoCancel() sl@0: /** sl@0: * Appends a special shutdown message into the log array. When this reaches sl@0: * the head and is run, it shuts down the second thread. sl@0: * @note Logs onto second thread and waits for it to finish. sl@0: */ sl@0: sl@0: { sl@0: iSecondaryThread.LogonCancel(iStatus); sl@0: if (iArrayAccess.AppendAndGiveOwnership(iShutDownMessage)!=KErrNone) sl@0: { //Nothing else we can do here. We'll have to just kill the other thread. sl@0: iSecondaryThread.Kill(KErrGeneral); sl@0: } sl@0: else sl@0: { sl@0: iShutDownMessage = NULL; sl@0: TRequestStatus status(KRequestPending); sl@0: iSecondaryThread.Logon(status); sl@0: User::WaitForRequest(status); sl@0: } sl@0: } sl@0: sl@0: void CSecondaryThread::StartSecondaryThreadL(TBool aRestarting) sl@0: /** sl@0: * Start the second/consumer/slave thread and issue a request to be told when it dies. sl@0: */ sl@0: { sl@0: TRequestStatus stat; sl@0: sl@0: User::LeaveIfError(iSecondaryThread.Create(KFloggerSecondaryThreadName,CLogManager::ThreadEntryPoint,KDefaultStackSize,NULL,&iArrayAccess)); sl@0: sl@0: iSecondaryThread.Rendezvous(stat); sl@0: sl@0: if (iFlushingOn) sl@0: { sl@0: iSecondaryThread.SetPriority(EPriorityAbsoluteHigh); //was EPriorityMuchMore sl@0: } sl@0: else sl@0: { sl@0: iSecondaryThread.SetPriority(EPriorityAbsoluteForeground); // was EPriorityMuchLess sl@0: } sl@0: sl@0: iSecondaryThread.Resume(); sl@0: sl@0: User::WaitForRequest(stat); sl@0: sl@0: iSecondaryThread.Logon(iStatus); sl@0: sl@0: if (aRestarting) sl@0: { sl@0: CLogCommentMessage* errorMessage = CLogCommentMessage::NewL(KThreadDiedString); sl@0: TInt err = iArrayAccess.AppendAndGiveOwnership(errorMessage); sl@0: if(err != KErrNone) sl@0: { sl@0: delete errorMessage; sl@0: User::Leave(err); sl@0: } sl@0: } sl@0: sl@0: SetActive(); sl@0: sl@0: } sl@0: sl@0: void CSecondaryThread::ConstructL() sl@0: /** sl@0: * Contructs and kicks off the secondary thread, while also issuing a request to be informed sl@0: * if the thread dies, which will run the active object sl@0: */ sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: //Preallocate a shutdown message sl@0: iShutDownMessage = new(ELeave) CShutDownMessage; sl@0: sl@0: StartSecondaryThreadL(EFalse); sl@0: } sl@0: sl@0: TInt CSecondaryThread::RunError(TInt /*aError*/) sl@0: { sl@0: CActiveScheduler::Stop(); //What the hell happened! Shut the server down sl@0: return KErrNone; sl@0: } sl@0: sl@0: CSecondaryThread::~CSecondaryThread() sl@0: { sl@0: Cancel(); sl@0: delete iShutDownMessage; sl@0: iSecondaryThread.Close(); sl@0: } sl@0: