// Needed for Workaround
#if !NET_4_6
using System;
using LinqInternal.Collections.ThreadSafe;
using LinqInternal.Threading.Needles;
namespace LinqInternal.Threading
{
///
/// Represents a context to execute operation without reentry.
///
[System.Diagnostics.DebuggerNonUserCode]
internal sealed class ReentryGuard
{
private readonly RuntimeUniqueIdProdiver.UniqueId _id;
private readonly SafeQueue _workQueue;
///
/// Initializes a new instance of the class.
///
public ReentryGuard()
{
_workQueue = new SafeQueue();
_id = RuntimeUniqueIdProdiver.GetNextId();
}
///
/// Gets a value indicating whether or not the current thread did enter.
///
public bool IsTaken
{
get { return ReentryGuardHelper.IsTaken(_id); }
}
///
/// Executes an operation-
///
/// The operation to execute.
/// Returns a promise to finish the execution.
public IPromise Execute(Action operation)
{
var result = AddExecution(operation, _workQueue);
ExecutePending(_workQueue, _id);
return result;
}
///
/// Executes an operation-
///
/// The return value of the operation.
/// The operation to execute.
/// Returns a promise to finish the execution.
public IPromise Execute(Func operation)
{
var result = AddExecution(operation, _workQueue);
ExecutePending(_workQueue, _id);
return result;
}
private static IPromise AddExecution(Action action, SafeQueue queue)
{
var promised = new Promise(false);
var result = new ReadOnlyPromise(promised, false);
queue.Add
(
() =>
{
try
{
action.Invoke();
promised.SetCompleted();
}
catch (Exception exception)
{
promised.SetError(exception);
}
}
);
return result;
}
private static IPromise AddExecution(Func action, SafeQueue queue)
{
var promised = new PromiseNeedle(false);
var result = new ReadOnlyPromiseNeedle(promised, false);
queue.Add
(
() =>
{
try
{
promised.Value = action.Invoke();
}
catch (Exception exception)
{
promised.SetError(exception);
}
}
);
return result;
}
private static void ExecutePending(SafeQueue queue, RuntimeUniqueIdProdiver.UniqueId id)
{
var didEnter = false;
try
{
didEnter = ReentryGuardHelper.Enter(id);
if (!didEnter)
{
// called from inside this method - skip
return;
}
Action action;
while (queue.TryTake(out action))
{
action.Invoke();
}
}
finally
{
if (didEnter)
{
ReentryGuardHelper.Leave(id);
}
}
}
}
}
#endif