< Summary

Information
Class: Renci.SshNet.Common.SemaphoreLight
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Common\SemaphoreLight.cs
Line coverage
67%
Covered lines: 78
Uncovered lines: 38
Coverable lines: 116
Total lines: 244
Line coverage: 67.2%
Branch coverage
50%
Covered branches: 23
Total branches: 46
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)50%275%
get_CurrentCount()100%1100%
get_AvailableWaitHandle()100%4100%
Release()100%1100%
Release(...)100%4100%
Wait()66.66%680%
Wait(...)50%266.66%
Wait(...)0%60%
WaitWithTimeout(...)27.77%1838.46%
Dispose()100%1100%
Dispose(...)100%4100%

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Common\SemaphoreLight.cs

#LineLine coverage
 1using System;
 2using System.Threading;
 3
 4namespace Renci.SshNet.Common
 5{
 6    /// <summary>
 7    /// Light implementation of SemaphoreSlim.
 8    /// </summary>
 9    public sealed class SemaphoreLight : IDisposable
 10    {
 161811        private readonly object _lock = new object();
 12        private ManualResetEvent _waitHandle;
 13
 14        private int _currentCount;
 15
 16        /// <summary>
 17        /// Initializes a new instance of the <see cref="SemaphoreLight"/> class, specifying the initial number of reque
 18        /// be granted concurrently.
 19        /// </summary>
 20        /// <param name="initialCount">The initial number of requests for the semaphore that can be granted concurrently
 21        /// <exception cref="ArgumentOutOfRangeException"><paramref name="initialCount"/> is a negative number.</excepti
 161822        public SemaphoreLight(int initialCount)
 161823        {
 161824            if (initialCount < 0)
 025            {
 026                throw new ArgumentOutOfRangeException(nameof(initialCount), "The value cannot be negative.");
 27            }
 28
 161829            _currentCount = initialCount;
 161830        }
 31
 32        /// <summary>
 33        /// Gets the current count of the <see cref="SemaphoreLight"/>.
 34        /// </summary>
 35        public int CurrentCount
 36        {
 18037            get { return _currentCount; }
 38        }
 39
 40        /// <summary>
 41        /// Gets a <see cref="WaitHandle"/> that can be used to wait on the semaphore.
 42        /// </summary>
 43        /// <value>
 44        /// A <see cref="WaitHandle"/> that can be used to wait on the semaphore.
 45        /// </value>
 46        /// <remarks>
 47        /// A successful wait on the <see cref="AvailableWaitHandle"/> does not imply a successful
 48        /// wait on the <see cref="SemaphoreLight"/> itself. It should be followed by a true wait
 49        /// on the semaphore.
 50        /// </remarks>
 51        public WaitHandle AvailableWaitHandle
 52        {
 53            get
 22054            {
 22055                if (_waitHandle is null)
 22056                {
 22057                    lock (_lock)
 22058                    {
 22059                        _waitHandle ??= new ManualResetEvent(_currentCount > 0);
 22060                    }
 22061                }
 62
 22063                return _waitHandle;
 22064            }
 65        }
 66
 67        /// <summary>
 68        /// Exits the <see cref="SemaphoreLight"/> once.
 69        /// </summary>
 70        /// <returns>The previous count of the <see cref="SemaphoreLight"/>.</returns>
 71        public int Release()
 797272        {
 797273            return Release(1);
 797274        }
 75
 76        /// <summary>
 77        /// Exits the <see cref="SemaphoreLight"/> a specified number of times.
 78        /// </summary>
 79        /// <param name="releaseCount">The number of times to exit the semaphore.</param>
 80        /// <returns>
 81        /// The previous count of the <see cref="SemaphoreLight"/>.
 82        /// </returns>
 83        public int Release(int releaseCount)
 797884        {
 797885            lock (_lock)
 797886            {
 797887                var oldCount = _currentCount;
 88
 797889                _currentCount += releaseCount;
 90
 91                // signal waithandle when the original semaphore count was zero
 797892                if (_waitHandle != null && oldCount == 0)
 218993                {
 218994                    _ = _waitHandle.Set();
 218995                }
 96
 797897                Monitor.PulseAll(_lock);
 98
 797899                return oldCount;
 100            }
 7978101        }
 102
 103        /// <summary>
 104        /// Blocks the current thread until it can enter the <see cref="SemaphoreLight"/>.
 105        /// </summary>
 106        public void Wait()
 3887107        {
 3887108            lock (_lock)
 3887109            {
 6642110                while (_currentCount < 1)
 2755111                {
 2755112                    _ = Monitor.Wait(_lock);
 2755113                }
 114
 3887115                _currentCount--;
 116
 117                // unsignal waithandle when the semaphore count reaches zero
 3887118                if (_waitHandle != null && _currentCount == 0)
 0119                {
 0120                    _ = _waitHandle.Reset();
 0121                }
 122
 3887123                Monitor.PulseAll(_lock);
 3887124            }
 3887125        }
 126
 127        /// <summary>
 128        /// Blocks the current thread until it can enter the <see cref="SemaphoreLight"/>, using a 32-bit signed
 129        /// integer that specifies the timeout.
 130        /// </summary>
 131        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Infinite(-1) to wait indefinitely.<
 132        /// <returns>
 133        /// <see langword="true"/> if the current thread successfully entered the <see cref="SemaphoreLight"/>; otherwis
 134        /// </returns>
 135        public bool Wait(int millisecondsTimeout)
 4202136        {
 4202137            if (millisecondsTimeout < -1)
 0138            {
 0139                throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), "The timeout must represent a value b
 140            }
 141
 4202142            return WaitWithTimeout(millisecondsTimeout);
 4202143        }
 144
 145        /// <summary>
 146        /// Blocks the current thread until it can enter the <see cref="SemaphoreLight"/>, using a <see cref="TimeSpan"/
 147        /// to specify the timeout.
 148        /// </summary>
 149        /// <param name="timeout">A <see cref="TimeSpan"/> that represents the number of milliseconds to wait, or a <see
 150        /// <returns>
 151        /// <see langword="true"/> if the current thread successfully entered the <see cref="SemaphoreLight"/>; otherwis
 152        /// </returns>
 153        public bool Wait(TimeSpan timeout)
 0154        {
 0155            var timeoutInMilliseconds = timeout.TotalMilliseconds;
 0156            if (timeoutInMilliseconds is < -1d or > int.MaxValue)
 0157            {
 0158                throw new ArgumentOutOfRangeException(nameof(timeout), "The timeout must represent a value between -1 an
 159            }
 160
 0161            return WaitWithTimeout((int) timeoutInMilliseconds);
 0162        }
 163
 164        private bool WaitWithTimeout(int timeoutInMilliseconds)
 4202165        {
 4202166            lock (_lock)
 4202167            {
 4202168                if (timeoutInMilliseconds == Session.Infinite)
 0169                {
 0170                    while (_currentCount < 1)
 0171                    {
 0172                        _ = Monitor.Wait(_lock);
 0173                    }
 0174                }
 175                else
 4202176                {
 4202177                    if (_currentCount < 1)
 0178                    {
 0179                        if (timeoutInMilliseconds > 0)
 0180                        {
 0181                            return false;
 182                        }
 183
 0184                        var remainingTimeInMilliseconds = timeoutInMilliseconds;
 0185                        var startTicks = Environment.TickCount;
 186
 0187                        while (_currentCount < 1)
 0188                        {
 0189                            if (!Monitor.Wait(_lock, remainingTimeInMilliseconds))
 0190                            {
 0191                                return false;
 192                            }
 193
 0194                            var elapsed = Environment.TickCount - startTicks;
 0195                            remainingTimeInMilliseconds -= elapsed;
 0196                            if (remainingTimeInMilliseconds < 0)
 0197                            {
 0198                                return false;
 199                            }
 0200                        }
 0201                    }
 4202202                }
 203
 4202204                _currentCount--;
 205
 206                // unsignal waithandle when the semaphore count is zero
 4202207                if (_waitHandle != null && _currentCount == 0)
 2269208                {
 2269209                    _ = _waitHandle.Reset();
 2269210                }
 211
 4202212                Monitor.PulseAll(_lock);
 213
 4202214                return true;
 215            }
 4202216        }
 217
 218        /// <summary>
 219        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
 220        /// </summary>
 221        public void Dispose()
 115222        {
 115223            Dispose(disposing: true);
 115224            GC.SuppressFinalize(this);
 115225        }
 226
 227        /// <summary>
 228        /// Releases unmanaged and - optionally - managed resources.
 229        /// </summary>
 230        /// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langwor
 231        private void Dispose(bool disposing)
 115232        {
 115233            if (disposing)
 115234            {
 115235                var waitHandle = _waitHandle;
 115236                if (waitHandle is not null)
 115237                {
 115238                    waitHandle.Dispose();
 115239                    _waitHandle = null;
 115240                }
 115241            }
 115242        }
 243    }
 244}