{
internal SetOnInvokeMres() : base(false, 0) { }
public void Invoke(Task completingTask) { Set(); }
+ public bool InvokeMayRunArbitraryCode { get { return false; } }
}
/// <summary>
ITaskCompletionAction singleTaskCompletionAction = continuationObject as ITaskCompletionAction;
if (singleTaskCompletionAction != null)
{
- if (bCanInlineContinuations)
+ if (bCanInlineContinuations || !singleTaskCompletionAction.InvokeMayRunArbitraryCode)
{
singleTaskCompletionAction.Invoke(this);
}
Contract.Assert(currentContinuation is ITaskCompletionAction, "Expected continuation element to be Action, TaskContinuation, or ITaskContinuationAction");
var action = (ITaskCompletionAction)currentContinuation;
- if (bCanInlineContinuations)
+ if (bCanInlineContinuations || !action.InvokeMayRunArbitraryCode)
{
action.Invoke(this);
}
if (Interlocked.Decrement(ref _count) == 0) Set();
Contract.Assert(_count >= 0, "Count should never go below 0");
}
+
+ public bool InvokeMayRunArbitraryCode { get { return false; } }
}
/// <summary>
Contract.Assert(m_count >= 0, "Count should never go below 0");
}
+ public bool InvokeMayRunArbitraryCode { get { return true; } }
+
/// <summary>
/// Returns whether we should notify the debugger of a wait completion. This returns
/// true iff at least one constituent task has its bit set.
Contract.Assert(m_count >= 0, "Count should never go below 0");
}
+ public bool InvokeMayRunArbitraryCode { get { return true; } }
+
/// <summary>
/// Returns whether we should notify the debugger of a wait completion. This returns true
/// iff at least one constituent task has its bit set.
// TaskFactory.CompleteOnCountdownPromise<T>, and TaskFactory.CompleteOnInvokePromise.
internal interface ITaskCompletionAction
{
+ /// <summary>Invoked to run the completion action.</summary>
void Invoke(Task completingTask);
+
+ /// <summary>
+ /// Some completion actions are considered internal implementation details of tasks,
+ /// using the continuation mechanism only for performance reasons. Such actions perform
+ /// known quantities and types of work, and can be invoked safely as a continuation even
+ /// if the system wants to prevent arbitrary continuations from running synchronously.
+ /// This should only return false for a limited set of implementations where a small amount
+ /// of work is guaranteed to be performed, e.g. setting a ManualResetEventSlim.
+ /// </summary>
+ bool InvokeMayRunArbitraryCode { get; }
}
// This class encapsulates all "unwrap" logic, and also implements ITaskCompletionAction,
}
}
+ public bool InvokeMayRunArbitraryCode { get { return true; } }
}
-
}
Contract.Assert(_count >= 0, "Count should never go below 0");
}
+ public bool InvokeMayRunArbitraryCode { get { return true; } }
+
/// <summary>
/// Returns whether we should notify the debugger of a wait completion. This returns
/// true iff at least one constituent task has its bit set.
Contract.Assert(_count >= 0, "Count should never go below 0");
}
+ public bool InvokeMayRunArbitraryCode { get { return true; } }
+
/// <summary>
/// Returns whether we should notify the debugger of a wait completion. This returns
/// true iff at least one constituent task has its bit set.
}
}
+
+ public bool InvokeMayRunArbitraryCode { get { return true; } }
}
// Common ContinueWhenAny logic
// If the tasks list is not an array, it must be an internal defensive copy so that