diff options
Diffstat (limited to 'src/mscorlib/src/System/Threading/CancellationTokenSource.cs')
-rw-r--r-- | src/mscorlib/src/System/Threading/CancellationTokenSource.cs | 102 |
1 files changed, 63 insertions, 39 deletions
diff --git a/src/mscorlib/src/System/Threading/CancellationTokenSource.cs b/src/mscorlib/src/System/Threading/CancellationTokenSource.cs index fe9e0dec76..1e70d6f30f 100644 --- a/src/mscorlib/src/System/Threading/CancellationTokenSource.cs +++ b/src/mscorlib/src/System/Threading/CancellationTokenSource.cs @@ -10,7 +10,6 @@ using System; using System.Security; using System.Collections.Generic; using System.Runtime.InteropServices; -using System.Security.Permissions; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Runtime; @@ -35,7 +34,6 @@ namespace System.Threading /// concurrently from multiple threads. /// </para> /// </remarks> - [ComVisible(false)] public class CancellationTokenSource : IDisposable { @@ -864,12 +862,19 @@ namespace System.Threading /// <param name="token2">The second <see cref="T:System.Threading.CancellationToken">CancellationToken</see> to observe.</param> /// <returns>A <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> that is linked /// to the source tokens.</returns> - public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2) - { - return token1.CanBeCanceled || token2.CanBeCanceled ? - new LinkedCancellationTokenSource(token1, token2) : - new CancellationTokenSource(); - } + public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2) => + !token1.CanBeCanceled ? CreateLinkedTokenSource(token2) : + token2.CanBeCanceled ? new Linked2CancellationTokenSource(token1, token2) : + (CancellationTokenSource)new Linked1CancellationTokenSource(token1); + + /// <summary> + /// Creates a <see cref="CancellationTokenSource"/> that will be in the canceled state + /// when any of the source tokens are in the canceled state. + /// </summary> + /// <param name="token">The first <see cref="T:System.Threading.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) => + token.CanBeCanceled ? new Linked1CancellationTokenSource(token) : new CancellationTokenSource(); /// <summary> /// Creates a <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> that will be in the canceled state @@ -884,14 +889,19 @@ namespace System.Threading if (tokens == null) throw new ArgumentNullException(nameof(tokens)); - if (tokens.Length == 0) - throw new ArgumentException(Environment.GetResourceString("CancellationToken_CreateLinkedToken_TokensIsEmpty")); - - // a defensive copy is not required as the array has value-items that have only a single IntPtr field, - // hence each item cannot be null itself, and reads of the payloads cannot be torn. - Contract.EndContractBlock(); - - return new LinkedCancellationTokenSource(tokens); + switch (tokens.Length) + { + case 0: + throw new ArgumentException(Environment.GetResourceString("CancellationToken_CreateLinkedToken_TokensIsEmpty")); + case 1: + return CreateLinkedTokenSource(tokens[0]); + case 2: + return CreateLinkedTokenSource(tokens[0], tokens[1]); + default: + // a defensive copy is not required as the array has value-items that have only a single reference field, + // hence each item cannot be null itself, and reads of the payloads cannot be torn. + return new LinkedNCancellationTokenSource(tokens); + } } @@ -907,35 +917,50 @@ namespace System.Threading } } - private sealed class LinkedCancellationTokenSource : CancellationTokenSource + private sealed class Linked1CancellationTokenSource : CancellationTokenSource { - private static readonly Action<object> s_linkedTokenCancelDelegate = - s => ((CancellationTokenSource)s).NotifyCancellation(throwOnFirstException: false); // skip ThrowIfDisposed() check in Cancel() - private CancellationTokenRegistration[] m_linkingRegistrations; + private readonly CancellationTokenRegistration _reg1; - internal LinkedCancellationTokenSource(CancellationToken token1, CancellationToken token2) + internal Linked1CancellationTokenSource(CancellationToken token1) { - bool token2CanBeCanceled = token2.CanBeCanceled; + _reg1 = token1.InternalRegisterWithoutEC(LinkedNCancellationTokenSource.s_linkedTokenCancelDelegate, this); + } - if (token1.CanBeCanceled) - { - m_linkingRegistrations = new CancellationTokenRegistration[token2CanBeCanceled ? 2 : 1]; // there will be at least 1 and at most 2 linkings - m_linkingRegistrations[0] = token1.InternalRegisterWithoutEC(s_linkedTokenCancelDelegate, this); - } + protected override void Dispose(bool disposing) + { + if (!disposing || m_disposed) return; + _reg1.Dispose(); + base.Dispose(disposing); + } + } - if (token2CanBeCanceled) - { - int index = 1; - if (m_linkingRegistrations == null) - { - m_linkingRegistrations = new CancellationTokenRegistration[1]; // this will be the only linking - index = 0; - } - m_linkingRegistrations[index] = token2.InternalRegisterWithoutEC(s_linkedTokenCancelDelegate, this); - } + private sealed class Linked2CancellationTokenSource : CancellationTokenSource + { + private readonly CancellationTokenRegistration _reg1; + private readonly CancellationTokenRegistration _reg2; + + internal Linked2CancellationTokenSource(CancellationToken token1, CancellationToken token2) + { + _reg1 = token1.InternalRegisterWithoutEC(LinkedNCancellationTokenSource.s_linkedTokenCancelDelegate, this); + _reg2 = token2.InternalRegisterWithoutEC(LinkedNCancellationTokenSource.s_linkedTokenCancelDelegate, this); } - internal LinkedCancellationTokenSource(params CancellationToken[] tokens) + protected override void Dispose(bool disposing) + { + if (!disposing || m_disposed) return; + _reg1.Dispose(); + _reg2.Dispose(); + base.Dispose(disposing); + } + } + + private sealed class LinkedNCancellationTokenSource : CancellationTokenSource + { + internal static readonly Action<object> s_linkedTokenCancelDelegate = + s => ((CancellationTokenSource)s).NotifyCancellation(throwOnFirstException: false); // skip ThrowIfDisposed() check in Cancel() + private CancellationTokenRegistration[] m_linkingRegistrations; + + internal LinkedNCancellationTokenSource(params CancellationToken[] tokens) { m_linkingRegistrations = new CancellationTokenRegistration[tokens.Length]; @@ -968,7 +993,6 @@ namespace System.Threading base.Dispose(disposing); } - } } |