Expose CreateLinkedTokenSource(CancellationToken) (#1379)
authorStephen Toub <stoub@microsoft.com>
Thu, 9 Jan 2020 13:56:42 +0000 (08:56 -0500)
committerGitHub <noreply@github.com>
Thu, 9 Jan 2020 13:56:42 +0000 (08:56 -0500)
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs
src/libraries/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBase.cs
src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs
src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs
src/libraries/System.Threading.Tasks/ref/System.Threading.Tasks.cs
src/libraries/System.Threading.Tasks/tests/CancellationTokenTests.cs
src/libraries/System.Threading.Tasks/tests/Task/TaskContinueWithTests.cs

index e4bde59..fa49bc4 100644 (file)
@@ -609,7 +609,7 @@ namespace System.Net.Http
             CancellationTokenSource cancellationWithConnectTimeout = null;
             if (Settings._connectTimeout != Timeout.InfiniteTimeSpan)
             {
-                cancellationWithConnectTimeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default);
+                cancellationWithConnectTimeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                 cancellationWithConnectTimeout.CancelAfter(Settings._connectTimeout);
                 cancellationToken = cancellationWithConnectTimeout.Token;
             }
index 1fdd601..586c0cb 100644 (file)
@@ -2294,17 +2294,7 @@ namespace System.Net.WebSockets
             // Has to be called under _ThisLock lock
             private CancellationToken CreateLinkedCancellationToken(CancellationToken cancellationToken)
             {
-                CancellationTokenSource linkedCancellationTokenSource;
-
-                if (cancellationToken == CancellationToken.None)
-                {
-                    linkedCancellationTokenSource = new CancellationTokenSource();
-                }
-                else
-                {
-                    linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken,
-                        new CancellationTokenSource().Token);
-                }
+                var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 
                 Debug.Assert(_cancellationTokenSource == null, "'_cancellationTokenSource' MUST be NULL.");
                 _cancellationTokenSource = linkedCancellationTokenSource;
index dd31213..e339f9a 100644 (file)
@@ -753,11 +753,11 @@ namespace System.Threading
 
         /// <summary>
         /// Creates a <see cref="CancellationTokenSource"/> that will be in the canceled state
-        /// when any of the source tokens are in the canceled state.
+        /// when the supplied token is in the canceled state.
         /// </summary>
-        /// <param name="token">The first <see cref="CancellationToken">CancellationToken</see> to observe.</param>
-        /// <returns>A <see cref="CancellationTokenSource"/> that is linked to the source tokens.</returns>
-        internal static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token) =>
+        /// <param name="token">The <see cref="CancellationToken">CancellationToken</see> to observe.</param>
+        /// <returns>A <see cref="CancellationTokenSource"/> that is linked to the source token.</returns>
+        public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token) =>
             token.CanBeCanceled ? new Linked1CancellationTokenSource(token) : new CancellationTokenSource();
 
         /// <summary>
index 03af031..0fd065d 100644 (file)
@@ -716,7 +716,7 @@ namespace System.Threading
                 // We need to ensure that the Task.Delay task is appropriately cleaned up if the await
                 // completes due to the asyncWaiter completing, so we use our own token that we can explicitly
                 // cancel, and we chain the caller's supplied token into it.
-                using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default))
+                using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
                 {
                     if (asyncWaiter == await TaskFactory.CommonCWAnyLogic(new Task[] { asyncWaiter, Task.Delay(millisecondsTimeout, cts.Token) }).ConfigureAwait(false))
                     {
index 4171ed4..95b2399 100644 (file)
@@ -105,6 +105,7 @@ namespace System.Threading
         public void Cancel(bool throwOnFirstException) { }
         public void CancelAfter(int millisecondsDelay) { }
         public void CancelAfter(System.TimeSpan delay) { }
+        public static System.Threading.CancellationTokenSource CreateLinkedTokenSource(System.Threading.CancellationToken token) { throw null; }
         public static System.Threading.CancellationTokenSource CreateLinkedTokenSource(System.Threading.CancellationToken token1, System.Threading.CancellationToken token2) { throw null; }
         public static System.Threading.CancellationTokenSource CreateLinkedTokenSource(params System.Threading.CancellationToken[] tokens) { throw null; }
         public void Dispose() { }
index 0f954d4..608a138 100644 (file)
@@ -380,6 +380,37 @@ namespace System.Threading.Tasks.Tests
         }
 
         [Fact]
+        public static void CreateLinkedTokenSource_OneToken()
+        {
+            CancellationTokenSource original;
+
+            original = new CancellationTokenSource();
+            using (CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(original.Token))
+            {
+                Assert.False(linked.Token.IsCancellationRequested);
+                original.Cancel();
+                Assert.True(linked.Token.IsCancellationRequested);
+            }
+
+            original = new CancellationTokenSource();
+            using (CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(original.Token))
+            {
+                Assert.False(linked.Token.IsCancellationRequested);
+                linked.Cancel();
+                Assert.True(linked.Token.IsCancellationRequested);
+                Assert.False(original.IsCancellationRequested);
+            }
+
+            original = new CancellationTokenSource();
+            using (CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(original.Token))
+            {
+                Assert.False(linked.Token.IsCancellationRequested);
+                original.Dispose();
+                Assert.False(linked.Token.IsCancellationRequested);
+            }
+        }
+
+        [Fact]
         public static void CreateLinkedTokenSource_Simple_TwoToken()
         {
             CancellationTokenSource signal1 = new CancellationTokenSource();
@@ -413,7 +444,20 @@ namespace System.Threading.Tasks.Tests
         }
 
         [Fact]
-        public static void CreateLinkedToken_SourceTokenAlreadySignalled()
+        public static void CreateLinkedToken_SourceTokenAlreadySignalled_OneToken()
+        {
+            //creating a combined token, when a source token is already signaled.
+            CancellationTokenSource signal = new CancellationTokenSource();
+
+            signal.Cancel(); //early signal.
+
+            CancellationTokenSource combined = CancellationTokenSource.CreateLinkedTokenSource(signal.Token);
+            Assert.True(combined.IsCancellationRequested,
+                "CreateLinkedToken_SourceTokenAlreadySignalled:  The combined token should immediately be in the signalled state.");
+        }
+
+        [Fact]
+        public static void CreateLinkedToken_SourceTokenAlreadySignalled_TwoTokens()
         {
             //creating a combined token, when a source token is already signalled.
             CancellationTokenSource signal1 = new CancellationTokenSource();
index 9c3f0ae..905c4fd 100644 (file)
@@ -1421,7 +1421,7 @@ namespace System.Threading.Tasks.Tests
             // Set up teardown cancellation.  We will request cancellation when a) the supplied options token
             // has cancellation requested or b) when we actually complete somewhere in order to tear down
             // the rest of our configured set up.
-            var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, CancellationToken.None);
+            var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 
             Task branch1 = CreateChooseBranch<int>(cts, result, TaskScheduler.Default);
             Task branch2 = CreateChooseBranch<int>(cts, result, TaskScheduler.Default);