/// <inheritdoc />
        public void OnCompletion(FileAsyncIOResult asyncIOResult)
        {
            lock (this)
            {
                Contract.Assume(m_pinningHandle.IsAllocated);
                m_pinningHandle.Free();
            }

            m_completion.SetResult(asyncIOResult);
        }
Beispiel #2
0
        void IIOCompletionTarget.OnCompletion(FileAsyncIOResult result)
        {
            // Note that this may be called on the same stack as StartBackgroundOperation (sync completion),
            Contract.Assume(result.Status != FileAsyncIOStatus.Pending);

            bool failed = result.Status == FileAsyncIOStatus.Failed;

            if (!failed)
            {
                // Note, that FileAsyncIOResult constructor can't enforce this check because in some other cases
                // 0 transfered bytes is ok for a successful IO operation.
                Contract.Assert(result.BytesTransferred > 0, "Zero bytes transferred is a failure indication (otherwise can be confused with EOF)");
            }

            TaskCompletionSource <BackgroundOperationSlot> completionSource;

            lock (m_backgroundOperationLock)
            {
                // Capture the completion source to use outside of the lock.
                completionSource = m_currentBackgroundOperationCompletionSource;

                switch (m_currentBackgroundOperation)
                {
                case StreamBackgroundOperation.Fill:
                    m_bufferPosition += result.BytesTransferred;
                    internalBuffer.FinishFillAndUnlock(numberOfBytesFilled: result.BytesTransferred);
                    break;

                case StreamBackgroundOperation.Flush:
                    m_bufferPosition += result.BytesTransferred;
                    internalBuffer.FinishFlushAndUnlock(numberOfBytesFlushed: result.BytesTransferred);
                    break;

                case StreamBackgroundOperation.None:
                    Contract.Assume(false, "Unexpected I/O completion (no background operation in progress)");
                    throw new InvalidOperationException("Unreachable");

                default:
                    throw Contract.AssertFailure("Unhandled StreamBackgroundOperation");
                }

                if (failed)
                {
                    StreamUsability newUsability;
                    if (result.ErrorIndicatesEndOfFile)
                    {
                        newUsability = StreamUsability.EndOfFileReached;
                    }
                    else
                    {
                        newUsability = StreamUsability.Broken;

                        m_brokenStreamException = new IOException(
                            "An error occurred while reading or writing to a file stream. The stream will no longer be usable.",
                            new NativeWin32Exception(result.Error));
                    }

                    m_usability = newUsability;
                }
                else
                {
                    Contract.Assume(m_usability == StreamUsability.Usable);
                }

                m_currentBackgroundOperation = StreamBackgroundOperation.None;
                m_currentBackgroundOperationCompletionSource = null;
            }

            // Since the lock is no longer held, it is safe to resume any waiters (note that they may run on this stack).
            if (completionSource != null)
            {
                completionSource.SetResult(new BackgroundOperationSlot(this));
            }
        }