// Jérémie Laval <jeremie dot laval at xamarin dot com>
//
// Copyright (c) 2008 Jérémie "Garuma" Laval
-// Copyright 2011 Xamarin Inc (http://www.xamarin.com).
+// Copyright 2011-2013 Xamarin Inc (http://www.xamarin.com).
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// and for Parent property.
[System.ThreadStatic]
static Task current;
- [System.ThreadStatic]
- static Action<Task> childWorkAdder;
// parent is the outer task in which this task is created
readonly Task parent;
- // contAncestor is the Task on which this continuation was setup
- readonly Task contAncestor;
+ // A reference to a Task on which this continuation is attached to
+ Task contAncestor;
static int id = -1;
static readonly TaskFactory defaultFactory = new TaskFactory ();
internal TaskScheduler scheduler;
TaskExceptionSlot exSlot;
+ ManualResetEvent wait_handle;
TaskStatus status;
internal void RunSynchronouslyCore (TaskScheduler scheduler)
{
SetupScheduler (scheduler);
- var saveStatus = status;
Status = TaskStatus.WaitingToRun;
try {
throw new TaskSchedulerException (inner);
}
- Status = saveStatus;
- Start (scheduler);
+ Schedule ();
Wait ();
}
#endregion
internal void Schedule ()
{
Status = TaskStatus.WaitingToRun;
-
- // If worker is null it means it is a local one, revert to the old behavior
- // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
- if (scheduler != TaskScheduler.Current || childWorkAdder == null || HasFlag (creationOptions, TaskCreationOptions.PreferFairness)) {
- scheduler.QueueTask (this);
- } else {
- /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom
- * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
- * the correct Thread during the creation
- */
- childWorkAdder (this);
- }
+ scheduler.QueueTask (this);
}
void ThreadStart ()
void InnerInvoke ()
{
if (IsContinuation) {
- invoker.Invoke (contAncestor, state, this);
+ var ancestor = contAncestor;
+ contAncestor = null;
+ invoker.Invoke (ancestor, state, this);
} else {
invoker.Invoke (this, state, this);
}
Status = TaskStatus.WaitingForChildrenToComplete;
}
+ if (wait_handle != null)
+ wait_handle.Set ();
+
// Tell parent that we are finished
if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) &&
#if NET_4_5
internal void CancelReal ()
{
Status = TaskStatus.Canceled;
+
+ if (wait_handle != null)
+ wait_handle.Set ();
+
ProcessCompleteDelegates ();
}
ExceptionSlot.Exception = e;
Thread.MemoryBarrier ();
Status = TaskStatus.Faulted;
+
+ if (wait_handle != null)
+ wait_handle.Set ();
+
ProcessCompleteDelegates ();
}
if (millisecondsTimeout < -1)
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
- bool result = true;
-
- if (!IsCompleted) {
- // 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 (!IsCompleted) {
- var continuation = new ManualResetContinuation ();
- try {
- ContinueWith (continuation);
- result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
- } finally {
- if (!result)
- RemoveContinuation (continuation);
- continuation.Dispose ();
- }
- }
- }
+ bool result = WaitCore (millisecondsTimeout, cancellationToken);
if (IsCanceled)
throw new AggregateException (new TaskCanceledException (this));
return result;
}
+
+ internal bool WaitCore (int millisecondsTimeout, CancellationToken cancellationToken)
+ {
+ 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);
+
+ bool result = true;
+
+ if (!IsCompleted) {
+ var continuation = new ManualResetContinuation ();
+ try {
+ ContinueWith (continuation);
+ result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
+ } finally {
+ if (!result)
+ RemoveContinuation (continuation);
+ continuation.Dispose ();
+ }
+ }
+
+ return result;
+ }
public static void WaitAll (params Task[] tasks)
{
#region Dispose
public void Dispose ()
{
- Dispose (true);
+ Dispose (true);
}
protected virtual void Dispose (bool disposing)
state = null;
if (cancellationRegistration != null)
cancellationRegistration.Value.Dispose ();
+ if (wait_handle != null)
+ wait_handle.Dispose ();
}
}
#endregion
if (millisecondsDelay < -1)
throw new ArgumentOutOfRangeException ("millisecondsDelay");
- var task = new Task (TaskActionInvoker.Delay, millisecondsDelay, cancellationToken, TaskCreationOptions.None, null, TaskConstants.Finished);
- task.SetupScheduler (TaskScheduler.Current);
-
- if (millisecondsDelay != Timeout.Infinite)
- task.scheduler.QueueTask (task);
+ if (cancellationToken.IsCancellationRequested)
+ return TaskConstants.Canceled;
+
+ var task = new Task (TaskActionInvoker.Empty, null, cancellationToken, TaskCreationOptions.None, null, null);
+ task.SetupScheduler (TaskScheduler.Default);
+
+ if (millisecondsDelay != Timeout.Infinite) {
+ var timer = new Timer (delegate (object state) {
+ var t = (Task) state;
+ if (t.Status == TaskStatus.WaitingForActivation) {
+ t.Status = TaskStatus.Running;
+ t.Finish ();
+ }
+ }, task, millisecondsDelay, -1);
+
+ task.ContinueWith (new DisposeContinuation (timer));
+ }
return task;
}
WaitHandle IAsyncResult.AsyncWaitHandle {
get {
- return null;
+ if (invoker == null)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (wait_handle == null)
+ Interlocked.CompareExchange (ref wait_handle, new ManualResetEvent (IsCompleted), null);
+
+ return wait_handle;
}
}