mulwidgets/mullogging/src/mullogchunk.cpp
changeset 17 3eca7e70b1b8
parent 3 4526337fb576
equal deleted inserted replaced
3:4526337fb576 17:3eca7e70b1b8
     1 /*
       
     2 * Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Logging to chunk wrappe for Mul
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 // CLASS HEADER
       
    20 #include "mullogchunk.h"
       
    21 
       
    22 // EXTERNAL INCLUDES
       
    23 #include <e32svr.h>
       
    24 
       
    25 // LOCAL DECLARATIONS
       
    26 namespace
       
    27 	{
       
    28 	// size for the chunks
       
    29 	const TInt KLogChunkSize = 1000000; // 1 million bytes
       
    30 	// name for chunk 1
       
    31 	_LIT( KLogChunk1Name, "MUL_Logchunk1" );
       
    32 	// name for chunk 2
       
    33 	_LIT( KLogChunk2Name, "MUL_Logchunk2" );
       
    34 	// extension for log file
       
    35 	_LIT( KLogFileExtension, ".log" );
       
    36 	// carriage return / line feed
       
    37 	_LIT8( KLogCR, "\r" );
       
    38 	_LIT8( KLogLF, "\n" );
       
    39 	// constant for machine word alignment
       
    40 	const TInt KBytesInAWord = sizeof( TInt32 );
       
    41 	}
       
    42 	
       
    43 inline void Panic(TInt aReason)
       
    44     {
       
    45 	_LIT(applicationName,"Mul Logging");
       
    46     User::Panic(applicationName, aReason);
       
    47     }
       
    48 
       
    49 // -----------------------------------------------------------------------------
       
    50 // RMulLogUtility::Open
       
    51 // -----------------------------------------------------------------------------
       
    52 TInt RMulLogUtility::Open( const TDesC& aName, TBool aReadOnly )
       
    53 	{
       
    54 	// open the chunk
       
    55 	return iChunk.OpenGlobal( aName, aReadOnly );
       
    56 	}
       
    57 
       
    58 // -----------------------------------------------------------------------------
       
    59 // RMulLogUtility::CreateL
       
    60 // -----------------------------------------------------------------------------
       
    61 void RMulLogUtility::CreateL( const TDesC& aName )
       
    62     {
       
    63 	// create the chunk, leave if error
       
    64 	TInt error = iChunk.CreateGlobal( aName, KLogChunkSize, KLogChunkSize  );
       
    65 	// dont treate already exists as an error
       
    66 	if( KErrAlreadyExists == error )
       
    67 		{
       
    68 		// open in read-write
       
    69 		User::LeaveIfError( iChunk.OpenGlobal( aName, EFalse ) );
       
    70 		}
       
    71 	else
       
    72 		{
       
    73 		User::LeaveIfError( error );
       
    74 		}
       
    75 
       
    76     // initialise the iChunk to all zeros.
       
    77     Mem::FillZ( iChunk.Base(), iChunk.Size() );
       
    78     // initialise current address to base
       
    79     SetCurrentAddress( BaseAddress() );
       
    80     // initialise last logged address to base
       
    81     SetLastLoggedAddress( BaseAddress() );
       
    82     }
       
    83 
       
    84 // -----------------------------------------------------------------------------
       
    85 // RMulLogUtility::Close
       
    86 // -----------------------------------------------------------------------------
       
    87 void RMulLogUtility::Close()
       
    88 	{
       
    89 	iChunk.Close();
       
    90 	}
       
    91 
       
    92 // -----------------------------------------------------------------------------
       
    93 // RMulLogUtility::ChunkSize
       
    94 // -----------------------------------------------------------------------------
       
    95 TInt RMulLogUtility::ChunkSize()
       
    96 	{
       
    97 	return iChunk.Size();
       
    98 	}
       
    99     
       
   100 // -----------------------------------------------------------------------------
       
   101 // RMulLogUtility::Id
       
   102 // -----------------------------------------------------------------------------
       
   103 TObjectId RMulLogUtility::Id()
       
   104 	{
       
   105 	// take chunk base address
       
   106 	TUint8* ptr_in_chunk = iChunk.Base();
       
   107 	// cast that to TObjectId*
       
   108 	TObjectId* ptr_as_tobjectid = reinterpret_cast< TObjectId* >( ptr_in_chunk );
       
   109 	// return the id
       
   110 	return *ptr_as_tobjectid;
       
   111 	}
       
   112 
       
   113 // -----------------------------------------------------------------------------
       
   114 // RMulLogUtility::SetId
       
   115 // -----------------------------------------------------------------------------
       
   116 void RMulLogUtility::SetId( TObjectId aId )
       
   117 	{
       
   118 	// take chunk base address
       
   119 	TUint8* ptr_in_chunk = iChunk.Base();
       
   120 	// cast that to TObjectId*
       
   121 	TObjectId* ptr_as_tobjectid = reinterpret_cast< TObjectId* >( ptr_in_chunk );
       
   122 	// assign the id in place
       
   123 	*ptr_as_tobjectid = aId;
       
   124 	}
       
   125 
       
   126 // -----------------------------------------------------------------------------
       
   127 // RMulLogUtility::CurrentAddress
       
   128 // -----------------------------------------------------------------------------
       
   129 TUint8* RMulLogUtility::CurrentAddress()
       
   130 	{
       
   131 	// take chunk base address plus object id
       
   132 	TUint8* ptr_in_chunk = iChunk.Base() + sizeof( TObjectId );
       
   133 	// cast that to TInt*
       
   134 	TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk );
       
   135 	// dereference that pointer to read the 32 bits that are the address
       
   136 	TUint32 value_of_pointer = *ptr_as_tint;
       
   137 	// then return the value as TUint8*
       
   138 	return reinterpret_cast< TUint8* >( value_of_pointer );
       
   139 	}
       
   140 
       
   141 // -----------------------------------------------------------------------------
       
   142 // RMulLogUtility::SetCurrentAddress
       
   143 // -----------------------------------------------------------------------------
       
   144 void RMulLogUtility::SetCurrentAddress( TUint8* aValue )
       
   145 	{
       
   146 	// take chunk base address plus object id
       
   147 	TUint8* ptr_in_chunk = iChunk.Base() + sizeof( TObjectId );
       
   148 	// cast that to TInt*
       
   149 	TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk );
       
   150 	// assign the addres to TInt
       
   151 	TUint32 new_value = reinterpret_cast< TUint32 >( aValue );
       
   152 	// ensure we're byte aligned - ARM requires 32 bit alignment to machine word
       
   153 	// boundary!!
       
   154 	TInt remainder = new_value % KBytesInAWord;
       
   155 	if ( remainder > 0 )
       
   156 	    {
       
   157 	    new_value += ( KBytesInAWord - remainder );
       
   158 	    }
       
   159 	// set the new value to the chunk
       
   160 	*ptr_as_tint = new_value;
       
   161 	}
       
   162 
       
   163 // -----------------------------------------------------------------------------
       
   164 // RMulLogUtility::LastLoggedAddress
       
   165 // -----------------------------------------------------------------------------
       
   166 TUint8* RMulLogUtility::LastLoggedAddress()
       
   167 	{
       
   168 	// take chunk base address plus object id plus one pointer
       
   169 	TUint8* ptr_in_chunk = 
       
   170 		iChunk.Base() + sizeof( TObjectId ) + sizeof( TUint8* );
       
   171 	// cast that to TInt*
       
   172 	TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk );
       
   173 	// dereference that pointer to read the 32 bits that are the address
       
   174 	TUint32 value_of_pointer = *ptr_as_tint;
       
   175 	// then return the value as TUint8*
       
   176 	return reinterpret_cast< TUint8* >( value_of_pointer );
       
   177 	}
       
   178 
       
   179 // -----------------------------------------------------------------------------
       
   180 // RMulLogUtility::SetLastLoggedAddress
       
   181 // -----------------------------------------------------------------------------
       
   182 void RMulLogUtility::SetLastLoggedAddress( TUint8* aValue )
       
   183 	{
       
   184 	// take chunk base address plus object id plus one pointer
       
   185 	TUint8* ptr_in_chunk = 
       
   186 		iChunk.Base() + sizeof( TObjectId ) + sizeof( TUint8* );
       
   187 	// cast that to TInt*
       
   188 	TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk );
       
   189 	// assign the addres to TInt
       
   190 	TUint32 new_value = reinterpret_cast< TUint32 >( aValue );
       
   191 	// ensure we're byte aligned - ARM requires 32 bit alignment to machine word
       
   192 	// boundary!!
       
   193     TInt remainder = new_value % KBytesInAWord;
       
   194 	if ( remainder > 0 )
       
   195 	    {
       
   196 	    new_value += ( KBytesInAWord - remainder );
       
   197 	    }	
       
   198 	// set the new value to the chunk
       
   199 	*ptr_as_tint = new_value;
       
   200 	}
       
   201 
       
   202 // -----------------------------------------------------------------------------
       
   203 // RMulLogUtility::BaseAddress
       
   204 // -----------------------------------------------------------------------------
       
   205 TUint8* RMulLogUtility::BaseAddress()
       
   206 	{
       
   207 	// take chunks base address
       
   208 	TUint8* base = iChunk.Base();
       
   209 	// calculate the topmost write address, our header is 
       
   210 	// TObjectId and two TUint8*
       
   211 	return base + sizeof( TObjectId ) + sizeof( TUint8* ) * 2;
       
   212 	}
       
   213 
       
   214 // -----------------------------------------------------------------------------
       
   215 // RMulLogUtility::LastAddress
       
   216 // -----------------------------------------------------------------------------
       
   217 TUint8* RMulLogUtility::LastAddress()
       
   218 	{
       
   219 	// return chunks base address plus its size
       
   220 	return iChunk.Base() + iChunk.Size();
       
   221 	}
       
   222 
       
   223 // -----------------------------------------------------------------------------
       
   224 // RMulLogClient::Open
       
   225 // -----------------------------------------------------------------------------
       
   226 EXPORT_C TInt RMulLogClient::Open( TObjectId aId )
       
   227     {
       
   228     // try to open first log chunk, in read-write mode
       
   229     TInt err = iLogUtility.Open( KLogChunk1Name(), EFalse );
       
   230     if ( err != KErrNone )
       
   231         {
       
   232         return err;
       
   233         }
       
   234     // check id
       
   235     TObjectId id = iLogUtility.Id();
       
   236     if ( id  == TObjectId( 0 ) )
       
   237         {
       
   238         // no id set, so reserve this for us and use this chunk
       
   239         iLogUtility.SetId( aId );
       
   240         }
       
   241     // check if our id was there?
       
   242     else if( id != aId )
       
   243         {
       
   244         // not our chunk, try second chunk in read-write mode
       
   245         err = iLogUtility.Open( KLogChunk2Name(), EFalse );
       
   246         if ( err != KErrNone )
       
   247             {
       
   248             return err;
       
   249             }
       
   250         // check id
       
   251         id = iLogUtility.Id();
       
   252         if ( id  == TObjectId( 0 ) )
       
   253             {
       
   254             // no id, reserve this for us and use this chunk
       
   255             iLogUtility.SetId( aId );
       
   256             }
       
   257         else if ( id != aId )
       
   258             {
       
   259             // both chunks already reserved, return error
       
   260             return KErrNotFound;
       
   261             }
       
   262        	}
       
   263     return KErrNone;
       
   264     }
       
   265 
       
   266 // -----------------------------------------------------------------------------
       
   267 // RMulLogClient::Close
       
   268 // -----------------------------------------------------------------------------
       
   269 EXPORT_C void RMulLogClient::Close()
       
   270 	{
       
   271     iLogUtility.Close();
       
   272 	}
       
   273 
       
   274 // -----------------------------------------------------------------------------
       
   275 // RMulLogClient::Write
       
   276 // -----------------------------------------------------------------------------
       
   277 EXPORT_C void RMulLogClient::Write( const TDesC8& aLogEntry )
       
   278     {
       
   279     // get the size of log entry (in bytes)
       
   280     TInt num_bytes = aLogEntry.Size();
       
   281     // take current address and chunk size to ensure log entry fits
       
   282     TUint8* current_address = iLogUtility.CurrentAddress();
       
   283     // calculate the new current address, we write the size and the data
       
   284     TUint8* after_write = current_address + num_bytes + sizeof( TInt );
       
   285     // chck that we fit
       
   286     if( after_write >= iLogUtility.LastAddress() )
       
   287     	{
       
   288     	// we dont fit in the end
       
   289     	// need to mark the old current_address so that
       
   290     	// manager knows we jumped to the start
       
   291 	    TInt* last_indicator_ptr = 
       
   292 	    	reinterpret_cast< TInt* >( current_address );
       
   293 	   	// assign KErrNotFound there
       
   294 		*last_indicator_ptr = KErrNotFound;
       
   295     	// write this entry to the base address
       
   296     	current_address = iLogUtility.BaseAddress();
       
   297     	}
       
   298     // we need to store the size in the chunk first so take a TInt*
       
   299     TInt* size_ptr = reinterpret_cast< TInt* >( current_address );
       
   300     // assign new value in place
       
   301     *size_ptr = num_bytes;
       
   302     // increase address
       
   303     current_address += sizeof( TInt );
       
   304     // copy the data, first target, then source and last number of bytes
       
   305     Mem::Copy( current_address, aLogEntry.Ptr(), num_bytes );
       
   306     // and set the new current address
       
   307     iLogUtility.SetCurrentAddress( current_address + num_bytes );
       
   308     }
       
   309 
       
   310 // -----------------------------------------------------------------------------
       
   311 // RMulLogManager::CreateL
       
   312 // -----------------------------------------------------------------------------
       
   313 EXPORT_C void RMulLogManager::CreateL()
       
   314     {
       
   315     // connect to the file server
       
   316     User::LeaveIfError( iFs.Connect() );
       
   317     
       
   318     // create two log chunks
       
   319     iLogUtility1.CreateL( KLogChunk1Name );
       
   320     iLogUtility2.CreateL( KLogChunk2Name );
       
   321     }
       
   322 
       
   323 // -----------------------------------------------------------------------------
       
   324 // RMulLogManager::Release
       
   325 // -----------------------------------------------------------------------------
       
   326 EXPORT_C void RMulLogManager::Release()
       
   327     {
       
   328     // close file server handle
       
   329     iFs.Close();
       
   330     
       
   331     // release both log chunks
       
   332     iLogUtility1.Close();
       
   333     iLogUtility2.Close();
       
   334     }
       
   335 
       
   336 // -----------------------------------------------------------------------------
       
   337 // RMulLogManager::CommitToFileL
       
   338 // -----------------------------------------------------------------------------
       
   339 EXPORT_C void RMulLogManager::CommitToFileL( const TDesC& aFolder )
       
   340 	{
       
   341 	// open the file
       
   342 	RFile file;
       
   343 	CleanupClosePushL( file );
       
   344 	
       
   345 	// chunk1
       
   346 	// create the file name
       
   347 	TFileName fileName;
       
   348 	fileName = aFolder;
       
   349 	fileName.Append( KLogChunk1Name );
       
   350 	fileName.Append( KLogFileExtension );
       
   351 	// try to open the file	
       
   352 	TInt err = file.Open( iFs, fileName, EFileWrite );
       
   353 	if ( err == KErrNotFound )
       
   354 	    {
       
   355 	    // file doesn't exist so create it
       
   356 	    err = file.Create( iFs, fileName, EFileWrite );
       
   357 	    }
       
   358 	User::LeaveIfError( err );
       
   359 	// write the first chunk to file
       
   360 	CommitToFileL( iLogUtility1, file );
       
   361 	// close the file
       
   362 	file.Close();
       
   363 	
       
   364 	// chunk2
       
   365 	// reset the file name
       
   366 	fileName.Zero();
       
   367 	// create the file name
       
   368 	fileName = aFolder;
       
   369 	fileName.Append( KLogChunk2Name );
       
   370 	fileName.Append( KLogFileExtension );
       
   371 	// try to open the file
       
   372 	err = file.Open( iFs, fileName, EFileWrite );
       
   373 	if ( err == KErrNotFound )
       
   374 	    {
       
   375 	    // file doesn't exist so create it
       
   376 	    err = file.Create( iFs, fileName, EFileWrite );
       
   377 	    }
       
   378 	User::LeaveIfError( err );
       
   379 	// write the second chunk to file
       
   380 	CommitToFileL( iLogUtility2, file );
       
   381 
       
   382 	CleanupStack::PopAndDestroy( &file );
       
   383 	}
       
   384 
       
   385 // -----------------------------------------------------------------------------
       
   386 // RMulLogManager::CommitToFileL
       
   387 // -----------------------------------------------------------------------------    
       
   388 void RMulLogManager::CommitToFileL( RMulLogUtility& aUtility, RFile& aFile )
       
   389     {
       
   390     // Need to explicitly move to the end of the file as it's not done
       
   391     // automatically on call to Write
       
   392     TInt pos = 0;
       
   393     TInt err = aFile.Seek( ESeekEnd, pos );
       
   394     User::LeaveIfError( err );
       
   395     TPtr8 logEntryPtr( 0, 0 );
       
   396     TInt logEntrySize = 0;
       
   397     
       
   398     // what's previously been logged to the file?
       
   399     TUint8* lastLoggedAddress = aUtility.LastLoggedAddress();
       
   400     
       
   401     // how much more has been added to the chunk?
       
   402     TUint8* currentAddress = aUtility.CurrentAddress();
       
   403     
       
   404     // write each of the chunk's logged entries to the file 
       
   405     TInt32* sizePtr = NULL;
       
   406     while ( currentAddress != lastLoggedAddress && err == KErrNone )
       
   407         {
       
   408         // get the logEntry's size
       
   409         sizePtr = reinterpret_cast< TInt32* >( lastLoggedAddress );
       
   410         logEntrySize = *sizePtr;
       
   411         if ( logEntrySize == KErrNotFound )
       
   412             {
       
   413             // logged entries have wrapped around the end of the chunk
       
   414             // so start from the beginning
       
   415             lastLoggedAddress = aUtility.BaseAddress();
       
   416             sizePtr = reinterpret_cast< TInt32* >( lastLoggedAddress );
       
   417             logEntrySize = *sizePtr;
       
   418             }
       
   419         // set an error - this will be reset to KErrNone if we succeed
       
   420         // with finding and writing a log entry
       
   421         err = KErrNotFound;
       
   422         if ( logEntrySize > 0 )
       
   423             {
       
   424             // move the current address to the data
       
   425             lastLoggedAddress += sizeof( TInt32 );
       
   426             // extract the log entry's data 
       
   427             logEntryPtr.Set( lastLoggedAddress, logEntrySize, logEntrySize );
       
   428             // write the log entry to the file
       
   429             err = aFile.Write( logEntryPtr );
       
   430             // append carriage return and line feed to the entry
       
   431             err = aFile.Write( KLogCR );
       
   432             err = aFile.Write( KLogLF );
       
   433             // ensure we align to a multiple of a 4-byte boundary
       
   434             TInt remainder = logEntrySize % KBytesInAWord;
       
   435             if ( remainder > 0 )
       
   436                 {
       
   437                 // not aligned so add some padding
       
   438                 logEntrySize += ( KBytesInAWord - remainder );
       
   439                 }
       
   440  
       
   441             // update the last logged address
       
   442             lastLoggedAddress += logEntrySize;
       
   443             }
       
   444         }
       
   445     // update the last logged address
       
   446     aUtility.SetLastLoggedAddress( lastLoggedAddress );
       
   447 	// 
       
   448 	// commit the data
       
   449 	err = aFile.Flush();
       
   450 	User::LeaveIfError( err );
       
   451     }