ExceptionHelper
Utility methods to handle lock-free combining of Exceptions
as well as hosting a terminal-exception indicator for
lock-free termination support.
using System.Collections.Generic;
using System.Threading;
namespace System.Reactive
{
internal static class ExceptionHelper
{
private sealed class TerminatedException : Exception
{
internal TerminatedException()
: base("No further exceptions")
{
}
}
public static Exception Terminated { get; } = new TerminatedException();
public static bool TrySetException(ref Exception field, Exception ex)
{
return Interlocked.CompareExchange(ref field, ex, null) == null;
}
public static Exception Terminate(ref Exception field)
{
Exception ex = Volatile.Read(ref field);
if (ex != Terminated)
ex = Interlocked.Exchange(ref field, Terminated);
return ex;
}
public static bool TryAddException(ref Exception field, Exception ex)
{
Exception ex2;
Exception value;
do {
ex2 = Volatile.Read(ref field);
if (ex2 == Terminated)
return false;
if (ex2 == null)
value = ex;
else {
AggregateException ex3 = ex2 as AggregateException;
value = ((ex3 == null) ? new AggregateException(ex2, ex) : new AggregateException(new List<Exception>(ex3.InnerExceptions) {
ex
}));
}
} while (Interlocked.CompareExchange(ref field, value, ex2) != ex2);
return true;
}
}
}