< Summary

Information
Class: Renci.SshNet.Common.AsyncResult
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Common\AsyncResult.cs
Line coverage
84%
Covered lines: 42
Uncovered lines: 8
Coverable lines: 50
Total lines: 158
Line coverage: 84%
Branch coverage
85%
Covered branches: 17
Total branches: 20
Branch coverage: 85%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
get_EndInvokeCalled()100%1100%
SetAsCompleted(...)75%880%
EndInvoke()100%4100%
get_AsyncState()100%1100%
get_CompletedSynchronously()100%1100%
get_AsyncWaitHandle()75%866.66%
get_IsCompleted()100%1100%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Threading;
 3
 4namespace Renci.SshNet.Common
 5{
 6    /// <summary>
 7    /// Base class to encapsulates the results of an asynchronous operation.
 8    /// </summary>
 9    public abstract class AsyncResult : IAsyncResult
 10    {
 11        private const int StatePending = 0;
 12
 13        private const int StateCompletedSynchronously = 1;
 14
 15        private const int StateCompletedAsynchronously = 2;
 16
 17        private readonly AsyncCallback _asyncCallback;
 18        private readonly object _asyncState;
 454819        private int _completedState = StatePending;
 20        private ManualResetEvent _asyncWaitHandle;
 21        private Exception _exception;
 22
 23        /// <summary>
 24        /// Initializes a new instance of the <see cref="AsyncResult"/> class.
 25        /// </summary>
 26        /// <param name="asyncCallback">The async callback.</param>
 27        /// <param name="state">The state.</param>
 454828        protected AsyncResult(AsyncCallback asyncCallback, object state)
 454829        {
 454830            _asyncCallback = asyncCallback;
 454831            _asyncState = state;
 454832        }
 33
 34        /// <summary>
 35        /// Gets a value indicating whether <see cref="EndInvoke()"/> has been called on the current <see cref="AsyncRes
 36        /// </summary>
 37        /// <value>
 38        /// <see langword="true"/> if <see cref="EndInvoke()"/> has been called on the current <see cref="AsyncResult"/>
 39        /// otherwise, <see langword="false"/>.
 40        /// </value>
 455341        public bool EndInvokeCalled { get; private set; }
 42
 43        /// <summary>
 44        /// Marks asynchronous operation as completed.
 45        /// </summary>
 46        /// <param name="exception">The exception.</param>
 47        /// <param name="completedSynchronously">If set to <see langword="true"/>, completed synchronously.</param>
 48        public void SetAsCompleted(Exception exception, bool completedSynchronously)
 431049        {
 50            // Passing null for exception means no error occurred; this is the common case
 431051            _exception = exception;
 52
 53            // The '_completedState' field MUST be set prior calling the callback
 431054            var prevState = Interlocked.Exchange(ref _completedState,
 431055                                                 completedSynchronously ? StateCompletedSynchronously : StateCompletedAs
 56
 431057            if (prevState != StatePending)
 058            {
 059                throw new InvalidOperationException("You can set a result only once");
 60            }
 61
 62            // If the event exists, set it
 431063            _ = _asyncWaitHandle?.Set();
 64
 65            // If a callback method was set, call it
 431066            _asyncCallback?.Invoke(this);
 431067        }
 68
 69        /// <summary>
 70        /// Waits until the asynchronous operation completes, and then returns.
 71        /// </summary>
 72        internal void EndInvoke()
 430373        {
 74            // This method assumes that only 1 thread calls EndInvoke for this object
 430375            if (!IsCompleted)
 1276            {
 77                // If the operation isn't done, wait for it
 1278                _ = AsyncWaitHandle.WaitOne();
 1279                _asyncWaitHandle = null;  // Allow early GC
 1280                AsyncWaitHandle.Dispose();
 1281            }
 82
 430383            EndInvokeCalled = true;
 84
 85            // Operation is done: if an exception occurred, throw it
 430386            if (_exception != null)
 4087            {
 4088                throw _exception;
 89            }
 426390        }
 91
 92        /// <summary>
 93        /// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
 94        /// </summary>
 95        /// <returns>
 96        /// A user-defined object that qualifies or contains information about an asynchronous operation.
 97        /// </returns>
 98        public object AsyncState
 99        {
 12090100            get { return _asyncState; }
 101        }
 102
 103        /// <summary>
 104        /// Gets a value indicating whether the asynchronous operation completed synchronously.
 105        /// </summary>
 106        /// <returns>
 107        /// <see langword="true"/> if the asynchronous operation completed synchronously; otherwise, <see langword="fals
 108        /// </returns>
 109        public bool CompletedSynchronously
 110        {
 24111            get { return _completedState == StateCompletedSynchronously; }
 112        }
 113
 114        /// <summary>
 115        /// Gets a <see cref="WaitHandle"/> that is used to wait for an asynchronous operation to complete.
 116        /// </summary>
 117        /// <returns>
 118        /// A <see cref="WaitHandle"/> that is used to wait for an asynchronous operation to complete.
 119        /// </returns>
 120        public WaitHandle AsyncWaitHandle
 121        {
 122            get
 232123            {
 232124                if (_asyncWaitHandle is null)
 231125                {
 231126                    var done = IsCompleted;
 231127                    var mre = new ManualResetEvent(done);
 231128                    if (Interlocked.CompareExchange(ref _asyncWaitHandle, mre, comparand: null) != null)
 0129                    {
 130                        // Another thread created this object's event; dispose the event we just created
 0131                        mre.Dispose();
 0132                    }
 133                    else
 231134                    {
 231135                        if (!done && IsCompleted)
 0136                        {
 137                            // If the operation wasn't done when we created the event but now it is done, set the event
 0138                            _ = _asyncWaitHandle.Set();
 0139                        }
 231140                    }
 231141                }
 142
 232143                return _asyncWaitHandle;
 232144            }
 145        }
 146
 147        /// <summary>
 148        /// Gets a value indicating whether the asynchronous operation has completed.
 149        /// </summary>
 150        /// <returns>
 151        /// <see langword="true"/> if the operation is complete; otherwise, <see langword="false"/>.
 152        /// </returns>
 153        public bool IsCompleted
 154        {
 15678155            get { return _completedState != StatePending; }
 156        }
 157    }
 158}