コード例 #1
0
ファイル: AsyncFileStream.cs プロジェクト: kittinap/kunnjae
        /// <summary>
        /// Starts a background operation. This causes the <see cref="internalBuffer"/> to fill or flush.
        /// It must be ensured that no other background operation will be in progress, and that the stream is still usable after it.
        /// - First start an operation with <see cref="StartNewOperation"/>; this reserves the right to start the next background operation.
        /// - Then, wait for the current background operation, if any. We've established another one will not follow it due to the prior point.
        /// - Then, respond to the current stream usability (EOF, broken, etc.) as updated by the prior operation.
        /// </summary>
        private unsafe void StartBackgroundOperation(BackgroundOperationSlot slot, StreamBackgroundOperation nextOperation)
        {
            Contract.Requires(nextOperation != StreamBackgroundOperation.None);
            Analysis.IgnoreArgument(slot);

            lock (m_backgroundOperationLock)
            {
                if (m_usability != StreamUsability.Usable)
                {
                    Contract.Assume(false, "Attempting to start a background operation on an unusable stream: " + m_usability.ToString("G"));
                }

                Contract.Assume(
                    m_currentBackgroundOperation == StreamBackgroundOperation.None,
                    "Background operation already in progress; wait on it first?");
                Contract.Assume(m_currentBackgroundOperationCompletionSource == null);
                m_currentBackgroundOperation = nextOperation;
            }

            // Now actually start the async operation.
            // Note that the callback to 'this' (IIOCompletionTarget) can happen on this same stack
            byte *pinnedBuffer;
            int   operationLength;

            switch (nextOperation)
            {
            case StreamBackgroundOperation.Fill:
                internalBuffer.LockForFill(out pinnedBuffer, out operationLength);
                m_file.ReadOverlapped(this, pinnedBuffer, operationLength, m_bufferPosition);
                break;

            case StreamBackgroundOperation.Flush:
                internalBuffer.LockForFlush(out pinnedBuffer, out operationLength);
                m_file.WriteOverlapped(this, pinnedBuffer, operationLength, m_bufferPosition);
                break;

            default:
                throw Contract.AssertFailure("Unhandled StreamBackgroundOperation");
            }
        }
コード例 #2
0
ファイル: AsyncFileStream.cs プロジェクト: kittinap/kunnjae
 /// <summary>
 /// Starts a background operation. No background operations may be in progress;
 /// ensure that is not the case by waiting for background operation completion if one may be in progress.
 /// </summary>
 public void StartBackgroundOperation(StreamBackgroundOperation nextOperation) => m_stream.StartBackgroundOperation(this, nextOperation);
コード例 #3
0
ファイル: AsyncFileStream.cs プロジェクト: kittinap/kunnjae
        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));
            }
        }