diff -r 4ea6f81c838a -r 0e9bb658ef58 mulwidgets/mullogging/src/mullogchunk.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mulwidgets/mullogging/src/mullogchunk.cpp Wed Sep 01 12:23:18 2010 +0100 @@ -0,0 +1,451 @@ +/* +* Copyright (c) 2006-2007 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: Logging to chunk wrappe for Mul +* +*/ + + +// CLASS HEADER +#include "mullogchunk.h" + +// EXTERNAL INCLUDES +#include + +// LOCAL DECLARATIONS +namespace + { + // size for the chunks + const TInt KLogChunkSize = 1000000; // 1 million bytes + // name for chunk 1 + _LIT( KLogChunk1Name, "MUL_Logchunk1" ); + // name for chunk 2 + _LIT( KLogChunk2Name, "MUL_Logchunk2" ); + // extension for log file + _LIT( KLogFileExtension, ".log" ); + // carriage return / line feed + _LIT8( KLogCR, "\r" ); + _LIT8( KLogLF, "\n" ); + // constant for machine word alignment + const TInt KBytesInAWord = sizeof( TInt32 ); + } + +inline void Panic(TInt aReason) + { + _LIT(applicationName,"Mul Logging"); + User::Panic(applicationName, aReason); + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::Open +// ----------------------------------------------------------------------------- +TInt RMulLogUtility::Open( const TDesC& aName, TBool aReadOnly ) + { + // open the chunk + return iChunk.OpenGlobal( aName, aReadOnly ); + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::CreateL +// ----------------------------------------------------------------------------- +void RMulLogUtility::CreateL( const TDesC& aName ) + { + // create the chunk, leave if error + TInt error = iChunk.CreateGlobal( aName, KLogChunkSize, KLogChunkSize ); + // dont treate already exists as an error + if( KErrAlreadyExists == error ) + { + // open in read-write + User::LeaveIfError( iChunk.OpenGlobal( aName, EFalse ) ); + } + else + { + User::LeaveIfError( error ); + } + + // initialise the iChunk to all zeros. + Mem::FillZ( iChunk.Base(), iChunk.Size() ); + // initialise current address to base + SetCurrentAddress( BaseAddress() ); + // initialise last logged address to base + SetLastLoggedAddress( BaseAddress() ); + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::Close +// ----------------------------------------------------------------------------- +void RMulLogUtility::Close() + { + iChunk.Close(); + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::ChunkSize +// ----------------------------------------------------------------------------- +TInt RMulLogUtility::ChunkSize() + { + return iChunk.Size(); + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::Id +// ----------------------------------------------------------------------------- +TObjectId RMulLogUtility::Id() + { + // take chunk base address + TUint8* ptr_in_chunk = iChunk.Base(); + // cast that to TObjectId* + TObjectId* ptr_as_tobjectid = reinterpret_cast< TObjectId* >( ptr_in_chunk ); + // return the id + return *ptr_as_tobjectid; + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::SetId +// ----------------------------------------------------------------------------- +void RMulLogUtility::SetId( TObjectId aId ) + { + // take chunk base address + TUint8* ptr_in_chunk = iChunk.Base(); + // cast that to TObjectId* + TObjectId* ptr_as_tobjectid = reinterpret_cast< TObjectId* >( ptr_in_chunk ); + // assign the id in place + *ptr_as_tobjectid = aId; + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::CurrentAddress +// ----------------------------------------------------------------------------- +TUint8* RMulLogUtility::CurrentAddress() + { + // take chunk base address plus object id + TUint8* ptr_in_chunk = iChunk.Base() + sizeof( TObjectId ); + // cast that to TInt* + TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk ); + // dereference that pointer to read the 32 bits that are the address + TUint32 value_of_pointer = *ptr_as_tint; + // then return the value as TUint8* + return reinterpret_cast< TUint8* >( value_of_pointer ); + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::SetCurrentAddress +// ----------------------------------------------------------------------------- +void RMulLogUtility::SetCurrentAddress( TUint8* aValue ) + { + // take chunk base address plus object id + TUint8* ptr_in_chunk = iChunk.Base() + sizeof( TObjectId ); + // cast that to TInt* + TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk ); + // assign the addres to TInt + TUint32 new_value = reinterpret_cast< TUint32 >( aValue ); + // ensure we're byte aligned - ARM requires 32 bit alignment to machine word + // boundary!! + TInt remainder = new_value % KBytesInAWord; + if ( remainder > 0 ) + { + new_value += ( KBytesInAWord - remainder ); + } + // set the new value to the chunk + *ptr_as_tint = new_value; + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::LastLoggedAddress +// ----------------------------------------------------------------------------- +TUint8* RMulLogUtility::LastLoggedAddress() + { + // take chunk base address plus object id plus one pointer + TUint8* ptr_in_chunk = + iChunk.Base() + sizeof( TObjectId ) + sizeof( TUint8* ); + // cast that to TInt* + TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk ); + // dereference that pointer to read the 32 bits that are the address + TUint32 value_of_pointer = *ptr_as_tint; + // then return the value as TUint8* + return reinterpret_cast< TUint8* >( value_of_pointer ); + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::SetLastLoggedAddress +// ----------------------------------------------------------------------------- +void RMulLogUtility::SetLastLoggedAddress( TUint8* aValue ) + { + // take chunk base address plus object id plus one pointer + TUint8* ptr_in_chunk = + iChunk.Base() + sizeof( TObjectId ) + sizeof( TUint8* ); + // cast that to TInt* + TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk ); + // assign the addres to TInt + TUint32 new_value = reinterpret_cast< TUint32 >( aValue ); + // ensure we're byte aligned - ARM requires 32 bit alignment to machine word + // boundary!! + TInt remainder = new_value % KBytesInAWord; + if ( remainder > 0 ) + { + new_value += ( KBytesInAWord - remainder ); + } + // set the new value to the chunk + *ptr_as_tint = new_value; + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::BaseAddress +// ----------------------------------------------------------------------------- +TUint8* RMulLogUtility::BaseAddress() + { + // take chunks base address + TUint8* base = iChunk.Base(); + // calculate the topmost write address, our header is + // TObjectId and two TUint8* + return base + sizeof( TObjectId ) + sizeof( TUint8* ) * 2; + } + +// ----------------------------------------------------------------------------- +// RMulLogUtility::LastAddress +// ----------------------------------------------------------------------------- +TUint8* RMulLogUtility::LastAddress() + { + // return chunks base address plus its size + return iChunk.Base() + iChunk.Size(); + } + +// ----------------------------------------------------------------------------- +// RMulLogClient::Open +// ----------------------------------------------------------------------------- +EXPORT_C TInt RMulLogClient::Open( TObjectId aId ) + { + // try to open first log chunk, in read-write mode + TInt err = iLogUtility.Open( KLogChunk1Name(), EFalse ); + if ( err != KErrNone ) + { + return err; + } + // check id + TObjectId id = iLogUtility.Id(); + if ( id == TObjectId( 0 ) ) + { + // no id set, so reserve this for us and use this chunk + iLogUtility.SetId( aId ); + } + // check if our id was there? + else if( id != aId ) + { + // not our chunk, try second chunk in read-write mode + err = iLogUtility.Open( KLogChunk2Name(), EFalse ); + if ( err != KErrNone ) + { + return err; + } + // check id + id = iLogUtility.Id(); + if ( id == TObjectId( 0 ) ) + { + // no id, reserve this for us and use this chunk + iLogUtility.SetId( aId ); + } + else if ( id != aId ) + { + // both chunks already reserved, return error + return KErrNotFound; + } + } + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// RMulLogClient::Close +// ----------------------------------------------------------------------------- +EXPORT_C void RMulLogClient::Close() + { + iLogUtility.Close(); + } + +// ----------------------------------------------------------------------------- +// RMulLogClient::Write +// ----------------------------------------------------------------------------- +EXPORT_C void RMulLogClient::Write( const TDesC8& aLogEntry ) + { + // get the size of log entry (in bytes) + TInt num_bytes = aLogEntry.Size(); + // take current address and chunk size to ensure log entry fits + TUint8* current_address = iLogUtility.CurrentAddress(); + // calculate the new current address, we write the size and the data + TUint8* after_write = current_address + num_bytes + sizeof( TInt ); + // chck that we fit + if( after_write >= iLogUtility.LastAddress() ) + { + // we dont fit in the end + // need to mark the old current_address so that + // manager knows we jumped to the start + TInt* last_indicator_ptr = + reinterpret_cast< TInt* >( current_address ); + // assign KErrNotFound there + *last_indicator_ptr = KErrNotFound; + // write this entry to the base address + current_address = iLogUtility.BaseAddress(); + } + // we need to store the size in the chunk first so take a TInt* + TInt* size_ptr = reinterpret_cast< TInt* >( current_address ); + // assign new value in place + *size_ptr = num_bytes; + // increase address + current_address += sizeof( TInt ); + // copy the data, first target, then source and last number of bytes + Mem::Copy( current_address, aLogEntry.Ptr(), num_bytes ); + // and set the new current address + iLogUtility.SetCurrentAddress( current_address + num_bytes ); + } + +// ----------------------------------------------------------------------------- +// RMulLogManager::CreateL +// ----------------------------------------------------------------------------- +EXPORT_C void RMulLogManager::CreateL() + { + // connect to the file server + User::LeaveIfError( iFs.Connect() ); + + // create two log chunks + iLogUtility1.CreateL( KLogChunk1Name ); + iLogUtility2.CreateL( KLogChunk2Name ); + } + +// ----------------------------------------------------------------------------- +// RMulLogManager::Release +// ----------------------------------------------------------------------------- +EXPORT_C void RMulLogManager::Release() + { + // close file server handle + iFs.Close(); + + // release both log chunks + iLogUtility1.Close(); + iLogUtility2.Close(); + } + +// ----------------------------------------------------------------------------- +// RMulLogManager::CommitToFileL +// ----------------------------------------------------------------------------- +EXPORT_C void RMulLogManager::CommitToFileL( const TDesC& aFolder ) + { + // open the file + RFile file; + CleanupClosePushL( file ); + + // chunk1 + // create the file name + TFileName fileName; + fileName = aFolder; + fileName.Append( KLogChunk1Name ); + fileName.Append( KLogFileExtension ); + // try to open the file + TInt err = file.Open( iFs, fileName, EFileWrite ); + if ( err == KErrNotFound ) + { + // file doesn't exist so create it + err = file.Create( iFs, fileName, EFileWrite ); + } + User::LeaveIfError( err ); + // write the first chunk to file + CommitToFileL( iLogUtility1, file ); + // close the file + file.Close(); + + // chunk2 + // reset the file name + fileName.Zero(); + // create the file name + fileName = aFolder; + fileName.Append( KLogChunk2Name ); + fileName.Append( KLogFileExtension ); + // try to open the file + err = file.Open( iFs, fileName, EFileWrite ); + if ( err == KErrNotFound ) + { + // file doesn't exist so create it + err = file.Create( iFs, fileName, EFileWrite ); + } + User::LeaveIfError( err ); + // write the second chunk to file + CommitToFileL( iLogUtility2, file ); + + CleanupStack::PopAndDestroy( &file ); + } + +// ----------------------------------------------------------------------------- +// RMulLogManager::CommitToFileL +// ----------------------------------------------------------------------------- +void RMulLogManager::CommitToFileL( RMulLogUtility& aUtility, RFile& aFile ) + { + // Need to explicitly move to the end of the file as it's not done + // automatically on call to Write + TInt pos = 0; + TInt err = aFile.Seek( ESeekEnd, pos ); + User::LeaveIfError( err ); + TPtr8 logEntryPtr( 0, 0 ); + TInt logEntrySize = 0; + + // what's previously been logged to the file? + TUint8* lastLoggedAddress = aUtility.LastLoggedAddress(); + + // how much more has been added to the chunk? + TUint8* currentAddress = aUtility.CurrentAddress(); + + // write each of the chunk's logged entries to the file + TInt32* sizePtr = NULL; + while ( currentAddress != lastLoggedAddress && err == KErrNone ) + { + // get the logEntry's size + sizePtr = reinterpret_cast< TInt32* >( lastLoggedAddress ); + logEntrySize = *sizePtr; + if ( logEntrySize == KErrNotFound ) + { + // logged entries have wrapped around the end of the chunk + // so start from the beginning + lastLoggedAddress = aUtility.BaseAddress(); + sizePtr = reinterpret_cast< TInt32* >( lastLoggedAddress ); + logEntrySize = *sizePtr; + } + // set an error - this will be reset to KErrNone if we succeed + // with finding and writing a log entry + err = KErrNotFound; + if ( logEntrySize > 0 ) + { + // move the current address to the data + lastLoggedAddress += sizeof( TInt32 ); + // extract the log entry's data + logEntryPtr.Set( lastLoggedAddress, logEntrySize, logEntrySize ); + // write the log entry to the file + err = aFile.Write( logEntryPtr ); + // append carriage return and line feed to the entry + err = aFile.Write( KLogCR ); + err = aFile.Write( KLogLF ); + // ensure we align to a multiple of a 4-byte boundary + TInt remainder = logEntrySize % KBytesInAWord; + if ( remainder > 0 ) + { + // not aligned so add some padding + logEntrySize += ( KBytesInAWord - remainder ); + } + + // update the last logged address + lastLoggedAddress += logEntrySize; + } + } + // update the last logged address + aUtility.SetLastLoggedAddress( lastLoggedAddress ); + // + // commit the data + err = aFile.Flush(); + User::LeaveIfError( err ); + }