if (IsContinuation)
throw new InvalidOperationException ("Start may not be called on a continuation task");
+ if (IsPromise)
+ throw new InvalidOperationException ("Start may not be called on a promise-style task");
+
SetupScheduler (scheduler);
- Schedule ();
+ Schedule (true);
}
internal void SetupScheduler (TaskScheduler scheduler)
if (IsContinuation)
throw new InvalidOperationException ("RunSynchronously may not be called on a continuation task");
- RunSynchronouslyCore (scheduler);
+ if (IsPromise)
+ throw new InvalidOperationException ("RunSynchronously may not be called on a promise-style task");
+
+ RunSynchronouslyCore (scheduler, true);
}
- internal void RunSynchronouslyCore (TaskScheduler scheduler)
+ internal void RunSynchronouslyCore (TaskScheduler scheduler, bool throwException)
{
SetupScheduler (scheduler);
Status = TaskStatus.WaitingToRun;
if (scheduler.RunInline (this, false))
return;
} catch (Exception inner) {
- throw new TaskSchedulerException (inner);
+ var ex = new TaskSchedulerException (inner);
+ TrySetException (new AggregateException (ex), false, true);
+ if (throwException)
+ throw ex;
+
+ return;
}
- Schedule ();
- Wait ();
+ Schedule (throwException);
+ WaitCore (Timeout.Infinite, CancellationToken.None, false);
}
#endregion
ContinueWith (new TaskContinuation (continuation, options));
}
- internal void ContinueWith (IContinuation continuation)
+ internal bool ContinueWith (IContinuation continuation, bool canExecuteInline = true)
{
if (IsCompleted) {
+ if (!canExecuteInline)
+ return false;
+
continuation.Execute ();
- return;
+ return true;
}
continuations.Add (continuation);
// Retry in case completion was achieved but event adding was too late
- if (IsCompleted && continuations.Remove (continuation))
+ if (IsCompleted && continuations.Remove (continuation)) {
+ if (!canExecuteInline)
+ return false;
+
continuation.Execute ();
+ }
+
+ return true;
}
internal void RemoveContinuation (IContinuation continuation)
#endregion
#region Internal and protected thingies
- internal void Schedule ()
+ internal void Schedule (bool throwException)
{
Status = TaskStatus.WaitingToRun;
- scheduler.QueueTask (this);
+ try {
+ scheduler.QueueTask (this);
+ } catch (Exception inner) {
+ var ex = new TaskSchedulerException (inner);
+ TrySetException (new AggregateException (ex), false, true);
+ if (throwException)
+ throw ex;
+ }
}
void ThreadStart ()
return true;
}
- internal bool TrySetException (AggregateException aggregate)
+ internal bool TrySetException (AggregateException aggregate, bool cancellation, bool observed)
{
if (IsCompleted)
return false;
return false;
}
-
- HandleGenericException (aggregate);
+
+ if (cancellation) {
+ ExceptionSlot.Exception = aggregate;
+ Thread.MemoryBarrier ();
+
+ CancelReal ();
+ } else {
+ HandleGenericException (aggregate);
+ }
+
+ if (observed)
+ exSlot.Observed = true;
+
return true;
}
if (millisecondsTimeout < -1)
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
- bool result = WaitCore (millisecondsTimeout, cancellationToken);
+ bool result = WaitCore (millisecondsTimeout, cancellationToken, true);
if (IsCanceled)
throw new AggregateException (new TaskCanceledException (this));
return result;
}
- internal bool WaitCore (int millisecondsTimeout, CancellationToken cancellationToken)
+ internal bool WaitCore (int millisecondsTimeout, CancellationToken cancellationToken, bool runInline)
{
if (IsCompleted)
return true;
// If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
- if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
- scheduler.RunInline (this, true);
+ if (runInline && Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled) {
+ try {
+ scheduler.RunInline (this, true);
+ } catch (Exception e) {
+ throw new TaskSchedulerException (e);
+ }
+ }
bool result = true;
internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
{
+ if (tasks.Count == 0)
+ return FromResult(new TResult[0]);
+
foreach (var t in tasks) {
if (t == null)
throw new ArgumentException ("tasks", "the tasks argument contains a null element");
public AggregateException Exception {
get {
- if (exSlot == null)
+ if (exSlot == null || !IsFaulted)
return null;
exSlot.Observed = true;
return exSlot.Exception;
}
}
- TaskExceptionSlot ExceptionSlot {
+ internal TaskExceptionSlot ExceptionSlot {
get {
if (exSlot != null)
return exSlot;
}
}
+ bool IsPromise {
+ get {
+ return invoker == TaskActionInvoker.Promise;
+ }
+ }
+
internal Task ContinuationAncestor {
get {
return contAncestor;