diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianCodeLib/SourceManagement/Source/CodeSource.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianCodeLib/SourceManagement/Source/CodeSource.cs Thu Feb 11 15:50:58 2010 +0200 @@ -0,0 +1,494 @@ +/* +* Copyright (c) 2004-2008 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: +* +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using SymbianUtils; +using SymbianUtils.Range; +using SymbianUtils.Threading; +using SymbianStructuresLib.Arm; +using SymbianStructuresLib.Arm.Instructions; +using SymbianStructuresLib.CodeSegments; +using SymbianStructuresLib.Debug.Code; +using SymbianStructuresLib.Debug.Code.Interfaces; +using SymbianStructuresLib.Debug.Common.FileName; +using SymbianCodeLib.SourceManagement.Provisioning; + +namespace SymbianCodeLib.SourceManagement.Source +{ + public abstract class CodeSource : DisposableObject, IEnumerable, ICodeCollectionRelocationHandler, ICodeCollectionInstructionConverter + { + #region Delegates & events + public delegate void EventHandlerFunction( TEvent aEvent, CodeSource aSource, object aData ); + public event EventHandlerFunction EventHandler; + #endregion + + #region Enumerations + public enum TEvent + { + EReadingStarted = 0, + EReadingProgress, + EReadingComplete + } + + public enum TTimeToRead + { + EReadWhenPriming = 0, + EReadWhenNeeded // i.e. relocated + } + #endregion + + #region Constructors + public CodeSource( string aURI, CodeSourceProvider aProvider ) + { + iURI = aURI; + iProvider = aProvider; + } + #endregion + + #region API + public virtual void Read( TSynchronicity aSynchronicity ) + { + bool isReading = this.IsReadInProgress; + if ( isReading ) + { + // Another thread is already reading this source. + // If the caller asked for asynchronous reading, then when the + // other thread completes the read the caller (in this thread) + // will be notified via the normal event callback framework - in which + // case we need do nothing at all - just let the other thread get on with it. + // + // If, on the other hand, the caller requested a synchronous read, then they + // will expect the code to be ready at the point in time which we return to them. + // + // In this situation, we should block this method until the code becomes ready. + if ( aSynchronicity == TSynchronicity.ESynchronous ) + { + while ( this.IsReadInProgress ) + { + System.Threading.Thread.Sleep( 0 ); + } + } + } + else + { + DoRead( aSynchronicity ); + } + } + + public virtual void Add( CodeCollection aCollection ) + { + // We can always do this task + aCollection.IfaceInstructionConverter = this; + + // We want to be told if the collection changes it's relocation state. + aCollection.RelocationStatusChanged += new CodeCollection.RelocationStatusChangeHandler( Collection_RelocationStatusChanged ); + + lock ( iCollectionsAll ) + { + iCollectionsAll.Add( aCollection ); + } + + CategoriseCollection( aCollection ); + } + + public virtual void Remove( CodeCollection aCollection ) + { + aCollection.RelocationStatusChanged -= new CodeCollection.RelocationStatusChangeHandler( Collection_RelocationStatusChanged ); + // + lock ( iCollectionsAll ) + { + iCollectionsAll.Remove( aCollection ); + } + lock ( iAlwaysActivatedCollections ) + { + iAlwaysActivatedCollections.Remove( aCollection ); + } + } + + public virtual bool Contains( uint aAddress ) + { + return iAlwaysActivatedCollections.Contains( aAddress ); + } + + public virtual bool ProvideInstructions( uint aAddress, TArmInstructionSet aInstructionSet, int aCount, out IArmInstruction[] aInstructions ) + { + lock ( iAlwaysActivatedCollections ) + { + bool ret = iAlwaysActivatedCollections.GetInstructions( aAddress, aInstructionSet, aCount, out aInstructions ); + return ret; + } + } + + protected abstract void DoRead( TSynchronicity aSynchronicity ); + + protected virtual void OnAddedToCollection( CodeSourceCollection aCollection ) + { + ++iReferenceCount; + } + + protected virtual void OnRemovedFromCollection( CodeSourceCollection aCollection ) + { + if ( --iReferenceCount <= 0 ) + { + this.Dispose(); + } + } + + protected virtual void OnPrepareForRelocation( CodeCollection aCollection, uint aOldBase, uint aNewBase ) + { + // If we read our data during priming, then we don't need to do anything... otherwise, we should + // read the data now. + // + // However, don't initiate a read if we already have obtained code for the specified collection + // (this can be the case if we are relocating a cloned code collection which has already been activated + // itself in the past). + if ( aCollection.IsCodeAvailable == false ) + { + System.Diagnostics.Debug.Assert( this.IsReady == false ); + // + if ( TimeToRead == TTimeToRead.EReadWhenNeeded ) + { + this.Read( TSynchronicity.ESynchronous ); + } + } + } + + protected virtual void OnReadComplete() + { + } + #endregion + + #region API - framework + public void ReportEvent( TEvent aEvent ) + { + ReportEvent( aEvent, null ); + } + + public void ReportEvent( TEvent aEvent, object aData ) + { + PreProcessEvent( aEvent ); + + // Cascade + if ( EventHandler != null ) + { + EventHandler( aEvent, this, aData ); + } + } + #endregion + + #region Properties + public int Count + { + get { return iCollectionsAll.Count; } + } + + public string URI + { + get + { + lock ( iURI ) + { + return iURI; + } + } + set + { + lock ( iURI ) + { + iURI = value; + } + } + + } + + public string FileName + { + get { return iProvider.GetFileName( this ); } + } + + public TTimeToRead TimeToRead + { + get { return iTimeToRead; } + set + { + iTimeToRead = value; + } + } + + public CodeSourceProvider Provider + { + get + { + lock ( iProvider ) + { + return iProvider; + } + } + } + + public CodeCollection this[ int aIndex ] + { + get { return iCollectionsAll[ aIndex ]; } + } + + public virtual CodeCollection this[ CodeSegDefinition aCodeSegment ] + { + get + { + CodeCollection ret = iCollectionsAll[ aCodeSegment ]; + return ret; + } + } + + public virtual CodeCollection this[ PlatformFileName aFileName ] + { + get + { + lock ( iCollectionsAll ) + { + CodeCollection ret = iCollectionsAll[ aFileName ]; + return ret; + } + } + } + + public bool IsReady + { + get + { + lock ( iFlagsSyncRoot ) + { + bool ret = ( iFlags & TFlags.EFlagsIsReady ) != 0; + return ret; + } + } + set + { + lock ( iFlagsSyncRoot ) + { + if ( value ) + { + iFlags |= TFlags.EFlagsIsReady; + } + else + { + iFlags &= ~TFlags.EFlagsIsReady; + } + } + } + } + + public bool IsReadInProgress + { + get + { + lock ( iFlagsSyncRoot ) + { + bool ret = ( iFlags & TFlags.EFlagsIsReadInProgress ) != 0; + return ret; + } + } + set + { + lock ( iFlagsSyncRoot ) + { + if ( value ) + { + iFlags |= TFlags.EFlagsIsReadInProgress; + } + else + { + iFlags &= ~TFlags.EFlagsIsReadInProgress; + } + } + } + } + #endregion + + #region Event handlers + private void Collection_RelocationStatusChanged( CodeCollection aCollection ) + { + CategoriseCollection( aCollection ); + } + #endregion + + #region Internal methods + internal int CountActivated + { + get { return iAlwaysActivatedCollections.Count; } + } + + internal void AddedToCollection( CodeSourceCollection aCollection ) + { + OnAddedToCollection( aCollection ); + } + + internal void RemovedFromCollection( CodeSourceCollection aCollection ) + { + OnRemovedFromCollection( aCollection ); + } + + private void CategoriseCollection( CodeCollection aCollection ) + { + // Reset state + lock ( iAlwaysActivatedCollections ) + { + iAlwaysActivatedCollections.Remove( aCollection ); + aCollection.IfaceRelocationHandler = null; + } + + // Collections which do not move from their pre-determined base address + // are transparently "activated" which means that they will be queried + // automatically during symbolic look up. + if ( aCollection.IsFixed ) + { + lock ( iAlwaysActivatedCollections ) + { + iAlwaysActivatedCollections.Add( aCollection ); + } + } + else + { + // Otherwise, we must wait until the client relocates the code + // and then we will be called back. During the callback processing + // we'll load the code (if needed) and fixup the base address. + aCollection.IfaceRelocationHandler = this; + } + } + + private void PreProcessEvent( TEvent aEvent ) + { + switch ( aEvent ) + { + case TEvent.EReadingStarted: + IsReady = false; + IsReadInProgress = true; + break; + case TEvent.EReadingComplete: + IsReady = true; + IsReadInProgress = false; + OnReadComplete(); + break; + } + } + #endregion + + #region Internal enumerations + [Flags] + private enum TFlags + { + EFlagsNone = 0, + EFlagsIsReady = 1, + EFlagsIsReadInProgress = 2 + } + #endregion + + #region From ICodeCollectionRelocationHandler + public void PrepareForRelocation( CodeCollection aCollection, uint aOldBase, uint aNewBase ) + { + OnPrepareForRelocation( aCollection, aOldBase, aNewBase ); + } + #endregion + + #region From ICodeCollectionInstructionConverter + public IArmInstruction[] ConvertRawValuesToInstructions( TArmInstructionSet aInstructionSet, uint[] aRawValues, uint aStartingAddress ) + { + IArmInstruction[] ret = iProvider.ConvertToInstructions( aInstructionSet, aRawValues, aStartingAddress ); + return ret; + } + #endregion + + #region From IEnumerable + public IEnumerator GetEnumerator() + { + foreach ( CodeCollection col in iCollectionsAll ) + { + yield return col; + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + foreach ( CodeCollection col in iCollectionsAll ) + { + yield return col; + } + } + #endregion + + #region From DisposableObject + protected override void CleanupManagedResources() + { + try + { + base.CleanupManagedResources(); + } + finally + { + int count = iCollectionsAll.Count; + for ( int i = count - 1; i >= 0; i-- ) + { + CodeCollection col = iCollectionsAll[ i ]; + Remove( col ); + col.Dispose(); + } + + // These should both be empty in any case + iCollectionsAll.Clear(); + iAlwaysActivatedCollections.Clear(); + } + } + #endregion + + #region From System.Object + public override string ToString() + { + return URI; + } + + public override int GetHashCode() + { + return URI.GetHashCode(); + } + + public override bool Equals( object aObject ) + { + if ( aObject is CodeSource ) + { + CodeSource other = (CodeSource) aObject; + bool ret = ( string.Compare( other.URI, this.URI, StringComparison.CurrentCultureIgnoreCase ) == 0 ); + return ret; + } + // + return base.Equals( aObject ); + } + #endregion + + #region Data members + private readonly CodeSourceProvider iProvider; + private string iURI = string.Empty; + private int iReferenceCount = 0; + private TTimeToRead iTimeToRead = TTimeToRead.EReadWhenPriming; + private CodeCollectionList iCollectionsAll = new CodeCollectionList(); + private CodeCollectionList iAlwaysActivatedCollections = new CodeCollectionList(); + private object iFlagsSyncRoot = new object(); + private TFlags iFlags = TFlags.EFlagsNone; + #endregion + } +}