< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Runtime.CancellationTokenSourceIOThreadTimer
Assembly: CoreWCF.NetTcp
File(s): /home/runner/work/CoreWCF/CoreWCF/src/Common/src/CoreWCF/Runtime/RecoverableTimeoutCancellationTokenSource.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 34
Coverable lines: 34
Total lines: 138
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 8
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%110%
SetCompletionCallback(...)100%110%
RegisterTokenSourceForCancellation(...)0%220%
CancelTokenSource(...)0%220%
OnTimer()0%440%
TimerCallback(...)100%110%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/Common/src/CoreWCF/Runtime/RecoverableTimeoutCancellationTokenSource.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Text;
 8using System.Threading;
 9using CoreWCF;
 10
 11namespace CoreWCF.Runtime
 12{
 13    internal class RecoverableTimeoutCancellationTokenSource : CancellationTokenSource
 14    {
 15        private TimeSpan _originalTimeout;
 16
 17        public RecoverableTimeoutCancellationTokenSource(TimeSpan timeout) : base()
 18        {
 19            if (timeout.TotalMilliseconds > int.MaxValue)
 20            {
 21                throw new ArgumentOutOfRangeException(nameof(timeout), $"Only TimeSpan's representing up to {int.MaxValu
 22            }
 23
 24            _originalTimeout = timeout;
 25        }
 26
 27        public RecoverableTimeoutCancellationTokenSource(int millisecondsDelay)
 28        {
 29            if (millisecondsDelay == Timeout.Infinite)
 30            {
 31                _originalTimeout = Timeout.InfiniteTimeSpan;
 32            }
 33            else
 34            {
 35                _originalTimeout = TimeSpan.FromMilliseconds(millisecondsDelay);
 36            }
 37        }
 38
 39        public override int GetHashCode()
 40        {
 41            return (int)_originalTimeout.TotalMilliseconds;
 42        }
 43
 44        internal static TimeSpan GetOriginalTimeout(CancellationToken token)
 45        {
 46            // Covers CancellationToken.None as well as any other non-cancellable token
 47            if (!token.CanBeCanceled)
 48            {
 49                return Timeout.InfiniteTimeSpan;
 50            }
 51
 52            return TimeSpan.FromMilliseconds(token.GetHashCode());
 53        }
 54    }
 55
 56    internal class CancellationTokenSourceIOThreadTimer : IOThreadTimer
 57    {
 058        private readonly List<CancellationTokenSource> _cancellationTokenSources = new List<CancellationTokenSource>();
 59        private bool _timerFired = false;
 60        private Action<object> _timerFiredCallback;
 61        private object _timerFiredState;
 62
 063        public CancellationTokenSourceIOThreadTimer() : base(TimerCallback, null, false)
 64        {
 065            Reinitialize(TimerCallback, this);
 066        }
 67
 68        public void SetCompletionCallback(Action<object> callback, object state)
 69        {
 070            _timerFiredCallback = Fx.ThunkCallback(callback);
 071            _timerFiredState = state;
 072        }
 73
 74        public void RegisterTokenSourceForCancellation(CancellationTokenSource cts)
 75        {
 76            // TODO: Consider if unregistering would be helpful. It would require
 77            // knowing that the CancellationToken is no longer needed.
 078            lock (_cancellationTokenSources)
 79            {
 080                if (!_timerFired)
 81                {
 082                    _cancellationTokenSources.Add(cts);
 083                    return;
 84                }
 085            }
 86
 87            // Timer has already fired so cancelling now.
 088            CancelTokenSource(cts);
 089        }
 90
 91        internal static void CancelTokenSource(object state)
 92        {
 093            var cts = (CancellationTokenSource)state;
 94            try
 95            {
 96                // Ensure all callbacks are fired
 097                cts.Cancel(throwOnFirstException: false);
 098                cts.Dispose();
 099            }
 100            catch (Exception e)
 101            {
 0102                if (Fx.IsFatal(e))
 103                {
 0104                    throw;
 105                }
 106                // Callbacks shouldn't be throwing
 0107                DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
 0108            }
 0109        }
 110
 111        internal void OnTimer()
 112        {
 0113            _timerFiredCallback(_timerFiredState);
 114
 0115            lock (_cancellationTokenSources)
 116            {
 0117                _timerFired = true;
 0118            }
 119            // Once _timerFired is set, there's no need to hold the lock as
 120            // no more will be added to the list.
 0121            foreach (CancellationTokenSource cts in _cancellationTokenSources)
 122            {
 123                // TODO: ActionItem.Schedule might be overkill here as I don't expect there
 124                // to be many cancellations. There's just no
 0125                if (!cts.IsCancellationRequested)
 126                {
 0127                    ActionItem.Schedule(CancelTokenSource, cts);
 128                }
 129            }
 0130        }
 131
 132        internal static void TimerCallback(object state)
 133        {
 0134            var thisPtr = (CancellationTokenSourceIOThreadTimer)state;
 0135            thisPtr.OnTimer();
 0136        }
 137    }
 138}