< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Runtime.RecoverableTimeoutCancellationTokenSource
Assembly: CoreWCF.MSMQ
File(s): /home/runner/work/CoreWCF/CoreWCF/src/Common/src/CoreWCF/Runtime/RecoverableTimeoutCancellationTokenSource.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 14
Coverable lines: 14
Total lines: 138
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 6
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(...)0%220%
.ctor(...)0%220%
GetHashCode()100%110%
GetOriginalTimeout(...)0%220%

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
 017        public RecoverableTimeoutCancellationTokenSource(TimeSpan timeout) : base()
 18        {
 019            if (timeout.TotalMilliseconds > int.MaxValue)
 20            {
 021                throw new ArgumentOutOfRangeException(nameof(timeout), $"Only TimeSpan's representing up to {int.MaxValu
 22            }
 23
 024            _originalTimeout = timeout;
 025        }
 26
 027        public RecoverableTimeoutCancellationTokenSource(int millisecondsDelay)
 28        {
 029            if (millisecondsDelay == Timeout.Infinite)
 30            {
 031                _originalTimeout = Timeout.InfiniteTimeSpan;
 32            }
 33            else
 34            {
 035                _originalTimeout = TimeSpan.FromMilliseconds(millisecondsDelay);
 36            }
 037        }
 38
 39        public override int GetHashCode()
 40        {
 041            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
 047            if (!token.CanBeCanceled)
 48            {
 049                return Timeout.InfiniteTimeSpan;
 50            }
 51
 052            return TimeSpan.FromMilliseconds(token.GetHashCode());
 53        }
 54    }
 55
 56    internal class CancellationTokenSourceIOThreadTimer : IOThreadTimer
 57    {
 58        private readonly List<CancellationTokenSource> _cancellationTokenSources = new List<CancellationTokenSource>();
 59        private bool _timerFired = false;
 60        private Action<object> _timerFiredCallback;
 61        private object _timerFiredState;
 62
 63        public CancellationTokenSourceIOThreadTimer() : base(TimerCallback, null, false)
 64        {
 65            Reinitialize(TimerCallback, this);
 66        }
 67
 68        public void SetCompletionCallback(Action<object> callback, object state)
 69        {
 70            _timerFiredCallback = Fx.ThunkCallback(callback);
 71            _timerFiredState = state;
 72        }
 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.
 78            lock (_cancellationTokenSources)
 79            {
 80                if (!_timerFired)
 81                {
 82                    _cancellationTokenSources.Add(cts);
 83                    return;
 84                }
 85            }
 86
 87            // Timer has already fired so cancelling now.
 88            CancelTokenSource(cts);
 89        }
 90
 91        internal static void CancelTokenSource(object state)
 92        {
 93            var cts = (CancellationTokenSource)state;
 94            try
 95            {
 96                // Ensure all callbacks are fired
 97                cts.Cancel(throwOnFirstException: false);
 98                cts.Dispose();
 99            }
 100            catch (Exception e)
 101            {
 102                if (Fx.IsFatal(e))
 103                {
 104                    throw;
 105                }
 106                // Callbacks shouldn't be throwing
 107                DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
 108            }
 109        }
 110
 111        internal void OnTimer()
 112        {
 113            _timerFiredCallback(_timerFiredState);
 114
 115            lock (_cancellationTokenSources)
 116            {
 117                _timerFired = true;
 118            }
 119            // Once _timerFired is set, there's no need to hold the lock as
 120            // no more will be added to the list.
 121            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
 125                if (!cts.IsCancellationRequested)
 126                {
 127                    ActionItem.Schedule(CancelTokenSource, cts);
 128                }
 129            }
 130        }
 131
 132        internal static void TimerCallback(object state)
 133        {
 134            var thisPtr = (CancellationTokenSourceIOThreadTimer)state;
 135            thisPtr.OnTimer();
 136        }
 137    }
 138}