From 75222a62c5924e0953a8f966b07a44a463af4718 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Laval?= Date: Mon, 23 Jul 2012 12:48:40 +0100 Subject: [PATCH] [corlib] Linked token callback to the proxy CancellationTokenSource shouldn't throw ODE in concurrent situations. --- .../CancellationTokenSource.cs | 13 ++++++++- .../CancellationTokenSourceTest.cs | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/mcs/class/corlib/System.Threading/CancellationTokenSource.cs b/mcs/class/corlib/System.Threading/CancellationTokenSource.cs index b6668313257..ac1461110ea 100644 --- a/mcs/class/corlib/System.Threading/CancellationTokenSource.cs +++ b/mcs/class/corlib/System.Threading/CancellationTokenSource.cs @@ -158,6 +158,17 @@ namespace System.Threading throw new AggregateException (exceptions); } + /* This is the callback registered on linked tokens + * so that they don't throw an ODE if the callback + * is called concurrently with a Dispose + */ + void SafeLinkedCancel () + { + try { + Cancel (); + } catch (ObjectDisposedException) {} + } + #if NET_4_5 public void CancelAfter (TimeSpan delay) { @@ -199,7 +210,7 @@ namespace System.Threading throw new ArgumentException ("Empty tokens array"); CancellationTokenSource src = new CancellationTokenSource (); - Action action = src.Cancel; + Action action = src.SafeLinkedCancel; var registrations = new List (tokens.Length); foreach (CancellationToken token in tokens) { diff --git a/mcs/class/corlib/Test/System.Threading/CancellationTokenSourceTest.cs b/mcs/class/corlib/Test/System.Threading/CancellationTokenSourceTest.cs index e8a6e3a15d5..e33802c431a 100644 --- a/mcs/class/corlib/Test/System.Threading/CancellationTokenSourceTest.cs +++ b/mcs/class/corlib/Test/System.Threading/CancellationTokenSourceTest.cs @@ -33,6 +33,7 @@ using System; using System.Threading; using NUnit.Framework; using System.Threading.Tasks; +using MonoTests.System.Threading.Tasks; namespace MonoTests.System.Threading { @@ -413,6 +414,32 @@ namespace MonoTests.System.Threading Assert.IsTrue (canceled, "#3"); } + + [Test] + public void ConcurrentCancelLinkedTokenSourceWhileDisposing () + { + ParallelTestHelper.Repeat (delegate { + var src = new CancellationTokenSource (); + var linked = CancellationTokenSource.CreateLinkedTokenSource (src.Token); + var cntd = new CountdownEvent (2); + + var t1 = new Thread (() => { + if (!cntd.Signal ()) + cntd.Wait (); + src.Cancel (); + }); + var t2 = new Thread (() => { + if (!cntd.Signal ()) + cntd.Wait (); + linked.Dispose (); + }); + + t1.Start (); + t2.Start (); + t1.Join (500); + t2.Join (500); + }, 500); + } } } -- 2.25.1