// 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