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.
189 lines
4.7 KiB
189 lines
4.7 KiB
#if FAT |
|
|
|
using System; |
|
using System.Threading; |
|
using LinqInternal.Core; |
|
|
|
namespace LinqInternal.Threading.Needles |
|
{ |
|
[Serializable] |
|
[System.Diagnostics.DebuggerNonUserCode] |
|
internal class LazyAction : Promise |
|
{ |
|
[NonSerialized] |
|
private Thread _runnerThread; |
|
|
|
private Action _action; |
|
|
|
public LazyAction() |
|
: base(true) |
|
{ |
|
_action = null; |
|
} |
|
|
|
public LazyAction(Action action) |
|
: base(false) |
|
{ |
|
if (action == null) |
|
{ |
|
throw new ArgumentNullException("action"); |
|
} |
|
_action = action; |
|
} |
|
|
|
public LazyAction(Action action, bool cacheExceptions) |
|
: base(false) |
|
{ |
|
if (action == null) |
|
{ |
|
throw new ArgumentNullException("action"); |
|
} |
|
_action = action; |
|
if (cacheExceptions) |
|
{ |
|
_action = () => |
|
{ |
|
try |
|
{ |
|
action.Invoke(); |
|
} |
|
catch (Exception exc) |
|
{ |
|
_action = ActionHelper.GetThrowAction(exc); |
|
throw; |
|
} |
|
}; |
|
} |
|
} |
|
|
|
protected Thread RunnerThread |
|
{ |
|
get { return _runnerThread; } |
|
} |
|
|
|
public virtual void Execute() |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
var action = Interlocked.Exchange(ref _action, null); |
|
if (action == null) |
|
{ |
|
base.Wait(); |
|
} |
|
else |
|
{ |
|
ExecuteExtracted(action); |
|
} |
|
} |
|
|
|
public void ReleaseAction() |
|
{ |
|
Volatile.Write(ref _action, null); |
|
} |
|
|
|
public override void Wait() |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(); |
|
} |
|
|
|
public override void Wait(CancellationToken cancellationToken) |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(cancellationToken); |
|
} |
|
|
|
public override void Wait(int milliseconds) |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(milliseconds); |
|
} |
|
|
|
public override void Wait(TimeSpan timeout) |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(timeout); |
|
} |
|
|
|
public override void Wait(int milliseconds, CancellationToken cancellationToken) |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(milliseconds, cancellationToken); |
|
} |
|
|
|
public override void Wait(TimeSpan timeout, CancellationToken cancellationToken) |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(timeout, cancellationToken); |
|
} |
|
|
|
protected virtual void Execute(Action beforeInitialize) |
|
{ |
|
if (beforeInitialize == null) |
|
{ |
|
throw new ArgumentNullException("beforeInitialize"); |
|
} |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
var valueFactory = Interlocked.Exchange(ref _action, null); |
|
if (valueFactory == null) |
|
{ |
|
base.Wait(); |
|
} |
|
else |
|
{ |
|
try |
|
{ |
|
beforeInitialize.Invoke(); |
|
} |
|
finally |
|
{ |
|
ExecuteExtracted(valueFactory); |
|
} |
|
} |
|
} |
|
|
|
private void ExecuteExtracted(Action action) |
|
{ |
|
_runnerThread = Thread.CurrentThread; |
|
try |
|
{ |
|
action.Invoke(); |
|
} |
|
catch (Exception exception) |
|
{ |
|
Interlocked.CompareExchange(ref _action, action, null); |
|
SetError(exception); |
|
throw; |
|
} |
|
finally |
|
{ |
|
_runnerThread = null; |
|
} |
|
} |
|
} |
|
} |
|
|
|
#endif |