You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			334 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			334 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //----------------------------------------------------------------
 | |
| // Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| //----------------------------------------------------------------
 | |
| 
 | |
| namespace System.ServiceModel.Discovery
 | |
| {
 | |
|     using System.Collections.Generic;
 | |
|     using System.Runtime;
 | |
|     using System.Threading;
 | |
| 
 | |
|     abstract class IteratorAsyncResult<TIteratorState> : AsyncResult
 | |
|     {
 | |
|         TIteratorState iterState;
 | |
|         TimeoutHelper timeoutHelper;
 | |
|         IEnumerator<AsyncStep> steps;
 | |
|         bool completedSynchronously;
 | |
|         int completedCalled;
 | |
|         int numPendingSteps;
 | |
|         bool shouldComplete;
 | |
|         object thisLock;
 | |
|         AsyncCallback onStepCompletedCallback;
 | |
| 
 | |
|         protected IteratorAsyncResult(AsyncCallback callback, object state)
 | |
|             : base(callback, state)
 | |
|         {
 | |
|             this.onStepCompletedCallback = Fx.ThunkCallback(new AsyncCallback(this.OnStepCompleted));
 | |
|             this.thisLock = new object();
 | |
|         }
 | |
| 
 | |
|         protected TimeSpan OriginalTimeout
 | |
|         {
 | |
|             get { return this.timeoutHelper.OriginalTimeout; }
 | |
|         }
 | |
| 
 | |
|         public static AsyncStep CallAsync(BeginCall begin, EndCall end)
 | |
|         {
 | |
|             return new AsyncStep(begin, end, false);
 | |
|         }
 | |
| 
 | |
|         public static AsyncStep CallAsync(BeginCall begin, EndCall end, IAsyncCatch[] catches)
 | |
|         {
 | |
|             return new AsyncStep(begin, end, false, catches);
 | |
|         }
 | |
| 
 | |
|         public static AsyncStep CallParallel(BeginCall begin, EndCall end)
 | |
|         {
 | |
|             return new AsyncStep(begin, end, true);
 | |
|         }
 | |
| 
 | |
|         public static AsyncStep CallParallel(BeginCall begin, EndCall end, IAsyncCatch[] catches)
 | |
|         {
 | |
|             return new AsyncStep(begin, end, true, catches);
 | |
|         }
 | |
| 
 | |
|         protected void Start(TIteratorState iterState, TimeSpan timeout)
 | |
|         {
 | |
|             this.iterState = iterState;
 | |
|             this.timeoutHelper = new TimeoutHelper(timeout);
 | |
|             this.completedSynchronously = true;
 | |
|             this.steps = this.GetAsyncSteps();
 | |
|             this.ExecuteSteps();
 | |
|         }
 | |
| 
 | |
|         protected TimeSpan RemainingTime()
 | |
|         {
 | |
|             return this.timeoutHelper.RemainingTime();
 | |
|         }
 | |
| 
 | |
|         protected abstract IEnumerator<AsyncStep> GetAsyncSteps();
 | |
| 
 | |
|         protected void CompleteOnce()
 | |
|         {
 | |
|             this.CompleteOnce(null);
 | |
|         }
 | |
| 
 | |
|         protected void CompleteOnce(Exception error)
 | |
|         {
 | |
|             if (Interlocked.CompareExchange(ref this.completedCalled, 1, 0) == 0)
 | |
|             {
 | |
|                 base.Complete(this.completedSynchronously, error);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void ExecuteSteps()
 | |
|         {
 | |
|             IAsyncResult result;
 | |
|             AsyncStep currentStep;
 | |
| 
 | |
|             while (!this.IsCompleted)
 | |
|             {
 | |
|                 if (!this.steps.MoveNext())
 | |
|                 {
 | |
|                     this.CompleteIfNoPendingSteps();
 | |
|                     break;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     currentStep = this.steps.Current;
 | |
|                     result = this.StartStep(currentStep);
 | |
|                     if (result != null)
 | |
|                     {
 | |
|                         if (result.CompletedSynchronously)
 | |
|                         {
 | |
|                             this.FinishStep(currentStep, result);
 | |
|                         }
 | |
|                         else if (!currentStep.IsParallel)
 | |
|                         {
 | |
|                             break;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         IAsyncResult StartStep(AsyncStep step)
 | |
|         {
 | |
|             IAsyncResult result = null;
 | |
|             Exception error = null;
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 this.OnStepStart();
 | |
| 
 | |
|                 result = step.Begin(
 | |
|                     this.iterState,
 | |
|                     this.timeoutHelper.RemainingTime(),
 | |
|                     this.onStepCompletedCallback,
 | |
|                     step);
 | |
|             }
 | |
|             catch (Exception e)
 | |
|             {
 | |
|                 if (Fx.IsFatal(e))
 | |
|                 {
 | |
|                     throw;
 | |
|                 }
 | |
| 
 | |
|                 error = e;
 | |
|             }
 | |
| 
 | |
|             if (error != null)
 | |
|             {
 | |
|                 this.HandleException(error, step);
 | |
|             }
 | |
| 
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
|         void OnStepStart()
 | |
|         {
 | |
|             lock (this.thisLock)
 | |
|             {
 | |
|                 this.numPendingSteps++;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void OnStepCompletion()
 | |
|         {
 | |
|             bool doComplete = false;
 | |
| 
 | |
|             lock (this.thisLock)
 | |
|             {
 | |
|                 this.numPendingSteps--;
 | |
|                 if ((this.numPendingSteps == 0) && this.shouldComplete)
 | |
|                 {
 | |
|                     doComplete = true;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (doComplete)
 | |
|             {
 | |
|                 this.CompleteOnce();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void CompleteIfNoPendingSteps()
 | |
|         {
 | |
|             bool doComplete = false;
 | |
| 
 | |
|             lock (this.thisLock)
 | |
|             {
 | |
|                 if (this.numPendingSteps == 0)
 | |
|                 {
 | |
|                     doComplete = true;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     this.shouldComplete = true;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (doComplete)
 | |
|             {
 | |
|                 this.CompleteOnce();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void OnStepCompleted(IAsyncResult result)
 | |
|         {
 | |
|             if (result.CompletedSynchronously)
 | |
|             {
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             this.completedSynchronously = false;
 | |
|             AsyncStep step = (AsyncStep)result.AsyncState;
 | |
|             this.FinishStep(step, result);
 | |
| 
 | |
|             if (!step.IsParallel)
 | |
|             {
 | |
|                 this.ExecuteSteps();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void FinishStep(AsyncStep step, IAsyncResult result)
 | |
|         {
 | |
|             Exception error = null;
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 step.End(this.iterState, result);             
 | |
|             }
 | |
|             catch (Exception e)
 | |
|             {
 | |
|                 if (Fx.IsFatal(e))
 | |
|                 {
 | |
|                     throw;
 | |
|                 }
 | |
| 
 | |
|                 error = e;
 | |
|             }
 | |
| 
 | |
|             if (error != null)
 | |
|             {
 | |
|                 this.HandleException(error, step);
 | |
|             }
 | |
| 
 | |
|             this.OnStepCompletion();
 | |
|         }
 | |
| 
 | |
|         void HandleException(Exception e, AsyncStep step)
 | |
|         {
 | |
|             if (step.Catches != null)
 | |
|             {
 | |
|                 Exception outException;
 | |
|                 for (int i = 0; i < step.Catches.Length; i++)
 | |
|                 {
 | |
|                     if (step.Catches[i].HandleException(iterState, e, out outException))
 | |
|                     {
 | |
|                         if (outException != null)
 | |
|                         {
 | |
|                             this.CompleteOnce(outException);
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             return;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // The exception wasn't handled
 | |
|             this.CompleteOnce(e);
 | |
|         }
 | |
| 
 | |
|         public delegate IAsyncResult BeginCall(
 | |
|             TIteratorState iterState,
 | |
|             TimeSpan timeout,
 | |
|             AsyncCallback asyncCallback,
 | |
|             object state);
 | |
| 
 | |
|         public delegate void EndCall(TIteratorState iterState, IAsyncResult result);
 | |
| 
 | |
|         public delegate Exception ExceptionHandler<TException>(TIteratorState iterState, TException exception)
 | |
|             where TException : Exception;
 | |
| 
 | |
|         public class AsyncStep
 | |
|         {
 | |
|             public AsyncStep(BeginCall begin, EndCall end, bool isParallel)
 | |
|             {
 | |
|                 this.Begin = begin;
 | |
|                 this.End = end;
 | |
|                 this.IsParallel = isParallel;
 | |
|             }
 | |
| 
 | |
|             public AsyncStep(BeginCall begin, EndCall end, bool isParallel, IAsyncCatch[] catches)
 | |
|                 : this(begin, end, isParallel)
 | |
|             {
 | |
|                 this.Catches = catches;
 | |
|             }
 | |
| 
 | |
|             public IAsyncCatch[] Catches { get; private set; }
 | |
| 
 | |
|             public BeginCall Begin { get; private set; }
 | |
| 
 | |
|             public EndCall End { get; private set; }
 | |
| 
 | |
|             public bool IsParallel { get; private set; }
 | |
|         }
 | |
| 
 | |
|         public interface IAsyncCatch
 | |
|         {
 | |
|             bool HandleException(TIteratorState iterState, Exception ex, out Exception outEx);
 | |
|         }
 | |
| 
 | |
|         public class AsyncCatch<TException> : IAsyncCatch
 | |
|             where TException : Exception
 | |
|         {
 | |
|             readonly ExceptionHandler<TException> handler;            
 | |
| 
 | |
|             public AsyncCatch(ExceptionHandler<TException> handler)
 | |
|             {
 | |
|                 this.handler = handler;                
 | |
|             }
 | |
| 
 | |
|             public bool HandleException(TIteratorState state, Exception ex, out Exception outEx)
 | |
|             {
 | |
|                 outEx = null;
 | |
| 
 | |
|                 TException casted = ex as TException;
 | |
|                 if (casted != null)
 | |
|                 {
 | |
|                     outEx = this.handler(state, casted);
 | |
|                     return true;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     // The exception wasn't matched, try next handler
 | |
|                     return false;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |