Пример #1
0
        private async Task FlushOrDiscardBufferAndResetPositionAsync(StreamOperationToken token, BackgroundOperationSlot slot, long newPosition)
        {
            Contract.Requires(slot.Usability != StreamUsability.Broken);
            Analysis.IgnoreArgument(token);

            m_position = newPosition;
            await FlushOrDiscardBufferAsync(slot);

            lock (m_backgroundOperationLock)
            {
                // Buffer is now empty, and so its position should be in sync with the virtual position (recall how both begin at zero on stream open).
                m_bufferPosition = m_position;

                // Buffer position changed, so an end-of-file indication is no longer valid.
                if (m_usability == StreamUsability.EndOfFileReached)
                {
                    m_usability = StreamUsability.Usable;
                }
                else
                {
                    Contract.Assume(m_usability == StreamUsability.Usable, "m_usability == slot.Usability is not Broken");
                }
            }
        }
Пример #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));
            }
        }