|
1 /* |
|
2 * Copyright (c) 2009 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 using System; |
|
18 using System.Collections.Generic; |
|
19 using System.Text; |
|
20 using SymbianDebugLib.Engine; |
|
21 using SymbianStackLib.Data.Output.Entry; |
|
22 using SymbianStackLib.Engine; |
|
23 using SymbianStackLib.Interfaces; |
|
24 using SymbianUtils; |
|
25 using SymbianUtils.PluginManager; |
|
26 using SymbianUtils.Range; |
|
27 |
|
28 namespace SymbianStackLib.Algorithms |
|
29 { |
|
30 internal sealed class StackAlgorithmManager : DisposableObject, IStackAlgorithmObserver, IStackAlgorithmManager |
|
31 { |
|
32 #region Delegates & events |
|
33 public enum TEvent |
|
34 { |
|
35 EAlgorithmStarted = 0, |
|
36 EAlgorithmProgress, |
|
37 EAlgorithmComplete |
|
38 } |
|
39 |
|
40 public delegate void AlgorithmEventHandler( StackAlgorithmManager aAlgManager, TEvent aEvent ); |
|
41 public event AlgorithmEventHandler EventHandler; |
|
42 |
|
43 public delegate void AlgorithmExceptionHandler( StackAlgorithmManager aAlgManager, Exception aException ); |
|
44 public event AlgorithmExceptionHandler ExceptionHandler; |
|
45 #endregion |
|
46 |
|
47 #region Constructors |
|
48 public StackAlgorithmManager( StackEngine aEngine ) |
|
49 { |
|
50 iEngine = aEngine; |
|
51 |
|
52 // Make the view name based upon the stack address range |
|
53 AddressRange range = aEngine.AddressInfo.Range; |
|
54 StringBuilder viewName = new StringBuilder(); |
|
55 viewName.AppendFormat( "StackReconstructor_{0}_{1}", range, DateTime.Now.Ticks ); |
|
56 iView = iEngine.DebugEngine.CreateView( viewName.ToString(), iEngine.CodeSegments ); |
|
57 } |
|
58 #endregion |
|
59 |
|
60 #region API |
|
61 public void Reconstruct( TSynchronicity aSynchronicity ) |
|
62 { |
|
63 iSynchronicity = aSynchronicity; |
|
64 try |
|
65 { |
|
66 PrepareForExecution(); |
|
67 ExecuteHeadAlgorithm(); |
|
68 } |
|
69 catch ( Exception e ) |
|
70 { |
|
71 // The only reason an exception should occur is if none of the algorithms indicate that |
|
72 // they are ready to process stack data (probably because symbols were not provided). |
|
73 // |
|
74 // In this situation, we must report the exception to our event handler |
|
75 if ( ExceptionHandler != null && EventHandler != null ) |
|
76 { |
|
77 // Make sure we sent the 'start' and 'end' events as well - we cannot send |
|
78 // these events twice so it's okay to try to send them (will be ignored if |
|
79 // already sent). |
|
80 ReportEvent( TEvent.EAlgorithmStarted ); |
|
81 |
|
82 // Now report the exception |
|
83 ExceptionHandler( this, e ); |
|
84 |
|
85 // Indicate completion since we're not going to be able to do anything anymore |
|
86 ReportEvent( TEvent.EAlgorithmComplete ); |
|
87 } |
|
88 else |
|
89 { |
|
90 // No exception handler so just rethrow... |
|
91 throw e; |
|
92 } |
|
93 } |
|
94 } |
|
95 #endregion |
|
96 |
|
97 #region Properties |
|
98 public int Progress |
|
99 { |
|
100 get |
|
101 { |
|
102 // Scale the progress back to a fraction of the total |
|
103 lock ( this ) |
|
104 { |
|
105 int totalProgressSoFar = iProgressValueCompleted + iProgressValueCurrent; |
|
106 float prog = ( (float) totalProgressSoFar ) / ( (float) iProgressValueMax ); |
|
107 prog *= 100.0f; |
|
108 return (int) prog; |
|
109 } |
|
110 } |
|
111 } |
|
112 #endregion |
|
113 |
|
114 #region From IStackAlgorithmObserver |
|
115 public void StackBuildingStarted( StackAlgorithm aAlg ) |
|
116 { |
|
117 Trace( "[SBAlgManager] StackBuildingStarted() - aAlg: {0}", aAlg ); |
|
118 ReportEvent( TEvent.EAlgorithmStarted ); |
|
119 } |
|
120 |
|
121 public void StackBuldingProgress( StackAlgorithm aAlg, int aPercent ) |
|
122 { |
|
123 Trace( "[SBAlgManager] StackBuldingProgress() - aAlg: {0}, aPercent: {1}", aAlg, aPercent ); |
|
124 lock ( this ) |
|
125 { |
|
126 iProgressValueCurrent = aPercent; |
|
127 } |
|
128 // |
|
129 ReportEvent( TEvent.EAlgorithmProgress ); |
|
130 } |
|
131 |
|
132 public void StackBuildingComplete( StackAlgorithm aAlg ) |
|
133 { |
|
134 // If the algorithm is still queued then everything went okay. If not, then we |
|
135 // had an exception and we should therefore ignore the completion as the algorithm |
|
136 // terminated unexpectedly. |
|
137 bool stillExists = iExecutionQueue.Contains( aAlg ); |
|
138 Trace( "[SBAlgManager] StackBuildingComplete() - aAlg: {0}, stillExists: {1}", aAlg, stillExists ); |
|
139 if ( stillExists ) |
|
140 { |
|
141 iExecutionQueue.Clear(); |
|
142 ReportEvent( TEvent.EAlgorithmComplete ); |
|
143 } |
|
144 } |
|
145 |
|
146 public void StackBuildingElementConstructed( StackAlgorithm aAlg, StackOutputEntry aEntry ) |
|
147 { |
|
148 lock ( this ) |
|
149 { |
|
150 iEngine.DataOutput.InsertAsFirstEntry( aEntry ); |
|
151 } |
|
152 } |
|
153 |
|
154 public void StackBuildingException( StackAlgorithm aAlg, Exception aException ) |
|
155 { |
|
156 Trace( "[SBAlgManager] STACK ALG EXCEPTION: " + aException.Message ); |
|
157 Trace( "[SBAlgManager] {0}", aException.StackTrace ); |
|
158 |
|
159 StackAlgorithm alg = CurrentAlgorithm; |
|
160 |
|
161 // If we're executing using the fallback entry, then we're in trouble. |
|
162 // There is nothing we can do besides report the problem upwards. |
|
163 if ( iExecutionQueue.Count == 1 ) |
|
164 { |
|
165 if ( ExceptionHandler != null ) |
|
166 { |
|
167 ExceptionHandler( this, aException ); |
|
168 } |
|
169 } |
|
170 else |
|
171 { |
|
172 // Report event |
|
173 string message = string.Format( LibResources.StackAlgorithmManager_FailedAlgorithmWarning + System.Environment.NewLine + "{1}", |
|
174 alg.Name, aException.Message.ToString() |
|
175 ); |
|
176 iEngine.ReportMessage( StackEngine.TMessageType.ETypeWarning, message ); |
|
177 |
|
178 // The primary algorithm has failed, let's roll back to the secondary |
|
179 // by dumping the primary algorithm and starting again. |
|
180 iExecutionQueue.Dequeue(); |
|
181 iEngine.DataOutput.Clear(); |
|
182 |
|
183 // Reset progress. |
|
184 iProgressValueCompleted += 100; |
|
185 iProgressValueCurrent = 0; |
|
186 |
|
187 // Start next algorithm... |
|
188 ExecuteHeadAlgorithm(); |
|
189 } |
|
190 } |
|
191 #endregion |
|
192 |
|
193 #region From IStackAlgorithmManager |
|
194 public StackEngine Engine |
|
195 { |
|
196 get { return iEngine; } |
|
197 } |
|
198 |
|
199 public DbgEngineView DebugEngineView |
|
200 { |
|
201 get { return iView; } |
|
202 } |
|
203 |
|
204 public void Trace( string aMessage ) |
|
205 { |
|
206 iEngine.Trace( aMessage ); |
|
207 } |
|
208 |
|
209 public void Trace( string aFormat, params object[] aParams ) |
|
210 { |
|
211 iEngine.Trace( aFormat, aParams ); |
|
212 } |
|
213 #endregion |
|
214 |
|
215 #region From DisposableObject |
|
216 protected override void CleanupManagedResources() |
|
217 { |
|
218 try |
|
219 { |
|
220 base.CleanupManagedResources(); |
|
221 } |
|
222 finally |
|
223 { |
|
224 if ( iMasterAlgorithmTable != null ) |
|
225 { |
|
226 iMasterAlgorithmTable.Dispose(); |
|
227 iMasterAlgorithmTable = null; |
|
228 } |
|
229 |
|
230 if ( iView != null ) |
|
231 { |
|
232 iView.Dispose(); |
|
233 iView = null; |
|
234 } |
|
235 } |
|
236 } |
|
237 #endregion |
|
238 |
|
239 #region Internal properties |
|
240 private StackAlgorithm CurrentAlgorithm |
|
241 { |
|
242 get |
|
243 { |
|
244 if ( iExecutionQueue.Count == 0 ) |
|
245 { |
|
246 throw new Exception( "No stack algorithms available" ); |
|
247 } |
|
248 // |
|
249 return iExecutionQueue.Peek(); |
|
250 } |
|
251 } |
|
252 #endregion |
|
253 |
|
254 #region Internal methods |
|
255 private void PrepareForExecution() |
|
256 { |
|
257 Trace( "[SBAlgManager] PrepareForExecution() - START" ); |
|
258 |
|
259 // Validate address info |
|
260 iEngine.AddressInfo.Validate(); |
|
261 |
|
262 // Clear data output |
|
263 iEngine.DataOutput.Clear(); |
|
264 |
|
265 // Reset master list |
|
266 IStackAlgorithmManager manager = (IStackAlgorithmManager) this; |
|
267 IStackAlgorithmObserver observer = (IStackAlgorithmObserver) this; |
|
268 iMasterAlgorithmTable.Load( new object[] { manager, observer } ); |
|
269 SortAlgorithms(); |
|
270 |
|
271 // Build list of algorithms we'll try to use |
|
272 PrepareExecutionQueue(); |
|
273 |
|
274 // Work out maximum progress value for this operation |
|
275 int numberOfPendingAlgs = iExecutionQueue.Count; |
|
276 iProgressValueMax = numberOfPendingAlgs * 100; |
|
277 |
|
278 // Reset current progress |
|
279 iProgressValueCurrent = 0; |
|
280 iProgressValueCompleted = 0; |
|
281 |
|
282 Trace( "[SBAlgManager] PrepareForExecution() - END" ); |
|
283 } |
|
284 |
|
285 private void PrepareExecutionQueue() |
|
286 { |
|
287 iExecutionQueue.Clear(); |
|
288 |
|
289 // Find most appropriate algorithm... |
|
290 StackAlgorithm primary = FindPrimaryAlgorithm(); |
|
291 if ( primary != null ) |
|
292 { |
|
293 iExecutionQueue.Enqueue( primary ); |
|
294 |
|
295 // Find backup algorithms |
|
296 EnqueueBackupAlgorithms( primary ); |
|
297 } |
|
298 else |
|
299 { |
|
300 throw new Exception( "No valid stack algorithms available" ); |
|
301 } |
|
302 } |
|
303 |
|
304 private StackAlgorithm FindPrimaryAlgorithm() |
|
305 { |
|
306 StackAlgorithm ret = null; |
|
307 // |
|
308 foreach ( StackAlgorithm alg in iMasterAlgorithmTable ) |
|
309 { |
|
310 if ( alg.IsAvailable() ) |
|
311 { |
|
312 ret = alg; |
|
313 break; |
|
314 } |
|
315 } |
|
316 // |
|
317 Trace( "[SBAlgManager] FindPrimaryAlgorithm() - ret: {0}", ret ); |
|
318 return ret; |
|
319 } |
|
320 |
|
321 private void EnqueueBackupAlgorithms( StackAlgorithm aExclude ) |
|
322 { |
|
323 foreach ( StackAlgorithm alg in iMasterAlgorithmTable ) |
|
324 { |
|
325 string name = alg.Name; |
|
326 bool available = alg.IsAvailable(); |
|
327 Trace( "[SBAlgManager] EnqueueBackupAlgorithms() - name: {0}, available: {1}", name, available ); |
|
328 |
|
329 if ( available && name != aExclude.Name ) |
|
330 { |
|
331 iExecutionQueue.Enqueue( alg ); |
|
332 } |
|
333 } |
|
334 } |
|
335 |
|
336 private void ExecuteHeadAlgorithm() |
|
337 { |
|
338 Trace( "[SBAlgManager] ExecuteHeadAlgorithm() - iSynchronicity: {0}", iSynchronicity ); |
|
339 StackAlgorithm alg = CurrentAlgorithm; |
|
340 alg.BuildStack( iSynchronicity ); |
|
341 } |
|
342 |
|
343 private void SortAlgorithms() |
|
344 { |
|
345 Comparison<StackAlgorithm> sorter = delegate( StackAlgorithm aLeft, StackAlgorithm aRight ) |
|
346 { |
|
347 int ret = 1; |
|
348 // |
|
349 if ( aLeft == null ) |
|
350 { |
|
351 ret = -1; |
|
352 } |
|
353 else if ( aRight == null ) |
|
354 { |
|
355 } |
|
356 else |
|
357 { |
|
358 ret = aLeft.Priority.CompareTo( aRight.Priority ); |
|
359 } |
|
360 // |
|
361 return ret; |
|
362 }; |
|
363 iMasterAlgorithmTable.Sort( sorter ); |
|
364 } |
|
365 |
|
366 private void ReportEvent( TEvent aEvent ) |
|
367 { |
|
368 // Ensure we only report significant events once |
|
369 if ( EventHandler != null ) |
|
370 { |
|
371 switch ( aEvent ) |
|
372 { |
|
373 case TEvent.EAlgorithmStarted: |
|
374 if ( ( iFlags & TFlags.EFlagsReportedStarted ) != TFlags.EFlagsReportedStarted ) |
|
375 { |
|
376 iFlags |= TFlags.EFlagsReportedStarted; |
|
377 EventHandler( this, aEvent ); |
|
378 } |
|
379 break; |
|
380 case TEvent.EAlgorithmComplete: |
|
381 if ( ( iFlags & TFlags.EFlagsReportedComplete ) != TFlags.EFlagsReportedComplete ) |
|
382 { |
|
383 iFlags |= TFlags.EFlagsReportedComplete; |
|
384 EventHandler( this, aEvent ); |
|
385 } |
|
386 break; |
|
387 default: |
|
388 EventHandler( this, aEvent ); |
|
389 break; |
|
390 } |
|
391 } |
|
392 } |
|
393 #endregion |
|
394 |
|
395 #region Internal enumerations |
|
396 [Flags] |
|
397 private enum TFlags |
|
398 { |
|
399 EFlagsNone = 0, |
|
400 EFlagsReportedStarted = 1, |
|
401 EFlagsReportedComplete = 2 |
|
402 } |
|
403 #endregion |
|
404 |
|
405 #region Data members |
|
406 private readonly StackEngine iEngine; |
|
407 private DbgEngineView iView; |
|
408 private PluginManager<StackAlgorithm> iMasterAlgorithmTable = new PluginManager<StackAlgorithm>( 2 ); |
|
409 |
|
410 // Transient variables |
|
411 private TSynchronicity iSynchronicity = TSynchronicity.EAsynchronous; |
|
412 private Queue<StackAlgorithm> iExecutionQueue = new Queue<StackAlgorithm>(); |
|
413 private int iProgressValueMax = 0; |
|
414 private int iProgressValueCompleted = 0; |
|
415 private int iProgressValueCurrent = 0; |
|
416 private TFlags iFlags = TFlags.EFlagsNone; |
|
417 #endregion |
|
418 } |
|
419 } |