Permalink
Browse files

Partially fixes broken Task.Wait

  • Loading branch information...
1 parent 99aa277 commit 8c3fd6835c1e2921061e5d3ffda21696ab31304a @marek-safar marek-safar committed Oct 11, 2011
View
65 mcs/class/corlib/System.Threading.Tasks/Task.cs
@@ -77,6 +77,7 @@ public class Task : IDisposable, IAsyncResult
CompletionSlot Slot;
CancellationToken token;
+ CancellationTokenRegistration? cancelation_registration;
const TaskCreationOptions MaxTaskCreationOptions =
#if NET_4_5
@@ -151,7 +152,7 @@ public Task (Action<object> action, object state, CancellationToken cancellation
parent.AddChild ();
if (token.CanBeCanceled) {
- token.Register (l => ((Task) l).CancelReal (), this);
+ cancelation_registration = token.Register (l => ((Task) l).CancelReal (), this);
}
}
@@ -491,10 +492,13 @@ internal void Finish ()
if (status != TaskStatus.WaitingForChildrenToComplete)
ProcessCompleteDelegates ();
-
+
// Reset the current thingies
current = null;
TaskScheduler.Current = null;
+
+ if (cancelation_registration.HasValue)
+ cancelation_registration.Value.Dispose ();
// Tell parent that we are finished
if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null) {
@@ -571,20 +575,12 @@ internal void HandleGenericException (AggregateException e)
public void Wait ()
{
- if (scheduler == null)
- schedWait.Wait ();
-
- if (!IsCompleted)
- scheduler.ParticipateUntil (this);
- if (exception != null)
- throw exception;
- if (IsCanceled)
- throw new AggregateException (new TaskCanceledException (this));
+ Wait (Timeout.Infinite, CancellationToken.None);
}
public void Wait (CancellationToken cancellationToken)
{
- Wait (-1, cancellationToken);
+ Wait (Timeout.Infinite, cancellationToken);
}
public bool Wait (TimeSpan timeout)
@@ -602,32 +598,41 @@ public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
if (millisecondsTimeout < -1)
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
- if (millisecondsTimeout == -1 && token == CancellationToken.None) {
- Wait ();
- return true;
- }
+ bool result = IsCompleted;
+ if (!result) {
+ if (scheduler == null) {
+ Watch watch = Watch.StartNew ();
- Watch watch = Watch.StartNew ();
+ schedWait.Wait (millisecondsTimeout, cancellationToken);
+ millisecondsTimeout = ComputeTimeout (millisecondsTimeout, watch);
+ }
- if (scheduler == null) {
- schedWait.Wait (millisecondsTimeout, cancellationToken);
- millisecondsTimeout = ComputeTimeout (millisecondsTimeout, watch);
- }
+ var wait_event = new ManualResetEventSlim (false);
+ CancellationTokenRegistration? registration = null;
- ManualResetEventSlim predicateEvt = new ManualResetEventSlim (false);
- if (cancellationToken != CancellationToken.None) {
- cancellationToken.Register (predicateEvt.Set);
- cancellationToken.ThrowIfCancellationRequested ();
+ try {
+ if (cancellationToken.CanBeCanceled) {
+ registration = cancellationToken.Register (wait_event.Set);
+ }
+
+ // FIXME: The implementation is wrong and slow
+ // It adds a continuation to the task which is then
+ // returned to parent causing all sort of problems when
+ // timeout is reached before task is finished
+ result = !scheduler.ParticipateUntil (this, wait_event, millisecondsTimeout);
+ } finally {
+ if (registration.HasValue)
+ registration.Value.Dispose ();
+ }
}
- bool result = scheduler.ParticipateUntil (this, predicateEvt, millisecondsTimeout);
+ if (IsCanceled)
+ exception = new AggregateException (new TaskCanceledException (this));
if (exception != null)
throw exception;
- if (IsCanceled)
- throw new AggregateException (new TaskCanceledException (this));
-
- return !result;
+
+ return result;
}
public static void WaitAll (params Task[] tasks)
View
27 mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs
@@ -115,10 +115,19 @@ public void CancelBeforeWait ()
src.Cancel ();
try {
- Assert.IsTrue (t.Wait (1000));
- Assert.Fail ();
+ t.Wait (1000);
+ Assert.Fail ("#1");
} catch (AggregateException e) {
- Assert.IsInstanceOfType (typeof (TaskCanceledException), e.InnerException);
+ var details = (TaskCanceledException) e.InnerException;
+ Assert.AreEqual (t, details.Task, "#1e");
+ }
+
+ try {
+ t.Wait ();
+ Assert.Fail ("#2");
+ } catch (AggregateException e) {
+ var details = (TaskCanceledException) e.InnerException;
+ Assert.AreEqual (t, details.Task, "#2e");
}
}
@@ -243,8 +252,8 @@ public void ContinueWithChildren ()
}, 2);
}
- [TestAttribute]
- public void MultipleTaskTestCase()
+ [Test]
+ public void MultipleTasks()
{
ParallelTestHelper.Repeat (delegate {
bool r1 = false, r2 = false, r3 = false;
@@ -259,9 +268,9 @@ public void MultipleTaskTestCase()
r3 = true;
});
- t1.Wait();
- t2.Wait();
- t3.Wait();
+ t1.Wait(2000);
+ t2.Wait(2000);
+ t3.Wait(2000);
Assert.IsTrue(r1, "#1");
Assert.IsTrue(r2, "#2");
@@ -292,7 +301,7 @@ public void WaitChildTestCase()
}, TaskCreationOptions.AttachedToParent);
});
- t.Wait();
+ Assert.IsTrue (t.Wait(2000), "#0");
Assert.IsTrue(r2, "#1");
Assert.IsTrue(r3, "#2");
Assert.IsTrue(r1, "#3");

0 comments on commit 8c3fd68

Please sign in to comment.