// 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 void IOCallback(uint errorCode, uint numBytes, NativeOverlapped *pOverlapped)
        {
            // Extract the completion source from the overlapped.  The state in the overlapped
            // will either be a FileStreamStrategy (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 FileStreamCompletionSource that's completing (in the case where the preallocated
            // overlapped was already in use by another operation).
            object?state = ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped);

            Debug.Assert(state is IFileStreamCompletionSourceStrategy || state is FileStreamCompletionSource);
            FileStreamCompletionSource completionSource = state switch
            {
                IFileStreamCompletionSourceStrategy strategy => strategy.CurrentOverlappedOwner !, // must be owned
                                       _ => (FileStreamCompletionSource)state
            };

            Debug.Assert(completionSource != null);
            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 != ERROR_BROKEN_PIPE && errorCode != 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
        }
Ejemplo n.º 2
0
            // When doing IO asynchronously (ie, _isAsync==true), this callback is
            // called by a free thread in the threadpool when the IO operation
            // completes.
            unsafe private static void AsyncFSCallback(uint errorCode, uint numBytes, NativeOverlapped *pOverlapped)
            {
                // Unpack overlapped
                Overlapped overlapped = Threading.Overlapped.Unpack(pOverlapped);

                // Extract async result from overlapped
                FileStreamCompletionSource completionSource = (FileStreamCompletionSource)overlapped.AsyncResult;

                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
            }