// When doing IO asynchronously (i.e. _isAsync==true), this callback is
            // called by a free thread in the threadpool when the IO operation
            // completes.
            internal static unsafe void IOCallback(uint errorCode, uint numBytes, NativeOverlapped *pOverlapped)
            {
                // Extract the completion source from the overlapped.  The state in the overlapped
                // will either be a Win32FileStream (in the case where the preallocated overlapped was used),
                // in which case the operation being completed is its _currentOverlappedOwner, or it'll
                // be directly the FileStreamCompletion that's completing (in the case where the preallocated
                // overlapped was already in use by another operation).
                object                     state            = ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped);
                Win32FileStream            fs               = state as Win32FileStream;
                FileStreamCompletionSource completionSource = fs != null ?
                                                              fs._currentOverlappedOwner :
                                                              (FileStreamCompletionSource)state;

                Debug.Assert(completionSource._overlapped == pOverlapped, "Overlaps don't match");

                // Handle reading from & writing to closed pipes.  While I'm not sure
                // this is entirely necessary anymore, maybe it's possible for
                // an async read on a pipe to be issued and then the pipe is closed,
                // returning this error.  This may very well be necessary.
                ulong packedResult;

                if (errorCode != 0 && errorCode != Win32FileStream.ERROR_BROKEN_PIPE && errorCode != Win32FileStream.ERROR_NO_DATA)
                {
                    packedResult = ((ulong)ResultError | errorCode);
                }
                else
                {
                    packedResult = ((ulong)ResultSuccess | numBytes);
                }

                // Stow the result so that other threads can observe it
                // And, if no other thread is registering cancellation, continue
                if (NoResult == Interlocked.Exchange(ref completionSource._result, (long)packedResult))
                {
                    // Successfully set the state, attempt to take back the callback
                    if (Interlocked.Exchange(ref completionSource._result, CompletedCallback) != NoResult)
                    {
                        // Successfully got the callback, finish the callback
                        completionSource.CompleteCallback(packedResult);
                    }
                    // else: Some other thread stole the result, so now it is responsible to finish the callback
                }
                // else: Some other thread is registering a cancellation, so it *must* finish the callback
            }
            private long _result;                  // Using long since this needs to be used in Interlocked APIs

            // Using RunContinuationsAsynchronously for compat reasons (old API used Task.Factory.StartNew for continuations)
            internal FileStreamCompletionSource(Win32FileStream stream, int numBufferedBytes, byte[] bytes, CancellationToken cancellationToken)
                : base(TaskCreationOptions.RunContinuationsAsynchronously)
            {
                _numBufferedBytes  = numBufferedBytes;
                _stream            = stream;
                _result            = NoResult;
                _cancellationToken = cancellationToken;

                // Create the native overlapped. We try to use the preallocated overlapped if possible:
                // it's possible if the byte buffer is the same one that's associated with the preallocated overlapped
                // and if no one else is currently using the preallocated overlapped.  This is the fast-path for cases
                // where the user-provided buffer is smaller than the FileStream's buffer (such that the FileStream's
                // buffer is used) and where operations on the FileStream are not being performed concurrently.
                _overlapped = ReferenceEquals(bytes, _stream._buffer) && Interlocked.CompareExchange(ref _stream._currentOverlappedOwner, this, null) == null?
                              _stream._handle.ThreadPoolBinding.AllocateNativeOverlapped(_stream._preallocatedOverlapped) :
                                  _stream._handle.ThreadPoolBinding.AllocateNativeOverlapped(s_ioCallback, this, bytes);

                Debug.Assert(_overlapped != null, "AllocateNativeOverlapped returned null");
            }
Exemplo n.º 3
0
 public FileStream(Microsoft.Win32.SafeHandles.SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync)
 {
     _innerStream = new Win32FileStream(handle, access, bufferSize, isAsync, this);
 }