crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianCodeLib/DbgEnginePlugin/CodePrimer.cs
changeset 0 818e61de6cd1
equal deleted inserted replaced
-1:000000000000 0:818e61de6cd1
       
     1 /*
       
     2 * Copyright (c) 2004-2008 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: 
       
    15 *
       
    16 */
       
    17 
       
    18 using System;
       
    19 using System.Collections.Generic;
       
    20 using System.Text;
       
    21 using System.IO;
       
    22 using SymbianUtils;
       
    23 using SymbianUtils.Tracer;
       
    24 using SymbianUtils.FileTypes;
       
    25 using SymbianStructuresLib.Debug.Symbols;
       
    26 using SymbianStructuresLib.CodeSegments;
       
    27 using SymbianDebugLib.Entity;
       
    28 using SymbianDebugLib.PluginAPI;
       
    29 using SymbianCodeLib.SourceManagement.Source;
       
    30 using SymbianCodeLib.SourceManagement.Provisioning;
       
    31 
       
    32 namespace SymbianCodeLib.DbgEnginePlugin
       
    33 {
       
    34     internal class CodePrimer : DbgPluginPrimer
       
    35     {
       
    36         #region Constructors
       
    37         public CodePrimer( CodePlugin aPlugin )
       
    38             : base( aPlugin )
       
    39 		{
       
    40 		}
       
    41 		#endregion
       
    42 
       
    43         #region From DbgPluginPrimer
       
    44         public override void Add( DbgEntity aEntity )
       
    45         {
       
    46             CodeSourceProvider provider = null;
       
    47             //
       
    48             if ( aEntity.FSEntity.IsFile )
       
    49             {
       
    50                 if ( aEntity.Exists && aEntity.FSEntity.IsValid )
       
    51                 {
       
    52                     provider = ProvisioningManager.GetProvider( aEntity.FSEntity.FullName );
       
    53                 }
       
    54                 //
       
    55                 if ( provider != null )
       
    56                 {
       
    57                     using ( CodeSourceCollection sources = provider.CreateSources( aEntity.FullName ) )
       
    58                     {
       
    59                         // Make sure the time to read attribute is setup in alignment with
       
    60                         // whether the entity was explicitly added by the user or found implicitly
       
    61                         // by scanning.
       
    62                         if ( aEntity.WasAddedExplicitly == false )
       
    63                         {
       
    64                             foreach ( CodeSource source in sources )
       
    65                             {
       
    66                                 // This means, don't read this source until it is actually
       
    67                                 // referenced by the client. I.e. until the client activates
       
    68                                 // a code segment that refers to this 
       
    69                                 source.TimeToRead = CodeSource.TTimeToRead.EReadWhenNeeded;
       
    70                             }
       
    71                         }
       
    72 
       
    73                         // Ownership is transferred
       
    74                         iSources.AddRange( sources );
       
    75                         sources.Clear();
       
    76                     }
       
    77                 }
       
    78                 else
       
    79                 {
       
    80                     throw new NotSupportedException( "Specified file type is not supported" );
       
    81                 }
       
    82             }
       
    83             else
       
    84             {
       
    85                 throw new ArgumentException( "SymbianCodeLib does not support directory entities" );
       
    86             }
       
    87         }
       
    88 
       
    89         public override void Prime( TSynchronicity aSynchronicity )
       
    90         {
       
    91             CodePlugin plugin = this.Plugin;
       
    92 
       
    93             // Wipe any state ready for new priming attempt
       
    94             base.OnPrepareToPrime();
       
    95             if ( base.ResetEngineBeforePriming )
       
    96             {
       
    97                 plugin.Clear();
       
    98             }
       
    99     
       
   100             // Report the "priming started event" prior to adding the sources
       
   101             base.ReportEvent( TPrimeEvent.EEventPrimingStarted, null );
       
   102 
       
   103             // Any sources already registered with the source manager at the start of a new
       
   104             // priming request are assumed to already be complete.
       
   105             RecordAlreadyCompletedSources();
       
   106 
       
   107             // Initially, whilst adding the sources to the source manager, we'll
       
   108             // operate synchronously. This prevents us from triggering the read
       
   109             // operation in the SourceAdded callback below.
       
   110             iSynchronicity = TSynchronicity.ESynchronous;
       
   111 
       
   112             // Listen to source manager events in case any new sources are
       
   113             // created whilst reading those we already know about.
       
   114             CodeSourceManager sourceManager = this.SourceManager;
       
   115             sourceManager.SourceAdded += new CodeSourceManager.SourceEventHandler( SourceManager_SourceAdded );
       
   116             sourceManager.SourceRemoved += new CodeSourceManager.SourceEventHandler( SourceManager_SourceRemoved );
       
   117 
       
   118             // Tell the source manager which sources we are reading. This also will
       
   119             // call our event handler (added above) so that we can observe source events.
       
   120             CodeSourceCollection sources = iSources;
       
   121             iSources = new CodeSourceCollection();
       
   122             sourceManager.AddRange( sources );
       
   123 
       
   124             // If we're operating asynchronously, then the loop below will potentially
       
   125             // complete quite quickly. This means that any (new/additional) sources which 
       
   126             // are created (asynchronously) whilst reading is underway will not themselves 
       
   127             // be read. 
       
   128             // 
       
   129             // Therefore, we store the synchronisation mode as a data member, and when
       
   130             // 'SourceAdded' is called, if operating asynchronously, we'll also initiate
       
   131             // a read operation for the source (as soon as it is added).
       
   132             //
       
   133             // If we're operating synchronously, then this isn't important. Because we're
       
   134             // behaving synchronously, the loop below will only process one source at a
       
   135             // time (before waiting) and therefore even if that source adds new/additional
       
   136             // sources to the source manager, we'll catch them as soon as we move the
       
   137             // next iteration around the loop.
       
   138             iSynchronicity = aSynchronicity;
       
   139 
       
   140             // TODO: possibly re-write this so that it uses two separate code paths
       
   141             // for synchronous and asynchronous priming? By trying to use one path
       
   142             // this code looks rather complex and isn't terribly robust.
       
   143             try
       
   144             {
       
   145                 // Now we can start the sources running.
       
   146                 int count = iSourcesYetToBePrimed.Count;
       
   147                 while ( count > 0 )
       
   148                 {
       
   149                     // Get the head source and remove it from the pending list
       
   150                     CodeSource source = iSourcesYetToBePrimed[ 0 ];
       
   151                     iSourcesYetToBePrimed.Remove( source );
       
   152                         
       
   153                     // If the source wants to read it's data immediately, then activated
       
   154                     // it right now...
       
   155                     if ( source.TimeToRead == CodeSource.TTimeToRead.EReadWhenPriming )
       
   156                     {
       
   157                         source.Read( aSynchronicity );
       
   158                     }
       
   159                     else
       
   160                     {
       
   161                         // This source will read it's data on it's own terms so skip
       
   162                         // it to ensure that we can track when all the other sources 
       
   163                         // (that do actually read their files now..) are ready.
       
   164                         Skip( source );
       
   165                     }
       
   166 
       
   167                     count = iSourcesYetToBePrimed.Count;
       
   168                 }
       
   169             }
       
   170             catch( Exception e )
       
   171             {
       
   172                 // If priming failed, report completion before rethrowing...
       
   173                 OnPrimeComplete();
       
   174                 throw e;
       
   175             }
       
   176        }
       
   177 
       
   178         protected override void OnPrimeComplete()
       
   179         {
       
   180             System.Diagnostics.Debug.Assert( iSourcesYetToBePrimed.Count == 0 );
       
   181             try
       
   182             {
       
   183                 SourceManager.SourceAdded -= new CodeSourceManager.SourceEventHandler( SourceManager_SourceAdded );
       
   184                 SourceManager.SourceRemoved -= new CodeSourceManager.SourceEventHandler( SourceManager_SourceRemoved );
       
   185                 //
       
   186                 base.OnPrimeComplete();
       
   187             }
       
   188             finally
       
   189             {
       
   190                 SourceEventsUnsubscribe();
       
   191             }
       
   192         }
       
   193 
       
   194         protected override int Count
       
   195         {
       
   196             get
       
   197             {
       
   198                 int count = SourceManager.Count;
       
   199                 return count; 
       
   200             }
       
   201         }
       
   202         #endregion
       
   203 
       
   204         #region API
       
   205         #endregion
       
   206 
       
   207 		#region Properties
       
   208         internal CodePlugin Plugin
       
   209         {
       
   210             get { return base.Engine as CodePlugin; }
       
   211         }
       
   212 
       
   213         internal CodeSourceManager SourceManager
       
   214         {
       
   215             get { return Plugin.SourceManager; }
       
   216         }
       
   217 
       
   218         internal CodeSourceProviderManager ProvisioningManager
       
   219         {
       
   220             get { return Plugin.ProvisioningManager; }
       
   221         }
       
   222         #endregion
       
   223 
       
   224         #region Event handlers
       
   225         private void SourceManager_SourceAdded( CodeSource aSource )
       
   226         {
       
   227             base.Engine.Trace( "[CodePrimer] SourceManager_SourceAdded - aSource: {0}, time to read: {1}", aSource, aSource.TimeToRead );
       
   228 
       
   229             aSource.EventHandler += new CodeSource.EventHandlerFunction( Source_EventHandler );
       
   230             bool needToSave = true;
       
   231 
       
   232             // If we're in async mode and the source wants to be read immediately
       
   233             // then kick it off. If we're operating in sync mode, then this will
       
   234             // be done as part of the loop within 'Prime'.
       
   235             if ( iSynchronicity == TSynchronicity.EAsynchronous )
       
   236             {
       
   237                 if ( aSource.TimeToRead == CodeSource.TTimeToRead.EReadWhenPriming )
       
   238                 {
       
   239                     aSource.Read( iSynchronicity );
       
   240                 }
       
   241                 else
       
   242                 {
       
   243                     // This source will read it's data on it's own terms so skip
       
   244                     // it to ensure that we can track when all the other sources 
       
   245                     // (that do actually read their files now..) are ready.
       
   246                     Skip( aSource );
       
   247                 }
       
   248 
       
   249                 // We don't need to add it to the 'yet to be primed' list because
       
   250                 // it's either been 'read' or then it only supports read-on-demand.
       
   251                 needToSave = false;
       
   252             }
       
   253 
       
   254             if ( needToSave )
       
   255             {
       
   256                 lock ( iSourcesYetToBePrimed )
       
   257                 {
       
   258                     iSourcesYetToBePrimed.Add( aSource );
       
   259                 }
       
   260             }
       
   261 
       
   262             base.Engine.Trace( string.Format( "[SourceManager_SourceAdded] {0}, srcCount: {1}, yetToBePrimed: {2}", aSource.URI, SourceManager.Count, iSourcesYetToBePrimed.Count ) );
       
   263         }
       
   264 
       
   265         private void SourceManager_SourceRemoved( CodeSource aSource )
       
   266         {
       
   267             base.Engine.Trace( string.Format( "[SourceManager_SourceRemoved] START - {0}, srcCount: {1}, yetToBePrimed: {2}", aSource.URI, SourceManager.Count, iSourcesYetToBePrimed.Count ) );
       
   268             
       
   269             aSource.EventHandler -= new CodeSource.EventHandlerFunction( Source_EventHandler );
       
   270 
       
   271             base.RemoveFromCompleted( aSource );
       
   272             lock ( iSourcesYetToBePrimed )
       
   273             {
       
   274                 iSourcesYetToBePrimed.Remove( aSource );
       
   275             }
       
   276 
       
   277             // Check for completion since removing a source might mean that we've now
       
   278             // reached completed state (if it was the last one that we were waiting for)
       
   279             bool amComplete = base.IsComplete;
       
   280             if ( amComplete )
       
   281             {
       
   282                 CheckForCompletion( amComplete );
       
   283             }
       
   284 
       
   285             base.Engine.Trace( string.Format( "[SourceManager_SourceRemoved] END - {0}, srcCount: {1}, yetToBePrimed: {2}, amComplete: {3}", aSource.URI, SourceManager.Count, iSourcesYetToBePrimed.Count, amComplete ) );
       
   286         }
       
   287 
       
   288         private void Source_EventHandler( CodeSource.TEvent aEvent, CodeSource aSource, object aData )
       
   289         {
       
   290             bool primeCompleted = false;
       
   291 
       
   292             // Map source event onto a primer event
       
   293             if ( aEvent == CodeSource.TEvent.EReadingProgress )
       
   294             {
       
   295                 base.SaveLatestProgress( aSource, (int) aData );
       
   296             }
       
   297             
       
   298             // If all sources are complete, then are we also done?
       
   299             if ( aEvent == CodeSource.TEvent.EReadingComplete )
       
   300             {
       
   301                 // We don't need to listen to this source anymore
       
   302                 aSource.EventHandler -= new CodeSource.EventHandlerFunction( Source_EventHandler );
       
   303 
       
   304                 // Source is 100% complete now.
       
   305                 base.SaveLatestProgress( aSource, 100 );
       
   306 
       
   307                 // It's complete, so record as such so that we can tell when all the sources
       
   308                 // are now ready.
       
   309                 primeCompleted = base.AddToCompleted( aSource );
       
   310             }
       
   311 
       
   312             CheckForCompletion( primeCompleted );
       
   313         }
       
   314         #endregion
       
   315 
       
   316         #region Internal methods
       
   317         private void Skip( CodeSource aSource )
       
   318         {
       
   319             System.Diagnostics.Debug.Assert( aSource.TimeToRead == CodeSource.TTimeToRead.EReadWhenNeeded );
       
   320             bool primeCompleted = base.AddToCompleted( aSource );
       
   321             CheckForCompletion( primeCompleted );
       
   322         }
       
   323 
       
   324         private void SourceEventsUnsubscribe()
       
   325         {
       
   326             foreach ( CodeSource source in SourceManager )
       
   327             {
       
   328                 source.EventHandler -= new CodeSource.EventHandlerFunction( Source_EventHandler );
       
   329             }
       
   330         }
       
   331 
       
   332         private void CheckForCompletion( bool aAmIComplete )
       
   333         {
       
   334             // Report any progress
       
   335             base.ReportProgressIfNeeded( aAmIComplete );
       
   336 
       
   337             // Tidy up and report completion
       
   338             if ( aAmIComplete )
       
   339             {
       
   340                 OnPrimeComplete();
       
   341             }
       
   342         }
       
   343 
       
   344         private void RecordAlreadyCompletedSources()
       
   345         {
       
   346             CodeSourceManager sourceManager = this.SourceManager;
       
   347             foreach ( CodeSource source in sourceManager )
       
   348             {
       
   349                 base.AddToCompleted( source );
       
   350             }
       
   351         }
       
   352         #endregion
       
   353 
       
   354         #region Data members
       
   355         private TSynchronicity iSynchronicity = TSynchronicity.ESynchronous;
       
   356         private CodeSourceCollection iSources = new CodeSourceCollection();
       
   357         private CodeSourceCollection iSourcesYetToBePrimed = new CodeSourceCollection();
       
   358         #endregion
       
   359     }
       
   360 }