diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Algorithms/StackAlgorithmManager.cs --- /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 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 iMasterAlgorithmTable = new PluginManager( 2 ); + + // Transient variables + private TSynchronicity iSynchronicity = TSynchronicity.EAsynchronous; + private Queue iExecutionQueue = new Queue(); + private int iProgressValueMax = 0; + private int iProgressValueCompleted = 0; + private int iProgressValueCurrent = 0; + private TFlags iFlags = TFlags.EFlagsNone; + #endregion + } +}