--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Algorithms/StackAlgorithmManager.cs Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,419 @@
+/*
+* Copyright (c) 2009 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 SymbianDebugLib.Engine;
+using SymbianStackLib.Data.Output.Entry;
+using SymbianStackLib.Engine;
+using SymbianStackLib.Interfaces;
+using SymbianUtils;
+using SymbianUtils.PluginManager;
+using SymbianUtils.Range;
+
+namespace SymbianStackLib.Algorithms
+{
+ internal sealed class StackAlgorithmManager : DisposableObject, IStackAlgorithmObserver, IStackAlgorithmManager
+ {
+ #region Delegates & events
+ public enum TEvent
+ {
+ EAlgorithmStarted = 0,
+ EAlgorithmProgress,
+ EAlgorithmComplete
+ }
+
+ public delegate void AlgorithmEventHandler( StackAlgorithmManager aAlgManager, TEvent aEvent );
+ public event AlgorithmEventHandler EventHandler;
+
+ public delegate void AlgorithmExceptionHandler( StackAlgorithmManager aAlgManager, Exception aException );
+ public event AlgorithmExceptionHandler ExceptionHandler;
+ #endregion
+
+ #region Constructors
+ public StackAlgorithmManager( StackEngine aEngine )
+ {
+ iEngine = aEngine;
+
+ // Make the view name based upon the stack address range
+ AddressRange range = aEngine.AddressInfo.Range;
+ StringBuilder viewName = new StringBuilder();
+ viewName.AppendFormat( "StackReconstructor_{0}_{1}", range, DateTime.Now.Ticks );
+ iView = iEngine.DebugEngine.CreateView( viewName.ToString(), iEngine.CodeSegments );
+ }
+ #endregion
+
+ #region API
+ public void Reconstruct( TSynchronicity aSynchronicity )
+ {
+ iSynchronicity = aSynchronicity;
+ try
+ {
+ PrepareForExecution();
+ ExecuteHeadAlgorithm();
+ }
+ catch ( Exception e )
+ {
+ // The only reason an exception should occur is if none of the algorithms indicate that
+ // they are ready to process stack data (probably because symbols were not provided).
+ //
+ // In this situation, we must report the exception to our event handler
+ if ( ExceptionHandler != null && EventHandler != null )
+ {
+ // Make sure we sent the 'start' and 'end' events as well - we cannot send
+ // these events twice so it's okay to try to send them (will be ignored if
+ // already sent).
+ ReportEvent( TEvent.EAlgorithmStarted );
+
+ // Now report the exception
+ ExceptionHandler( this, e );
+
+ // Indicate completion since we're not going to be able to do anything anymore
+ ReportEvent( TEvent.EAlgorithmComplete );
+ }
+ else
+ {
+ // No exception handler so just rethrow...
+ throw e;
+ }
+ }
+ }
+ #endregion
+
+ #region Properties
+ public int Progress
+ {
+ get
+ {
+ // Scale the progress back to a fraction of the total
+ lock ( this )
+ {
+ int totalProgressSoFar = iProgressValueCompleted + iProgressValueCurrent;
+ float prog = ( (float) totalProgressSoFar ) / ( (float) iProgressValueMax );
+ prog *= 100.0f;
+ return (int) prog;
+ }
+ }
+ }
+ #endregion
+
+ #region From IStackAlgorithmObserver
+ public void StackBuildingStarted( StackAlgorithm aAlg )
+ {
+ Trace( "[SBAlgManager] StackBuildingStarted() - aAlg: {0}", aAlg );
+ ReportEvent( TEvent.EAlgorithmStarted );
+ }
+
+ public void StackBuldingProgress( StackAlgorithm aAlg, int aPercent )
+ {
+ Trace( "[SBAlgManager] StackBuldingProgress() - aAlg: {0}, aPercent: {1}", aAlg, aPercent );
+ lock ( this )
+ {
+ iProgressValueCurrent = aPercent;
+ }
+ //
+ ReportEvent( TEvent.EAlgorithmProgress );
+ }
+
+ public void StackBuildingComplete( StackAlgorithm aAlg )
+ {
+ // If the algorithm is still queued then everything went okay. If not, then we
+ // had an exception and we should therefore ignore the completion as the algorithm
+ // terminated unexpectedly.
+ bool stillExists = iExecutionQueue.Contains( aAlg );
+ Trace( "[SBAlgManager] StackBuildingComplete() - aAlg: {0}, stillExists: {1}", aAlg, stillExists );
+ if ( stillExists )
+ {
+ iExecutionQueue.Clear();
+ ReportEvent( TEvent.EAlgorithmComplete );
+ }
+ }
+
+ public void StackBuildingElementConstructed( StackAlgorithm aAlg, StackOutputEntry aEntry )
+ {
+ lock ( this )
+ {
+ iEngine.DataOutput.InsertAsFirstEntry( aEntry );
+ }
+ }
+
+ public void StackBuildingException( StackAlgorithm aAlg, Exception aException )
+ {
+ Trace( "[SBAlgManager] STACK ALG EXCEPTION: " + aException.Message );
+ Trace( "[SBAlgManager] {0}", aException.StackTrace );
+
+ StackAlgorithm alg = CurrentAlgorithm;
+
+ // If we're executing using the fallback entry, then we're in trouble.
+ // There is nothing we can do besides report the problem upwards.
+ if ( iExecutionQueue.Count == 1 )
+ {
+ if ( ExceptionHandler != null )
+ {
+ ExceptionHandler( this, aException );
+ }
+ }
+ else
+ {
+ // Report event
+ string message = string.Format( LibResources.StackAlgorithmManager_FailedAlgorithmWarning + System.Environment.NewLine + "{1}",
+ alg.Name, aException.Message.ToString()
+ );
+ iEngine.ReportMessage( StackEngine.TMessageType.ETypeWarning, message );
+
+ // The primary algorithm has failed, let's roll back to the secondary
+ // by dumping the primary algorithm and starting again.
+ iExecutionQueue.Dequeue();
+ iEngine.DataOutput.Clear();
+
+ // Reset progress.
+ iProgressValueCompleted += 100;
+ iProgressValueCurrent = 0;
+
+ // Start next algorithm...
+ ExecuteHeadAlgorithm();
+ }
+ }
+ #endregion
+
+ #region From IStackAlgorithmManager
+ public StackEngine Engine
+ {
+ get { return iEngine; }
+ }
+
+ public DbgEngineView DebugEngineView
+ {
+ get { return iView; }
+ }
+
+ public void Trace( string aMessage )
+ {
+ iEngine.Trace( aMessage );
+ }
+
+ public void Trace( string aFormat, params object[] aParams )
+ {
+ iEngine.Trace( aFormat, aParams );
+ }
+ #endregion
+
+ #region From DisposableObject
+ protected override void CleanupManagedResources()
+ {
+ try
+ {
+ base.CleanupManagedResources();
+ }
+ finally
+ {
+ if ( iMasterAlgorithmTable != null )
+ {
+ iMasterAlgorithmTable.Dispose();
+ iMasterAlgorithmTable = null;
+ }
+
+ if ( iView != null )
+ {
+ iView.Dispose();
+ iView = null;
+ }
+ }
+ }
+ #endregion
+
+ #region Internal properties
+ private StackAlgorithm CurrentAlgorithm
+ {
+ get
+ {
+ if ( iExecutionQueue.Count == 0 )
+ {
+ throw new Exception( "No stack algorithms available" );
+ }
+ //
+ return iExecutionQueue.Peek();
+ }
+ }
+ #endregion
+
+ #region Internal methods
+ private void PrepareForExecution()
+ {
+ Trace( "[SBAlgManager] PrepareForExecution() - START" );
+
+ // Validate address info
+ iEngine.AddressInfo.Validate();
+
+ // Clear data output
+ iEngine.DataOutput.Clear();
+
+ // Reset master list
+ IStackAlgorithmManager manager = (IStackAlgorithmManager) this;
+ IStackAlgorithmObserver observer = (IStackAlgorithmObserver) this;
+ iMasterAlgorithmTable.Load( new object[] { manager, observer } );
+ SortAlgorithms();
+
+ // Build list of algorithms we'll try to use
+ PrepareExecutionQueue();
+
+ // Work out maximum progress value for this operation
+ int numberOfPendingAlgs = iExecutionQueue.Count;
+ iProgressValueMax = numberOfPendingAlgs * 100;
+
+ // Reset current progress
+ iProgressValueCurrent = 0;
+ iProgressValueCompleted = 0;
+
+ Trace( "[SBAlgManager] PrepareForExecution() - END" );
+ }
+
+ private void PrepareExecutionQueue()
+ {
+ iExecutionQueue.Clear();
+
+ // Find most appropriate algorithm...
+ StackAlgorithm primary = FindPrimaryAlgorithm();
+ if ( primary != null )
+ {
+ iExecutionQueue.Enqueue( primary );
+
+ // Find backup algorithms
+ EnqueueBackupAlgorithms( primary );
+ }
+ else
+ {
+ throw new Exception( "No valid stack algorithms available" );
+ }
+ }
+
+ private StackAlgorithm FindPrimaryAlgorithm()
+ {
+ StackAlgorithm ret = null;
+ //
+ foreach ( StackAlgorithm alg in iMasterAlgorithmTable )
+ {
+ if ( alg.IsAvailable() )
+ {
+ ret = alg;
+ break;
+ }
+ }
+ //
+ Trace( "[SBAlgManager] FindPrimaryAlgorithm() - ret: {0}", ret );
+ return ret;
+ }
+
+ private void EnqueueBackupAlgorithms( StackAlgorithm aExclude )
+ {
+ foreach ( StackAlgorithm alg in iMasterAlgorithmTable )
+ {
+ string name = alg.Name;
+ bool available = alg.IsAvailable();
+ Trace( "[SBAlgManager] EnqueueBackupAlgorithms() - name: {0}, available: {1}", name, available );
+
+ if ( available && name != aExclude.Name )
+ {
+ iExecutionQueue.Enqueue( alg );
+ }
+ }
+ }
+
+ private void ExecuteHeadAlgorithm()
+ {
+ Trace( "[SBAlgManager] ExecuteHeadAlgorithm() - iSynchronicity: {0}", iSynchronicity );
+ StackAlgorithm alg = CurrentAlgorithm;
+ alg.BuildStack( iSynchronicity );
+ }
+
+ private void SortAlgorithms()
+ {
+ Comparison<StackAlgorithm> sorter = delegate( StackAlgorithm aLeft, StackAlgorithm aRight )
+ {
+ int ret = 1;
+ //
+ if ( aLeft == null )
+ {
+ ret = -1;
+ }
+ else if ( aRight == null )
+ {
+ }
+ else
+ {
+ ret = aLeft.Priority.CompareTo( aRight.Priority );
+ }
+ //
+ return ret;
+ };
+ iMasterAlgorithmTable.Sort( sorter );
+ }
+
+ private void ReportEvent( TEvent aEvent )
+ {
+ // Ensure we only report significant events once
+ if ( EventHandler != null )
+ {
+ switch ( aEvent )
+ {
+ case TEvent.EAlgorithmStarted:
+ if ( ( iFlags & TFlags.EFlagsReportedStarted ) != TFlags.EFlagsReportedStarted )
+ {
+ iFlags |= TFlags.EFlagsReportedStarted;
+ EventHandler( this, aEvent );
+ }
+ break;
+ case TEvent.EAlgorithmComplete:
+ if ( ( iFlags & TFlags.EFlagsReportedComplete ) != TFlags.EFlagsReportedComplete )
+ {
+ iFlags |= TFlags.EFlagsReportedComplete;
+ EventHandler( this, aEvent );
+ }
+ break;
+ default:
+ EventHandler( this, aEvent );
+ break;
+ }
+ }
+ }
+ #endregion
+
+ #region Internal enumerations
+ [Flags]
+ private enum TFlags
+ {
+ EFlagsNone = 0,
+ EFlagsReportedStarted = 1,
+ EFlagsReportedComplete = 2
+ }
+ #endregion
+
+ #region Data members
+ private readonly StackEngine iEngine;
+ private DbgEngineView iView;
+ private PluginManager<StackAlgorithm> iMasterAlgorithmTable = new PluginManager<StackAlgorithm>( 2 );
+
+ // Transient variables
+ private TSynchronicity iSynchronicity = TSynchronicity.EAsynchronous;
+ private Queue<StackAlgorithm> iExecutionQueue = new Queue<StackAlgorithm>();
+ private int iProgressValueMax = 0;
+ private int iProgressValueCompleted = 0;
+ private int iProgressValueCurrent = 0;
+ private TFlags iFlags = TFlags.EFlagsNone;
+ #endregion
+ }
+}