crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianCodeLib/SourceManagement/Source/CodeSource.cs
changeset 0 818e61de6cd1
--- /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<CodeCollection>, 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<CodeCollection>
+        public IEnumerator<CodeCollection> 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
+    }
+}