You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
6.7 KiB
257 lines
6.7 KiB
// Needed for Workaround |
|
#if !NET_4_6 |
|
using System; |
|
using System.Threading; |
|
|
|
namespace LinqInternal.Threading.Needles |
|
{ |
|
[Serializable] |
|
[System.Diagnostics.DebuggerNonUserCode] |
|
internal class Promise : IWaitablePromise |
|
{ |
|
private readonly int _hashCode; |
|
private Exception _exception; |
|
private StructNeedle<ManualResetEventSlim> _waitHandle; |
|
|
|
public Promise(bool done) |
|
{ |
|
_exception = null; |
|
_hashCode = base.GetHashCode(); |
|
if (!done) |
|
{ |
|
_waitHandle = new ManualResetEventSlim(false); |
|
} |
|
} |
|
|
|
public Promise(Exception exception) |
|
{ |
|
_exception = exception; |
|
_hashCode = exception.GetHashCode(); |
|
_waitHandle = new ManualResetEventSlim(true); |
|
} |
|
|
|
~Promise() |
|
{ |
|
ReleaseWaitHandle(false); |
|
} |
|
|
|
public Exception Exception |
|
{ |
|
get { return _exception; } |
|
} |
|
|
|
bool IPromise.IsCanceled |
|
{ |
|
get { return false; } |
|
} |
|
|
|
public bool IsCompleted |
|
{ |
|
get |
|
{ |
|
var waitHandle = _waitHandle.Value; |
|
return waitHandle == null || waitHandle.IsSet; |
|
} |
|
} |
|
|
|
public bool IsFaulted |
|
{ |
|
get { return _exception != null; } |
|
} |
|
|
|
protected IRecyclableNeedle<ManualResetEventSlim> WaitHandle |
|
{ |
|
get { return _waitHandle; } |
|
} |
|
|
|
public virtual void Free() |
|
{ |
|
var waitHandle = _waitHandle.Value; |
|
if (waitHandle == null) |
|
{ |
|
_waitHandle.Value = new ManualResetEventSlim(false); |
|
} |
|
else |
|
{ |
|
waitHandle.Reset(); |
|
} |
|
_exception = null; |
|
} |
|
|
|
public virtual void Free(Action beforeFree) |
|
{ |
|
if (beforeFree == null) |
|
{ |
|
throw new ArgumentNullException("beforeFree"); |
|
} |
|
var waitHandle = _waitHandle.Value; |
|
if (waitHandle == null || waitHandle.IsSet) |
|
{ |
|
try |
|
{ |
|
beforeFree(); |
|
} |
|
finally |
|
{ |
|
if (waitHandle == null) |
|
{ |
|
_waitHandle.Value = new ManualResetEventSlim(false); |
|
} |
|
else |
|
{ |
|
waitHandle.Reset(); |
|
} |
|
_exception = null; |
|
} |
|
} |
|
else |
|
{ |
|
waitHandle.Reset(); |
|
_exception = null; |
|
} |
|
} |
|
|
|
public override int GetHashCode() |
|
{ |
|
return _hashCode; |
|
} |
|
|
|
public void SetCompleted() |
|
{ |
|
_exception = null; |
|
ReleaseWaitHandle(true); |
|
} |
|
|
|
public void SetError(Exception error) |
|
{ |
|
_exception = error; |
|
ReleaseWaitHandle(true); |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
return IsCompleted |
|
? (_exception == null |
|
? "[Done]" |
|
: _exception.ToString()) |
|
: "[Not Created]"; |
|
} |
|
|
|
public virtual void Wait() |
|
{ |
|
var waitHandle = _waitHandle.Value; |
|
if (waitHandle != null) |
|
{ |
|
try |
|
{ |
|
waitHandle.Wait(); |
|
} |
|
catch (ObjectDisposedException exception) |
|
{ |
|
// Came late to the party, initialization was done |
|
GC.KeepAlive(exception); |
|
} |
|
} |
|
} |
|
|
|
public virtual void Wait(CancellationToken cancellationToken) |
|
{ |
|
var waitHandle = _waitHandle.Value; |
|
if (waitHandle != null) |
|
{ |
|
try |
|
{ |
|
waitHandle.Wait(cancellationToken); |
|
} |
|
catch (ObjectDisposedException exception) |
|
{ |
|
// Came late to the party, initialization was done |
|
GC.KeepAlive(exception); |
|
} |
|
} |
|
} |
|
|
|
public virtual void Wait(int milliseconds) |
|
{ |
|
var waitHandle = _waitHandle.Value; |
|
if (waitHandle != null) |
|
{ |
|
try |
|
{ |
|
waitHandle.Wait(milliseconds); |
|
} |
|
catch (ObjectDisposedException exception) |
|
{ |
|
// Came late to the party, initialization was done |
|
GC.KeepAlive(exception); |
|
} |
|
} |
|
} |
|
|
|
public virtual void Wait(TimeSpan timeout) |
|
{ |
|
var waitHandle = _waitHandle.Value; |
|
if (waitHandle != null) |
|
{ |
|
try |
|
{ |
|
waitHandle.Wait(timeout); |
|
} |
|
catch (ObjectDisposedException exception) |
|
{ |
|
// Came late to the party, initialization was done |
|
GC.KeepAlive(exception); |
|
} |
|
} |
|
} |
|
|
|
public virtual void Wait(int milliseconds, CancellationToken cancellationToken) |
|
{ |
|
var waitHandle = _waitHandle.Value; |
|
if (waitHandle != null) |
|
{ |
|
try |
|
{ |
|
waitHandle.Wait(milliseconds, cancellationToken); |
|
} |
|
catch (ObjectDisposedException exception) |
|
{ |
|
// Came late to the party, initialization was done |
|
GC.KeepAlive(exception); |
|
} |
|
} |
|
} |
|
|
|
public virtual void Wait(TimeSpan timeout, CancellationToken cancellationToken) |
|
{ |
|
var waitHandle = _waitHandle.Value; |
|
if (waitHandle != null) |
|
{ |
|
try |
|
{ |
|
waitHandle.Wait(timeout, cancellationToken); |
|
} |
|
catch (ObjectDisposedException exception) |
|
{ |
|
// Came late to the party, initialization was done |
|
GC.KeepAlive(exception); |
|
} |
|
} |
|
} |
|
|
|
protected void ReleaseWaitHandle(bool done) |
|
{ |
|
var waitHandle = _waitHandle.Value; |
|
if (waitHandle != null) |
|
{ |
|
if (done) |
|
{ |
|
waitHandle.Set(); |
|
} |
|
waitHandle.Dispose(); |
|
} |
|
_waitHandle.Value = null; |
|
} |
|
} |
|
} |
|
#endif |